问题
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();
}
}
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.
回答1:
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.
来源:https://stackoverflow.com/questions/9627242/c-sharp-streaming-video-over-networkstream-tcpclient