| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include <memory> |
| |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "webrtc/modules/video_coding/include/mock/mock_video_codec_interface.h" |
| #include "webrtc/modules/video_coding/include/mock/mock_vcm_callbacks.h" |
| #include "webrtc/modules/video_coding/include/video_coding.h" |
| #include "webrtc/modules/video_coding/test/test_util.h" |
| #include "webrtc/system_wrappers/include/clock.h" |
| |
| namespace webrtc { |
| |
| using ::testing::Return; |
| using ::testing::_; |
| using ::testing::ElementsAre; |
| using ::testing::AllOf; |
| using ::testing::Args; |
| using ::testing::Field; |
| using ::testing::Pointee; |
| using ::testing::NiceMock; |
| using ::testing::Sequence; |
| |
| class VCMRobustnessTest : public ::testing::Test { |
| protected: |
| static const size_t kPayloadLen = 10; |
| |
| virtual void SetUp() { |
| clock_.reset(new SimulatedClock(0)); |
| ASSERT_TRUE(clock_.get() != NULL); |
| vcm_.reset(VideoCodingModule::Create(clock_.get(), &event_factory_)); |
| ASSERT_TRUE(vcm_ != NULL); |
| const size_t kMaxNackListSize = 250; |
| const int kMaxPacketAgeToNack = 450; |
| vcm_->SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, 0); |
| ASSERT_EQ(0, vcm_->RegisterFrameTypeCallback(&frame_type_callback_)); |
| ASSERT_EQ(0, vcm_->RegisterPacketRequestCallback(&request_callback_)); |
| VideoCodingModule::Codec(kVideoCodecVP8, &video_codec_); |
| ASSERT_EQ(VCM_OK, vcm_->RegisterReceiveCodec(&video_codec_, 1)); |
| vcm_->RegisterExternalDecoder(&decoder_, video_codec_.plType); |
| } |
| |
| virtual void TearDown() { vcm_.reset(); } |
| |
| void InsertPacket(uint32_t timestamp, |
| uint16_t seq_no, |
| bool first, |
| bool marker_bit, |
| FrameType frame_type) { |
| const uint8_t payload[kPayloadLen] = {0}; |
| WebRtcRTPHeader rtp_info; |
| memset(&rtp_info, 0, sizeof(rtp_info)); |
| rtp_info.frameType = frame_type; |
| rtp_info.header.timestamp = timestamp; |
| rtp_info.header.sequenceNumber = seq_no; |
| rtp_info.header.markerBit = marker_bit; |
| rtp_info.header.payloadType = video_codec_.plType; |
| rtp_info.type.Video.codec = kRtpVideoVp8; |
| rtp_info.type.Video.codecHeader.VP8.InitRTPVideoHeaderVP8(); |
| rtp_info.type.Video.isFirstPacket = first; |
| |
| ASSERT_EQ(VCM_OK, vcm_->IncomingPacket(payload, kPayloadLen, rtp_info)); |
| } |
| |
| std::unique_ptr<VideoCodingModule> vcm_; |
| VideoCodec video_codec_; |
| MockVCMFrameTypeCallback frame_type_callback_; |
| MockPacketRequestCallback request_callback_; |
| NiceMock<MockVideoDecoder> decoder_; |
| NiceMock<MockVideoDecoder> decoderCopy_; |
| std::unique_ptr<SimulatedClock> clock_; |
| NullEventFactory event_factory_; |
| }; |
| |
| TEST_F(VCMRobustnessTest, TestHardNack) { |
| Sequence s; |
| EXPECT_CALL(request_callback_, ResendPackets(_, 2)) |
| .With(Args<0, 1>(ElementsAre(6, 7))) |
| .Times(1); |
| for (int ts = 0; ts <= 6000; ts += 3000) { |
| EXPECT_CALL(decoder_, |
| Decode(AllOf(Field(&EncodedImage::_timeStamp, ts), |
| Field(&EncodedImage::_length, kPayloadLen * 3), |
| Field(&EncodedImage::_completeFrame, true)), |
| false, _, _, _)) |
| .Times(1) |
| .InSequence(s); |
| } |
| |
| ASSERT_EQ(VCM_OK, vcm_->SetReceiverRobustnessMode( |
| VideoCodingModule::kHardNack, kNoErrors)); |
| |
| InsertPacket(0, 0, true, false, kVideoFrameKey); |
| InsertPacket(0, 1, false, false, kVideoFrameKey); |
| InsertPacket(0, 2, false, true, kVideoFrameKey); |
| clock_->AdvanceTimeMilliseconds(1000 / 30); |
| |
| InsertPacket(3000, 3, true, false, kVideoFrameDelta); |
| InsertPacket(3000, 4, false, false, kVideoFrameDelta); |
| InsertPacket(3000, 5, false, true, kVideoFrameDelta); |
| clock_->AdvanceTimeMilliseconds(1000 / 30); |
| |
| ASSERT_EQ(VCM_OK, vcm_->Decode(0)); |
| ASSERT_EQ(VCM_OK, vcm_->Decode(0)); |
| ASSERT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0)); |
| |
| clock_->AdvanceTimeMilliseconds(10); |
| |
| vcm_->Process(); |
| |
| ASSERT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0)); |
| |
| InsertPacket(6000, 8, false, true, kVideoFrameDelta); |
| clock_->AdvanceTimeMilliseconds(10); |
| vcm_->Process(); |
| |
| ASSERT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0)); |
| |
| InsertPacket(6000, 6, true, false, kVideoFrameDelta); |
| InsertPacket(6000, 7, false, false, kVideoFrameDelta); |
| clock_->AdvanceTimeMilliseconds(10); |
| vcm_->Process(); |
| |
| ASSERT_EQ(VCM_OK, vcm_->Decode(0)); |
| } |
| |
| TEST_F(VCMRobustnessTest, TestHardNackNoneDecoded) { |
| EXPECT_CALL(request_callback_, ResendPackets(_, _)).Times(0); |
| EXPECT_CALL(frame_type_callback_, RequestKeyFrame()).Times(1); |
| |
| ASSERT_EQ(VCM_OK, vcm_->SetReceiverRobustnessMode( |
| VideoCodingModule::kHardNack, kNoErrors)); |
| |
| InsertPacket(3000, 3, true, false, kVideoFrameDelta); |
| InsertPacket(3000, 4, false, false, kVideoFrameDelta); |
| InsertPacket(3000, 5, false, true, kVideoFrameDelta); |
| |
| EXPECT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0)); |
| vcm_->Process(); |
| |
| clock_->AdvanceTimeMilliseconds(10); |
| |
| EXPECT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0)); |
| vcm_->Process(); |
| } |
| |
| TEST_F(VCMRobustnessTest, TestModeNoneWithErrors) { |
| EXPECT_CALL(decoder_, InitDecode(_, _)).Times(1); |
| EXPECT_CALL(decoder_, Release()).Times(1); |
| Sequence s1; |
| EXPECT_CALL(request_callback_, ResendPackets(_, 1)) |
| .With(Args<0, 1>(ElementsAre(4))) |
| .Times(0); |
| |
| EXPECT_CALL(decoder_, Copy()).Times(0); |
| EXPECT_CALL(decoderCopy_, Copy()).Times(0); |
| |
| // Decode operations |
| EXPECT_CALL(decoder_, |
| Decode(AllOf(Field(&EncodedImage::_timeStamp, 0), |
| Field(&EncodedImage::_completeFrame, true)), |
| false, _, _, _)) |
| .Times(1) |
| .InSequence(s1); |
| EXPECT_CALL(decoder_, |
| Decode(AllOf(Field(&EncodedImage::_timeStamp, 3000), |
| Field(&EncodedImage::_completeFrame, false)), |
| false, _, _, _)) |
| .Times(1) |
| .InSequence(s1); |
| EXPECT_CALL(decoder_, |
| Decode(AllOf(Field(&EncodedImage::_timeStamp, 6000), |
| Field(&EncodedImage::_completeFrame, true)), |
| false, _, _, _)) |
| .Times(1) |
| .InSequence(s1); |
| EXPECT_CALL(decoder_, |
| Decode(AllOf(Field(&EncodedImage::_timeStamp, 9000), |
| Field(&EncodedImage::_completeFrame, true)), |
| false, _, _, _)) |
| .Times(1) |
| .InSequence(s1); |
| |
| ASSERT_EQ(VCM_OK, vcm_->SetReceiverRobustnessMode(VideoCodingModule::kNone, |
| kWithErrors)); |
| |
| InsertPacket(0, 0, true, false, kVideoFrameKey); |
| InsertPacket(0, 1, false, false, kVideoFrameKey); |
| InsertPacket(0, 2, false, true, kVideoFrameKey); |
| EXPECT_EQ(VCM_OK, vcm_->Decode(33)); // Decode timestamp 0. |
| vcm_->Process(); |
| |
| clock_->AdvanceTimeMilliseconds(33); |
| InsertPacket(3000, 3, true, false, kVideoFrameDelta); |
| // Packet 4 missing |
| InsertPacket(3000, 5, false, true, kVideoFrameDelta); |
| EXPECT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0)); |
| vcm_->Process(); |
| |
| clock_->AdvanceTimeMilliseconds(33); |
| InsertPacket(6000, 6, true, false, kVideoFrameDelta); |
| InsertPacket(6000, 7, false, false, kVideoFrameDelta); |
| InsertPacket(6000, 8, false, true, kVideoFrameDelta); |
| EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 3000 incomplete. |
| vcm_->Process(); |
| |
| clock_->AdvanceTimeMilliseconds(10); |
| EXPECT_EQ(VCM_OK, vcm_->Decode(23)); // Decode timestamp 6000 complete. |
| vcm_->Process(); |
| |
| clock_->AdvanceTimeMilliseconds(23); |
| InsertPacket(3000, 4, false, false, kVideoFrameDelta); |
| |
| InsertPacket(9000, 9, true, false, kVideoFrameDelta); |
| InsertPacket(9000, 10, false, false, kVideoFrameDelta); |
| InsertPacket(9000, 11, false, true, kVideoFrameDelta); |
| EXPECT_EQ(VCM_OK, vcm_->Decode(33)); // Decode timestamp 9000 complete. |
| } |
| } // namespace webrtc |