From e72e9ee12a2e1c7fa80d09bd3369c878e0345935 Mon Sep 17 00:00:00 2001 From: "stefan@webrtc.org" Date: Wed, 19 Sep 2012 11:08:05 +0000 Subject: [PATCH] If present, only use picture ids to identify missing frames. This is necessary in some scenarios to avoid false non-zero loss reports when doing stream thinning. BUG= Review URL: https://webrtc-codereview.appspot.com/793008 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2784 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../main/source/decoding_state.cc | 22 +++++++------ .../video_coding/main/source/decoding_state.h | 1 + .../main/source/decoding_state_unittest.cc | 32 +++++++++++++++++++ 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/modules/video_coding/main/source/decoding_state.cc b/src/modules/video_coding/main/source/decoding_state.cc index eea0a2c612..e347a2c768 100644 --- a/src/modules/video_coding/main/source/decoding_state.cc +++ b/src/modules/video_coding/main/source/decoding_state.cc @@ -127,10 +127,11 @@ void VCMDecodingState::UpdateSyncState(const VCMFrameBuffer* frame) { // Verify that we are still in sync. // Sync will be broken if continuity is true for layers but not for the // other methods (PictureId and SeqNum). - if (!ContinuousPictureId(frame->PictureId()) && - !ContinuousSeqNum(static_cast(frame->GetLowSeqNum()))) { - // Non-layered methods have failed. - full_sync_ = false; + if (UsingPictureId(frame)) { + full_sync_ = ContinuousPictureId(frame->PictureId()); + } else { + full_sync_ = ContinuousSeqNum(static_cast( + frame->GetLowSeqNum())); } } } @@ -152,17 +153,16 @@ bool VCMDecodingState::ContinuousFrame(const VCMFrameBuffer* frame) const { // continuity if sync can be restored by this frame. if (!full_sync_ && !frame->LayerSync()) return false; - else if (!ContinuousPictureId(frame->PictureId())) + else if (UsingPictureId(frame)) { + return ContinuousPictureId(frame->PictureId()); + } else { return ContinuousSeqNum(static_cast(frame->GetLowSeqNum())); + } } return true; } bool VCMDecodingState::ContinuousPictureId(int picture_id) const { - // First, check if applicable. - if (picture_id == kNoPictureId || picture_id_ == kNoPictureId) - return false; - int next_picture_id = picture_id_ + 1; if (picture_id < picture_id_) { // Wrap @@ -199,4 +199,8 @@ bool VCMDecodingState::ContinuousLayer(int temporal_id, return (static_cast(tl0_pic_id_ + 1) == tl0_pic_id); } +bool VCMDecodingState::UsingPictureId(const VCMFrameBuffer* frame) const { + return (frame->PictureId() != kNoPictureId && picture_id_ != kNoPictureId); +} + } // namespace webrtc diff --git a/src/modules/video_coding/main/source/decoding_state.h b/src/modules/video_coding/main/source/decoding_state.h index afec3ba44c..136bae6b68 100644 --- a/src/modules/video_coding/main/source/decoding_state.h +++ b/src/modules/video_coding/main/source/decoding_state.h @@ -52,6 +52,7 @@ class VCMDecodingState { bool ContinuousPictureId(int picture_id) const; bool ContinuousSeqNum(uint16_t seq_num) const; bool ContinuousLayer(int temporal_id, int tl0_pic_id) const; + bool UsingPictureId(const VCMFrameBuffer* frame) const; // Keep state of last decoded frame. // TODO(mikhal/stefan): create designated classes to handle these types. diff --git a/src/modules/video_coding/main/source/decoding_state_unittest.cc b/src/modules/video_coding/main/source/decoding_state_unittest.cc index 853f42ada2..5f0a59de5e 100644 --- a/src/modules/video_coding/main/source/decoding_state_unittest.cc +++ b/src/modules/video_coding/main/source/decoding_state_unittest.cc @@ -405,6 +405,38 @@ TEST(TestDecodingState, MultiLayerBehavior) { delete packet; } +TEST(TestDecodingState, DiscontinuousPicIdContinuousSeqNum) { + VCMDecodingState dec_state; + VCMFrameBuffer frame; + VCMPacket packet; + frame.Reset(); + frame.SetState(kStateEmpty); + packet.frameType = kVideoFrameKey; + packet.codecSpecificHeader.codec = kRTPVideoVP8; + packet.timestamp = 0; + packet.seqNum = 0; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 0; + frame.InsertPacket(packet, 0, false, 0); + dec_state.SetState(&frame); + EXPECT_TRUE(dec_state.full_sync()); + + // Continuous sequence number but discontinuous picture id. This implies a + // a loss and we have to fall back to only decoding the base layer. + frame.Reset(); + frame.SetState(kStateEmpty); + packet.frameType = kVideoFrameDelta; + packet.timestamp += 3000; + ++packet.seqNum; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 1; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 2; + frame.InsertPacket(packet, 0, false, 0); + EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); + dec_state.SetState(&frame); + EXPECT_FALSE(dec_state.full_sync()); +} + TEST(TestDecodingState, OldInput) { VCMDecodingState dec_state; // Identify packets belonging to old frames/packets.