diff --git a/src/modules/video_coding/main/source/jitter_buffer.cc b/src/modules/video_coding/main/source/jitter_buffer.cc index 5cc92b165..191857342 100644 --- a/src/modules/video_coding/main/source/jitter_buffer.cc +++ b/src/modules/video_coding/main/source/jitter_buffer.cc @@ -298,7 +298,7 @@ VCMJitterBuffer::ReleaseFrameInternal(VCMFrameBuffer* frame) // Doing it here increases the degree of freedom for e.g. future // reconstructability of separate layers. Must be called under the // critical section _critSect. -void +VCMFrameBufferEnum VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame) { if (frame == NULL) @@ -306,7 +306,7 @@ VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame) WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), "JB(0x%x) FB(0x%x): " "UpdateFrameState NULL frame pointer", this, frame); - return; + return kNoError; } int length = frame->Length(); @@ -350,11 +350,11 @@ VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame) _dropCount, _numConsecutiveOldFrames); // Flush() if this happens consistently. _numConsecutiveOldFrames++; - if (_numConsecutiveOldFrames > kMaxConsecutiveOldFrames) - { - FlushInternal(); + if (_numConsecutiveOldFrames > kMaxConsecutiveOldFrames) { + FlushInternal(); + return kFlushIndicator; } - return; + return kNoError; } _numConsecutiveOldFrames = 0; frame->SetState(kStateComplete); @@ -405,6 +405,7 @@ VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame) { _frameEvent.Set(); } + return kNoError; } // Get received key and delta frames @@ -451,6 +452,8 @@ VCMJitterBuffer::GetFrame(const VCMPacket& packet, VCMEncodedFrame*& frame) if (_numConsecutiveOldPackets > kMaxConsecutiveOldPackets) { FlushInternal(); + _critSect.Leave(); + return VCM_FLUSH_INDICATOR; } _critSect.Leave(); return VCM_OLD_PACKET_ERROR; @@ -1697,7 +1700,9 @@ VCMJitterBuffer::InsertPacket(VCMEncodedFrame* buffer, const VCMPacket& packet) } case kCompleteSession: { - UpdateFrameState(frame); + // Only update return value for a JB flush indicator. + if (UpdateFrameState(frame) == kFlushIndicator) + ret = kFlushIndicator; // Signal that we have a received packet _packetEvent.Set(); break; @@ -1719,8 +1724,7 @@ VCMJitterBuffer::InsertPacket(VCMEncodedFrame* buffer, const VCMPacket& packet) assert(!"JitterBuffer::InsertPacket: Undefined value"); } } - - return ret; + return ret; } // Must be called from within _critSect diff --git a/src/modules/video_coding/main/source/jitter_buffer.h b/src/modules/video_coding/main/source/jitter_buffer.h index 2a5a5054a..467552866 100644 --- a/src/modules/video_coding/main/source/jitter_buffer.h +++ b/src/modules/video_coding/main/source/jitter_buffer.h @@ -145,7 +145,7 @@ private: bool RecycleFramesUntilKeyFrame(); // Update frame state // (set as complete or reconstructable if conditions are met) - void UpdateFrameState(VCMFrameBuffer* frameListItem); + VCMFrameBufferEnum UpdateFrameState(VCMFrameBuffer* frameListItem); // Help functions for getting a frame // Find oldest complete frame, used for getting next frame to decode diff --git a/src/modules/video_coding/main/source/jitter_buffer_common.h b/src/modules/video_coding/main/source/jitter_buffer_common.h index 167399d41..cbcf1e306 100644 --- a/src/modules/video_coding/main/source/jitter_buffer_common.h +++ b/src/modules/video_coding/main/source/jitter_buffer_common.h @@ -33,12 +33,13 @@ enum VCMJitterBufferEnum enum VCMFrameBufferEnum { kStateError = -4, + kFlushIndicator = -3, // Indicator that a flush has occurred. kTimeStampError = -2, kSizeError = -1, kNoError = 0, kIncomplete = 1, // Frame incomplete kFirstPacket = 2, - kCompleteSession = 3, // at least one layer in the frame complete + kCompleteSession = 3, // at least one layer in the frame complete. kDecodableSession = 4, // Frame incomplete, but ready to be decoded kDuplicatePacket = 5 // We're receiving a duplicate packet. }; diff --git a/src/modules/video_coding/main/source/receiver.cc b/src/modules/video_coding/main/source/receiver.cc index 9137c8912..92fdb13f5 100644 --- a/src/modules/video_coding/main/source/receiver.cc +++ b/src/modules/video_coding/main/source/receiver.cc @@ -112,10 +112,11 @@ VCMReceiver::InsertPacket(const VCMPacket& packet, { // Only trace the primary receiver to make it possible // to parse and plot the trace file. - WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), - "Packet seqNo %u of frame %u at %u", - packet.seqNum, packet.timestamp, - MaskWord64ToUWord32(VCMTickTime::MillisecondTimestamp())); + WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, + VCMId(_vcmId, _receiverId), + "Packet seqNo %u of frame %u at %u", + packet.seqNum, packet.timestamp, + MaskWord64ToUWord32(VCMTickTime::MillisecondTimestamp())); } const WebRtc_Word64 nowMs = VCMTickTime::MillisecondTimestamp(); @@ -128,7 +129,7 @@ VCMReceiver::InsertPacket(const VCMPacket& packet, // the incoming video stream and reset the JB and the timing. _jitterBuffer.Flush(); _timing.Reset(); - return VCM_OK; + return VCM_FLUSH_INDICATOR; } else if (renderTimeMs < nowMs - kMaxVideoDelayMs) { @@ -137,7 +138,7 @@ VCMReceiver::InsertPacket(const VCMPacket& packet, "Flushing jitter buffer and resetting timing.", kMaxVideoDelayMs); _jitterBuffer.Flush(); _timing.Reset(); - return VCM_OK; + return VCM_FLUSH_INDICATOR; } else if (_timing.TargetVideoDelay() > kMaxVideoDelayMs) { @@ -146,7 +147,7 @@ VCMReceiver::InsertPacket(const VCMPacket& packet, kMaxVideoDelayMs); _jitterBuffer.Flush(); _timing.Reset(); - return VCM_OK; + return VCM_FLUSH_INDICATOR; } // First packet received belonging to this frame. @@ -171,16 +172,18 @@ VCMReceiver::InsertPacket(const VCMPacket& packet, } } - // Insert packet into jitter buffer + // Insert packet into the jitter buffer // both media and empty packets - const VCMFrameBufferEnum ret = _jitterBuffer.InsertPacket(buffer, packet); - - if (ret < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), + const VCMFrameBufferEnum + ret = _jitterBuffer.InsertPacket(buffer, packet); + if (ret == kFlushIndicator) { + return VCM_FLUSH_INDICATOR; + } else if (ret < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, + VCMId(_vcmId, _receiverId), "Error inserting packet seqNo=%u, timeStamp=%u", packet.seqNum, packet.timestamp); - return VCM_JITTER_BUFFER_ERROR; + return VCM_JITTER_BUFFER_ERROR; } } return VCM_OK; diff --git a/src/modules/video_coding/main/source/video_coding_impl.cc b/src/modules/video_coding/main/source/video_coding_impl.cc index c64273060..2031fc4c8 100644 --- a/src/modules/video_coding/main/source/video_coding_impl.cc +++ b/src/modules/video_coding/main/source/video_coding_impl.cc @@ -1409,16 +1409,20 @@ VideoCodingModuleImpl::IncomingPacket(const WebRtc_UWord8* incomingPayload, ret = _dualReceiver.InsertPacket(packet, rtpInfo.type.Video.width, rtpInfo.type.Video.height); - if (ret < 0) - { - return ret; + if (ret == VCM_FLUSH_INDICATOR) { + RequestKeyFrame(); + ResetDecoder(); + } else if (ret < 0) { + return ret; } } ret = _receiver.InsertPacket(packet, rtpInfo.type.Video.width, rtpInfo.type.Video.height); - if (ret < 0) - { - return ret; + if (ret == VCM_FLUSH_INDICATOR) { + RequestKeyFrame(); + ResetDecoder(); + } else if (ret < 0) { + return ret; } return VCM_OK; } diff --git a/src/modules/video_coding/main/test/jitter_buffer_test.cc b/src/modules/video_coding/main/test/jitter_buffer_test.cc index 8a0f36c25..a842e18ff 100644 --- a/src/modules/video_coding/main/test/jitter_buffer_test.cc +++ b/src/modules/video_coding/main/test/jitter_buffer_test.cc @@ -24,9 +24,12 @@ using namespace webrtc; -void CheckOutFrame(VCMEncodedFrame* frameOut, unsigned int size, bool startCode) +int CheckOutFrame(VCMEncodedFrame* frameOut, unsigned int size, bool startCode) { - TEST(frameOut != 0); + if (frameOut == 0) + { + return -1; + } const WebRtc_UWord8* outData = frameOut->Buffer(); @@ -71,6 +74,7 @@ void CheckOutFrame(VCMEncodedFrame* frameOut, unsigned int size, bool startCode) } } } + return 0; } @@ -200,7 +204,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size, false); + TEST(CheckOutFrame(frameOut, size, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -258,7 +262,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*2, false); + TEST(CheckOutFrame(frameOut, size*2, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -335,7 +339,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*100, false); + TEST(CheckOutFrame(frameOut, size*100, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameKey); @@ -411,7 +415,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*100, false); + TEST(CheckOutFrame(frameOut, size*100, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -488,7 +492,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*100, false); + TEST(CheckOutFrame(frameOut, size*100, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -588,7 +592,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*2, false); + TEST(CheckOutFrame(frameOut, size*2, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -599,7 +603,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*2, false); + TEST(CheckOutFrame(frameOut, size*2, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -664,7 +668,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, (size*2)-1, false); + TEST(CheckOutFrame(frameOut, (size*2)-1, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -729,7 +733,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*2, false); + TEST(CheckOutFrame(frameOut, size*2, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -788,7 +792,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*2+4*2, true); + TEST(CheckOutFrame(frameOut, size*2+4*2, true) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -825,7 +829,7 @@ int JitterBufferTest(CmdArgs& args) // TEST packet loss. Verify missing packets statistics and not decodable // packets statistics. // Insert 10 frames consisting of 4 packets and remove one from all of them. - // The last packet is a empty (non-media) packet + // The last packet is an empty (non-media) packet // // Select a start seqNum which triggers a difficult wrap situation @@ -851,16 +855,16 @@ int JitterBufferTest(CmdArgs& args) // Insert a packet into a frame TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - // get packet notification + // Get packet notification TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs)); - // check incoming frame type + // Check incoming frame type TEST(incomingFrameType == frametype); - // get the frame + // Get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - // it should not be complete + // Should not be complete TEST(frameOut == 0); seqNum += 2; @@ -890,11 +894,11 @@ int JitterBufferTest(CmdArgs& args) // Insert a packet into a frame TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - // get the frame + // Get the frame frameOut = jb.GetFrameForDecoding(); // One of the packets has been discarded by the jitter buffer - CheckOutFrame(frameOut, size, false); + TEST(CheckOutFrame(frameOut, size, false) == 0); // check the frame type TEST(frameOut->FrameType() == frametype); @@ -1017,7 +1021,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*100, false); + TEST(CheckOutFrame(frameOut, size*100, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -1110,7 +1114,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*100, false); + TEST(CheckOutFrame(frameOut, size*100, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -1195,7 +1199,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*3, false); + TEST(CheckOutFrame(frameOut, size*3, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -1238,7 +1242,7 @@ int JitterBufferTest(CmdArgs& args) frameOut = jb.GetCompleteFrameForDecoding(10); TEST(3000 == frameOut->TimeStamp()); - CheckOutFrame(frameOut, size, false); + TEST(CheckOutFrame(frameOut, size, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -1290,7 +1294,7 @@ int JitterBufferTest(CmdArgs& args) frameOut = jb.GetCompleteFrameForDecoding(10); TEST(timeStamp == frameOut->TimeStamp()); - CheckOutFrame(frameOut, size, false); + TEST(CheckOutFrame(frameOut, size, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -1356,7 +1360,7 @@ int JitterBufferTest(CmdArgs& args) frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*2, false); + TEST(CheckOutFrame(frameOut, size*2, false) == 0); seqNum++; timeStamp += 33*90; @@ -1398,7 +1402,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size*2, false); + TEST(CheckOutFrame(frameOut, size*2, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -1459,7 +1463,7 @@ int JitterBufferTest(CmdArgs& args) frameOut = jb.GetCompleteFrameForDecoding(10); TEST(0xffffff00 == frameOut->TimeStamp()); - CheckOutFrame(frameOut, size, false); + TEST(CheckOutFrame(frameOut, size, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -1472,7 +1476,7 @@ int JitterBufferTest(CmdArgs& args) VCMEncodedFrame* frameOut2 = jb.GetCompleteFrameForDecoding(10); TEST(2700 == frameOut2->TimeStamp()); - CheckOutFrame(frameOut2, size, false); + TEST(CheckOutFrame(frameOut2, size, false) == 0); // check the frame type TEST(frameOut2->FrameType() == kVideoFrameDelta); @@ -1534,7 +1538,7 @@ int JitterBufferTest(CmdArgs& args) frameOut = jb.GetCompleteFrameForDecoding(10); TEST(0xffffff00 == frameOut->TimeStamp()); - CheckOutFrame(frameOut, size, false); + TEST(CheckOutFrame(frameOut, size, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameDelta); @@ -1547,7 +1551,7 @@ int JitterBufferTest(CmdArgs& args) frameOut2 = jb.GetCompleteFrameForDecoding(10); TEST(2700 == frameOut2->TimeStamp()); - CheckOutFrame(frameOut2, size, false); + TEST(CheckOutFrame(frameOut2, size, false) == 0); // check the frame type TEST(frameOut2->FrameType() == kVideoFrameDelta); @@ -1684,7 +1688,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); - CheckOutFrame(frameOut, size, false); + TEST(CheckOutFrame(frameOut, size, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameKey); @@ -1971,7 +1975,7 @@ int JitterBufferTest(CmdArgs& args) frameOut = jb.GetCompleteFrameForDecoding(10); TEST(ptrFirstKeyFrame == frameOut); - CheckOutFrame(frameOut, size, false); + TEST(CheckOutFrame(frameOut, size, false) == 0); // check the frame type TEST(frameOut->FrameType() == kVideoFrameKey); @@ -2149,7 +2153,7 @@ int JitterBufferTest(CmdArgs& args) // We can decode everything from a NALU until a packet has been lost. // Thus we can decode the first packet of the first NALU and the second NALU // which consists of one packet. - CheckOutFrame(frameOut, packet.sizeBytes * 2, false); + TEST(CheckOutFrame(frameOut, packet.sizeBytes * 2, false) == 0); jb.ReleaseFrame(frameOut); // Test reordered start frame + 1 lost @@ -2213,7 +2217,7 @@ int JitterBufferTest(CmdArgs& args) frameOut = jb.GetFrameForDecoding(); // Only last NALU is complete - CheckOutFrame(frameOut, insertedLength, false); + TEST(CheckOutFrame(frameOut, insertedLength, false) == 0); jb.ReleaseFrame(frameOut); @@ -2262,7 +2266,7 @@ int JitterBufferTest(CmdArgs& args) // get the frame frameOut = jb.GetCompleteFrameForDecoding(10); // Only last NALU is complete - CheckOutFrame(frameOut, packet.sizeBytes, false); + TEST(CheckOutFrame(frameOut, packet.sizeBytes, false) == 0); jb.Flush(); // Three reordered H263 packets with bits. @@ -2352,7 +2356,7 @@ int JitterBufferTest(CmdArgs& args) frameOut = jb.GetFrameForDecoding(); TEST(frameOut != NULL); - CheckOutFrame(frameOut, packet.sizeBytes, false); + TEST(CheckOutFrame(frameOut, packet.sizeBytes, false) == 0); jb.Flush();