| /* |
| * Copyright (c) 2011 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 <string> |
| |
| #include <list> |
| #include <memory> |
| #include <vector> |
| |
| #include "common_video/h264/h264_common.h" |
| #include "modules/video_coding/frame_buffer.h" |
| #include "modules/video_coding/jitter_buffer.h" |
| #include "modules/video_coding/media_opt_util.h" |
| #include "modules/video_coding/packet.h" |
| #include "modules/video_coding/test/stream_generator.h" |
| #include "rtc_base/location.h" |
| #include "system_wrappers/include/clock.h" |
| #include "system_wrappers/include/field_trial.h" |
| #include "system_wrappers/include/metrics.h" |
| #include "test/field_trial.h" |
| #include "test/gmock.h" |
| #include "test/gtest.h" |
| |
| namespace webrtc { |
| |
| namespace { |
| const uint32_t kProcessIntervalSec = 60; |
| } // namespace |
| |
| class Vp9SsMapTest : public ::testing::Test { |
| protected: |
| Vp9SsMapTest() : packet_() {} |
| |
| virtual void SetUp() { |
| auto& vp9_header = |
| packet_.video_header.video_type_header.emplace<RTPVideoHeaderVP9>(); |
| packet_.video_header.is_first_packet_in_frame = true; |
| packet_.dataPtr = data_; |
| packet_.sizeBytes = 1400; |
| packet_.seqNum = 1234; |
| packet_.timestamp = 1; |
| packet_.markerBit = true; |
| packet_.frameType = kVideoFrameKey; |
| packet_.video_header.codec = kVideoCodecVP9; |
| packet_.video_header.codec = kVideoCodecVP9; |
| vp9_header.flexible_mode = false; |
| vp9_header.gof_idx = 0; |
| vp9_header.temporal_idx = kNoTemporalIdx; |
| vp9_header.temporal_up_switch = false; |
| vp9_header.ss_data_available = true; |
| vp9_header.gof.SetGofInfoVP9( |
| kTemporalStructureMode3); // kTemporalStructureMode3: 0-2-1-2.. |
| } |
| |
| Vp9SsMap map_; |
| uint8_t data_[1500]; |
| VCMPacket packet_; |
| }; |
| |
| TEST_F(Vp9SsMapTest, Insert) { |
| EXPECT_TRUE(map_.Insert(packet_)); |
| } |
| |
| TEST_F(Vp9SsMapTest, Insert_NoSsData) { |
| absl::get<RTPVideoHeaderVP9>(packet_.video_header.video_type_header) |
| .ss_data_available = false; |
| EXPECT_FALSE(map_.Insert(packet_)); |
| } |
| |
| TEST_F(Vp9SsMapTest, Find) { |
| EXPECT_TRUE(map_.Insert(packet_)); |
| Vp9SsMap::SsMap::iterator it; |
| EXPECT_TRUE(map_.Find(packet_.timestamp, &it)); |
| EXPECT_EQ(packet_.timestamp, it->first); |
| } |
| |
| TEST_F(Vp9SsMapTest, Find_WithWrap) { |
| const uint32_t kSsTimestamp1 = 0xFFFFFFFF; |
| const uint32_t kSsTimestamp2 = 100; |
| packet_.timestamp = kSsTimestamp1; |
| EXPECT_TRUE(map_.Insert(packet_)); |
| packet_.timestamp = kSsTimestamp2; |
| EXPECT_TRUE(map_.Insert(packet_)); |
| Vp9SsMap::SsMap::iterator it; |
| EXPECT_FALSE(map_.Find(kSsTimestamp1 - 1, &it)); |
| EXPECT_TRUE(map_.Find(kSsTimestamp1, &it)); |
| EXPECT_EQ(kSsTimestamp1, it->first); |
| EXPECT_TRUE(map_.Find(0, &it)); |
| EXPECT_EQ(kSsTimestamp1, it->first); |
| EXPECT_TRUE(map_.Find(kSsTimestamp2 - 1, &it)); |
| EXPECT_EQ(kSsTimestamp1, it->first); |
| EXPECT_TRUE(map_.Find(kSsTimestamp2, &it)); |
| EXPECT_EQ(kSsTimestamp2, it->first); |
| EXPECT_TRUE(map_.Find(kSsTimestamp2 + 1, &it)); |
| EXPECT_EQ(kSsTimestamp2, it->first); |
| } |
| |
| TEST_F(Vp9SsMapTest, Reset) { |
| EXPECT_TRUE(map_.Insert(packet_)); |
| Vp9SsMap::SsMap::iterator it; |
| EXPECT_TRUE(map_.Find(packet_.timestamp, &it)); |
| EXPECT_EQ(packet_.timestamp, it->first); |
| |
| map_.Reset(); |
| EXPECT_FALSE(map_.Find(packet_.timestamp, &it)); |
| } |
| |
| TEST_F(Vp9SsMapTest, RemoveOld) { |
| Vp9SsMap::SsMap::iterator it; |
| const uint32_t kSsTimestamp1 = 10000; |
| packet_.timestamp = kSsTimestamp1; |
| EXPECT_TRUE(map_.Insert(packet_)); |
| |
| const uint32_t kTimestamp = kSsTimestamp1 + kProcessIntervalSec * 90000; |
| map_.RemoveOld(kTimestamp - 1); // Interval not passed. |
| EXPECT_TRUE(map_.Find(kSsTimestamp1, &it)); // Should not been removed. |
| |
| map_.RemoveOld(kTimestamp); |
| EXPECT_FALSE(map_.Find(kSsTimestamp1, &it)); |
| EXPECT_TRUE(map_.Find(kTimestamp, &it)); |
| EXPECT_EQ(kTimestamp, it->first); |
| } |
| |
| TEST_F(Vp9SsMapTest, RemoveOld_WithWrap) { |
| Vp9SsMap::SsMap::iterator it; |
| const uint32_t kSsTimestamp1 = 0xFFFFFFFF - kProcessIntervalSec * 90000; |
| const uint32_t kSsTimestamp2 = 10; |
| const uint32_t kSsTimestamp3 = 1000; |
| packet_.timestamp = kSsTimestamp1; |
| EXPECT_TRUE(map_.Insert(packet_)); |
| packet_.timestamp = kSsTimestamp2; |
| EXPECT_TRUE(map_.Insert(packet_)); |
| packet_.timestamp = kSsTimestamp3; |
| EXPECT_TRUE(map_.Insert(packet_)); |
| |
| map_.RemoveOld(kSsTimestamp3); |
| EXPECT_FALSE(map_.Find(kSsTimestamp1, &it)); |
| EXPECT_FALSE(map_.Find(kSsTimestamp2, &it)); |
| EXPECT_TRUE(map_.Find(kSsTimestamp3, &it)); |
| } |
| |
| TEST_F(Vp9SsMapTest, UpdatePacket_NoSsData) { |
| absl::get<RTPVideoHeaderVP9>(packet_.video_header.video_type_header).gof_idx = |
| 0; |
| EXPECT_FALSE(map_.UpdatePacket(&packet_)); |
| } |
| |
| TEST_F(Vp9SsMapTest, UpdatePacket_NoGofIdx) { |
| EXPECT_TRUE(map_.Insert(packet_)); |
| absl::get<RTPVideoHeaderVP9>(packet_.video_header.video_type_header).gof_idx = |
| kNoGofIdx; |
| EXPECT_FALSE(map_.UpdatePacket(&packet_)); |
| } |
| |
| TEST_F(Vp9SsMapTest, UpdatePacket_InvalidGofIdx) { |
| EXPECT_TRUE(map_.Insert(packet_)); |
| absl::get<RTPVideoHeaderVP9>(packet_.video_header.video_type_header).gof_idx = |
| 4; |
| EXPECT_FALSE(map_.UpdatePacket(&packet_)); |
| } |
| |
| TEST_F(Vp9SsMapTest, UpdatePacket) { |
| auto& vp9_header = |
| absl::get<RTPVideoHeaderVP9>(packet_.video_header.video_type_header); |
| EXPECT_TRUE(map_.Insert(packet_)); // kTemporalStructureMode3: 0-2-1-2.. |
| |
| vp9_header.gof_idx = 0; |
| EXPECT_TRUE(map_.UpdatePacket(&packet_)); |
| EXPECT_EQ(0, vp9_header.temporal_idx); |
| EXPECT_FALSE(vp9_header.temporal_up_switch); |
| EXPECT_EQ(1U, vp9_header.num_ref_pics); |
| EXPECT_EQ(4, vp9_header.pid_diff[0]); |
| |
| vp9_header.gof_idx = 1; |
| EXPECT_TRUE(map_.UpdatePacket(&packet_)); |
| EXPECT_EQ(2, vp9_header.temporal_idx); |
| EXPECT_TRUE(vp9_header.temporal_up_switch); |
| EXPECT_EQ(1U, vp9_header.num_ref_pics); |
| EXPECT_EQ(1, vp9_header.pid_diff[0]); |
| |
| vp9_header.gof_idx = 2; |
| EXPECT_TRUE(map_.UpdatePacket(&packet_)); |
| EXPECT_EQ(1, vp9_header.temporal_idx); |
| EXPECT_TRUE(vp9_header.temporal_up_switch); |
| EXPECT_EQ(1U, vp9_header.num_ref_pics); |
| EXPECT_EQ(2, vp9_header.pid_diff[0]); |
| |
| vp9_header.gof_idx = 3; |
| EXPECT_TRUE(map_.UpdatePacket(&packet_)); |
| EXPECT_EQ(2, vp9_header.temporal_idx); |
| EXPECT_TRUE(vp9_header.temporal_up_switch); |
| EXPECT_EQ(1U, vp9_header.num_ref_pics); |
| EXPECT_EQ(1, vp9_header.pid_diff[0]); |
| } |
| |
| class TestBasicJitterBuffer : public ::testing::TestWithParam<std::string>, |
| public NackSender, |
| public KeyFrameRequestSender { |
| public: |
| void SendNack(const std::vector<uint16_t>& sequence_numbers) override { |
| nack_sent_.insert(nack_sent_.end(), sequence_numbers.begin(), |
| sequence_numbers.end()); |
| } |
| |
| void RequestKeyFrame() override { ++keyframe_requests_; } |
| |
| std::vector<uint16_t> nack_sent_; |
| int keyframe_requests_; |
| |
| protected: |
| TestBasicJitterBuffer() {} |
| void SetUp() override { |
| clock_.reset(new SimulatedClock(0)); |
| jitter_buffer_.reset(new VCMJitterBuffer( |
| clock_.get(), absl::WrapUnique(EventWrapper::Create()), this, this)); |
| 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; |
| } |
| } |
| RTPHeader rtp_header; |
| RTPVideoHeader video_header; |
| rtp_header.sequenceNumber = seq_num_; |
| rtp_header.timestamp = timestamp_; |
| rtp_header.markerBit = true; |
| video_header.codec = kVideoCodecGeneric; |
| video_header.is_first_packet_in_frame = true; |
| packet_.reset(new VCMPacket(data_, size_, rtp_header, video_header, |
| kVideoFrameDelta, /*ntp_time_ms=*/0)); |
| } |
| |
| VCMEncodedFrame* DecodeCompleteFrame() { |
| VCMEncodedFrame* found_frame = jitter_buffer_->NextCompleteFrame(10); |
| if (!found_frame) |
| return nullptr; |
| return jitter_buffer_->ExtractAndSetDecode(found_frame->Timestamp()); |
| } |
| |
| void CheckOutFrame(VCMEncodedFrame* frame_out, |
| unsigned int size, |
| bool startCode) { |
| ASSERT_TRUE(frame_out); |
| |
| const uint8_t* outData = frame_out->data(); |
| 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->size()); |
| 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; |
| } |
| } |
| } |
| } |
| |
| uint16_t seq_num_; |
| uint32_t timestamp_; |
| int size_; |
| uint8_t data_[1500]; |
| std::unique_ptr<VCMPacket> packet_; |
| std::unique_ptr<SimulatedClock> clock_; |
| std::unique_ptr<VCMJitterBuffer> jitter_buffer_; |
| }; |
| |
| class TestRunningJitterBuffer : public ::testing::TestWithParam<std::string>, |
| public NackSender, |
| public KeyFrameRequestSender { |
| public: |
| void SendNack(const std::vector<uint16_t>& sequence_numbers) { |
| nack_sent_.insert(nack_sent_.end(), sequence_numbers.begin(), |
| sequence_numbers.end()); |
| } |
| |
| void RequestKeyFrame() { ++keyframe_requests_; } |
| |
| std::vector<uint16_t> nack_sent_; |
| int keyframe_requests_; |
| |
| protected: |
| enum { kDataBufferSize = 10 }; |
| |
| virtual void SetUp() { |
| clock_.reset(new SimulatedClock(0)); |
| max_nack_list_size_ = 150; |
| oldest_packet_to_nack_ = 250; |
| jitter_buffer_ = new VCMJitterBuffer( |
| clock_.get(), absl::WrapUnique(EventWrapper::Create()), this, this); |
| stream_generator_ = new StreamGenerator(0, clock_->TimeInMilliseconds()); |
| jitter_buffer_->Start(); |
| jitter_buffer_->SetNackSettings(max_nack_list_size_, oldest_packet_to_nack_, |
| 0); |
| memset(data_buffer_, 0, kDataBufferSize); |
| } |
| |
| virtual void TearDown() { |
| jitter_buffer_->Stop(); |
| delete stream_generator_; |
| delete jitter_buffer_; |
| } |
| |
| VCMFrameBufferEnum InsertPacketAndPop(int index) { |
| VCMPacket packet; |
| packet.dataPtr = data_buffer_; |
| bool packet_available = stream_generator_->PopPacket(&packet, index); |
| EXPECT_TRUE(packet_available); |
| if (!packet_available) |
| return kGeneralError; // Return here to avoid crashes below. |
| bool retransmitted = false; |
| return jitter_buffer_->InsertPacket(packet, &retransmitted); |
| } |
| |
| VCMFrameBufferEnum InsertPacket(int index) { |
| VCMPacket packet; |
| packet.dataPtr = data_buffer_; |
| bool packet_available = stream_generator_->GetPacket(&packet, index); |
| EXPECT_TRUE(packet_available); |
| if (!packet_available) |
| return kGeneralError; // Return here to avoid crashes below. |
| bool retransmitted = false; |
| return jitter_buffer_->InsertPacket(packet, &retransmitted); |
| } |
| |
| VCMFrameBufferEnum InsertFrame(VideoFrameType frame_type) { |
| stream_generator_->GenerateFrame( |
| frame_type, (frame_type != kEmptyFrame) ? 1 : 0, |
| (frame_type == kEmptyFrame) ? 1 : 0, clock_->TimeInMilliseconds()); |
| VCMFrameBufferEnum ret = InsertPacketAndPop(0); |
| clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs); |
| return ret; |
| } |
| |
| VCMFrameBufferEnum InsertFrames(int num_frames, VideoFrameType frame_type) { |
| VCMFrameBufferEnum ret_for_all = kNoError; |
| for (int i = 0; i < num_frames; ++i) { |
| VCMFrameBufferEnum ret = InsertFrame(frame_type); |
| if (ret < kNoError) { |
| ret_for_all = ret; |
| } else if (ret_for_all >= kNoError) { |
| ret_for_all = ret; |
| } |
| } |
| return ret_for_all; |
| } |
| |
| void DropFrame(int num_packets) { |
| stream_generator_->GenerateFrame(kVideoFrameDelta, num_packets, 0, |
| clock_->TimeInMilliseconds()); |
| for (int i = 0; i < num_packets; ++i) |
| stream_generator_->DropLastPacket(); |
| clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs); |
| } |
| |
| bool DecodeCompleteFrame() { |
| VCMEncodedFrame* found_frame = jitter_buffer_->NextCompleteFrame(0); |
| if (!found_frame) |
| return false; |
| |
| VCMEncodedFrame* frame = |
| jitter_buffer_->ExtractAndSetDecode(found_frame->Timestamp()); |
| bool ret = (frame != NULL); |
| jitter_buffer_->ReleaseFrame(frame); |
| return ret; |
| } |
| |
| VCMJitterBuffer* jitter_buffer_; |
| StreamGenerator* stream_generator_; |
| std::unique_ptr<SimulatedClock> clock_; |
| size_t max_nack_list_size_; |
| int oldest_packet_to_nack_; |
| uint8_t data_buffer_[kDataBufferSize]; |
| }; |
| |
| class TestJitterBufferNack : public TestRunningJitterBuffer { |
| protected: |
| TestJitterBufferNack() {} |
| virtual void SetUp() { |
| TestRunningJitterBuffer::SetUp(); |
| jitter_buffer_->SetNackMode(kNack, -1, -1); |
| } |
| |
| virtual void TearDown() { TestRunningJitterBuffer::TearDown(); } |
| }; |
| |
| TEST_F(TestBasicJitterBuffer, StopRunning) { |
| jitter_buffer_->Stop(); |
| EXPECT_TRUE(NULL == DecodeCompleteFrame()); |
| jitter_buffer_->Start(); |
| |
| // No packets inserted. |
| EXPECT_TRUE(NULL == DecodeCompleteFrame()); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, SinglePacketFrame) { |
| // Always start with a complete key frame when not allowing errors. |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->timestamp += 123 * 90; |
| |
| // Insert the packet to the jitter buffer and get a frame. |
| bool retransmitted = false; |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| CheckOutFrame(frame_out, size_, false); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, VerifyHistogramStats) { |
| metrics::Reset(); |
| // Always start with a complete key frame when not allowing errors. |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->timestamp += 123 * 90; |
| |
| // Insert single packet frame to the jitter buffer and get a frame. |
| bool retransmitted = false; |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| CheckOutFrame(frame_out, size_, false); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| // Verify that histograms are updated when the jitter buffer is stopped. |
| clock_->AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000); |
| jitter_buffer_->Stop(); |
| EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.DiscardedPacketsInPercent", 0)); |
| EXPECT_EQ(1, |
| metrics::NumEvents("WebRTC.Video.DuplicatedPacketsInPercent", 0)); |
| EXPECT_EQ( |
| 1, metrics::NumSamples("WebRTC.Video.CompleteFramesReceivedPerSecond")); |
| EXPECT_EQ( |
| 1, metrics::NumEvents("WebRTC.Video.KeyFramesReceivedInPermille", 1000)); |
| |
| // Verify that histograms are not updated if stop is called again. |
| jitter_buffer_->Stop(); |
| EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DiscardedPacketsInPercent")); |
| EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DuplicatedPacketsInPercent")); |
| EXPECT_EQ( |
| 1, metrics::NumSamples("WebRTC.Video.CompleteFramesReceivedPerSecond")); |
| EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille")); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, DualPacketFrame) { |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| // Should not be complete. |
| EXPECT_TRUE(frame_out == NULL); |
| |
| ++seq_num_; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| CheckOutFrame(frame_out, 2 * size_, false); |
| |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, 100PacketKeyFrame) { |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| |
| // Frame should not be complete. |
| EXPECT_TRUE(frame_out == NULL); |
| |
| // Insert 98 frames. |
| int loop = 0; |
| do { |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| loop++; |
| } while (loop < 98); |
| |
| // Insert last packet. |
| ++seq_num_; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| |
| CheckOutFrame(frame_out, 100 * size_, false); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, 100PacketDeltaFrame) { |
| // Always start with a complete key frame. |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_FALSE(frame_out == NULL); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| ++seq_num_; |
| packet_->seqNum = seq_num_; |
| packet_->markerBit = false; |
| packet_->frameType = kVideoFrameDelta; |
| packet_->timestamp += 33 * 90; |
| |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| |
| // Frame should not be complete. |
| EXPECT_TRUE(frame_out == NULL); |
| |
| packet_->video_header.is_first_packet_in_frame = false; |
| // Insert 98 frames. |
| int loop = 0; |
| do { |
| ++seq_num_; |
| packet_->seqNum = seq_num_; |
| |
| // Insert a packet into a frame. |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| loop++; |
| } while (loop < 98); |
| |
| // Insert the last packet. |
| ++seq_num_; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| |
| CheckOutFrame(frame_out, 100 * size_, false); |
| EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, PacketReorderingReverseOrder) { |
| // Insert the "first" packet last. |
| seq_num_ += 100; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| |
| EXPECT_TRUE(frame_out == NULL); |
| |
| // Insert 98 packets. |
| int loop = 0; |
| do { |
| seq_num_--; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| loop++; |
| } while (loop < 98); |
| |
| // Insert the last packet. |
| seq_num_--; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| |
| CheckOutFrame(frame_out, 100 * size_, false); |
| |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, FrameReordering2Frames2PacketsEach) { |
| packet_->frameType = kVideoFrameDelta; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| |
| EXPECT_TRUE(frame_out == NULL); |
| |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| // 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_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| |
| // It should not be complete. |
| EXPECT_TRUE(frame_out == NULL); |
| |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| CheckOutFrame(frame_out, 2 * size_, false); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| frame_out = DecodeCompleteFrame(); |
| CheckOutFrame(frame_out, 2 * size_, false); |
| EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, TestReorderingWithPadding) { |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| |
| // Send in an initial good packet/frame (Frame A) to start things off. |
| bool retransmitted = false; |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_TRUE(frame_out != NULL); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| // Now send in a complete delta frame (Frame C), but with a sequence number |
| // gap. No pic index either, so no temporal scalability cheating :) |
| packet_->frameType = kVideoFrameDelta; |
| // Leave a gap of 2 sequence numbers and two frames. |
| packet_->seqNum = seq_num_ + 3; |
| packet_->timestamp = timestamp_ + (66 * 90); |
| // Still isFirst = marker = true. |
| // Session should be complete (frame is complete), but there's nothing to |
| // decode yet. |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| frame_out = DecodeCompleteFrame(); |
| EXPECT_TRUE(frame_out == NULL); |
| |
| // Now send in a complete delta frame (Frame B) that is continuous from A, but |
| // doesn't fill the full gap to C. The rest of the gap is going to be padding. |
| packet_->seqNum = seq_num_ + 1; |
| packet_->timestamp = timestamp_ + (33 * 90); |
| // Still isFirst = marker = true. |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| frame_out = DecodeCompleteFrame(); |
| EXPECT_TRUE(frame_out != NULL); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| // But Frame C isn't continuous yet. |
| frame_out = DecodeCompleteFrame(); |
| EXPECT_TRUE(frame_out == NULL); |
| |
| // Add in the padding. These are empty packets (data length is 0) with no |
| // marker bit and matching the timestamp of Frame B. |
| RTPHeader rtp_header; |
| RTPVideoHeader video_header; |
| rtp_header.sequenceNumber = seq_num_ + 2; |
| rtp_header.timestamp = timestamp_ + (33 * 90); |
| rtp_header.markerBit = false; |
| video_header.codec = kVideoCodecGeneric; |
| VCMPacket empty_packet(data_, 0, rtp_header, video_header, |
| VideoFrameType::kEmptyFrame, /*ntp_time_ms=*/0); |
| EXPECT_EQ(kOldPacket, |
| jitter_buffer_->InsertPacket(empty_packet, &retransmitted)); |
| empty_packet.seqNum += 1; |
| EXPECT_EQ(kOldPacket, |
| jitter_buffer_->InsertPacket(empty_packet, &retransmitted)); |
| |
| // But now Frame C should be ready! |
| frame_out = DecodeCompleteFrame(); |
| EXPECT_TRUE(frame_out != NULL); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, DuplicatePackets) { |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| EXPECT_EQ(0, jitter_buffer_->num_packets()); |
| EXPECT_EQ(0, jitter_buffer_->num_duplicated_packets()); |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| |
| EXPECT_TRUE(frame_out == NULL); |
| EXPECT_EQ(1, jitter_buffer_->num_packets()); |
| EXPECT_EQ(0, jitter_buffer_->num_duplicated_packets()); |
| |
| // Insert a packet into a frame. |
| EXPECT_EQ(kDuplicatePacket, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| EXPECT_EQ(2, jitter_buffer_->num_packets()); |
| EXPECT_EQ(1, jitter_buffer_->num_duplicated_packets()); |
| |
| seq_num_++; |
| packet_->seqNum = seq_num_; |
| packet_->markerBit = true; |
| packet_->video_header.is_first_packet_in_frame = false; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| ASSERT_TRUE(frame_out != NULL); |
| CheckOutFrame(frame_out, 2 * size_, false); |
| |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| EXPECT_EQ(3, jitter_buffer_->num_packets()); |
| EXPECT_EQ(1, jitter_buffer_->num_duplicated_packets()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, DuplicatePreviousDeltaFramePacket) { |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| EXPECT_EQ(0, jitter_buffer_->num_packets()); |
| EXPECT_EQ(0, jitter_buffer_->num_duplicated_packets()); |
| |
| bool retransmitted = false; |
| // Insert first complete frame. |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| ASSERT_TRUE(frame_out != NULL); |
| CheckOutFrame(frame_out, size_, false); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| // Insert 3 delta frames. |
| for (uint16_t i = 1; i <= 3; ++i) { |
| packet_->seqNum = seq_num_ + i; |
| packet_->timestamp = timestamp_ + (i * 33) * 90; |
| packet_->frameType = kVideoFrameDelta; |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| EXPECT_EQ(i + 1, jitter_buffer_->num_packets()); |
| EXPECT_EQ(0, jitter_buffer_->num_duplicated_packets()); |
| } |
| |
| // Retransmit second delta frame. |
| packet_->seqNum = seq_num_ + 2; |
| packet_->timestamp = timestamp_ + 66 * 90; |
| |
| EXPECT_EQ(kDuplicatePacket, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| EXPECT_EQ(5, jitter_buffer_->num_packets()); |
| EXPECT_EQ(1, jitter_buffer_->num_duplicated_packets()); |
| |
| // Should be able to decode 3 delta frames, key frame already decoded. |
| for (size_t i = 0; i < 3; ++i) { |
| frame_out = DecodeCompleteFrame(); |
| ASSERT_TRUE(frame_out != NULL); |
| CheckOutFrame(frame_out, size_, false); |
| EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| } |
| |
| TEST_F(TestBasicJitterBuffer, TestSkipForwardVp9) { |
| // Verify that JB skips forward to next base layer frame. |
| // ------------------------------------------------- |
| // | 65485 | 65486 | 65487 | 65488 | 65489 | ... |
| // | pid:5 | pid:6 | pid:7 | pid:8 | pid:9 | ... |
| // | tid:0 | tid:2 | tid:1 | tid:2 | tid:0 | ... |
| // | ss | x | x | x | | |
| // ------------------------------------------------- |
| // |<----------tl0idx:200--------->|<---tl0idx:201--- |
| |
| auto& vp9_header = |
| packet_->video_header.video_type_header.emplace<RTPVideoHeaderVP9>(); |
| |
| bool re = false; |
| packet_->video_header.codec = kVideoCodecVP9; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| vp9_header.flexible_mode = false; |
| vp9_header.spatial_idx = 0; |
| vp9_header.beginning_of_frame = true; |
| vp9_header.end_of_frame = true; |
| vp9_header.temporal_up_switch = false; |
| |
| packet_->seqNum = 65485; |
| packet_->timestamp = 1000; |
| packet_->frameType = kVideoFrameKey; |
| vp9_header.picture_id = 5; |
| vp9_header.tl0_pic_idx = 200; |
| vp9_header.temporal_idx = 0; |
| vp9_header.ss_data_available = true; |
| vp9_header.gof.SetGofInfoVP9( |
| kTemporalStructureMode3); // kTemporalStructureMode3: 0-2-1-2.. |
| EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_, &re)); |
| |
| // Insert next temporal layer 0. |
| packet_->seqNum = 65489; |
| packet_->timestamp = 13000; |
| packet_->frameType = kVideoFrameDelta; |
| vp9_header.picture_id = 9; |
| vp9_header.tl0_pic_idx = 201; |
| vp9_header.temporal_idx = 0; |
| vp9_header.ss_data_available = false; |
| EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_, &re)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(1000U, frame_out->Timestamp()); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(13000U, frame_out->Timestamp()); |
| EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, ReorderedVp9SsData_3TlLayers) { |
| // Verify that frames are updated with SS data when SS packet is reordered. |
| // -------------------------------- |
| // | 65486 | 65487 | 65485 |... |
| // | pid:6 | pid:7 | pid:5 |... |
| // | tid:2 | tid:1 | tid:0 |... |
| // | | | ss | |
| // -------------------------------- |
| // |<--------tl0idx:200--------->| |
| |
| auto& vp9_header = |
| packet_->video_header.video_type_header.emplace<RTPVideoHeaderVP9>(); |
| |
| bool re = false; |
| packet_->video_header.codec = kVideoCodecVP9; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| vp9_header.flexible_mode = false; |
| vp9_header.spatial_idx = 0; |
| vp9_header.beginning_of_frame = true; |
| vp9_header.end_of_frame = true; |
| vp9_header.tl0_pic_idx = 200; |
| |
| packet_->seqNum = 65486; |
| packet_->timestamp = 6000; |
| packet_->frameType = kVideoFrameDelta; |
| vp9_header.picture_id = 6; |
| vp9_header.temporal_idx = 2; |
| vp9_header.temporal_up_switch = true; |
| EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_, &re)); |
| |
| packet_->seqNum = 65487; |
| packet_->timestamp = 9000; |
| packet_->frameType = kVideoFrameDelta; |
| vp9_header.picture_id = 7; |
| vp9_header.temporal_idx = 1; |
| vp9_header.temporal_up_switch = true; |
| EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_, &re)); |
| |
| // Insert first frame with SS data. |
| packet_->seqNum = 65485; |
| packet_->timestamp = 3000; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.width = 352; |
| packet_->video_header.height = 288; |
| vp9_header.picture_id = 5; |
| vp9_header.temporal_idx = 0; |
| vp9_header.temporal_up_switch = false; |
| vp9_header.ss_data_available = true; |
| vp9_header.gof.SetGofInfoVP9( |
| kTemporalStructureMode3); // kTemporalStructureMode3: 0-2-1-2.. |
| EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_, &re)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(3000U, frame_out->Timestamp()); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| EXPECT_EQ(0, frame_out->CodecSpecific()->codecSpecific.VP9.temporal_idx); |
| EXPECT_FALSE( |
| frame_out->CodecSpecific()->codecSpecific.VP9.temporal_up_switch); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(6000U, frame_out->Timestamp()); |
| EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); |
| EXPECT_EQ(2, frame_out->CodecSpecific()->codecSpecific.VP9.temporal_idx); |
| EXPECT_TRUE(frame_out->CodecSpecific()->codecSpecific.VP9.temporal_up_switch); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(9000U, frame_out->Timestamp()); |
| EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); |
| EXPECT_EQ(1, frame_out->CodecSpecific()->codecSpecific.VP9.temporal_idx); |
| EXPECT_TRUE(frame_out->CodecSpecific()->codecSpecific.VP9.temporal_up_switch); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, ReorderedVp9SsData_2Tl2SLayers) { |
| // Verify that frames are updated with SS data when SS packet is reordered. |
| // ----------------------------------------- |
| // | 65486 | 65487 | 65485 | 65484 |... |
| // | pid:6 | pid:6 | pid:5 | pid:5 |... |
| // | tid:1 | tid:1 | tid:0 | tid:0 |... |
| // | sid:0 | sid:1 | sid:1 | sid:0 |... |
| // | t:6000 | t:6000 | t:3000 | t:3000 | |
| // | | | | ss | |
| // ----------------------------------------- |
| // |<-----------tl0idx:200------------>| |
| |
| auto& vp9_header = |
| packet_->video_header.video_type_header.emplace<RTPVideoHeaderVP9>(); |
| |
| bool re = false; |
| packet_->video_header.codec = kVideoCodecVP9; |
| vp9_header.flexible_mode = false; |
| vp9_header.beginning_of_frame = true; |
| vp9_header.end_of_frame = true; |
| vp9_header.tl0_pic_idx = 200; |
| |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->seqNum = 65486; |
| packet_->timestamp = 6000; |
| packet_->frameType = kVideoFrameDelta; |
| vp9_header.spatial_idx = 0; |
| vp9_header.picture_id = 6; |
| vp9_header.temporal_idx = 1; |
| vp9_header.temporal_up_switch = true; |
| EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(*packet_, &re)); |
| |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = 65487; |
| packet_->frameType = kVideoFrameDelta; |
| vp9_header.spatial_idx = 1; |
| vp9_header.picture_id = 6; |
| vp9_header.temporal_idx = 1; |
| vp9_header.temporal_up_switch = true; |
| EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_, &re)); |
| |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = 65485; |
| packet_->timestamp = 3000; |
| packet_->frameType = kVideoFrameKey; |
| vp9_header.spatial_idx = 1; |
| vp9_header.picture_id = 5; |
| vp9_header.temporal_idx = 0; |
| vp9_header.temporal_up_switch = false; |
| EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(*packet_, &re)); |
| |
| // Insert first frame with SS data. |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->seqNum = 65484; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.width = 352; |
| packet_->video_header.height = 288; |
| vp9_header.spatial_idx = 0; |
| vp9_header.picture_id = 5; |
| vp9_header.temporal_idx = 0; |
| vp9_header.temporal_up_switch = false; |
| vp9_header.ss_data_available = true; |
| vp9_header.gof.SetGofInfoVP9( |
| kTemporalStructureMode2); // kTemporalStructureMode3: 0-1-0-1.. |
| EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(*packet_, &re)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(3000U, frame_out->Timestamp()); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| EXPECT_EQ(0, frame_out->CodecSpecific()->codecSpecific.VP9.temporal_idx); |
| EXPECT_FALSE( |
| frame_out->CodecSpecific()->codecSpecific.VP9.temporal_up_switch); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(6000U, frame_out->Timestamp()); |
| EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); |
| EXPECT_EQ(1, frame_out->CodecSpecific()->codecSpecific.VP9.temporal_idx); |
| EXPECT_TRUE(frame_out->CodecSpecific()->codecSpecific.VP9.temporal_up_switch); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, H264InsertStartCode) { |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| packet_->insertStartCode = true; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| |
| // Frame should not be complete. |
| EXPECT_TRUE(frame_out == NULL); |
| |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| CheckOutFrame(frame_out, size_ * 2 + 4 * 2, true); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, SpsAndPpsHandling) { |
| auto& h264_header = |
| packet_->video_header.video_type_header.emplace<RTPVideoHeaderH264>(); |
| packet_->timestamp = timestamp_; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->video_header.codec = kVideoCodecH264; |
| h264_header.nalu_type = H264::NaluType::kIdr; |
| h264_header.nalus[0].type = H264::NaluType::kIdr; |
| h264_header.nalus[0].sps_id = -1; |
| h264_header.nalus[0].pps_id = 0; |
| h264_header.nalus_length = 1; |
| bool retransmitted = false; |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| // Not decodable since sps and pps are missing. |
| EXPECT_EQ(nullptr, DecodeCompleteFrame()); |
| |
| timestamp_ += 3000; |
| packet_->timestamp = timestamp_; |
| ++seq_num_; |
| packet_->seqNum = seq_num_; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->video_header.codec = kVideoCodecH264; |
| h264_header.nalu_type = H264::NaluType::kStapA; |
| h264_header.nalus[0].type = H264::NaluType::kSps; |
| h264_header.nalus[0].sps_id = 0; |
| h264_header.nalus[0].pps_id = -1; |
| h264_header.nalus[1].type = H264::NaluType::kPps; |
| h264_header.nalus[1].sps_id = 0; |
| h264_header.nalus[1].pps_id = 0; |
| h264_header.nalus_length = 2; |
| // Not complete since the marker bit hasn't been received. |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| ++seq_num_; |
| packet_->seqNum = seq_num_; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->video_header.codec = kVideoCodecH264; |
| h264_header.nalu_type = H264::NaluType::kIdr; |
| h264_header.nalus[0].type = H264::NaluType::kIdr; |
| h264_header.nalus[0].sps_id = -1; |
| h264_header.nalus[0].pps_id = 0; |
| h264_header.nalus_length = 1; |
| // Complete and decodable since the pps and sps are received in the first |
| // packet of this frame. |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| ASSERT_NE(nullptr, frame_out); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| timestamp_ += 3000; |
| packet_->timestamp = timestamp_; |
| ++seq_num_; |
| packet_->seqNum = seq_num_; |
| packet_->frameType = kVideoFrameDelta; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->video_header.codec = kVideoCodecH264; |
| h264_header.nalu_type = H264::NaluType::kSlice; |
| h264_header.nalus[0].type = H264::NaluType::kSlice; |
| h264_header.nalus[0].sps_id = -1; |
| h264_header.nalus[0].pps_id = 0; |
| h264_header.nalus_length = 1; |
| // Complete and decodable since sps, pps and key frame has been received. |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| frame_out = DecodeCompleteFrame(); |
| ASSERT_NE(nullptr, frame_out); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, DeltaFrame100PacketsWithSeqNumWrap) { |
| seq_num_ = 0xfff0; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| |
| EXPECT_TRUE(frame_out == NULL); |
| |
| int loop = 0; |
| do { |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| |
| EXPECT_TRUE(frame_out == NULL); |
| |
| loop++; |
| } while (loop < 98); |
| |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| |
| CheckOutFrame(frame_out, 100 * size_, false); |
| |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, PacketReorderingReverseWithNegSeqNumWrap) { |
| // Insert "first" packet last seqnum. |
| seq_num_ = 10; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| |
| // Should not be complete. |
| EXPECT_TRUE(frame_out == NULL); |
| |
| // Insert 98 frames. |
| int loop = 0; |
| do { |
| seq_num_--; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| |
| EXPECT_TRUE(frame_out == NULL); |
| |
| loop++; |
| } while (loop < 98); |
| |
| // Insert last packet. |
| seq_num_--; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| CheckOutFrame(frame_out, 100 * size_, false); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, TestInsertOldFrame) { |
| // ------- ------- |
| // | 2 | | 1 | |
| // ------- ------- |
| // t = 3000 t = 2000 |
| seq_num_ = 2; |
| timestamp_ = 3000; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->timestamp = timestamp_; |
| packet_->seqNum = seq_num_; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(3000u, frame_out->Timestamp()); |
| CheckOutFrame(frame_out, size_, false); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| seq_num_--; |
| timestamp_ = 2000; |
| packet_->frameType = kVideoFrameDelta; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| EXPECT_EQ(kOldPacket, jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, TestInsertOldFrameWithSeqNumWrap) { |
| // ------- ------- |
| // | 2 | | 1 | |
| // ------- ------- |
| // t = 3000 t = 0xffffff00 |
| |
| seq_num_ = 2; |
| timestamp_ = 3000; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(timestamp_, frame_out->Timestamp()); |
| |
| CheckOutFrame(frame_out, size_, false); |
| |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| seq_num_--; |
| timestamp_ = 0xffffff00; |
| packet_->frameType = kVideoFrameDelta; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| // This timestamp is old. |
| EXPECT_EQ(kOldPacket, jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, TimestampWrap) { |
| // --------------- --------------- |
| // | 1 | 2 | | 3 | 4 | |
| // --------------- --------------- |
| // t = 0xffffff00 t = 33*90 |
| |
| timestamp_ = 0xffffff00; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_TRUE(frame_out == NULL); |
| |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| CheckOutFrame(frame_out, 2 * size_, false); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| seq_num_++; |
| timestamp_ += 33 * 90; |
| packet_->frameType = kVideoFrameDelta; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| EXPECT_TRUE(frame_out == NULL); |
| |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| frame_out = DecodeCompleteFrame(); |
| CheckOutFrame(frame_out, 2 * size_, false); |
| EXPECT_EQ(kVideoFrameDelta, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, 2FrameWithTimestampWrap) { |
| // ------- ------- |
| // | 1 | | 2 | |
| // ------- ------- |
| // t = 0xffffff00 t = 2700 |
| |
| timestamp_ = 0xffffff00; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->timestamp = timestamp_; |
| |
| bool retransmitted = false; |
| // Insert first frame (session will be complete). |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| // Insert next frame. |
| seq_num_++; |
| timestamp_ = 2700; |
| packet_->frameType = kVideoFrameDelta; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(0xffffff00, frame_out->Timestamp()); |
| CheckOutFrame(frame_out, size_, false); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| VCMEncodedFrame* frame_out2 = DecodeCompleteFrame(); |
| EXPECT_EQ(2700u, frame_out2->Timestamp()); |
| CheckOutFrame(frame_out2, size_, false); |
| EXPECT_EQ(kVideoFrameDelta, frame_out2->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out2); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, Insert2FramesReOrderedWithTimestampWrap) { |
| // ------- ------- |
| // | 2 | | 1 | |
| // ------- ------- |
| // t = 2700 t = 0xffffff00 |
| |
| seq_num_ = 2; |
| timestamp_ = 2700; |
| packet_->frameType = kVideoFrameDelta; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| bool retransmitted = false; |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| // Insert second frame |
| seq_num_--; |
| timestamp_ = 0xffffff00; |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(0xffffff00, frame_out->Timestamp()); |
| CheckOutFrame(frame_out, size_, false); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| VCMEncodedFrame* frame_out2 = DecodeCompleteFrame(); |
| EXPECT_EQ(2700u, frame_out2->Timestamp()); |
| CheckOutFrame(frame_out2, size_, false); |
| EXPECT_EQ(kVideoFrameDelta, frame_out2->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out2); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, DeltaFrameWithMoreThanMaxNumberOfPackets) { |
| int loop = 0; |
| bool firstPacket = true; |
| bool retransmitted = false; |
| // Insert kMaxPacketsInJitterBuffer into frame. |
| do { |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| |
| if (firstPacket) { |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| firstPacket = false; |
| } else { |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| } |
| |
| loop++; |
| } while (loop < kMaxPacketsInSession); |
| |
| // Max number of packets inserted. |
| // Insert one more packet. |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| |
| // Insert the packet -> frame recycled. |
| EXPECT_EQ(kSizeError, jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| 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----->| |
| |
| // Make sure the jitter doesn't request a keyframe after too much non- |
| // decodable frames. |
| jitter_buffer_->SetNackMode(kNack, -1, -1); |
| jitter_buffer_->SetNackSettings(kMaxNumberOfFrames, kMaxNumberOfFrames, 0); |
| |
| int loop = 0; |
| seq_num_ = 65485; |
| uint32_t first_key_frame_timestamp = 0; |
| bool retransmitted = false; |
| // Insert MAX_NUMBER_OF_FRAMES frames. |
| do { |
| timestamp_ += 33 * 90; |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| if (loop == 50) { |
| first_key_frame_timestamp = packet_->timestamp; |
| packet_->frameType = kVideoFrameKey; |
| } |
| |
| // Insert frame. |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| loop++; |
| } while (loop < kMaxNumberOfFrames); |
| |
| // Max number of frames inserted. |
| |
| // Insert one more frame. |
| timestamp_ += 33 * 90; |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| |
| // Now, no free frame - frames will be recycled until first key frame. |
| EXPECT_EQ(kFlushIndicator, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_EQ(first_key_frame_timestamp, frame_out->Timestamp()); |
| CheckOutFrame(frame_out, size_, false); |
| EXPECT_EQ(kVideoFrameKey, frame_out->FrameType()); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| } |
| |
| TEST_F(TestBasicJitterBuffer, EmptyLastFrame) { |
| 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; |
| bool retransmitted = false; |
| for (int i = 0; i < maxSize + 10; i++) { |
| timestamp_ += 33 * 90; |
| seq_num_++; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = false; |
| packet_->seqNum = seq_num_; |
| packet_->timestamp = timestamp_; |
| packet_->frameType = kEmptyFrame; |
| |
| EXPECT_EQ(kNoError, jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| } |
| } |
| |
| 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. |
| // Start with a complete key frame - insert and decode. |
| packet_->frameType = kVideoFrameKey; |
| packet_->video_header.is_first_packet_in_frame = true; |
| packet_->markerBit = true; |
| bool retransmitted = false; |
| |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| VCMEncodedFrame* frame_out = DecodeCompleteFrame(); |
| EXPECT_TRUE(frame_out != NULL); |
| jitter_buffer_->ReleaseFrame(frame_out); |
| |
| packet_->seqNum += 2; |
| packet_->timestamp += 33 * 90; |
| packet_->frameType = kVideoFrameDelta; |
| packet_->video_header.is_first_packet_in_frame = false; |
| packet_->markerBit = false; |
| |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| |
| packet_->seqNum += 2; |
| packet_->timestamp += 33 * 90; |
| packet_->video_header.is_first_packet_in_frame = true; |
| |
| EXPECT_EQ(kIncomplete, |
| jitter_buffer_->InsertPacket(*packet_, &retransmitted)); |
| } |
| |
| TEST_F(TestRunningJitterBuffer, Full) { |
| // Make sure the jitter doesn't request a keyframe after too much non- |
| // decodable frames. |
| jitter_buffer_->SetNackMode(kNack, -1, -1); |
| jitter_buffer_->SetNackSettings(kMaxNumberOfFrames, kMaxNumberOfFrames, 0); |
| // Insert a key frame and decode it. |
| EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| DropFrame(1); |
| // Fill the jitter buffer. |
| EXPECT_GE(InsertFrames(kMaxNumberOfFrames, kVideoFrameDelta), kNoError); |
| // Make sure we can't decode these frames. |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| // This frame will make the jitter buffer recycle frames until a key frame. |
| // Since none is found it will have to wait until the next key frame before |
| // decoding. |
| EXPECT_EQ(kFlushIndicator, InsertFrame(kVideoFrameDelta)); |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| } |
| |
| TEST_F(TestRunningJitterBuffer, EmptyPackets) { |
| // Make sure a frame can get complete even though empty packets are missing. |
| stream_generator_->GenerateFrame(kVideoFrameKey, 3, 3, |
| clock_->TimeInMilliseconds()); |
| bool request_key_frame = false; |
| // Insert empty packet. |
| EXPECT_EQ(kNoError, InsertPacketAndPop(4)); |
| EXPECT_FALSE(request_key_frame); |
| // Insert 3 media packets. |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| EXPECT_FALSE(request_key_frame); |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| EXPECT_FALSE(request_key_frame); |
| EXPECT_EQ(kCompleteSession, InsertPacketAndPop(0)); |
| EXPECT_FALSE(request_key_frame); |
| // Insert empty packet. |
| EXPECT_EQ(kCompleteSession, InsertPacketAndPop(0)); |
| EXPECT_FALSE(request_key_frame); |
| } |
| |
| TEST_F(TestRunningJitterBuffer, StatisticsTest) { |
| FrameCounts frame_stats(jitter_buffer_->FrameStatistics()); |
| EXPECT_EQ(0, frame_stats.delta_frames); |
| EXPECT_EQ(0, frame_stats.key_frames); |
| |
| uint32_t framerate = 0; |
| uint32_t bitrate = 0; |
| jitter_buffer_->IncomingRateStatistics(&framerate, &bitrate); |
| EXPECT_EQ(0u, framerate); |
| EXPECT_EQ(0u, bitrate); |
| |
| // Insert a couple of key and delta frames. |
| InsertFrame(kVideoFrameKey); |
| InsertFrame(kVideoFrameDelta); |
| InsertFrame(kVideoFrameDelta); |
| InsertFrame(kVideoFrameKey); |
| InsertFrame(kVideoFrameDelta); |
| // Decode some of them to make sure the statistics doesn't depend on frames |
| // being decoded. |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| frame_stats = jitter_buffer_->FrameStatistics(); |
| EXPECT_EQ(3, frame_stats.delta_frames); |
| EXPECT_EQ(2, frame_stats.key_frames); |
| |
| // Insert 20 more frames to get estimates of bitrate and framerate over |
| // 1 second. |
| for (int i = 0; i < 20; ++i) { |
| InsertFrame(kVideoFrameDelta); |
| } |
| jitter_buffer_->IncomingRateStatistics(&framerate, &bitrate); |
| // TODO(holmer): The current implementation returns the average of the last |
| // two framerate calculations, which is why it takes two calls to reach the |
| // actual framerate. This should be fixed. |
| EXPECT_EQ(kDefaultFrameRate / 2u, framerate); |
| EXPECT_EQ(kDefaultBitrateKbps, bitrate); |
| // Insert 25 more frames to get estimates of bitrate and framerate over |
| // 2 seconds. |
| for (int i = 0; i < 25; ++i) { |
| InsertFrame(kVideoFrameDelta); |
| } |
| jitter_buffer_->IncomingRateStatistics(&framerate, &bitrate); |
| EXPECT_EQ(kDefaultFrameRate, framerate); |
| EXPECT_EQ(kDefaultBitrateKbps, bitrate); |
| } |
| |
| TEST_F(TestRunningJitterBuffer, SkipToKeyFrame) { |
| // Insert delta frames. |
| EXPECT_GE(InsertFrames(5, kVideoFrameDelta), kNoError); |
| // Can't decode without a key frame. |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| InsertFrame(kVideoFrameKey); |
| // Skip to the next key frame. |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| } |
| |
| TEST_F(TestRunningJitterBuffer, DontSkipToKeyFrameIfDecodable) { |
| InsertFrame(kVideoFrameKey); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| const int kNumDeltaFrames = 5; |
| EXPECT_GE(InsertFrames(kNumDeltaFrames, kVideoFrameDelta), kNoError); |
| InsertFrame(kVideoFrameKey); |
| for (int i = 0; i < kNumDeltaFrames + 1; ++i) { |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| } |
| } |
| |
| TEST_F(TestRunningJitterBuffer, KeyDeltaKeyDelta) { |
| InsertFrame(kVideoFrameKey); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| const int kNumDeltaFrames = 5; |
| EXPECT_GE(InsertFrames(kNumDeltaFrames, kVideoFrameDelta), kNoError); |
| InsertFrame(kVideoFrameKey); |
| EXPECT_GE(InsertFrames(kNumDeltaFrames, kVideoFrameDelta), kNoError); |
| InsertFrame(kVideoFrameKey); |
| for (int i = 0; i < 2 * (kNumDeltaFrames + 1); ++i) { |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| } |
| } |
| |
| TEST_F(TestRunningJitterBuffer, TwoPacketsNonContinuous) { |
| InsertFrame(kVideoFrameKey); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| stream_generator_->GenerateFrame(kVideoFrameDelta, 1, 0, |
| clock_->TimeInMilliseconds()); |
| clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs); |
| stream_generator_->GenerateFrame(kVideoFrameDelta, 2, 0, |
| clock_->TimeInMilliseconds()); |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(1)); |
| EXPECT_EQ(kCompleteSession, InsertPacketAndPop(1)); |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| EXPECT_EQ(kCompleteSession, InsertPacketAndPop(0)); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| } |
| |
| TEST_F(TestJitterBufferNack, EmptyPackets) { |
| // Make sure empty packets doesn't clog the jitter buffer. |
| jitter_buffer_->SetNackMode(kNack, media_optimization::kLowRttNackMs, -1); |
| EXPECT_GE(InsertFrames(kMaxNumberOfFrames, kEmptyFrame), kNoError); |
| InsertFrame(kVideoFrameKey); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| } |
| |
| TEST_F(TestJitterBufferNack, NackTooOldPackets) { |
| // Insert a key frame and decode it. |
| EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| |
| // Drop one frame and insert |kNackHistoryLength| to trigger NACKing a too |
| // old packet. |
| DropFrame(1); |
| // Insert a frame which should trigger a recycle until the next key frame. |
| EXPECT_EQ(kFlushIndicator, |
| InsertFrames(oldest_packet_to_nack_ + 1, kVideoFrameDelta)); |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| |
| bool request_key_frame = false; |
| std::vector<uint16_t> nack_list = |
| jitter_buffer_->GetNackList(&request_key_frame); |
| // No key frame will be requested since the jitter buffer is empty. |
| EXPECT_FALSE(request_key_frame); |
| EXPECT_EQ(0u, nack_list.size()); |
| |
| EXPECT_GE(InsertFrame(kVideoFrameDelta), kNoError); |
| // Waiting for a key frame. |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| |
| // The next complete continuous frame isn't a key frame, but we're waiting |
| // for one. |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError); |
| // Skipping ahead to the key frame. |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| } |
| |
| TEST_F(TestJitterBufferNack, NackLargeJitterBuffer) { |
| // Insert a key frame and decode it. |
| EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| |
| // Insert a frame which should trigger a recycle until the next key frame. |
| EXPECT_GE(InsertFrames(oldest_packet_to_nack_, kVideoFrameDelta), kNoError); |
| |
| bool request_key_frame = false; |
| std::vector<uint16_t> nack_list = |
| jitter_buffer_->GetNackList(&request_key_frame); |
| // Verify that the jitter buffer does not request a key frame. |
| EXPECT_FALSE(request_key_frame); |
| // Verify that no packets are NACKed. |
| EXPECT_EQ(0u, nack_list.size()); |
| // Verify that we can decode the next frame. |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| } |
| |
| TEST_F(TestJitterBufferNack, NackListFull) { |
| // Insert a key frame and decode it. |
| EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| |
| // Generate and drop |kNackHistoryLength| packets to fill the NACK list. |
| DropFrame(max_nack_list_size_ + 1); |
| // Insert a frame which should trigger a recycle until the next key frame. |
| EXPECT_EQ(kFlushIndicator, InsertFrame(kVideoFrameDelta)); |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| |
| bool request_key_frame = false; |
| jitter_buffer_->GetNackList(&request_key_frame); |
| // The jitter buffer is empty, so we won't request key frames until we get a |
| // packet. |
| EXPECT_FALSE(request_key_frame); |
| |
| EXPECT_GE(InsertFrame(kVideoFrameDelta), kNoError); |
| // Now we have a packet in the jitter buffer, a key frame will be requested |
| // since it's not a key frame. |
| jitter_buffer_->GetNackList(&request_key_frame); |
| // The jitter buffer is empty, so we won't request key frames until we get a |
| // packet. |
| EXPECT_TRUE(request_key_frame); |
| // The next complete continuous frame isn't a key frame, but we're waiting |
| // for one. |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError); |
| // Skipping ahead to the key frame. |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| } |
| |
| TEST_F(TestJitterBufferNack, NoNackListReturnedBeforeFirstDecode) { |
| DropFrame(10); |
| // Insert a frame and try to generate a NACK list. Shouldn't get one. |
| EXPECT_GE(InsertFrame(kVideoFrameDelta), kNoError); |
| bool request_key_frame = false; |
| std::vector<uint16_t> nack_list = |
| jitter_buffer_->GetNackList(&request_key_frame); |
| // No list generated, and a key frame request is signaled. |
| EXPECT_EQ(0u, nack_list.size()); |
| EXPECT_TRUE(request_key_frame); |
| } |
| |
| TEST_F(TestJitterBufferNack, NackListBuiltBeforeFirstDecode) { |
| stream_generator_->Init(0, clock_->TimeInMilliseconds()); |
| InsertFrame(kVideoFrameKey); |
| stream_generator_->GenerateFrame(kVideoFrameDelta, 2, 0, |
| clock_->TimeInMilliseconds()); |
| stream_generator_->NextPacket(NULL); // Drop packet. |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| bool extended = false; |
| std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended); |
| EXPECT_EQ(1u, nack_list.size()); |
| } |
| |
| TEST_F(TestJitterBufferNack, VerifyRetransmittedFlag) { |
| stream_generator_->Init(0, clock_->TimeInMilliseconds()); |
| stream_generator_->GenerateFrame(kVideoFrameKey, 3, 0, |
| clock_->TimeInMilliseconds()); |
| VCMPacket packet; |
| stream_generator_->PopPacket(&packet, 0); |
| bool retransmitted = false; |
| EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(packet, &retransmitted)); |
| EXPECT_FALSE(retransmitted); |
| // Drop second packet. |
| stream_generator_->PopPacket(&packet, 1); |
| EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(packet, &retransmitted)); |
| EXPECT_FALSE(retransmitted); |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| bool extended = false; |
| std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended); |
| uint16_t seq_num; |
| EXPECT_EQ(1u, nack_list.size()); |
| seq_num = nack_list[0]; |
| stream_generator_->PopPacket(&packet, 0); |
| EXPECT_EQ(packet.seqNum, seq_num); |
| EXPECT_EQ(kCompleteSession, |
| jitter_buffer_->InsertPacket(packet, &retransmitted)); |
| EXPECT_TRUE(retransmitted); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| } |
| |
| TEST_F(TestJitterBufferNack, UseNackToRecoverFirstKeyFrame) { |
| stream_generator_->Init(0, clock_->TimeInMilliseconds()); |
| stream_generator_->GenerateFrame(kVideoFrameKey, 3, 0, |
| clock_->TimeInMilliseconds()); |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| // Drop second packet. |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(1)); |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| bool extended = false; |
| std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended); |
| uint16_t seq_num; |
| ASSERT_EQ(1u, nack_list.size()); |
| seq_num = nack_list[0]; |
| VCMPacket packet; |
| stream_generator_->GetPacket(&packet, 0); |
| EXPECT_EQ(packet.seqNum, seq_num); |
| } |
| |
| TEST_F(TestJitterBufferNack, UseNackToRecoverFirstKeyFrameSecondInQueue) { |
| VCMPacket packet; |
| stream_generator_->Init(0, clock_->TimeInMilliseconds()); |
| // First frame is delta. |
| stream_generator_->GenerateFrame(kVideoFrameDelta, 3, 0, |
| clock_->TimeInMilliseconds()); |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| // Drop second packet in frame. |
| ASSERT_TRUE(stream_generator_->PopPacket(&packet, 0)); |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| // Second frame is key. |
| stream_generator_->GenerateFrame(kVideoFrameKey, 3, 0, |
| clock_->TimeInMilliseconds() + 10); |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| // Drop second packet in frame. |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(1)); |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| bool extended = false; |
| std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended); |
| uint16_t seq_num; |
| ASSERT_EQ(1u, nack_list.size()); |
| seq_num = nack_list[0]; |
| stream_generator_->GetPacket(&packet, 0); |
| EXPECT_EQ(packet.seqNum, seq_num); |
| } |
| |
| TEST_F(TestJitterBufferNack, NormalOperation) { |
| EXPECT_EQ(kNack, jitter_buffer_->nack_mode()); |
| |
| EXPECT_GE(InsertFrame(kVideoFrameKey), kNoError); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| |
| // ---------------------------------------------------------------- |
| // | 1 | 2 | .. | 8 | 9 | x | 11 | 12 | .. | 19 | x | 21 | .. | 100 | |
| // ---------------------------------------------------------------- |
| stream_generator_->GenerateFrame(kVideoFrameKey, 100, 0, |
| clock_->TimeInMilliseconds()); |
| clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs); |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| // Verify that the frame is incomplete. |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| while (stream_generator_->PacketsRemaining() > 1) { |
| if (stream_generator_->NextSequenceNumber() % 10 != 0) { |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| } else { |
| stream_generator_->NextPacket(NULL); // Drop packet |
| } |
| } |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| EXPECT_EQ(0, stream_generator_->PacketsRemaining()); |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| bool request_key_frame = false; |
| |
| // Verify the NACK list. |
| std::vector<uint16_t> nack_list = |
| jitter_buffer_->GetNackList(&request_key_frame); |
| const size_t kExpectedNackSize = 9; |
| ASSERT_EQ(kExpectedNackSize, nack_list.size()); |
| for (size_t i = 0; i < nack_list.size(); ++i) |
| EXPECT_EQ((1 + i) * 10, nack_list[i]); |
| } |
| |
| TEST_F(TestJitterBufferNack, NormalOperationWrap) { |
| bool request_key_frame = false; |
| // ------- ------------------------------------------------------------ |
| // | 65532 | | 65533 | 65534 | 65535 | x | 1 | .. | 9 | x | 11 |.....| 96 | |
| // ------- ------------------------------------------------------------ |
| stream_generator_->Init(65532, clock_->TimeInMilliseconds()); |
| InsertFrame(kVideoFrameKey); |
| EXPECT_FALSE(request_key_frame); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| stream_generator_->GenerateFrame(kVideoFrameDelta, 100, 0, |
| clock_->TimeInMilliseconds()); |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| while (stream_generator_->PacketsRemaining() > 1) { |
| if (stream_generator_->NextSequenceNumber() % 10 != 0) { |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| EXPECT_FALSE(request_key_frame); |
| } else { |
| stream_generator_->NextPacket(NULL); // Drop packet |
| } |
| } |
| EXPECT_EQ(kIncomplete, InsertPacketAndPop(0)); |
| EXPECT_FALSE(request_key_frame); |
| EXPECT_EQ(0, stream_generator_->PacketsRemaining()); |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| EXPECT_FALSE(DecodeCompleteFrame()); |
| bool extended = false; |
| std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended); |
| // Verify the NACK list. |
| const size_t kExpectedNackSize = 10; |
| ASSERT_EQ(kExpectedNackSize, nack_list.size()); |
| for (size_t i = 0; i < nack_list.size(); ++i) |
| EXPECT_EQ(i * 10, nack_list[i]); |
| } |
| |
| TEST_F(TestJitterBufferNack, NormalOperationWrap2) { |
| bool request_key_frame = false; |
| // ----------------------------------- |
| // | 65532 | 65533 | 65534 | x | 0 | 1 | |
| // ----------------------------------- |
| stream_generator_->Init(65532, clock_->TimeInMilliseconds()); |
| InsertFrame(kVideoFrameKey); |
| EXPECT_FALSE(request_key_frame); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| stream_generator_->GenerateFrame(kVideoFrameDelta, 1, 0, |
| clock_->TimeInMilliseconds()); |
| clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs); |
| for (int i = 0; i < 5; ++i) { |
| if (stream_generator_->NextSequenceNumber() != 65535) { |
| EXPECT_EQ(kCompleteSession, InsertPacketAndPop(0)); |
| EXPECT_FALSE(request_key_frame); |
| } else { |
| stream_generator_->NextPacket(NULL); // Drop packet |
| } |
| stream_generator_->GenerateFrame(kVideoFrameDelta, 1, 0, |
| clock_->TimeInMilliseconds()); |
| clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs); |
| } |
| EXPECT_EQ(kCompleteSession, InsertPacketAndPop(0)); |
| EXPECT_FALSE(request_key_frame); |
| bool extended = false; |
| std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended); |
| // Verify the NACK list. |
| ASSERT_EQ(1u, nack_list.size()); |
| EXPECT_EQ(65535, nack_list[0]); |
| } |
| |
| TEST_F(TestJitterBufferNack, ResetByFutureKeyFrameDoesntError) { |
| stream_generator_->Init(0, clock_->TimeInMilliseconds()); |
| InsertFrame(kVideoFrameKey); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| bool extended = false; |
| std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended); |
| EXPECT_EQ(0u, nack_list.size()); |
| |
| // Far-into-the-future video frame, could be caused by resetting the encoder |
| // or otherwise restarting. This should not fail when error when the packet is |
| // a keyframe, even if all of the nack list needs to be flushed. |
| stream_generator_->Init(10000, clock_->TimeInMilliseconds()); |
| clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs); |
| InsertFrame(kVideoFrameKey); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| nack_list = jitter_buffer_->GetNackList(&extended); |
| EXPECT_EQ(0u, nack_list.size()); |
| |
| // Stream should be decodable from this point. |
| clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs); |
| InsertFrame(kVideoFrameDelta); |
| EXPECT_TRUE(DecodeCompleteFrame()); |
| nack_list = jitter_buffer_->GetNackList(&extended); |
| EXPECT_EQ(0u, nack_list.size()); |
| } |
| } // namespace webrtc |