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/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 <uint16_t>(frame->GetHighSeqNum()) - 1u;
sequence_num_ = static_cast<uint16_t>(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<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
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<uint8_t>(tl0_pic_id_ + 1) ==
static_cast<uint8_t>(tl0_pic_id));
return (static_cast<uint8_t>(tl0_pic_id_ + 1) == tl0_pic_id);
}
} // namespace webrtc

View File

@ -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.

View File

@ -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");