From 39670f6aa6e0c99a9ceec04949c5e34f86c2b0b5 Mon Sep 17 00:00:00 2001 From: "stefan@webrtc.org" Date: Fri, 23 Dec 2011 09:08:51 +0000 Subject: [PATCH] Only reset the last decoded sequence number after flushing until key frame. We can't reset the complete last decoded state when we recycle until a key frame because that will allow any delta frame to be decoded afterwards, and since the decoder isn't reset we will get decode errors. BUG= TEST= Review URL: http://webrtc-codereview.appspot.com/330003 git-svn-id: http://webrtc.googlecode.com/svn/trunk@1295 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../main/source/decoding_state.cc | 20 ++++---- .../video_coding/main/source/jitter_buffer.cc | 19 +++----- .../main/test/jitter_buffer_test.cc | 47 +++++++++++++++++++ 3 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/modules/video_coding/main/source/decoding_state.cc b/src/modules/video_coding/main/source/decoding_state.cc index cbbde9b891..1280a22cbb 100644 --- a/src/modules/video_coding/main/source/decoding_state.cc +++ b/src/modules/video_coding/main/source/decoding_state.cc @@ -9,10 +9,10 @@ */ #include "modules/video_coding/main/source/decoding_state.h" + #include "modules/video_coding/main/source/frame_buffer.h" #include "modules/video_coding/main/source/jitter_buffer_common.h" #include "modules/video_coding/main/source/packet.h" - #include "modules/interface/module_common_types.h" namespace webrtc { @@ -76,7 +76,7 @@ void VCMDecodingState::SetState(const VCMFrameBuffer* frame) { void VCMDecodingState::SetStateOneBack(const VCMFrameBuffer* frame) { assert(frame != NULL && frame->GetHighSeqNum() >= 0); - sequence_num_ = static_cast (frame->GetHighSeqNum()) - 1u; + sequence_num_ = static_cast(frame->GetHighSeqNum()) - 1u; time_stamp_ = frame->TimeStamp() - 1u; temporal_id_ = frame->TemporalId(); if (frame->PictureId() != kNoPictureId) { @@ -162,21 +162,20 @@ bool VCMDecodingState::ContinuousPictureId(int picture_id) const { // First, check if applicable. if (picture_id == kNoPictureId || picture_id_ == kNoPictureId) return false; - uint16_t local_pic_id = static_cast(picture_id_); - uint16_t new_pic_id = static_cast(picture_id); - if (new_pic_id < local_pic_id) { + int next_picture_id = picture_id_ + 1; + if (picture_id < picture_id_) { // Wrap - if (local_pic_id >= (1 << 8)) { + if (picture_id_ >= 0x80) { // 15 bits used for picture id - return (((local_pic_id + 1) % 0x7FFF) == new_pic_id); + return ((next_picture_id & 0x7FFF) == picture_id); } else { // 7 bits used for picture id - return (((local_pic_id + 1) % 0x7F) == new_pic_id); + return ((next_picture_id & 0x7F) == picture_id); } } // No wrap - return (local_pic_id + 1 == new_pic_id); + return (next_picture_id == picture_id); } bool VCMDecodingState::ContinuousSeqNum(uint16_t seq_num) const { @@ -197,8 +196,7 @@ bool VCMDecodingState::ContinuousLayer(int temporal_id, // Current implementation: Look for base layer continuity. if (temporal_id != 0) return false; - return (static_cast(tl0_pic_id_ + 1) == - static_cast(tl0_pic_id)); + return (static_cast(tl0_pic_id_ + 1) == tl0_pic_id); } } // namespace webrtc diff --git a/src/modules/video_coding/main/source/jitter_buffer.cc b/src/modules/video_coding/main/source/jitter_buffer.cc index 4985f8d0a6..d6012a6dd5 100644 --- a/src/modules/video_coding/main/source/jitter_buffer.cc +++ b/src/modules/video_coding/main/source/jitter_buffer.cc @@ -1720,8 +1720,7 @@ VCMJitterBuffer::RecycleFramesUntilKeyFrame() } // Remove up to oldest key frame - bool foundKeyFrame = false; - while (oldestFrameListItem != NULL && !foundKeyFrame) + while (oldestFrameListItem != NULL) { // Throw at least one frame. _dropCount++; @@ -1737,21 +1736,15 @@ VCMJitterBuffer::RecycleFramesUntilKeyFrame() { oldestFrame = oldestFrameListItem->GetItem(); } - - if (oldestFrame != NULL) + if (oldestFrame != NULL && oldestFrame->FrameType() == kVideoFrameKey) { - foundKeyFrame = foundKeyFrame || - (oldestFrame->FrameType() != kVideoFrameDelta); - if (foundKeyFrame) - { - // Fake the lastDecodedState to match this key frame. - _lastDecodedState.SetStateOneBack(oldestFrame); - break; - } + // Fake the lastDecodedState to match this key frame. + _lastDecodedState.SetStateOneBack(oldestFrame); + return true; } } _lastDecodedState.Reset(); // TODO (mikhal): no sync - return foundKeyFrame; + return false; } // Must be called under the critical section _critSect. 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 b419d8a0f1..42bddbd09d 100644 --- a/src/modules/video_coding/main/test/jitter_buffer_test.cc +++ b/src/modules/video_coding/main/test/jitter_buffer_test.cc @@ -2428,6 +2428,53 @@ int JitterBufferTest(CmdArgs& args) jb.Flush(); + // Verify that a key frame is the next frame after the nack list gets full. + jb.SetNackMode(kNackInfinite, -1, -1); + seqNum += 1; + timeStamp += 33 * 90; + packet.seqNum = seqNum; + packet.timestamp = timeStamp; + packet.frameType = kVideoFrameKey; + packet.isFirstPacket = true; + packet.completeNALU = kNaluComplete; + packet.markerBit = true; + TEST(frameIn = jb.GetFrame(packet)); + TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); + + TEST(jb.GetCompleteFrameForDecoding(0) != NULL); + + seqNum += kNackHistoryLength + 1; + timeStamp += 33 * 90; + packet.seqNum = seqNum; + packet.timestamp = timeStamp; + packet.frameType = kVideoFrameDelta; + packet.isFirstPacket = true; + packet.completeNALU = kNaluComplete; + packet.markerBit = true; + TEST(frameIn = jb.GetFrame(packet)); + TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); + + TEST(jb.GetCompleteFrameForDecoding(0) == NULL); + + uint16_t nack_list_length = kNackHistoryLength; + uint16_t *nack_list; + nack_list = jb.GetNackList(nack_list_length, extended); + TEST(nack_list_length == 0xffff && nack_list == NULL); + + seqNum += 1; + timeStamp += 33 * 90; + packet.seqNum = seqNum; + packet.timestamp = timeStamp; + packet.frameType = kVideoFrameDelta; + packet.isFirstPacket = true; + packet.completeNALU = kNaluComplete; + packet.markerBit = true; + TEST(frameIn = jb.GetFrame(packet)); + TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); + + TEST(jb.GetCompleteFrameForDecoding(0) == NULL); + TEST(jb.GetFrameForDecoding() == NULL); + jb.Stop(); printf("DONE !!!\n");