C# Streaming video over NetworkStream / TCPClient

不问归期 提交于 2019-12-13 07:13:07

问题


I am sending a video feed from an Xbox Kinect from a client program to a server. I have everything working but the problem is the frame rate. I'm thinking what is happening is it is sending faster than it can read. So when it can't send anymore it stores what it is about to send and waits until there is room in the buffer. The reason I think this is what is happening is because I can see the memory usage of the program steadily growing. Also because when I watch the video feed, I see everything that happened about 10 seconds ago and on a slower play back but it's not skipping any frames. So what I have done is decrease the frame rate to 5 fps, when I do that it is steady. But this is not the best way to do it. What I want to do is when the buffer is full just skip that frame and wait until there is room on the buffer to send a frame. Does this sound like it could be the problem, and if so how should I fix it? Thanks.

Here is the code from sending and receiving data.

    private const int constChunkSize = 4096;
    private const int constIntSize = 4;

    protected TcpClient tcpObject;
    protected NetworkStream tcpStream;

    private void HandleComm()
    {
        try
        {
            tcpStream = tcpObject.GetStream();
            byte[] totalByteAray = new byte[constIntSize];
            byte[] message = new byte[constChunkSize];
            byte[] fullMessage = new byte[0];

            //this is how many bytes long the message will be
            int totalBytes = 0;
            int currentBytes = 0;
            int chunkSize = constChunkSize;
            int bytesRead = 0;

            pingThread = new Thread(sendPing);
            pingThread.Start();

            while (true)
            {                    
                //skip reading if no data is available
                //DataAvailable does not tell you when all the data has arrived
                //it just tell you if some data has arrived
                if (tcpStream.CanRead)
                {
                    totalBytes = 0;
                    currentBytes = 0;
                    message = new byte[constChunkSize];
                    chunkSize = constChunkSize;
                    bytesRead = 0;

                    //The first 4 bytes of the message will always contain the length of the message, not including
                    //the first 4 bytes. This is how you know when to stop reading.                                                
                    bytesRead = tcpStream.Read(totalByteAray, 0, constIntSize);
                    if (bytesRead == 0)                        
                        Disconnect();                        
                    //there are 4 bytes in a 32 bit number, so totalByteArrayContains 4 index that is a byte which is
                    //the 32 bit int that tells us how many bytes the whole message will be.
                    //now convert the totalByteArray to a 32bit int
                    totalBytes = BitConverter.ToInt32(totalByteAray, 0);
                    //fullMessage will contain the entire message but it has to be built message by message.                    
                    fullMessage = new byte[totalBytes];
                    //keep reading until we get all the data
                    while (currentBytes < totalBytes)
                    {
                        //when you send something over TCP it will some times get split up
                        //this is why you only read in chuncks, 4096 is a safe amount of bytes
                        //to split the data into.
                        if (totalBytes - currentBytes < constChunkSize)
                        {
                            chunkSize = totalBytes - currentBytes;
                            message = new byte[chunkSize];
                        }

                        bytesRead = tcpStream.Read(message, 0, chunkSize);
                        if (bytesRead == 0)                            
                            Disconnect();                            
                        //since we know each chunk will always come in at 4096 bytes if it doesn't that means that it's the end
                        //this part cuts off the extra empty bytes                           

                        //copy the message to fullMessage starting at current bytes and ending with the bytes left
                        message.CopyTo(fullMessage, currentBytes);
                        currentBytes += bytesRead;                            
                    }

                    //message has successfully been received
                    if (totalBytes != 0)
                    {
                        //if the message was a ping handle it here to reduce the size of the packet
                        if (fullMessage.Length == 1 && (fullMessage[0] == 0 || fullMessage[0] == 255))
                        {
                            //if the message matches your ping byte, then it's yours
                            if (fullMessage[0] == pingByte[0])
                            {
                                lastReceivedPing = DateTime.Now;
                                latency = (lastReceivedPing - lastSentPing).TotalMilliseconds;

                                if (OnPingReceived != null)
                                {
                                    PingReceivedArgs args = new PingReceivedArgs();
                                    args.receivedTime = lastReceivedPing;
                                    args.latency = latency;
                                    OnPingReceived(this, args);
                                }
                            }
                            //if it doesn't then send it off
                            else
                            {
                                sendData(fullMessage);
                            }
                        }
                        //if it's anything else pass it on
                        else
                        {
                            if (OnRawDataReceived != null)
                            {
                                RawDataReceivedArgs args = new RawDataReceivedArgs();
                                args.Data = new byte[fullMessage.Length];
                                fullMessage.CopyTo(args.Data, 0);
                                OnRawDataReceived(this, args);
                            }
                        }
                        totalBytes = 0;
                    }
                }
            }
        }
        catch
        {
            Disconnect();
        }
    }

    protected void sendData(byte[] data)
    {
        try
        {
            //we need to know how big the data that we are sending will be
            int length = data.Length;
            //convert the 32bit int to a 4 byte array
            byte[] lengthArray = BitConverter.GetBytes(length);

            //init the main byte array that will be sent over
            byte[] buffer = new byte[length + constIntSize];

            //the first 4 bytes will contain the length of the data
            lengthArray.CopyTo(buffer, 0);

            //the rest of the buffer will contain the data being sent
            data.CopyTo(buffer, constIntSize);

            tcpStream.BeginWrite(buffer, 0, buffer.Length, new AsyncCallback(sendingData), tcpStream);
        }
        catch
        {
            Disconnect();
        }
    }

I looked into using the Socket.Available property (http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.available.aspx) to see how much data is on the buffer but it seems to never be full.


回答1:


TCP might be inefficient in this task. You should use the connectionless and not reliable transfer with UDP (datagram sockets). Because of TCP requires connection and provides security, it is slower than UDP and therefore it should not be preffered during a video streaming.



来源:https://stackoverflow.com/questions/9627242/c-sharp-streaming-video-over-networkstream-tcpclient

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!