C#通过NetworkStream / TCPClient流式传输视频 [英] C# Streaming video over NetworkStream / TCPClient

查看:161
本文介绍了C#通过NetworkStream / TCPClient流式传输视频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从Xbox Kinect将视频提要从客户端程序发送到服务器。我一切正常,但问题是帧速率。我在想发生了什么事,就是它的发送速度快于其读取速度。因此,当它不再发送时,它将存储要发送的内容,并等待直到缓冲区中有足够的空间。我认为这是正在发生的原因是因为我可以看到程序的内存使用量正在稳定增长。另外,因为当我观看视频Feed时,可以看到大约10秒钟前发生的所有事件,并且播放速度较慢,但​​是不会跳过任何帧。因此,我要做的就是将帧速率降低到5 fps,这是稳定的。但这不是最好的方法。我想做的是,当缓冲区已满时,只需跳过该帧,然后等待直到缓冲区上有空间发送帧即可。听起来像是问题所在,如果是,该如何解决?谢谢。

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

我调查了使用Socket.Available属性(http http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.available.aspx)以查看缓冲区上有多少数据,但似乎永远不会满。

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.

推荐答案

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

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.

这篇关于C#通过NetworkStream / TCPClient流式传输视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆