2012-03-09 8 views
0

Xbox Kinectからクライアントプログラムからサーバーへのビデオフィードを送信しています。私はすべてが動作しているが、問題はフレームレートです。私は起こっていることが、それが読むことができるよりも速く送信していると思っています。だからそれ以上送信することができないときには、それはバッファに空きがあるまで、それは送信しようとしているものを保存し、待機します。これが起こっていると思うのは、プログラムのメモリ使用量が着実に増えていることがわかるからです。また、私がビデオフィードを見ると、約10秒前と遅い再生で起こったことがすべて表示されますが、フレームはスキップされません。だから私がやったことは、フレームレートを5 fpsに下げることです。しかし、これはそれを行う最良の方法ではありません。私がしたいのは、バッファがいっぱいになってそのフレームをスキップし、バッファにフレームを送る余地があるまで待つことです。これは問題のように聞こえますか?それではどうすればいいですか?ありがとう。C#NetworkStream/TCPClientを介したビデオストリーミング

ここには、データを送受信するコードがあります。私はどのくらいのデータを見ることがSocket.Availableプロパティ(http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.available.aspx)を使用して、に見えた

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

バッファー上にありますが、決して満杯にならないようです。

+0

一度に1つのフレームを送信することの意味を説明できますか?コードを投稿してもよろしいですか? –

答えて

0

このタスクでは、TCPが非効率的な場合があります。 UDP(データグラムソケット)を使用したコネクションレスで信頼できない転送を使用する必要があります。 TCPは接続を必要とし、セキュリティを提供するため、UDPよりも遅いため、ビデオストリーミング中に優先されるべきではありません。

+0

私はあなたが正しいと思います、私はちょうどUDPを使用する方法を学ぶ必要はありませんが、私はする必要があります。 – Rickyman35

+1

私はそれがTCPで動作するようになった。解決策は、フレームの解像度をカットし、一度に1つのフレームしか送信しないようにすることでした。新しいスレッドを送信していたので、一度に複数のフレームを送信して問題を引き起こしていました。 – Rickyman35

+0

実際には、ストリーミングビデオにU​​DPよりもTCPを使用する方が一般的です。たとえば、Adobe Flash Player(YouTubeなどで使用されている)はTCPを使用して動画をストリーミングします。送信されるデータの量を最小限に抑えることによって効率が向上します。メッセージごとにフレーム全体を送信するのではなく、フルフレームを表す「キーフレーム」を送信し、そのキーフレームに関連してビジュアルを更新するメッセージを送信します。毎回新しいキーフレームが送信され、次のメッセージは最後のキーフレームに関連して更新されます。 – blachniet