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
This commit is contained in:
stefan@webrtc.org 2012-09-19 11:08:05 +00:00
parent 2db85bcba7
commit e72e9ee12a
3 changed files with 46 additions and 9 deletions

View File

@ -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<uint16_t>(frame->GetLowSeqNum()))) {
// Non-layered methods have failed.
full_sync_ = false;
if (UsingPictureId(frame)) {
full_sync_ = ContinuousPictureId(frame->PictureId());
} else {
full_sync_ = ContinuousSeqNum(static_cast<uint16_t>(
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<uint16_t>(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<uint8_t>(tl0_pic_id_ + 1) == tl0_pic_id);
}
bool VCMDecodingState::UsingPictureId(const VCMFrameBuffer* frame) const {
return (frame->PictureId() != kNoPictureId && picture_id_ != kNoPictureId);
}
} // namespace webrtc

View File

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

View File

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