2012-03-09 5 views
0

클라이언트 프로그램에서 서버로 Xbox Kinect의 비디오 피드를 보내고 있습니다. 모든 것이 작동하지만 문제는 프레임 속도입니다. 무슨 일이 일어나고 있는지 나는 그것이 읽을 수있는 것보다 빨리 보내고 있다고 생각하고있다. 그래서 더 이상 보낼 수 없게되면 버퍼에 공간이 생길 때까지 보낼 내용을 저장하고 기다립니다. 이것이 내가 생각하는 이유는 꾸준히 성장하는 프로그램의 메모리 사용량을 볼 수 있기 때문입니다. 또한 내가 비디오 피드를 볼 때 약 10 초 전에 일어난 모든 일들과 더 느린 플레이 백을 볼 수 있기 때문에 어떤 프레임도 건너 뛰지는 않습니다. 그래서 내가 한 것은 프레임 속도를 5fps로 줄이는 것입니다. 그렇게 할 때 안정적입니다. 그러나 이것이 최선의 방법은 아닙니다. 내가 원하는 것은 버퍼가 꽉 차서 프레임을 건너 뛰고 프레임을 보낼 버퍼가있을 때까지 기다리는 것입니다. 문제가 될 수있는 것처럼 들리지만, 그렇다면 어떻게 수정해야합니까? 감사.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

실제로 스트리밍 비디오에 UDP보다 TCP를 사용하는 것이 더 일반적입니다. 예를 들어, Adobe Flash Player (YouTube에서 다른 사람들과 함께 사용)는 TCP를 사용하여 비디오를 스트리밍합니다. 전송되는 데이터의 양을 최소화하여 효율성을 얻습니다. 모든 메시지를 전체 메시지로 보내는 대신 전체 프레임을 나타내는 "키 프레임"을 보낸 다음 해당 키 프레임을 기준으로 비주얼을 업데이트하는 메시지를 보냅니다. 가끔씩 새 키 프레임이 전송되고 다음 메시지는 마지막 키 프레임을 기준으로 업데이트됩니다. – blachniet

관련 문제