diff --git a/webrtc/modules/video_coding/main/source/jitter_buffer_unittest.cc b/webrtc/modules/video_coding/main/source/jitter_buffer_unittest.cc index b5307f072..2b24597a7 100644 --- a/webrtc/modules/video_coding/main/source/jitter_buffer_unittest.cc +++ b/webrtc/modules/video_coding/main/source/jitter_buffer_unittest.cc @@ -13,6 +13,7 @@ #include #include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/modules/video_coding/main/source/frame_buffer.h" #include "webrtc/modules/video_coding/main/source/jitter_buffer.h" #include "webrtc/modules/video_coding/main/source/media_opt_util.h" #include "webrtc/modules/video_coding/main/source/packet.h" @@ -22,6 +23,101 @@ namespace webrtc { +class TestBasicJitterBuffer : public ::testing::Test { + protected: + virtual void SetUp() { + clock_.reset(new SimulatedClock(0)); + jitter_buffer_.reset(new VCMJitterBuffer(clock_.get(), + &event_factory_, -1, -1, true)); + jitter_buffer_->Start(); + seq_num_ = 1234; + timestamp_ = 0; + size_ = 1400; + // Data vector - 0, 0, 0x80, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0x80, 3.... + data_[0] = 0; + data_[1] = 0; + data_[2] = 0x80; + int count = 3; + for (unsigned int i = 3; i < sizeof(data_) - 3; ++i) { + data_[i] = count; + count++; + if (count == 10) { + data_[i + 1] = 0; + data_[i + 2] = 0; + data_[i + 3] = 0x80; + count = 3; + i += 3; + } + } + packet_.reset(new VCMPacket(data_, size_, seq_num_, timestamp_, true)); + } + + VCMEncodedFrame* DecodeCompleteFrame() { + uint32_t timestamp = 0; + bool found_frame = jitter_buffer_->NextCompleteTimestamp(10, ×tamp); + if (!found_frame) + return NULL; + VCMEncodedFrame* frame = jitter_buffer_->ExtractAndSetDecode(timestamp); + return frame; + } + + VCMEncodedFrame* DecodeIncompleteFrame() { + uint32_t timestamp = 0; + bool found_frame = jitter_buffer_->NextMaybeIncompleteTimestamp(×tamp); + if (!found_frame) + return NULL; + VCMEncodedFrame* frame = jitter_buffer_->ExtractAndSetDecode(timestamp); + return frame; + } + int CheckOutFrame(VCMEncodedFrame* frame_out, + unsigned int size, + bool startCode) { + EXPECT_FALSE(frame_out == NULL); + + const uint8_t* outData = frame_out->Buffer(); + unsigned int i = 0; + + if (startCode) { + EXPECT_EQ(0, outData[0]); + EXPECT_EQ(0, outData[1]); + EXPECT_EQ(0, outData[2]); + EXPECT_EQ(1, outData[3]); + i += 4; + } + + EXPECT_EQ(size, frame_out->Length()); + int count = 3; + for (; i < size; i++) { + if (outData[i] == 0 && outData[i + 1] == 0 && outData[i + 2] == 0x80) { + i += 2; + } else if (startCode && outData[i] == 0 && outData[i + 1] == 0) { + EXPECT_EQ(0, outData[0]); + EXPECT_EQ(0, outData[1]); + EXPECT_EQ(0, outData[2]); + EXPECT_EQ(1, outData[3]); + i += 3; + } else { + EXPECT_EQ(count, outData[i]); + count++; + if (count == 10) { + count = 3; + } + } + } + return 0; + } + + uint16_t seq_num_; + uint32_t timestamp_; + int size_; + uint8_t data_[1500]; + scoped_ptr jitter_buffer_; + scoped_ptr packet_; + scoped_ptr clock_; + NullEventFactory event_factory_; +}; + + class TestRunningJitterBuffer : public ::testing::Test { protected: enum { kDataBufferSize = 10 }; @@ -144,6 +240,1169 @@ class TestJitterBufferNack : public TestRunningJitterBuffer { } }; +TEST_F(TestBasicJitterBuffer, StopRunning) { + jitter_buffer_->Stop(); + EXPECT_EQ(0, jitter_buffer_->GetFrame(*packet_)); + EXPECT_TRUE(NULL == DecodeCompleteFrame()); + EXPECT_TRUE(NULL == DecodeIncompleteFrame()); + jitter_buffer_->Start(); + // Allow decoding with errors. + jitter_buffer_->DecodeWithErrors(true); + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + // No packets inserted. + EXPECT_TRUE(NULL == DecodeCompleteFrame()); + EXPECT_TRUE(NULL == DecodeIncompleteFrame()); +} + +TEST_F(TestBasicJitterBuffer, SinglePacketFrame) { + // Always start with a complete key frame. + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->timestamp += 123*90; + + // Insert the packet to the jitter buffer and get a frame. + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + EXPECT_EQ(0, CheckOutFrame(frame_out, size_, false)); + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, DualPacketFrame) { + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = false; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + // Should not be complete. + EXPECT_TRUE(frame_out == NULL); + + ++seq_num_; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_FALSE(frame_in == NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + EXPECT_EQ(0, CheckOutFrame(frame_out, 2 * size_, false)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, 100PacketKeyFrame) { + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = false; + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + + // Frame should not be complete. + EXPECT_TRUE(frame_out == NULL); + + // Insert 98 frames. + int loop = 0; + do { + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_FALSE(frame_in == NULL); + + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + loop++; + } while (loop < 98); + + // Insert last packet. + ++seq_num_; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_FALSE(frame_in == NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_EQ(0, CheckOutFrame(frame_out, 100 * size_, false)); + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, 100PacketDeltaFrame) { + // Always start with a complete key frame. + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = true; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + EXPECT_FALSE(frame_out == NULL); + + ++seq_num_; + packet_->seqNum = seq_num_; + packet_->markerBit = false; + packet_->frameType = kVideoFrameDelta; + packet_->timestamp += 33 * 90; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_FALSE(frame_in == NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + // Frame should not be complete. + EXPECT_TRUE(frame_out == NULL); + + packet_->isFirstPacket = false; + // Insert 98 frames. + int loop = 0; + do { + ++seq_num_; + packet_->seqNum = seq_num_; + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_FALSE(frame_in == NULL); + // Insert a packet into a frame. + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + loop++; + } while (loop < 98); + + // Insert the last packet. + ++seq_num_; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_FALSE(frame_in == NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_EQ(0, CheckOutFrame(frame_out, 100 * size_, false)); + EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, PacketReorderingReverseOrder) { + // Insert the "first" packet last. + seq_num_ += 100; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + + EXPECT_TRUE(frame_out == NULL); + + // Insert 98 packets. + int loop = 0; + do { + seq_num_--; + packet_->isFirstPacket = false; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + loop++; + } while (loop < 98); + + // Insert the last packet. + seq_num_--; + packet_->isFirstPacket = true; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame();; + + EXPECT_EQ(0, CheckOutFrame(frame_out, 100 * size_, false)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, FrameReordering2Frames2PacketsEach) { + packet_->frameType = kVideoFrameDelta; + packet_->isFirstPacket = true; + packet_->markerBit = false; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + + EXPECT_TRUE(frame_out == NULL); + + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + // check that we fail to get frame since seqnum is not continuous + frame_out = DecodeCompleteFrame(); + EXPECT_TRUE(frame_out == NULL); + + seq_num_ -= 3; + timestamp_ -= 33*90; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + // It should not be complete. + EXPECT_TRUE(frame_out == NULL); + + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_EQ(0, CheckOutFrame(frame_out, 2 * size_, false)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); + + jitter_buffer_->ReleaseFrame(frame_out); + + frame_out = DecodeCompleteFrame(); + + EXPECT_EQ(0, CheckOutFrame(frame_out, 2 * size_, false)); + + EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, DuplicatePackets) { + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + + EXPECT_TRUE(frame_out == NULL); + + packet_->isFirstPacket = false; + packet_->markerBit = true; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + // Insert a packet into a frame. + EXPECT_EQ(kDuplicatePacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + seq_num_++; + packet_->seqNum = seq_num_; + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_EQ(0, CheckOutFrame(frame_out, 2 * size_, false)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, H264InsertStartCode) { + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->insertStartCode = true; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + + // Frame should not be complete. + EXPECT_TRUE(frame_out == NULL); + + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_EQ(0, CheckOutFrame(frame_out, size_ * 2 + 4 * 2, true)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, PacketLoss) { + // Verify missing packets statistics and not decodable packets statistics. + // Insert 10 frames consisting of 4 packets and remove one from all of them. + // The last packet is an empty (non-media) packet. + + // Select a start seqNum which triggers a difficult wrap situation + // The JB will only output (incomplete)frames if the next one has started + // to arrive. Start by inserting one frame (key). + jitter_buffer_->DecodeWithErrors(true); + seq_num_ = 0xffff - 4; + seq_num_++; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->completeNALU = kNaluStart; + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + for (int i = 0; i < 11; ++i) { + webrtc::FrameType frametype = kVideoFrameDelta; + seq_num_++; + timestamp_ += 33*90; + packet_->frameType = frametype; + packet_->isFirstPacket = true; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->completeNALU = kNaluStart; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + + // Should not be complete. + EXPECT_TRUE(frame_out == NULL); + + seq_num_ += 2; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + packet_->completeNALU = kNaluEnd; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + + // Insert an empty (non-media) packet. + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + packet_->completeNALU = kNaluEnd; + packet_->frameType = kFrameEmpty; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeIncompleteFrame(); + + // One of the packets has been discarded by the jitter buffer. + // Last frame can't be extracted yet. + if (i < 10) { + EXPECT_EQ(0, CheckOutFrame(frame_out, size_, false)); + + if (i == 0) { + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); + } else { + EXPECT_EQ(frametype, frame_out->FrameType()); + } + EXPECT_FALSE(frame_out->Complete()); + EXPECT_FALSE(frame_out->MissingFrame()); + } + + jitter_buffer_->ReleaseFrame(frame_out); + } + + EXPECT_EQ(10, jitter_buffer_->num_not_decodable_packets()); + + // Insert 3 old packets and verify that we have 3 discarded packets + // Match value to actual latest timestamp decoded. + timestamp_ -= 33 * 90; + packet_->timestamp = timestamp_ - 1000; + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in == NULL); + + packet_->timestamp = timestamp_ - 500; + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in == NULL); + + packet_->timestamp = timestamp_ - 100; + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in == NULL); + + EXPECT_EQ(3, jitter_buffer_->num_discarded_packets()); + + jitter_buffer_->Flush(); + + // This statistic shouldn't be reset by a flush. + EXPECT_EQ(3, jitter_buffer_->num_discarded_packets()); +} + +TEST_F(TestBasicJitterBuffer, DeltaFrame100PacketsWithSeqNumWrap) { + seq_num_ = 0xfff0; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + + EXPECT_TRUE(frame_out == NULL); + + int loop = 0; + do { + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_TRUE(frame_out == NULL); + + loop++; + } while (loop < 98); + + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_EQ(0, CheckOutFrame(frame_out, 100 * size_, false)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, PacketReorderingReverseWithNegSeqNumWrap) { + // Insert "first" packet last seqnum. + seq_num_ = 10; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + + // Should not be complete. + EXPECT_TRUE(frame_out == NULL); + + // Insert 98 frames. + int loop = 0; + do { + seq_num_--; + packet_->isFirstPacket = false; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_TRUE(frame_out == NULL); + + loop++; + } while (loop < 98); + + // Insert last packet. + seq_num_--; + packet_->isFirstPacket = true; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + EXPECT_EQ(0, CheckOutFrame(frame_out, 100 * size_, false)); + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, TestInsertOldFrame) { + // ------- ------- + // | 2 | | 1 | + // ------- ------- + // t = 3000 t = 2000 + seq_num_ = 2; + timestamp_ = 3000; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->timestamp = timestamp_; + packet_->seqNum = seq_num_; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + EXPECT_EQ(3000u, frame_out->TimeStamp()); + + EXPECT_EQ(0, CheckOutFrame(frame_out, size_, false)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); + + jitter_buffer_->ReleaseFrame(frame_out); + + seq_num_--; + timestamp_ = 2000; + packet_->frameType = kVideoFrameDelta; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + // Changed behavior, never insert packets into frames older than the + // last decoded frame. + EXPECT_TRUE(frame_in == NULL); +} + +TEST_F(TestBasicJitterBuffer, TestInsertOldFrameWithSeqNumWrap) { + // ------- ------- + // | 2 | | 1 | + // ------- ------- + // t = 3000 t = 0xffffff00 + + seq_num_ = 2; + timestamp_ = 3000; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + EXPECT_EQ(timestamp_, frame_out->TimeStamp()); + + EXPECT_EQ(0, CheckOutFrame(frame_out, size_, false)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); + + jitter_buffer_->ReleaseFrame(frame_out); + + seq_num_--; + timestamp_ = 0xffffff00; + packet_->frameType = kVideoFrameDelta; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + // This timestamp is old. + EXPECT_TRUE(frame_in == NULL); +} + +TEST_F(TestBasicJitterBuffer, TimestampWrap) { + // --------------- --------------- + // | 1 | 2 | | 3 | 4 | + // --------------- --------------- + // t = 0xffffff00 t = 33*90 + + timestamp_ = 0xffffff00; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + + EXPECT_TRUE(frame_out == NULL); + + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_EQ(0, CheckOutFrame(frame_out, 2 * size_, false)); + + jitter_buffer_->ReleaseFrame(frame_out); + + seq_num_++; + timestamp_ += 33*90; + packet_->frameType = kVideoFrameDelta; + packet_->isFirstPacket = true; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_TRUE(frame_out == NULL); + + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeCompleteFrame(); + + EXPECT_EQ(0, CheckOutFrame(frame_out, 2 * size_, false)); + + EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, 2FrameWithTimestampWrap) { + // ------- ------- + // | 1 | | 2 | + // ------- ------- + // t = 0xffffff00 t = 2700 + + timestamp_ = 0xffffff00; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->timestamp = timestamp_; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + // Insert first frame (session will be complete). + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + // Insert next frame. + seq_num_++; + timestamp_ = 2700; + packet_->frameType = kVideoFrameDelta; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + EXPECT_EQ(0xffffff00, frame_out->TimeStamp()); + + EXPECT_EQ(0, CheckOutFrame(frame_out, size_, false)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); + + VCMEncodedFrame* frame_out2 = DecodeCompleteFrame(); + EXPECT_EQ(2700u, frame_out2->TimeStamp()); + + EXPECT_EQ(0, CheckOutFrame(frame_out2, size_, false)); + + EXPECT_EQ(kVideoFrameDelta, frame_out2->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, Insert2FramesReOrderedWithTimestampWrap) { + // ------- ------- + // | 2 | | 1 | + // ------- ------- + // t = 2700 t = 0xffffff00 + + seq_num_ = 2; + timestamp_ = 2700; + packet_->frameType = kVideoFrameDelta; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + // Insert second frame + seq_num_--; + timestamp_ = 0xffffff00; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + EXPECT_EQ(0xffffff00, frame_out->TimeStamp()); + + EXPECT_EQ(0, CheckOutFrame(frame_out, size_, false)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); + + VCMEncodedFrame* frame_out2 = DecodeCompleteFrame(); + EXPECT_EQ(2700u, frame_out2->TimeStamp()); + + EXPECT_EQ(0, CheckOutFrame(frame_out2, size_, false)); + + EXPECT_EQ(kVideoFrameDelta, frame_out2->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, DeltaFrameWithMoreThanMaxNumberOfPackets) { + int loop = 0; + bool firstPacket = true; + VCMEncodedFrame* frame_in; + // Insert kMaxPacketsInJitterBuffer into frame. + do { + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + if (firstPacket) { + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + firstPacket = false; + } else { + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + } + + loop++; + } while (loop < kMaxPacketsInSession); + + // Max number of packets inserted. + // Insert one more packet. + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + // Insert the packet -> frame recycled. + EXPECT_EQ(kSizeError, jitter_buffer_->InsertPacket(frame_in, *packet_)); + EXPECT_TRUE(NULL == DecodeCompleteFrame()); + +} + +TEST_F(TestBasicJitterBuffer, ExceedNumOfFrameWithSeqNumWrap) { + // TEST fill JB with more than max number of frame (50 delta frames + + // 51 key frames) with wrap in seq_num_ + // + // -------------------------------------------------------------- + // | 65485 | 65486 | 65487 | .... | 65535 | 0 | 1 | 2 | .....| 50 | + // -------------------------------------------------------------- + // |<-----------delta frames------------->|<------key frames----->| + + int loop = 0; + seq_num_ = 65485; + VCMEncodedFrame* ptrLastDeltaFrame = NULL; + VCMEncodedFrame* ptrFirstKeyFrame = NULL; + VCMEncodedFrame* frame_in; + // Insert MAX_NUMBER_OF_FRAMES frames. + do { + timestamp_ += 33*90; + seq_num_++; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_TRUE(frame_in != NULL); + + if (loop == 49) { // last delta + ptrLastDeltaFrame = frame_in; + } + if (loop == 50) { // first key + ptrFirstKeyFrame = frame_in; + packet_->frameType = kVideoFrameKey; + } + + // Insert frame. + EXPECT_EQ(kCompleteSession, + jitter_buffer_->InsertPacket(frame_in, *packet_)); + + loop++; + } while (loop < kMaxNumberOfFrames); + + // Max number of frames inserted. + + // Insert one more frame. + timestamp_ += 33*90; + seq_num_++; + packet_->isFirstPacket = true; + packet_->markerBit = true; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + + // Now, no free frame - frames will be recycled until first key frame. + frame_in = jitter_buffer_->GetFrame(*packet_); + // Pointer to last inserted delta frame should be returned. + EXPECT_TRUE(frame_in != NULL && frame_in && ptrLastDeltaFrame); + + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeCompleteFrame();; + EXPECT_EQ(ptrFirstKeyFrame, frame_out); + + EXPECT_EQ(0, CheckOutFrame(frame_out, size_, false)); + + EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); +} + +TEST_F(TestBasicJitterBuffer, EmptyLastFrame) { + jitter_buffer_->DecodeWithErrors(true); + seq_num_ = 3; + // Insert one empty packet per frame, should never return the last timestamp + // inserted. Only return empty frames in the presence of subsequent frames. + int maxSize = 1000; + for (int i = 0; i < maxSize + 10; i++) { + timestamp_ += 33 * 90; + seq_num_++; + packet_->isFirstPacket = false; + packet_->markerBit = false; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->frameType = kFrameEmpty; + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + VCMEncodedFrame* testFrame = DecodeIncompleteFrame(); + // Timestamp should never be the last TS inserted. + if (testFrame != NULL) { + EXPECT_TRUE(testFrame->TimeStamp() < timestamp_); + } + } +} + +TEST_F(TestBasicJitterBuffer, H264IncompleteNalu) { + jitter_buffer_->SetNackMode(kNoNack, -1, -1); + jitter_buffer_->DecodeWithErrors(true); + seq_num_ ++; + timestamp_ += 33 * 90; + int insertedLength = 0; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->completeNALU = kNaluStart; + packet_->markerBit = false; + + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + seq_num_ += 2; // Skip one packet + packet_->seqNum = seq_num_; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = false; + packet_->completeNALU = kNaluIncomplete; + packet_->markerBit = false; + + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + seq_num_++; + packet_->seqNum = seq_num_; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = false; + packet_->completeNALU = kNaluEnd; + packet_->markerBit = false; + + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + seq_num_++; + packet_->seqNum = seq_num_; + packet_->completeNALU = kNaluComplete; + packet_->markerBit = true; // Last packet + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + // The JB will only output (incomplete) frames if a packet belonging to a + // subsequent frame was already inserted. Insert one packet of a subsequent + // frame. place high timestamp so the JB would always have a next frame + // (otherwise, for every inserted frame we need to take care of the next + // frame as well). + packet_->seqNum = 1; + packet_->timestamp = timestamp_ + 33 * 90 * 10; + packet_->frameType = kVideoFrameDelta; + packet_->isFirstPacket = false; + packet_->completeNALU = kNaluStart; + packet_->markerBit = false; + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + VCMEncodedFrame* frame_out = DecodeIncompleteFrame(); + + // We can decode everything from a NALU until a packet has been lost. + // Thus we can decode the first packet of the first NALU and the second NALU + // which consists of one packet. + EXPECT_EQ(0, CheckOutFrame(frame_out, packet_->sizeBytes * 2, false)); + jitter_buffer_->ReleaseFrame(frame_out); + + // Test reordered start frame + 1 lost. + seq_num_ += 2; // Re-order 1 frame. + timestamp_ += 33*90; + insertedLength = 0; + + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = false; + packet_->completeNALU = kNaluEnd; + packet_->markerBit = false; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + insertedLength += packet_->sizeBytes; // This packet should be decoded. + + seq_num_--; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->completeNALU = kNaluStart; + packet_->markerBit = false; + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + insertedLength += packet_->sizeBytes; // This packet should be decoded. + + seq_num_ += 3; // One packet drop + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = false; + packet_->completeNALU = kNaluComplete; + packet_->markerBit = false; + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + insertedLength += packet_->sizeBytes; // This packet should be decoded. + + seq_num_ += 1; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = false; + packet_->completeNALU = kNaluStart; + packet_->markerBit = false; + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + // This packet should be decoded since it's the beginning of a NAL. + insertedLength += packet_->sizeBytes; + + seq_num_ += 2; + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = false; + packet_->completeNALU = kNaluEnd; + packet_->markerBit = true; + EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(frame_in, *packet_)); + // This packet should not be decoded because it is an incomplete NAL if it + // is the last. + frame_out = DecodeIncompleteFrame(); + // Only last NALU is complete. + EXPECT_EQ(0, CheckOutFrame(frame_out, insertedLength, false)); + jitter_buffer_->ReleaseFrame(frame_out); + + + // Test to insert empty packet. + seq_num_ += 1; + timestamp_ += 33 * 90; + VCMPacket emptypacket(data_, 0, seq_num_, timestamp_, true); + emptypacket.seqNum = seq_num_; + emptypacket.timestamp = timestamp_; + emptypacket.frameType = kVideoFrameKey; + emptypacket.isFirstPacket = true; + emptypacket.completeNALU = kNaluComplete; + emptypacket.markerBit = true; + frame_in = jitter_buffer_->GetFrame(emptypacket); + EXPECT_EQ(kCompleteSession, + jitter_buffer_->InsertPacket(frame_in, emptypacket)); + // This packet should not be decoded because it is an incomplete NAL if it + // is the last. + insertedLength += 0; + + // Will be sent to the decoder, as a packet belonging to a subsequent frame + // has arrived. + frame_out = DecodeIncompleteFrame(); + + + // Test that a frame can include an empty packet. + seq_num_ += 1; + timestamp_ += 33 * 90; + + packet_->seqNum = seq_num_; + packet_->timestamp = timestamp_; + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->completeNALU = kNaluComplete; + packet_->markerBit = false; + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + seq_num_ += 1; + emptypacket.seqNum = seq_num_; + emptypacket.timestamp = timestamp_; + emptypacket.frameType = kVideoFrameKey; + emptypacket.isFirstPacket = true; + emptypacket.completeNALU = kNaluComplete; + emptypacket.markerBit = true; + EXPECT_EQ(kCompleteSession, + jitter_buffer_->InsertPacket(frame_in, emptypacket)); + + frame_out = DecodeCompleteFrame(); + // Only last NALU is complete + EXPECT_EQ(0, CheckOutFrame(frame_out, packet_->sizeBytes, false)); +} + +TEST_F(TestBasicJitterBuffer, NextFrameWhenIncomplete) { + // Test that a we cannot get incomplete frames from the JB if we haven't + // received the marker bit, unless we have received a packet from a later + // timestamp. + jitter_buffer_->DecodeWithErrors(true); + // Start with a complete key frame - insert and decode. + packet_->frameType = kVideoFrameKey; + packet_->isFirstPacket = true; + packet_->markerBit = true; + VCMEncodedFrame* frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(frame_in, *packet_)); + VCMEncodedFrame* frame_out = DecodeCompleteFrame(); + EXPECT_TRUE(frame_out != NULL); + + packet_->seqNum += 2; + packet_->timestamp += 33 * 90; + packet_->frameType = kVideoFrameDelta; + packet_->isFirstPacket = false; + packet_->markerBit = false; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeIncompleteFrame(); + EXPECT_TRUE(frame_out == NULL); + + packet_->seqNum += 2; + packet_->timestamp += 33 * 90; + packet_->isFirstPacket = true; + + frame_in = jitter_buffer_->GetFrame(*packet_); + EXPECT_EQ(kFirstPacket, jitter_buffer_->InsertPacket(frame_in, *packet_)); + + frame_out = DecodeIncompleteFrame(); + + EXPECT_EQ(0, CheckOutFrame(frame_out, packet_->sizeBytes, false)); +} + TEST_F(TestRunningJitterBuffer, Full) { // Insert a key frame and decode it. EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError); diff --git a/webrtc/modules/video_coding/main/test/jitter_buffer_test.cc b/webrtc/modules/video_coding/main/test/jitter_buffer_test.cc deleted file mode 100644 index 9edbd2a82..000000000 --- a/webrtc/modules/video_coding/main/test/jitter_buffer_test.cc +++ /dev/null @@ -1,1755 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/modules/video_coding/main/test/jitter_estimate_test.h" - -#include - -#include "webrtc/common_types.h" -#include "webrtc/modules/video_coding/main/interface/video_coding.h" -#include "webrtc/modules/video_coding/main/source/frame_buffer.h" -#include "webrtc/modules/video_coding/main/source/inter_frame_delay.h" -#include "webrtc/modules/video_coding/main/source/jitter_buffer.h" -#include "webrtc/modules/video_coding/main/source/jitter_estimator.h" -#include "webrtc/modules/video_coding/main/source/media_opt_util.h" -#include "webrtc/modules/video_coding/main/source/packet.h" -#include "webrtc/modules/video_coding/main/test/test_util.h" -#include "webrtc/modules/video_coding/main/test/test_macros.h" -#include "webrtc/system_wrappers/interface/clock.h" - -// TODO(holmer): Get rid of this to conform with style guide. -using namespace webrtc; - -// TODO (Mikhal/Stefan): Update as gtest and separate to specific tests. - -int CheckOutFrame(VCMEncodedFrame* frameOut, unsigned int size, bool startCode) -{ - if (frameOut == 0) - { - return -1; - } - - const uint8_t* outData = frameOut->Buffer(); - - unsigned int i = 0; - - if(startCode) - { - if (outData[0] != 0 || outData[1] != 0 || outData[2] != 0 || - outData[3] != 1) - { - return -2; - } - i+= 4; - } - - // check the frame data - int count = 3; - - // check the frame length - if (frameOut->Length() != size) - { - return -3; - } - - for(; i < size; i++) - { - if (outData[i] == 0 && outData[i + 1] == 0 && outData[i + 2] == 0x80) - { - i += 2; - } - else if(startCode && outData[i] == 0 && outData[i + 1] == 0) - { - if (outData[i] != 0 || outData[i + 1] != 0 || - outData[i + 2] != 0 || outData[i + 3] != 1) - { - return -3; - } - i += 3; - } - else - { - if (outData[i] != count) - { - return -4; - } - count++; - if(count == 10) - { - count = 3; - } - } - } - return 0; -} - -VCMEncodedFrame* DecodeCompleteFrame(uint32_t max_wait_time_ms) { - uint32_t timestamp = 0; - bool found_frame = jb.NextCompleteTimestamp(max_wait_time_ms, ×tamp); - if (!found_frame) - return NULL; - - return jb.ExtractAndSetDecode(timestamp); -} - -VCMEncodedFrame* DecodeIncompleteFrame() { - uint32_t timestamp = 0; - bool found_frame = - jb.MaybeGetIncompleteFrameTimestampForDecoding(×tamp); - if (!found_frame) - return NULL; - return frame = jb.ExtractAndSetDecode(timestamp); -} - -int JitterBufferTest(CmdArgs& args) -{ - Clock* clock = Clock::GetRealTimeClock(); - - // Start test - uint16_t seqNum = 1234; - uint32_t timeStamp = 0; - int size = 1400; - uint8_t data[1500]; - VCMPacket packet(data, size, seqNum, timeStamp, true); - - NullEventFactory event_factory; - VCMJitterBuffer jb(clock, &event_factory, -1, -1, true); - - seqNum = 1234; - timeStamp = 123*90; - VCMEncodedFrame* frameOut=NULL; - packet.timestamp = timeStamp; - packet.seqNum = seqNum; - - // build a data vector with 0, 0, 0x80, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0x80, 3.... - data[0] = 0; - data[1] = 0; - data[2] = 0x80; - int count = 3; - for (unsigned int i = 3; i < sizeof(data) - 3; ++i) - { - data[i] = count; - count++; - if(count == 10) - { - data[i+1] = 0; - data[i+2] = 0; - data[i+3] = 0x80; - count = 3; - i += 3; - } - } - - // Not started - TEST(0 == jb.GetFrame(packet)); - TEST(0 == DecodeCompleteFrame(10)); - TEST(0 == DecodeIncompleteFrame()); - - // Start - jb.Start(); - - // Allow decoding with errors. - jb.DecodeWithErrors(true); - - // Get frame to use for this timestamp - VCMEncodedFrame* frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // No packets inserted - TEST(0 == DecodeCompleteFrame(10)); - - - // - // TEST single packet frame - // - // -------- - // | 1234 | - // -------- - - // packet.frameType; - // packet.dataPtr; - // packet.sizeBytes; - // packet.timestamp; - // packet.seqNum; - // packet.isFirstPacket; - // packet.markerBit; - // - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = true; - packet.markerBit = true; - - // Insert a packet into a frame. - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // Get the frame (always starts with a key frame). - frameOut = DecodeCompleteFrame(10); - - TEST(CheckOutFrame(frameOut, size, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameKey); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - //printf("DONE delta frame 1 packet\n"); - - // - // TEST dual packet frame - // - // ----------------- - // | 1235 | 1236 | - // ----------------- - // - - seqNum++; - timeStamp += 33*90; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - TEST(CheckOutFrame(frameOut, size*2, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - //printf("DONE delta frame 2 packets\n"); - - - // - // TEST 100 packets frame Key frame - // - // ---------------------------------- - // | 1237 | 1238 | .... | 1336 | - // ---------------------------------- - - // insert first packet - timeStamp += 33*90; - seqNum++; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - // insert 98 frames - int loop = 0; - do - { - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = false; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - loop++; - } while (loop < 98); - - // insert last packet - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - TEST(CheckOutFrame(frameOut, size*100, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameKey); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - //printf("DONE key frame 100 packets\n"); - - // - // TEST 100 packets frame Delta frame - // - // ---------------------------------- - // | 1337 | 1238 | .... | 1436 | - // ---------------------------------- - - // insert first packet - timeStamp += 33*90; - seqNum++; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - // insert 98 frames - loop = 0; - do - { - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = false; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - loop++; - } while (loop < 98); - - // insert last packet - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - TEST(CheckOutFrame(frameOut, size*100, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - //printf("DONE delta frame 100 packets\n"); - - // - // TEST packet re-ordering reverse order - // - // ---------------------------------- - // | 1437 | 1238 | .... | 1536 | - // ---------------------------------- - // <---------- - - // insert "first" packet last seqnum - timeStamp += 33*90; - seqNum += 100; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - // insert 98 packets - loop = 0; - do - { - seqNum--; - packet.isFirstPacket = false; - packet.markerBit = false; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - loop++; - } while (loop < 98); - - // insert last packet - seqNum--; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - TEST(CheckOutFrame(frameOut, size*100, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - //printf("DONE delta frame 100 packets reverse order\n"); - - seqNum+= 100; - - // - // TEST frame re-ordering 2 frames 2 packets each - // - // ----------------- ----------------- - // | 1539 | 1540 | | 1537 | 1538 | - // ----------------- ----------------- - - seqNum += 2; - timeStamp += 2* 33 * 90; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // check that we fail to get frame since seqnum is not continuous - frameOut = DecodeCompleteFrame(10); - TEST(frameOut == 0); - - seqNum -= 3; - timeStamp -= 33*90; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = jb.GetCompleteFrameForDecoding(10); - - // it should not be complete - TEST(frameOut == 0); - - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - TEST(CheckOutFrame(frameOut, size*2, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - TEST(CheckOutFrame(frameOut, size*2, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - seqNum += 2; - //printf("DONE frame re-ordering 2 frames 2 packets\n"); - - // restore - packet.dataPtr = data; - packet.codec = kVideoCodecUnknown; - - // - // TEST duplicate packets - // - // ----------------- - // | 1543 | 1543 | - // ----------------- - // - - seqNum++; - timeStamp += 2*33*90; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - packet.isFirstPacket = false; - packet.markerBit = true; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kDuplicatePacket == jb.InsertPacket(frameIn, packet)); - - seqNum++; - packet.seqNum = seqNum; - - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - TEST(CheckOutFrame(frameOut, size*2, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - //printf("DONE test duplicate packets\n"); - - // - // TEST H.264 insert start code - // - // ----------------- - // | 1544 | 1545 | - // ----------------- - // insert start code, both packets - - seqNum++; - timeStamp += 33 * 90; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.insertStartCode = true; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - TEST(CheckOutFrame(frameOut, size * 2 + 4 * 2, true) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - // reset - packet.insertStartCode = false; - //printf("DONE H.264 insert start code test 2 packets\n"); - - - jb.Flush(); - - // - // TEST packet loss. Verify missing packets statistics and not decodable - // packets statistics. - // Insert 10 frames consisting of 4 packets and remove one from all of them. - // The last packet is an empty (non-media) packet - // - - // Select a start seqNum which triggers a difficult wrap situation - // The JB will only output (incomplete)frames if the next one has started - // to arrive. Start by inserting one frame (key). - seqNum = 0xffff - 4; - seqNum++; - timeStamp += 33*90; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.completeNALU = kNaluStart; - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - for (int i = 0; i < 11; ++i) { - webrtc::FrameType frametype = kVideoFrameDelta; - seqNum++; - timeStamp += 33*90; - packet.frameType = frametype; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.completeNALU = kNaluStart; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // Get the frame - frameOut = DecodeCompleteFrame(10); - - // Should not be complete - TEST(frameOut == 0); - - seqNum += 2; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.completeNALU = kNaluEnd; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - - - // Insert an empty (non-media) packet - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.completeNALU = kNaluEnd; - packet.frameType = kFrameEmpty; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - - // Get the frame - frameOut = DecodeIncompleteFrame(); - - // One of the packets has been discarded by the jitter buffer. - // Last frame can't be extracted yet. - if (i < 10) - { - TEST(CheckOutFrame(frameOut, size, false) == 0); - - // check the frame type - if (i == 0) - { - TEST(frameOut->FrameType() == kVideoFrameKey); - } - else - { - TEST(frameOut->FrameType() == frametype); - } - TEST(frameOut->Complete() == false); - TEST(frameOut->MissingFrame() == false); - } - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - } - - TEST(jb.num_not_decodable_packets() == 10); - - // Insert 3 old packets and verify that we have 3 discarded packets - // Match value to actual latest timestamp decoded - timeStamp -= 33 * 90; - packet.timestamp = timeStamp - 1000; - frameIn = jb.GetFrame(packet); - TEST(frameIn == NULL); - - packet.timestamp = timeStamp - 500; - frameIn = jb.GetFrame(packet); - TEST(frameIn == NULL); - - packet.timestamp = timeStamp - 100; - frameIn = jb.GetFrame(packet); - TEST(frameIn == NULL); - - TEST(jb.num_discarded_packets() == 3); - - jb.Flush(); - - // This statistic shouldn't be reset by a flush. - TEST(jb.num_discarded_packets() == 3); - - //printf("DONE Statistics\n"); - - - // Temporarily do this to make the rest of the test work: - timeStamp += 33*90; - seqNum += 4; - - - // - // TEST delta frame 100 packets with seqNum wrap - // - // --------------------------------------- - // | 65520 | 65521 | ... | 82 | 83 | - // --------------------------------------- - // - - jb.Flush(); - - // insert first packet - timeStamp += 33*90; - seqNum = 0xfff0; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - // Insert 98 packets. - loop = 0; - do - { - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = false; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(2); - - // it should not be complete - TEST(frameOut == 0); - - loop++; - } while (loop < 98); - - // insert last packet - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - TEST(CheckOutFrame(frameOut, size*100, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameKey); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - //printf("DONE delta frame 100 packets with wrap in seqNum\n"); - - // - // TEST packet re-ordering reverse order with neg seqNum warp - // - // ---------------------------------------- - // | 65447 | 65448 | ... | 9 | 10 | - // ---------------------------------------- - // <------------- - - // test flush - jb.Flush(); - - // insert "first" packet last seqnum - timeStamp += 33*90; - seqNum = 10; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeIncompleteFrame(); - - // it should not be complete - TEST(frameOut == 0); - - // insert 98 frames - loop = 0; - do - { - seqNum--; - packet.isFirstPacket = false; - packet.markerBit = false; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(2); - - // it should not be complete - TEST(frameOut == 0); - - loop++; - } while (loop < 98); - - // insert last packet - seqNum--; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeIncompleteFrame(); - - TEST(CheckOutFrame(frameOut, size*100, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - //printf("DONE delta frame 100 packets reverse order with wrap in seqNum \n"); - - // test flush - jb.Flush(); - - // - // TEST packet re-ordering with seqNum wrap - // - // ----------------------- - // | 1 | 65535 | 0 | - // ----------------------- - - // insert "first" packet last seqnum - timeStamp += 33*90; - seqNum = 1; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - // insert last packet - seqNum -= 2; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeIncompleteFrame(); - - // it should not be complete - TEST(frameOut == 0); - - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = false; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeIncompleteFrame(); - - TEST(CheckOutFrame(frameOut, size*3, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - //printf("DONE delta frame 3 packets re-ordering with wrap in seqNum \n"); - - // test flush - jb.Flush(); - - // - // TEST insert old frame - // - // ------- ------- - // | 2 | | 1 | - // ------- ------- - // t = 3000 t = 2000 - - seqNum = 2; - timeStamp = 3000; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // Get the frame - frameOut = DecodeCompleteFrame(); - TEST(3000 == frameOut->TimeStamp()); - - TEST(CheckOutFrame(frameOut, size, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - jb.ReleaseFrame(frameOut); - - seqNum--; - timeStamp = 2000; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - // Changed behavior, never insert packets into frames older than the - // last decoded frame. - TEST(frameIn == 0); - - //printf("DONE insert old frame\n"); - - jb.Flush(); - - // - // TEST insert old frame with wrap in timestamp - // - // ------- ------- - // | 2 | | 1 | - // ------- ------- - // t = 3000 t = 0xffffff00 - - seqNum = 2; - timeStamp = 3000; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // Get the frame - frameOut = DecodeIncompleteFrame(); - TEST(timeStamp == frameOut->TimeStamp()); - - TEST(CheckOutFrame(frameOut, size, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - jb.ReleaseFrame(frameOut); - - seqNum--; - timeStamp = 0xffffff00; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - // This timestamp is old - TEST(frameIn == 0); - - jb.Flush(); - - // - // TEST wrap in timeStamp - // - // --------------- --------------- - // | 1 | 2 | | 3 | 4 | - // --------------- --------------- - // t = 0xffffff00 t = 33*90 - - seqNum = 1; - timeStamp = 0xffffff00; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - frameOut = DecodeIncompleteFrame(); - - TEST(CheckOutFrame(frameOut, size*2, false) == 0); - - jb.ReleaseFrame(frameOut); - - seqNum++; - timeStamp += 33*90; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeCompleteFrame(10); - - // it should not be complete - TEST(frameOut == 0); - - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kCompleteSession == jb.InsertPacket(frameIn, packet)); - - // get the frame - frameOut = DecodeIncompleteFrame(); - - TEST(CheckOutFrame(frameOut, size*2, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - //printf("DONE time stamp wrap 2 frames 2 packets\n"); - - jb.Flush(); - - // - // TEST insert 2 frames with wrap in timeStamp - // - // ------- ------- - // | 1 | | 2 | - // ------- ------- - // t = 0xffffff00 t = 2700 - - seqNum = 1; - timeStamp = 0xffffff00; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert first frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // Insert next frame - seqNum++; - timeStamp = 2700; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // Get frame - frameOut = jb.GetFrameForDecoding(); - TEST(0xffffff00 == frameOut->TimeStamp()); - - TEST(CheckOutFrame(frameOut, size, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Get frame - VCMEncodedFrame* frameOut2 = DecodeIncompleteFrame(); - TEST(2700 == frameOut2->TimeStamp()); - - TEST(CheckOutFrame(frameOut2, size, false) == 0); - - // check the frame type - TEST(frameOut2->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - jb.ReleaseFrame(frameOut2); - - //printf("DONE insert 2 frames (1 packet) with wrap in timestamp\n"); - - jb.Flush(); - - // - // TEST insert 2 frames re-ordered with wrap in timeStamp - // - // ------- ------- - // | 2 | | 1 | - // ------- ------- - // t = 2700 t = 0xffffff00 - - seqNum = 2; - timeStamp = 2700; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert first frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // Insert second frame - seqNum--; - timeStamp = 0xffffff00; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = true; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // Get frame - frameOut = jb.GetFrameForDecoding(); - TEST(0xffffff00 == frameOut->TimeStamp()); - - TEST(CheckOutFrame(frameOut, size, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameDelta); - - // Get frame - frameOut2 = DecodeIncompleteFrame(); - TEST(2700 == frameOut2->TimeStamp()); - - TEST(CheckOutFrame(frameOut2, size, false) == 0); - - // check the frame type - TEST(frameOut2->FrameType() == kVideoFrameDelta); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - jb.ReleaseFrame(frameOut2); - - //printf("DONE insert 2 frames (1 packet) re-ordered with wrap in timestamp\n"); - - // - // TEST delta frame with more than max number of packets - // - - jb.Start(); - - loop = 0; - packet.timestamp += 33*90; - bool firstPacket = true; - // insert kMaxPacketsInJitterBuffer into frame - do - { - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = false; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert frame - if (firstPacket) - { - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - firstPacket = false; - } - else - { - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - } - - loop++; - } while (loop < kMaxPacketsInSession); - - // Max number of packets inserted - - // Insert one more packet - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = true; - packet.seqNum = seqNum; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - // Insert the packet -> frame recycled - TEST(kSizeError == jb.InsertPacket(frameIn, packet)); - - TEST(0 == DecodeIncompleteFrame()); - - //printf("DONE fill frame - packets > max number of packets\n"); - - // - // TEST fill JB with more than max number of frame (50 delta frames + - // 51 key frames) with wrap in seqNum - // - // -------------------------------------------------------------- - // | 65485 | 65486 | 65487 | .... | 65535 | 0 | 1 | 2 | .....| 50 | - // -------------------------------------------------------------- - // |<-----------delta frames------------->|<------key frames----->| - - jb.Flush(); - - loop = 0; - seqNum = 65485; - VCMEncodedFrame* ptrLastDeltaFrame = NULL; - VCMEncodedFrame* ptrFirstKeyFrame = NULL; - // insert MAX_NUMBER_OF_FRAMES frames - do - { - timeStamp += 33*90; - seqNum++; - packet.isFirstPacket = true; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - frameIn = jb.GetFrame(packet); - TEST(frameIn != 0); - - if (loop == 49) // last delta - { - ptrLastDeltaFrame = frameIn; - } - if (loop == 50) // first key - { - ptrFirstKeyFrame = frameIn; - packet.frameType = kVideoFrameKey; - } - - // Insert frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - loop++; - } while (loop < kMaxNumberOfFrames); - - // Max number of frames inserted - - // Insert one more frame - timeStamp += 33*90; - seqNum++; - packet.isFirstPacket = true; - packet.markerBit = true; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - - // Now, no free frame - frames will be recycled until first key frame - frameIn = jb.GetFrame(packet); - // ptr to last inserted delta frame should be returned - TEST(frameIn != 0 && frameIn && ptrLastDeltaFrame); - - // Insert frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - // get the first key frame - frameOut = jb.GetFrameForDecoding(); - TEST(ptrFirstKeyFrame == frameOut); - - TEST(CheckOutFrame(frameOut, size, false) == 0); - - // check the frame type - TEST(frameOut->FrameType() == kVideoFrameKey); - - // Release frame (when done with decoding) - jb.ReleaseFrame(frameOut); - - jb.Flush(); - - // printf("DONE fill JB - nr of delta + key frames (w/ wrap in seqNum) > - // max nr of frames\n"); - - // Testing that 1 empty packet inserted last will not be set for decoding - seqNum = 3; - // Insert one empty packet per frame, should never return the last timestamp - // inserted. Only return empty frames in the presence of subsequent frames. - int maxSize = 1000; - for (int i = 0; i < maxSize + 10; i++) - { - timeStamp += 33 * 90; - seqNum++; - packet.isFirstPacket = false; - packet.markerBit = false; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.frameType = kFrameEmpty; - VCMEncodedFrame* testFrame = jb.MaybeGetIncompleteFrameForDecoding(); - // timestamp should bever be the last TS inserted - if (testFrame != NULL) - { - TEST(testFrame->TimeStamp() < timeStamp); - printf("Not null TS = %d\n",testFrame->TimeStamp()); - } - } - - jb.Flush(); - - - // printf(DONE testing inserting empty packets to the JB) - - - // H.264 tests - // Test incomplete NALU frames - - jb.Flush(); - jb.SetNackMode(kNoNack, -1, -1); - seqNum ++; - timeStamp += 33 * 90; - int insertedLength = 0; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = true; - packet.completeNALU = kNaluStart; - packet.markerBit = false; - - frameIn = jb.GetFrame(packet); - - // Insert a packet into a frame - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - seqNum += 2; // Skip one packet - packet.seqNum = seqNum; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = false; - packet.completeNALU = kNaluIncomplete; - packet.markerBit = false; - - // Insert a packet into a frame - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - - seqNum++; - packet.seqNum = seqNum; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = false; - packet.completeNALU = kNaluEnd; - packet.markerBit = false; - - // Insert a packet into a frame - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - - seqNum++; - packet.seqNum = seqNum; - packet.completeNALU = kNaluComplete; - packet.markerBit = true; // Last packet - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - - - // The JB will only output (incomplete) frames if a packet belonging to a - // subsequent frame was already inserted. Insert one packet of a subsequent - // frame. place high timestamp so the JB would always have a next frame - // (otherwise, for every inserted frame we need to take care of the next - // frame as well). - packet.seqNum = 1; - packet.timestamp = timeStamp + 33 * 90 * 10; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = false; - packet.completeNALU = kNaluStart; - packet.markerBit = false; - frameIn = jb.GetFrame(packet); - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - frameOut = jb.MaybeGetIncompleteFrameForDecoding(); - - // We can decode everything from a NALU until a packet has been lost. - // Thus we can decode the first packet of the first NALU and the second NALU - // which consists of one packet. - TEST(CheckOutFrame(frameOut, packet.sizeBytes * 2, false) == 0); - jb.ReleaseFrame(frameOut); - - // Test reordered start frame + 1 lost - seqNum += 2; // Reoreder 1 frame - timeStamp += 33*90; - insertedLength = 0; - - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = false; - packet.completeNALU = kNaluEnd; - packet.markerBit = false; - - TEST(frameIn = jb.GetFrame(packet)); - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - insertedLength += packet.sizeBytes; // This packet should be decoded - - seqNum--; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = true; - packet.completeNALU = kNaluStart; - packet.markerBit = false; - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - insertedLength += packet.sizeBytes; // This packet should be decoded - - seqNum += 3; // One packet drop - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = false; - packet.completeNALU = kNaluComplete; - packet.markerBit = false; - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - insertedLength += packet.sizeBytes; // This packet should be decoded - - seqNum += 1; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = false; - packet.completeNALU = kNaluStart; - packet.markerBit = false; - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - // This packet should be decoded since it's the beginning of a NAL - insertedLength += packet.sizeBytes; - - seqNum += 2; - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = false; - packet.completeNALU = kNaluEnd; - packet.markerBit = true; - TEST(kIncomplete == jb.InsertPacket(frameIn, packet)); - // This packet should not be decoded because it is an incomplete NAL if it - // is the last - - frameOut = jb.MaybeGetIncompleteFrameForDecoding(); - // Only last NALU is complete - TEST(CheckOutFrame(frameOut, insertedLength, false) == 0); - jb.ReleaseFrame(frameOut); - - - // Test to insert empty packet - seqNum += 1; - timeStamp += 33 * 90; - VCMPacket emptypacket(data, 0, seqNum, timeStamp, true); - emptypacket.seqNum = seqNum; - emptypacket.timestamp = timeStamp; - emptypacket.frameType = kVideoFrameKey; - emptypacket.isFirstPacket = true; - emptypacket.completeNALU = kNaluComplete; - emptypacket.markerBit = true; - TEST(frameIn = jb.GetFrame(emptypacket)); - TEST(kFirstPacket == jb.InsertPacket(frameIn, emptypacket)); - // This packet should not be decoded because it is an incomplete NAL if it - // is the last - insertedLength += 0; - - // Will be sent to the decoder, as a packet belonging to a subsequent frame - // has arrived. - frameOut = jb.MaybeGetIncompleteFrameForDecoding(); - - - // Test that a frame can include an empty packet. - seqNum += 1; - timeStamp += 33 * 90; - - packet.seqNum = seqNum; - packet.timestamp = timeStamp; - packet.frameType = kVideoFrameKey; - packet.isFirstPacket = true; - packet.completeNALU = kNaluComplete; - packet.markerBit = false; - TEST(frameIn = jb.GetFrame(packet)); - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - seqNum += 1; - emptypacket.seqNum = seqNum; - emptypacket.timestamp = timeStamp; - emptypacket.frameType = kVideoFrameKey; - emptypacket.isFirstPacket = true; - emptypacket.completeNALU = kNaluComplete; - emptypacket.markerBit = true; - TEST(kCompleteSession == jb.InsertPacket(frameIn, emptypacket)); - - // get the frame - frameOut = jb.GetFrameForDecoding(); - // Only last NALU is complete - TEST(CheckOutFrame(frameOut, packet.sizeBytes, false) == 0); - - jb.ReleaseFrame(frameOut); - - jb.Flush(); - - // Test that a we cannot get incomplete frames from the JB if we haven't - // received the marker bit, unless we have received a packet from a later - // timestamp. - - packet.seqNum += 2; - packet.frameType = kVideoFrameDelta; - packet.isFirstPacket = false; - packet.markerBit = false; - - TEST(frameIn = jb.GetFrame(packet)); - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - frameOut = jb.MaybeGetIncompleteFrameForDecoding(); - TEST(frameOut == NULL); - - packet.seqNum += 2; - packet.timestamp += 33 * 90; - - TEST(frameIn = jb.GetFrame(packet)); - TEST(kFirstPacket == jb.InsertPacket(frameIn, packet)); - - frameOut = jb.MaybeGetIncompleteFrameForDecoding(); - - TEST(frameOut != NULL); - TEST(CheckOutFrame(frameOut, packet.sizeBytes, false) == 0); - jb.ReleaseFrame(frameOut); - - jb.Stop(); - - printf("DONE !!!\n"); - - printf("\nVCM Jitter Buffer Test: \n\n%i tests completed\n", - vcmMacrosTests); - if (vcmMacrosErrors > 0) - { - printf("%i FAILED\n\n", vcmMacrosErrors); - } - else - { - printf("ALL PASSED\n\n"); - } - - return 0; - -}