/* * 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 "testing/gtest/include/gtest/gtest.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/modules/video_coding/codecs/interface/mock/mock_video_codec_interface.h" #include "webrtc/modules/video_coding/main/interface/mock/mock_vcm_callbacks.h" #include "webrtc/modules/video_coding/main/interface/video_coding.h" #include "webrtc/modules/video_coding/main/source/video_coding_impl.h" #include "webrtc/modules/video_coding/main/test/test_util.h" #include "webrtc/system_wrappers/include/clock.h" using ::testing::_; using ::testing::NiceMock; namespace webrtc { namespace vcm { namespace { class TestVideoReceiver : public ::testing::Test { protected: static const int kUnusedPayloadType = 10; TestVideoReceiver() : clock_(0) {} virtual void SetUp() { receiver_.reset(new VideoReceiver(&clock_, &event_factory_)); EXPECT_EQ(0, receiver_->RegisterExternalDecoder(&decoder_, kUnusedPayloadType, true)); const size_t kMaxNackListSize = 250; const int kMaxPacketAgeToNack = 450; receiver_->SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, 0); memset(&settings_, 0, sizeof(settings_)); EXPECT_EQ(0, VideoCodingModule::Codec(kVideoCodecVP8, &settings_)); settings_.plType = kUnusedPayloadType; // Use the mocked encoder. EXPECT_EQ(0, receiver_->RegisterReceiveCodec(&settings_, 1, true)); } void InsertAndVerifyPaddingFrame(const uint8_t* payload, WebRtcRTPHeader* header) { ASSERT_TRUE(header != NULL); for (int j = 0; j < 5; ++j) { // Padding only packets are passed to the VCM with payload size 0. EXPECT_EQ(0, receiver_->IncomingPacket(payload, 0, *header)); ++header->header.sequenceNumber; } EXPECT_EQ(0, receiver_->Process()); EXPECT_CALL(decoder_, Decode(_, _, _, _, _)).Times(0); EXPECT_EQ(VCM_FRAME_NOT_READY, receiver_->Decode(0)); } void InsertAndVerifyDecodableFrame(const uint8_t* payload, size_t length, WebRtcRTPHeader* header) { ASSERT_TRUE(header != NULL); EXPECT_EQ(0, receiver_->IncomingPacket(payload, length, *header)); ++header->header.sequenceNumber; EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0); EXPECT_EQ(0, receiver_->Process()); EXPECT_CALL(decoder_, Decode(_, _, _, _, _)).Times(1); EXPECT_EQ(0, receiver_->Decode(0)); } SimulatedClock clock_; NullEventFactory event_factory_; VideoCodec settings_; NiceMock decoder_; NiceMock packet_request_callback_; rtc::scoped_ptr receiver_; }; TEST_F(TestVideoReceiver, PaddingOnlyFrames) { EXPECT_EQ(0, receiver_->SetVideoProtection(kProtectionNack, true)); EXPECT_EQ( 0, receiver_->RegisterPacketRequestCallback(&packet_request_callback_)); const size_t kPaddingSize = 220; const uint8_t payload[kPaddingSize] = {0}; WebRtcRTPHeader header; memset(&header, 0, sizeof(header)); header.frameType = kEmptyFrame; header.header.markerBit = false; header.header.paddingLength = kPaddingSize; header.header.payloadType = kUnusedPayloadType; header.header.ssrc = 1; header.header.headerLength = 12; header.type.Video.codec = kRtpVideoVp8; for (int i = 0; i < 10; ++i) { EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0); InsertAndVerifyPaddingFrame(payload, &header); clock_.AdvanceTimeMilliseconds(33); header.header.timestamp += 3000; } } TEST_F(TestVideoReceiver, PaddingOnlyFramesWithLosses) { EXPECT_EQ(0, receiver_->SetVideoProtection(kProtectionNack, true)); EXPECT_EQ( 0, receiver_->RegisterPacketRequestCallback(&packet_request_callback_)); const size_t kFrameSize = 1200; const size_t kPaddingSize = 220; const uint8_t payload[kFrameSize] = {0}; WebRtcRTPHeader header; memset(&header, 0, sizeof(header)); header.frameType = kEmptyFrame; header.header.markerBit = false; header.header.paddingLength = kPaddingSize; header.header.payloadType = kUnusedPayloadType; header.header.ssrc = 1; header.header.headerLength = 12; header.type.Video.codec = kRtpVideoVp8; // Insert one video frame to get one frame decoded. header.frameType = kVideoFrameKey; header.type.Video.isFirstPacket = true; header.header.markerBit = true; InsertAndVerifyDecodableFrame(payload, kFrameSize, &header); clock_.AdvanceTimeMilliseconds(33); header.header.timestamp += 3000; header.frameType = kEmptyFrame; header.type.Video.isFirstPacket = false; header.header.markerBit = false; // Insert padding frames. for (int i = 0; i < 10; ++i) { // Lose one packet from the 6th frame. if (i == 5) { ++header.header.sequenceNumber; } // Lose the 4th frame. if (i == 3) { header.header.sequenceNumber += 5; } else { if (i > 3 && i < 5) { EXPECT_CALL(packet_request_callback_, ResendPackets(_, 5)).Times(1); } else if (i >= 5) { EXPECT_CALL(packet_request_callback_, ResendPackets(_, 6)).Times(1); } else { EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0); } InsertAndVerifyPaddingFrame(payload, &header); } clock_.AdvanceTimeMilliseconds(33); header.header.timestamp += 3000; } } TEST_F(TestVideoReceiver, PaddingOnlyAndVideo) { EXPECT_EQ(0, receiver_->SetVideoProtection(kProtectionNack, true)); EXPECT_EQ( 0, receiver_->RegisterPacketRequestCallback(&packet_request_callback_)); const size_t kFrameSize = 1200; const size_t kPaddingSize = 220; const uint8_t payload[kFrameSize] = {0}; WebRtcRTPHeader header; memset(&header, 0, sizeof(header)); header.frameType = kEmptyFrame; header.type.Video.isFirstPacket = false; header.header.markerBit = false; header.header.paddingLength = kPaddingSize; header.header.payloadType = kUnusedPayloadType; header.header.ssrc = 1; header.header.headerLength = 12; header.type.Video.codec = kRtpVideoVp8; header.type.Video.codecHeader.VP8.pictureId = -1; header.type.Video.codecHeader.VP8.tl0PicIdx = -1; for (int i = 0; i < 3; ++i) { // Insert 2 video frames. for (int j = 0; j < 2; ++j) { if (i == 0 && j == 0) // First frame should be a key frame. header.frameType = kVideoFrameKey; else header.frameType = kVideoFrameDelta; header.type.Video.isFirstPacket = true; header.header.markerBit = true; InsertAndVerifyDecodableFrame(payload, kFrameSize, &header); clock_.AdvanceTimeMilliseconds(33); header.header.timestamp += 3000; } // Insert 2 padding only frames. header.frameType = kEmptyFrame; header.type.Video.isFirstPacket = false; header.header.markerBit = false; for (int j = 0; j < 2; ++j) { // InsertAndVerifyPaddingFrame(payload, &header); clock_.AdvanceTimeMilliseconds(33); header.header.timestamp += 3000; } } } TEST_F(TestVideoReceiver, ReceiverDelay) { EXPECT_EQ(0, receiver_->SetMinReceiverDelay(0)); EXPECT_EQ(0, receiver_->SetMinReceiverDelay(5000)); EXPECT_EQ(-1, receiver_->SetMinReceiverDelay(-100)); EXPECT_EQ(-1, receiver_->SetMinReceiverDelay(10010)); } } // namespace } // namespace vcm } // namespace webrtc