2012-03-09 3 views
0

Я отправляю видеоролик из Xbox Kinect из клиентской программы на сервер. У меня все работает, но проблема в частоте кадров. Я думаю, что происходит, это передача быстрее, чем может быть прочитана. Поэтому, когда он больше не может отправлять, он сохраняет то, что собирается отправить, и ждет, пока в буфере не останется место. Причина, по которой я думаю, это то, что происходит, потому что я вижу, что использование памяти в программе постоянно растет. Также потому, что, когда я смотрю видеоролик, я вижу все, что произошло около 10 секунд назад, и более медленное воспроизведение, но оно не пропускает никаких кадров. Итак, что я сделал, это уменьшить частоту кадров до 5 кадров в секунду, когда я делаю, что он устойчив. Но это не лучший способ сделать это. То, что я хочу сделать, - это когда буфер заполнен, просто пропустите этот кадр и подождите, пока в буфере не будет места для отправки фрейма. Это звучит так, как будто это может быть проблемой, и если да, то как мне ее исправить? Благодарю.C# Потоковое видео через NetworkStream/TCPClient

Вот код отправки и получения данных.

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), чтобы увидеть, как много данных находится в буфере, но, похоже, он никогда не будет полным.

+0

Вы можете объяснить, что вы имеете в виду при отправке одного кадра за раз? не могли бы вы опубликовать код? –

ответ

0

TCP может оказаться неэффективным в этой задаче. Вы должны использовать бесконтактную и ненадежную передачу с UDP (сокетами дейтаграмм). Из-за того, что TCP требует подключения и обеспечивает безопасность, он медленнее, чем UDP, и поэтому он не должен использоваться во время потоковой передачи видео.

+0

Я думаю, что вы правы, я просто не хотел изучать, как использовать UDP, но мне, возможно, придется это сделать. – Rickyman35

+1

В итоге я получил его для работы с TCP. Решение заключалось в том, чтобы разрезать разрешение кадра и убедиться, что я отправляю только один кадр за раз. Поскольку я отправлял новый поток, он позволял мне отправлять несколько кадров одновременно, что вызывало мои проблемы. – Rickyman35

+0

На самом деле чаще используется TCP, чем UDP для потоковой передачи видео. Например, Adobe Flash Player (используемый YouTube среди других) использует TCP для потокового видео. Эффективность достигается за счет сведения к минимуму количества отправленных данных. Вместо отправки всего кадра каждое сообщение, он отправляет «ключевой кадр», который представляет полный кадр, а затем отправляет сообщения, которые обновляют визуальные изображения относительно этого ключевого кадра. Время от времени посылается новый ключевой кадр, и следующие сообщения обновляются по сравнению с последним ключевым кадром. – blachniet

Смежные вопросы