/* Copyright (c) 2013 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 #include #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/modules/video_coding/main/source/receiver.h" #include "webrtc/modules/video_coding/main/source/packet.h" #include "webrtc/modules/video_coding/main/source/timing.h" #include "webrtc/modules/video_coding/main/test/test_util.h" #include "webrtc/modules/video_coding/main/source/stream_generator.h" #include "webrtc/system_wrappers/interface/clock.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" namespace webrtc { class TestVCMReceiver : public ::testing::Test { protected: enum { kDataBufferSize = 10 }; enum { kWidth = 640 }; enum { kHeight = 480 }; TestVCMReceiver() : clock_(new SimulatedClock(0)), timing_(clock_.get()), receiver_(&timing_, clock_.get(), &event_factory_, 1, 1, true) { stream_generator_.reset(new StreamGenerator(0, 0, clock_->TimeInMilliseconds())); memset(data_buffer_, 0, kDataBufferSize); } virtual void SetUp() { receiver_.Reset(); } int32_t 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. // Arbitrary width and height. return receiver_.InsertPacket(packet, 640, 480); } int32_t 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. return receiver_.InsertPacket(packet, kWidth, kHeight); } int32_t InsertFrame(FrameType frame_type, bool complete) { int num_of_packets = complete ? 1 : 2; stream_generator_->GenerateFrame( frame_type, (frame_type != kFrameEmpty) ? num_of_packets : 0, (frame_type == kFrameEmpty) ? 1 : 0, clock_->TimeInMilliseconds()); int32_t ret = InsertPacketAndPop(0); if (!complete) { // Drop the second packet. VCMPacket packet; stream_generator_->PopPacket(&packet, 0); } clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs); return ret; } bool DecodeNextFrame() { int64_t render_time_ms = 0; VCMEncodedFrame* frame = receiver_.FrameForDecoding(0, render_time_ms, false, NULL); if (!frame) return false; receiver_.ReleaseFrame(frame); return true; } scoped_ptr clock_; VCMTiming timing_; NullEventFactory event_factory_; VCMReceiver receiver_; scoped_ptr stream_generator_; uint8_t data_buffer_[kDataBufferSize]; }; TEST_F(TestVCMReceiver, RenderBufferSize_AllComplete) { EXPECT_EQ(0, receiver_.RenderBufferSizeMs()); EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError); int num_of_frames = 10; for (int i = 0; i < num_of_frames; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } EXPECT_EQ(num_of_frames * kDefaultFramePeriodMs, receiver_.RenderBufferSizeMs()); } TEST_F(TestVCMReceiver, RenderBufferSize_SkipToKeyFrame) { EXPECT_EQ(0, receiver_.RenderBufferSizeMs()); const int kNumOfNonDecodableFrames = 2; for (int i = 0; i < kNumOfNonDecodableFrames; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } const int kNumOfFrames = 10; EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError); for (int i = 0; i < kNumOfFrames - 1; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } EXPECT_EQ((kNumOfFrames - 1) * kDefaultFramePeriodMs, receiver_.RenderBufferSizeMs()); } TEST_F(TestVCMReceiver, RenderBufferSize_NotAllComplete) { EXPECT_EQ(0, receiver_.RenderBufferSizeMs()); EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError); int num_of_frames = 10; for (int i = 0; i < num_of_frames; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } num_of_frames++; EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError); for (int i = 0; i < num_of_frames; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } EXPECT_EQ((num_of_frames - 1) * kDefaultFramePeriodMs, receiver_.RenderBufferSizeMs()); } TEST_F(TestVCMReceiver, RenderBufferSize_NoKeyFrame) { EXPECT_EQ(0, receiver_.RenderBufferSizeMs()); int num_of_frames = 10; for (int i = 0; i < num_of_frames; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } int64_t next_render_time_ms = 0; VCMEncodedFrame* frame = receiver_.FrameForDecoding(10, next_render_time_ms); EXPECT_TRUE(frame == NULL); receiver_.ReleaseFrame(frame); EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError); for (int i = 0; i < num_of_frames; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } EXPECT_EQ(0, receiver_.RenderBufferSizeMs()); } TEST_F(TestVCMReceiver, NonDecodableDuration_Empty) { // Enable NACK and with no RTT thresholds for disabling retransmission delay. receiver_.SetNackMode(kNack, -1, -1); const size_t kMaxNackListSize = 1000; const int kMaxPacketAgeToNack = 1000; const int kMaxNonDecodableDuration = 500; const int kMinDelayMs = 500; receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, kMaxNonDecodableDuration); EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError); // Advance time until it's time to decode the key frame. clock_->AdvanceTimeMilliseconds(kMinDelayMs); EXPECT_TRUE(DecodeNextFrame()); uint16_t nack_list[kMaxNackListSize]; uint16_t nack_list_length = 0; VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize, &nack_list_length); EXPECT_EQ(kNackOk, ret); } TEST_F(TestVCMReceiver, NonDecodableDuration_NoKeyFrame) { // Enable NACK and with no RTT thresholds for disabling retransmission delay. receiver_.SetNackMode(kNack, -1, -1); const size_t kMaxNackListSize = 1000; const int kMaxPacketAgeToNack = 1000; const int kMaxNonDecodableDuration = 500; receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, kMaxNonDecodableDuration); const int kNumFrames = kDefaultFrameRate * kMaxNonDecodableDuration / 1000; for (int i = 0; i < kNumFrames; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } uint16_t nack_list[kMaxNackListSize]; uint16_t nack_list_length = 0; VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize, &nack_list_length); EXPECT_EQ(kNackKeyFrameRequest, ret); } TEST_F(TestVCMReceiver, NonDecodableDuration_OneIncomplete) { // Enable NACK and with no RTT thresholds for disabling retransmission delay. receiver_.SetNackMode(kNack, -1, -1); const size_t kMaxNackListSize = 1000; const int kMaxPacketAgeToNack = 1000; const int kMaxNonDecodableDuration = 500; const int kMaxNonDecodableDurationFrames = (kDefaultFrameRate * kMaxNonDecodableDuration + 500) / 1000; const int kMinDelayMs = 500; receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, kMaxNonDecodableDuration); receiver_.SetMinReceiverDelay(kMinDelayMs); int64_t key_frame_inserted = clock_->TimeInMilliseconds(); EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError); // Insert an incomplete frame. EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError); // Insert enough frames to have too long non-decodable sequence. for (int i = 0; i < kMaxNonDecodableDurationFrames; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } // Advance time until it's time to decode the key frame. clock_->AdvanceTimeMilliseconds(kMinDelayMs - clock_->TimeInMilliseconds() - key_frame_inserted); EXPECT_TRUE(DecodeNextFrame()); // Make sure we get a key frame request. uint16_t nack_list[kMaxNackListSize]; uint16_t nack_list_length = 0; VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize, &nack_list_length); EXPECT_EQ(kNackKeyFrameRequest, ret); } TEST_F(TestVCMReceiver, NonDecodableDuration_NoTrigger) { // Enable NACK and with no RTT thresholds for disabling retransmission delay. receiver_.SetNackMode(kNack, -1, -1); const size_t kMaxNackListSize = 1000; const int kMaxPacketAgeToNack = 1000; const int kMaxNonDecodableDuration = 500; const int kMaxNonDecodableDurationFrames = (kDefaultFrameRate * kMaxNonDecodableDuration + 500) / 1000; const int kMinDelayMs = 500; receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, kMaxNonDecodableDuration); receiver_.SetMinReceiverDelay(kMinDelayMs); int64_t key_frame_inserted = clock_->TimeInMilliseconds(); EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError); // Insert an incomplete frame. EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError); // Insert all but one frame to not trigger a key frame request due to // too long duration of non-decodable frames. for (int i = 0; i < kMaxNonDecodableDurationFrames - 1; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } // Advance time until it's time to decode the key frame. clock_->AdvanceTimeMilliseconds(kMinDelayMs - clock_->TimeInMilliseconds() - key_frame_inserted); EXPECT_TRUE(DecodeNextFrame()); // Make sure we don't get a key frame request since we haven't generated // enough frames. uint16_t nack_list[kMaxNackListSize]; uint16_t nack_list_length = 0; VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize, &nack_list_length); EXPECT_EQ(kNackOk, ret); } TEST_F(TestVCMReceiver, NonDecodableDuration_NoTrigger2) { // Enable NACK and with no RTT thresholds for disabling retransmission delay. receiver_.SetNackMode(kNack, -1, -1); const size_t kMaxNackListSize = 1000; const int kMaxPacketAgeToNack = 1000; const int kMaxNonDecodableDuration = 500; const int kMaxNonDecodableDurationFrames = (kDefaultFrameRate * kMaxNonDecodableDuration + 500) / 1000; const int kMinDelayMs = 500; receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, kMaxNonDecodableDuration); receiver_.SetMinReceiverDelay(kMinDelayMs); int64_t key_frame_inserted = clock_->TimeInMilliseconds(); EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError); // Insert enough frames to have too long non-decodable sequence, except that // we don't have any losses. for (int i = 0; i < kMaxNonDecodableDurationFrames; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } // Insert an incomplete frame. EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError); // Advance time until it's time to decode the key frame. clock_->AdvanceTimeMilliseconds(kMinDelayMs - clock_->TimeInMilliseconds() - key_frame_inserted); EXPECT_TRUE(DecodeNextFrame()); // Make sure we don't get a key frame request since the non-decodable duration // is only one frame. uint16_t nack_list[kMaxNackListSize]; uint16_t nack_list_length = 0; VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize, &nack_list_length); EXPECT_EQ(kNackOk, ret); } TEST_F(TestVCMReceiver, NonDecodableDuration_KeyFrameAfterIncompleteFrames) { // Enable NACK and with no RTT thresholds for disabling retransmission delay. receiver_.SetNackMode(kNack, -1, -1); const size_t kMaxNackListSize = 1000; const int kMaxPacketAgeToNack = 1000; const int kMaxNonDecodableDuration = 500; const int kMaxNonDecodableDurationFrames = (kDefaultFrameRate * kMaxNonDecodableDuration + 500) / 1000; const int kMinDelayMs = 500; receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, kMaxNonDecodableDuration); receiver_.SetMinReceiverDelay(kMinDelayMs); int64_t key_frame_inserted = clock_->TimeInMilliseconds(); EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError); // Insert an incomplete frame. EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError); // Insert enough frames to have too long non-decodable sequence. for (int i = 0; i < kMaxNonDecodableDurationFrames; ++i) { EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError); } EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError); // Advance time until it's time to decode the key frame. clock_->AdvanceTimeMilliseconds(kMinDelayMs - clock_->TimeInMilliseconds() - key_frame_inserted); EXPECT_TRUE(DecodeNextFrame()); // Make sure we don't get a key frame request since we have a key frame // in the list. uint16_t nack_list[kMaxNackListSize]; uint16_t nack_list_length = 0; VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize, &nack_list_length); EXPECT_EQ(kNackOk, ret); } } // namespace webrtc