Improve tolerance to dropped packets

This commit is contained in:
Cameron Gutman 2014-07-31 15:20:43 -07:00
parent cbe40fde92
commit 2d55562dd3

View File

@ -19,6 +19,7 @@ public class VideoDepacketizer {
private int nextFrameNumber = 1; private int nextFrameNumber = 1;
private int startFrameNumber = 1; private int startFrameNumber = 1;
private boolean waitingForNextSuccessfulFrame; private boolean waitingForNextSuccessfulFrame;
private boolean waitingForIdrFrame = true;
private long frameStartTime; private long frameStartTime;
private boolean decodingFrame; private boolean decodingFrame;
@ -131,6 +132,11 @@ public class VideoDepacketizer {
// Setup state for the new NAL // Setup state for the new NAL
avcFrameDataChain = new LinkedList<ByteBufferDescriptor>(); avcFrameDataChain = new LinkedList<ByteBufferDescriptor>();
avcFrameDataLength = 0; avcFrameDataLength = 0;
if (cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x65) {
// This is the NALU code for I-frame data
waitingForIdrFrame = false;
}
} }
// Skip the start sequence // Skip the start sequence
@ -227,16 +233,22 @@ public class VideoDepacketizer {
return; return;
} }
// Drop packets from a previously completed frame
if (frameIndex < nextFrameNumber) {
return;
}
// Look for a frame start before receiving a frame end // Look for a frame start before receiving a frame end
if (firstPacket && decodingFrame) if (firstPacket && decodingFrame)
{ {
LimeLog.warning("Network dropped end of a frame"); LimeLog.warning("Network dropped end of a frame");
nextFrameNumber = frameIndex + 1; nextFrameNumber = frameIndex;
// Unexpected start of next frame before terminating the last // Unexpected start of next frame before terminating the last
waitingForNextSuccessfulFrame = true; waitingForNextSuccessfulFrame = true;
waitingForIdrFrame = true;
// Clear the old state and decode this frame // Clear the old state and wait for an IDR
clearAvcFrameState(); clearAvcFrameState();
decodingFrame = true; decodingFrame = true;
} }
@ -251,6 +263,8 @@ public class VideoDepacketizer {
nextFrameNumber = frameIndex + 1; nextFrameNumber = frameIndex + 1;
waitingForNextSuccessfulFrame = true; waitingForNextSuccessfulFrame = true;
waitingForIdrFrame = true;
clearAvcFrameState(); clearAvcFrameState();
decodingFrame = false; decodingFrame = false;
return; return;
@ -266,10 +280,11 @@ public class VideoDepacketizer {
// Make sure this is the next consecutive frame // Make sure this is the next consecutive frame
if (nextFrameNumber < frameIndex) { if (nextFrameNumber < frameIndex) {
LimeLog.warning("Network dropped an entire frame"); LimeLog.warning("Network dropped an entire frame");
nextFrameNumber = frameIndex + 1; nextFrameNumber = frameIndex;
// Decode this one and hope for the best // Wait until an IDR frame comes
waitingForNextSuccessfulFrame = true; waitingForNextSuccessfulFrame = true;
waitingForIdrFrame = true;
clearAvcFrameState(); clearAvcFrameState();
} }
else if (nextFrameNumber > frameIndex){ else if (nextFrameNumber > frameIndex){
@ -277,10 +292,6 @@ public class VideoDepacketizer {
decodingFrame = false; decodingFrame = false;
return; return;
} }
else {
// This will be the next expected frame
nextFrameNumber = frameIndex + 1;
}
// We're now decoding a frame // We're now decoding a frame
decodingFrame = true; decodingFrame = true;
@ -295,6 +306,8 @@ public class VideoDepacketizer {
nextFrameNumber = frameIndex + 1; nextFrameNumber = frameIndex + 1;
waitingForNextSuccessfulFrame = true; waitingForNextSuccessfulFrame = true;
waitingForIdrFrame = true;
clearAvcFrameState(); clearAvcFrameState();
decodingFrame = false; decodingFrame = false;
@ -324,15 +337,28 @@ public class VideoDepacketizer {
} }
if ((flags & VideoPacket.FLAG_EOF) != 0) { if ((flags & VideoPacket.FLAG_EOF) != 0) {
reassembleAvcFrame(packet.getFrameIndex()); // Move on to the next frame
decodingFrame = false; decodingFrame = false;
nextFrameNumber = frameIndex + 1;
// If waiting for next successful frame and we got here
// with an end flag, we can send a message to the server
if (waitingForNextSuccessfulFrame) { if (waitingForNextSuccessfulFrame) {
// This is the next successful frame after a loss event // This is the next successful frame after a loss event
controlListener.connectionDetectedFrameLoss(startFrameNumber, nextFrameNumber - 1); controlListener.connectionDetectedFrameLoss(startFrameNumber, nextFrameNumber - 1);
waitingForNextSuccessfulFrame = false; waitingForNextSuccessfulFrame = false;
} }
// If we need an IDR frame first, then drop this frame
if (waitingForIdrFrame) {
LimeLog.warning("Waiting for IDR frame");
clearAvcFrameState();
return;
}
reassembleAvcFrame(frameIndex);
startFrameNumber = nextFrameNumber; startFrameNumber = nextFrameNumber;
} }
} }