C#通过NetworkStream/TCPClient流式传输视频

本文关键字:传输 视频 TCPClient 通过 NetworkStream | 更新日期: 2023-09-27 18:27:16

我正在将Xbox Kinect的视频馈送从客户端程序发送到服务器。我有一切工作,但问题是帧速率。我在想,现在发生的事情是它发送的速度快于读取的速度。因此,当它不能再发送时,它会存储要发送的内容,并等待缓冲区中有空间。我之所以认为这是正在发生的事情,是因为我可以看到程序的内存使用量稳步增长。也因为当我观看视频时,我看到了大约10秒前发生的一切,播放速度较慢,但没有跳过任何帧。所以我所做的是将帧速率降低到每秒5帧,当我这样做的时候,它是稳定的。但这不是最好的方法。我想做的是,当缓冲区满了时,跳过那个帧,等到缓冲区有空间发送帧。这听起来可能是问题所在吗?如果是,我该如何解决?谢谢

这是发送和接收数据的代码。

    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();
        }
    }

我研究过使用Socket.Available属性(http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.available.aspx)看看缓冲区上有多少数据,但它似乎永远不会满。

C#通过NetworkStream/TCPClient流式传输视频

TCP在该任务中可能效率低下。您应该使用UDP(数据报套接字)进行无连接且不可靠的传输。由于TCP需要连接并提供安全性,它比UDP慢,因此在视频流传输过程中不应优先使用它。