From 0aeb22e32c5cb2aa8c1ae97731a56a04bdc184f7 Mon Sep 17 00:00:00 2001 From: "mikhal@webrtc.org" Date: Mon, 28 Oct 2013 22:26:14 +0000 Subject: [PATCH] Adding tl0idx consideration for continuity R=stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/2879004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5046 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../main/source/decoding_state.cc | 34 +- .../main/source/decoding_state_unittest.cc | 410 ++++++++++-------- 2 files changed, 238 insertions(+), 206 deletions(-) diff --git a/webrtc/modules/video_coding/main/source/decoding_state.cc b/webrtc/modules/video_coding/main/source/decoding_state.cc index 2d970fc8d0..aa5e54c4f2 100644 --- a/webrtc/modules/video_coding/main/source/decoding_state.cc +++ b/webrtc/modules/video_coding/main/source/decoding_state.cc @@ -133,7 +133,12 @@ void VCMDecodingState::UpdateSyncState(const VCMFrameBuffer* frame) { // Sync will be broken if continuity is true for layers but not for the // other methods (PictureId and SeqNum). if (UsingPictureId(frame)) { - full_sync_ = ContinuousPictureId(frame->PictureId()); + // First check for a valid tl0PicId. + if (frame->Tl0PicId() - tl0_pic_id_ > 1) { + full_sync_ = false; + } else { + full_sync_ = ContinuousPictureId(frame->PictureId()); + } } else { full_sync_ = ContinuousSeqNum(static_cast( frame->GetLowSeqNum())); @@ -157,20 +162,21 @@ bool VCMDecodingState::ContinuousFrame(const VCMFrameBuffer* frame) const { // When in the initial state we always require a key frame to start decoding. if (in_initial_state_) return false; - - if (!ContinuousLayer(frame->TemporalId(), frame->Tl0PicId())) { - // Base layers are not continuous or temporal layers are inactive. - // In the presence of temporal layers, check for Picture ID/sequence number - // continuity if sync can be restored by this frame. - if (!full_sync_ && !frame->LayerSync()) - return false; - else if (UsingPictureId(frame)) { - return ContinuousPictureId(frame->PictureId()); - } else { - return ContinuousSeqNum(static_cast(frame->GetLowSeqNum())); - } + if (ContinuousLayer(frame->TemporalId(), frame->Tl0PicId())) + return true; + // tl0picId is either not used, or should remain unchanged. + if (frame->Tl0PicId() != tl0_pic_id_) + return false; + // Base layers are not continuous or temporal layers are inactive. + // In the presence of temporal layers, check for Picture ID/sequence number + // continuity if sync can be restored by this frame. + if (!full_sync_ && !frame->LayerSync()) + return false; + if (UsingPictureId(frame)) { + return ContinuousPictureId(frame->PictureId()); + } else { + return ContinuousSeqNum(static_cast(frame->GetLowSeqNum())); } - return true; } bool VCMDecodingState::ContinuousPictureId(int picture_id) const { diff --git a/webrtc/modules/video_coding/main/source/decoding_state_unittest.cc b/webrtc/modules/video_coding/main/source/decoding_state_unittest.cc index 48c8c79ee4..10f1d6e4dd 100644 --- a/webrtc/modules/video_coding/main/source/decoding_state_unittest.cc +++ b/webrtc/modules/video_coding/main/source/decoding_state_unittest.cc @@ -31,49 +31,49 @@ TEST(TestDecodingState, FrameContinuity) { // Check that makes decision based on correct method. VCMFrameBuffer frame; VCMFrameBuffer frame_key; - VCMPacket* packet = new VCMPacket(); - packet->isFirstPacket = true; - packet->timestamp = 1; - packet->seqNum = 0xffff; - packet->frameType = kVideoFrameDelta; - packet->codecSpecificHeader.codec = kRtpVideoVp8; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 0x007F; + VCMPacket packet; + packet.isFirstPacket = true; + packet.timestamp = 1; + packet.seqNum = 0xffff; + packet.frameType = kVideoFrameDelta; + packet.codecSpecificHeader.codec = kRtpVideoVp8; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 0x007F; FrameData frame_data; frame_data.rtt_ms = 0; frame_data.rolling_average_packets_per_frame = -1; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); // Always start with a key frame. dec_state.Reset(); EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); - packet->frameType = kVideoFrameKey; - EXPECT_LE(0, frame_key.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.frameType = kVideoFrameKey; + EXPECT_LE(0, frame_key.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_TRUE(dec_state.ContinuousFrame(&frame_key)); dec_state.SetState(&frame); frame.Reset(); - packet->frameType = kVideoFrameDelta; + packet.frameType = kVideoFrameDelta; // Use pictureId - packet->isFirstPacket = false; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 0x0002; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.isFirstPacket = false; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 0x0002; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); frame.Reset(); - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 0; - packet->seqNum = 10; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 0; + packet.seqNum = 10; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); // Use sequence numbers. - packet->codecSpecificHeader.codecHeader.VP8.pictureId = kNoPictureId; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = kNoPictureId; frame.Reset(); - packet->seqNum = dec_state.sequence_num() - 1u; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.seqNum = dec_state.sequence_num() - 1u; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); frame.Reset(); - packet->seqNum = dec_state.sequence_num() + 1u; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.seqNum = dec_state.sequence_num() + 1u; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); // Insert another packet to this frame - packet->seqNum++; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.seqNum++; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); // Verify wrap. EXPECT_LE(dec_state.sequence_num(), 0xffff); EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); @@ -82,81 +82,80 @@ TEST(TestDecodingState, FrameContinuity) { // Insert packet with temporal info. dec_state.Reset(); frame.Reset(); - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 0; - packet->seqNum = 1; - packet->timestamp = 1; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 0; + packet.seqNum = 1; + packet.timestamp = 1; EXPECT_TRUE(dec_state.full_sync()); - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); dec_state.SetState(&frame); EXPECT_TRUE(dec_state.full_sync()); frame.Reset(); // 1 layer up - still good. - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 1; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 1; - packet->seqNum = 2; - packet->timestamp = 2; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 1; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 1; + packet.seqNum = 2; + packet.timestamp = 2; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); dec_state.SetState(&frame); EXPECT_TRUE(dec_state.full_sync()); frame.Reset(); // Lost non-base layer packet => should update sync parameter. - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 3; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 3; - packet->seqNum = 4; - packet->timestamp = 4; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 3; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 3; + packet.seqNum = 4; + packet.timestamp = 4; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); // Now insert the next non-base layer (belonging to a next tl0PicId). frame.Reset(); - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 1; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 2; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 4; - packet->seqNum = 5; - packet->timestamp = 5; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 1; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 2; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 4; + packet.seqNum = 5; + packet.timestamp = 5; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); // Checking continuity and not updating the state - this should not trigger // an update of sync state. EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); EXPECT_TRUE(dec_state.full_sync()); // Next base layer (dropped interim non-base layers) - should update sync. frame.Reset(); - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 1; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 5; - packet->seqNum = 6; - packet->timestamp = 6; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 1; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 5; + packet.seqNum = 6; + packet.timestamp = 6; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); dec_state.SetState(&frame); EXPECT_FALSE(dec_state.full_sync()); // Check wrap for temporal layers. frame.Reset(); - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0x00FF; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 6; - packet->seqNum = 7; - packet->timestamp = 7; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0x00FF; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 6; + packet.seqNum = 7; + packet.timestamp = 7; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); dec_state.SetState(&frame); EXPECT_FALSE(dec_state.full_sync()); frame.Reset(); - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0x0000; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 7; - packet->seqNum = 8; - packet->timestamp = 8; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0x0000; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 7; + packet.seqNum = 8; + packet.timestamp = 8; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); // The current frame is not continuous dec_state.SetState(&frame); EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); - delete packet; } TEST(TestDecodingState, UpdateOldPacket) { @@ -164,45 +163,43 @@ TEST(TestDecodingState, UpdateOldPacket) { // Update only if zero size and newer than previous. // Should only update if the timeStamp match. VCMFrameBuffer frame; - VCMPacket* packet = new VCMPacket(); - packet->timestamp = 1; - packet->seqNum = 1; - packet->frameType = kVideoFrameDelta; + VCMPacket packet; + packet.timestamp = 1; + packet.seqNum = 1; + packet.frameType = kVideoFrameDelta; FrameData frame_data; frame_data.rtt_ms = 0; frame_data.rolling_average_packets_per_frame = -1; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); dec_state.SetState(&frame); EXPECT_EQ(dec_state.sequence_num(), 1); // Insert an empty packet that does not belong to the same frame. // => Sequence num should be the same. - packet->timestamp = 2; - dec_state.UpdateOldPacket(packet); + packet.timestamp = 2; + dec_state.UpdateOldPacket(&packet); EXPECT_EQ(dec_state.sequence_num(), 1); // Now insert empty packet belonging to the same frame. - packet->timestamp = 1; - packet->seqNum = 2; - packet->frameType = kFrameEmpty; - packet->sizeBytes = 0; - dec_state.UpdateOldPacket(packet); + packet.timestamp = 1; + packet.seqNum = 2; + packet.frameType = kFrameEmpty; + packet.sizeBytes = 0; + dec_state.UpdateOldPacket(&packet); EXPECT_EQ(dec_state.sequence_num(), 2); // Now insert delta packet belonging to the same frame. - packet->timestamp = 1; - packet->seqNum = 3; - packet->frameType = kVideoFrameDelta; - packet->sizeBytes = 1400; - dec_state.UpdateOldPacket(packet); + packet.timestamp = 1; + packet.seqNum = 3; + packet.frameType = kVideoFrameDelta; + packet.sizeBytes = 1400; + dec_state.UpdateOldPacket(&packet); EXPECT_EQ(dec_state.sequence_num(), 3); // Insert a packet belonging to an older timestamp - should not update the // sequence number. - packet->timestamp = 0; - packet->seqNum = 4; - packet->frameType = kFrameEmpty; - packet->sizeBytes = 0; - dec_state.UpdateOldPacket(packet); + packet.timestamp = 0; + packet.seqNum = 4; + packet.frameType = kFrameEmpty; + packet.sizeBytes = 0; + dec_state.UpdateOldPacket(&packet); EXPECT_EQ(dec_state.sequence_num(), 3); - - delete packet; } TEST(TestDecodingState, MultiLayerBehavior) { @@ -212,88 +209,88 @@ TEST(TestDecodingState, MultiLayerBehavior) { // Set state for current frames. // tl0PicIdx 0, temporal id 0. VCMFrameBuffer frame; - VCMPacket* packet = new VCMPacket(); - packet->frameType = kVideoFrameDelta; - 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; + VCMPacket packet; + packet.frameType = kVideoFrameDelta; + 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; FrameData frame_data; frame_data.rtt_ms = 0; frame_data.rolling_average_packets_per_frame = -1; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); dec_state.SetState(&frame); // tl0PicIdx 0, temporal id 1. frame.Reset(); - packet->timestamp = 1; - packet->seqNum = 1; - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 1; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 1; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.timestamp = 1; + packet.seqNum = 1; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 1; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 1; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); dec_state.SetState(&frame); EXPECT_TRUE(dec_state.full_sync()); // Lost tl0PicIdx 0, temporal id 2. // Insert tl0PicIdx 0, temporal id 3. frame.Reset(); - packet->timestamp = 3; - packet->seqNum = 3; - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 3; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 3; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.timestamp = 3; + packet.seqNum = 3; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 3; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 3; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); dec_state.SetState(&frame); EXPECT_FALSE(dec_state.full_sync()); // Insert next base layer frame.Reset(); - packet->timestamp = 4; - packet->seqNum = 4; - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 1; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 4; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.timestamp = 4; + packet.seqNum = 4; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 1; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 4; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); dec_state.SetState(&frame); EXPECT_FALSE(dec_state.full_sync()); // Insert key frame - should update sync value. // A key frame is always a base layer. frame.Reset(); - packet->frameType = kVideoFrameKey; - packet->isFirstPacket = 1; - packet->timestamp = 5; - packet->seqNum = 5; - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 2; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 5; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.frameType = kVideoFrameKey; + packet.isFirstPacket = 1; + packet.timestamp = 5; + packet.seqNum = 5; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 2; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 5; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); dec_state.SetState(&frame); EXPECT_TRUE(dec_state.full_sync()); // After sync, a continuous PictureId is required // (continuous base layer is not enough ) frame.Reset(); - packet->frameType = kVideoFrameDelta; - packet->timestamp = 6; - packet->seqNum = 6; - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 3; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 6; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.frameType = kVideoFrameDelta; + packet.timestamp = 6; + packet.seqNum = 6; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 3; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 6; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); EXPECT_TRUE(dec_state.full_sync()); frame.Reset(); - packet->frameType = kVideoFrameDelta; - packet->isFirstPacket = 1; - packet->timestamp = 8; - packet->seqNum = 8; - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 4; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 8; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.frameType = kVideoFrameDelta; + packet.isFirstPacket = 1; + packet.timestamp = 8; + packet.seqNum = 8; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 4; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 8; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); EXPECT_TRUE(dec_state.full_sync()); dec_state.SetState(&frame); @@ -301,15 +298,15 @@ TEST(TestDecodingState, MultiLayerBehavior) { // Insert a non-ref frame - should update sync value. frame.Reset(); - packet->frameType = kVideoFrameDelta; - packet->isFirstPacket = 1; - packet->timestamp = 9; - packet->seqNum = 9; - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 4; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 2; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 9; - packet->codecSpecificHeader.codecHeader.VP8.layerSync = true; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.frameType = kVideoFrameDelta; + packet.isFirstPacket = 1; + packet.timestamp = 9; + packet.seqNum = 9; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 4; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 2; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 9; + packet.codecSpecificHeader.codecHeader.VP8.layerSync = true; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); dec_state.SetState(&frame); EXPECT_TRUE(dec_state.full_sync()); @@ -321,47 +318,45 @@ TEST(TestDecodingState, MultiLayerBehavior) { // Base layer. frame.Reset(); dec_state.Reset(); - packet->frameType = kVideoFrameDelta; - packet->isFirstPacket = 1; - packet->markerBit = 1; - packet->timestamp = 0; - packet->seqNum = 0; - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 0; - packet->codecSpecificHeader.codecHeader.VP8.layerSync = false; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.frameType = kVideoFrameDelta; + packet.isFirstPacket = 1; + packet.markerBit = 1; + packet.timestamp = 0; + packet.seqNum = 0; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 0; + packet.codecSpecificHeader.codecHeader.VP8.layerSync = false; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); dec_state.SetState(&frame); EXPECT_TRUE(dec_state.full_sync()); // Layer 2 - 2 packets (insert one, lose one). frame.Reset(); - packet->frameType = kVideoFrameDelta; - packet->isFirstPacket = 1; - packet->markerBit = 0; - packet->timestamp = 1; - packet->seqNum = 1; - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 2; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 1; - packet->codecSpecificHeader.codecHeader.VP8.layerSync = true; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.frameType = kVideoFrameDelta; + packet.isFirstPacket = 1; + packet.markerBit = 0; + packet.timestamp = 1; + packet.seqNum = 1; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 2; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 1; + packet.codecSpecificHeader.codecHeader.VP8.layerSync = true; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); // Layer 1 frame.Reset(); - packet->frameType = kVideoFrameDelta; - packet->isFirstPacket = 1; - packet->markerBit = 1; - packet->timestamp = 2; - packet->seqNum = 3; - packet->codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; - packet->codecSpecificHeader.codecHeader.VP8.temporalIdx = 1; - packet->codecSpecificHeader.codecHeader.VP8.pictureId = 2; - packet->codecSpecificHeader.codecHeader.VP8.layerSync = true; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + packet.frameType = kVideoFrameDelta; + packet.isFirstPacket = 1; + packet.markerBit = 1; + packet.timestamp = 2; + packet.seqNum = 3; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 0; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx = 1; + packet.codecSpecificHeader.codecHeader.VP8.pictureId = 2; + packet.codecSpecificHeader.codecHeader.VP8.layerSync = true; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); EXPECT_TRUE(dec_state.full_sync()); - - delete packet; } TEST(TestDecodingState, DiscontinuousPicIdContinuousSeqNum) { @@ -402,22 +397,53 @@ TEST(TestDecodingState, OldInput) { // Identify packets belonging to old frames/packets. // Set state for current frames. VCMFrameBuffer frame; - VCMPacket* packet = new VCMPacket(); - packet->timestamp = 10; - packet->seqNum = 1; + VCMPacket packet; + packet.timestamp = 10; + packet.seqNum = 1; FrameData frame_data; frame_data.rtt_ms = 0; frame_data.rolling_average_packets_per_frame = -1; - EXPECT_LE(0, frame.InsertPacket(*packet, 0, kNoErrors, frame_data)); + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); dec_state.SetState(&frame); - packet->timestamp = 9; - EXPECT_TRUE(dec_state.IsOldPacket(packet)); + packet.timestamp = 9; + EXPECT_TRUE(dec_state.IsOldPacket(&packet)); // Check for old frame frame.Reset(); - frame.InsertPacket(*packet, 0, kNoErrors, frame_data); + frame.InsertPacket(packet, 0, kNoErrors, frame_data); EXPECT_TRUE(dec_state.IsOldFrame(&frame)); - - - delete packet; } + +TEST(TestDecodingState, PictureIdRepeat) { + VCMDecodingState dec_state; + VCMFrameBuffer frame; + VCMPacket packet; + packet.frameType = kVideoFrameDelta; + 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; + FrameData frame_data; + frame_data.rtt_ms = 0; + frame_data.rolling_average_packets_per_frame = -1; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); + dec_state.SetState(&frame); + // tl0PicIdx 0, temporal id 1. + frame.Reset(); + ++packet.timestamp; + ++packet.seqNum; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx++; + packet.codecSpecificHeader.codecHeader.VP8.pictureId++; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); + EXPECT_TRUE(dec_state.ContinuousFrame(&frame)); + frame.Reset(); + // Testing only gap in tl0PicIdx when tl0PicIdx in continuous. + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx += 3; + packet.codecSpecificHeader.codecHeader.VP8.temporalIdx++; + packet.codecSpecificHeader.codecHeader.VP8.tl0PicIdx = 1; + EXPECT_LE(0, frame.InsertPacket(packet, 0, kNoErrors, frame_data)); + EXPECT_FALSE(dec_state.ContinuousFrame(&frame)); +} + } // namespace webrtc