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
This commit is contained in:
stefan@webrtc.org 2011-12-23 09:08:51 +00:00
parent 1ce66e4dfb
commit 39670f6aa6
3 changed files with 62 additions and 24 deletions

View File

@ -9,10 +9,10 @@
*/ */
#include "modules/video_coding/main/source/decoding_state.h" #include "modules/video_coding/main/source/decoding_state.h"
#include "modules/video_coding/main/source/frame_buffer.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/jitter_buffer_common.h"
#include "modules/video_coding/main/source/packet.h" #include "modules/video_coding/main/source/packet.h"
#include "modules/interface/module_common_types.h" #include "modules/interface/module_common_types.h"
namespace webrtc { namespace webrtc {
@ -162,21 +162,20 @@ bool VCMDecodingState::ContinuousPictureId(int picture_id) const {
// First, check if applicable. // First, check if applicable.
if (picture_id == kNoPictureId || picture_id_ == kNoPictureId) if (picture_id == kNoPictureId || picture_id_ == kNoPictureId)
return false; return false;
uint16_t local_pic_id = static_cast<uint16_t>(picture_id_);
uint16_t new_pic_id = static_cast<uint16_t>(picture_id);
if (new_pic_id < local_pic_id) { int next_picture_id = picture_id_ + 1;
if (picture_id < picture_id_) {
// Wrap // Wrap
if (local_pic_id >= (1 << 8)) { if (picture_id_ >= 0x80) {
// 15 bits used for picture id // 15 bits used for picture id
return (((local_pic_id + 1) % 0x7FFF) == new_pic_id); return ((next_picture_id & 0x7FFF) == picture_id);
} else { } else {
// 7 bits used for picture id // 7 bits used for picture id
return (((local_pic_id + 1) % 0x7F) == new_pic_id); return ((next_picture_id & 0x7F) == picture_id);
} }
} }
// No wrap // No wrap
return (local_pic_id + 1 == new_pic_id); return (next_picture_id == picture_id);
} }
bool VCMDecodingState::ContinuousSeqNum(uint16_t seq_num) const { 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. // Current implementation: Look for base layer continuity.
if (temporal_id != 0) if (temporal_id != 0)
return false; return false;
return (static_cast<uint8_t>(tl0_pic_id_ + 1) == return (static_cast<uint8_t>(tl0_pic_id_ + 1) == tl0_pic_id);
static_cast<uint8_t>(tl0_pic_id));
} }
} // namespace webrtc } // namespace webrtc

View File

@ -1720,8 +1720,7 @@ VCMJitterBuffer::RecycleFramesUntilKeyFrame()
} }
// Remove up to oldest key frame // Remove up to oldest key frame
bool foundKeyFrame = false; while (oldestFrameListItem != NULL)
while (oldestFrameListItem != NULL && !foundKeyFrame)
{ {
// Throw at least one frame. // Throw at least one frame.
_dropCount++; _dropCount++;
@ -1737,21 +1736,15 @@ VCMJitterBuffer::RecycleFramesUntilKeyFrame()
{ {
oldestFrame = oldestFrameListItem->GetItem(); oldestFrame = oldestFrameListItem->GetItem();
} }
if (oldestFrame != NULL && oldestFrame->FrameType() == kVideoFrameKey)
if (oldestFrame != NULL)
{
foundKeyFrame = foundKeyFrame ||
(oldestFrame->FrameType() != kVideoFrameDelta);
if (foundKeyFrame)
{ {
// Fake the lastDecodedState to match this key frame. // Fake the lastDecodedState to match this key frame.
_lastDecodedState.SetStateOneBack(oldestFrame); _lastDecodedState.SetStateOneBack(oldestFrame);
break; return true;
}
} }
} }
_lastDecodedState.Reset(); // TODO (mikhal): no sync _lastDecodedState.Reset(); // TODO (mikhal): no sync
return foundKeyFrame; return false;
} }
// Must be called under the critical section _critSect. // Must be called under the critical section _critSect.

View File

@ -2428,6 +2428,53 @@ int JitterBufferTest(CmdArgs& args)
jb.Flush(); 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(); jb.Stop();
printf("DONE !!!\n"); printf("DONE !!!\n");