video_receiver_unittest.cc (8507B)
1 /* 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <cstddef> 12 #include <cstdint> 13 14 #include "api/field_trials.h" 15 #include "api/rtp_headers.h" 16 #include "api/test/mock_video_decoder.h" 17 #include "api/video/video_codec_type.h" 18 #include "api/video/video_frame_type.h" 19 #include "api/video_codecs/video_decoder.h" 20 #include "modules/rtp_rtcp/source/rtp_video_header.h" 21 #include "modules/video_coding/codecs/vp8/include/vp8_globals.h" 22 #include "modules/video_coding/include/video_coding_defines.h" 23 #include "modules/video_coding/timing/timing.h" 24 #include "modules/video_coding/video_coding_impl.h" 25 #include "system_wrappers/include/clock.h" 26 #include "test/create_test_field_trials.h" 27 #include "test/gmock.h" 28 #include "test/gtest.h" 29 30 using ::testing::_; 31 using ::testing::AnyNumber; 32 using ::testing::NiceMock; 33 34 namespace webrtc { 35 namespace vcm { 36 namespace { 37 38 class MockPacketRequestCallback : public VCMPacketRequestCallback { 39 public: 40 MOCK_METHOD(int32_t, 41 ResendPackets, 42 (const uint16_t* sequenceNumbers, uint16_t length), 43 (override)); 44 }; 45 46 class MockVCMReceiveCallback : public VCMReceiveCallback { 47 public: 48 MockVCMReceiveCallback() {} 49 ~MockVCMReceiveCallback() override {} 50 51 MOCK_METHOD(int32_t, OnFrameToRender, (const FrameToRender&), (override)); 52 MOCK_METHOD(void, OnIncomingPayloadType, (int), (override)); 53 MOCK_METHOD(void, 54 OnDecoderInfoChanged, 55 (const VideoDecoder::DecoderInfo&), 56 (override)); 57 }; 58 59 class TestVideoReceiver : public ::testing::Test { 60 protected: 61 static const int kUnusedPayloadType = 10; 62 static const uint16_t kMaxWaitTimeMs = 100; 63 64 TestVideoReceiver() 65 : field_trials_(CreateTestFieldTrials()), 66 clock_(0), 67 timing_(&clock_, field_trials_), 68 receiver_(&clock_, &timing_, field_trials_) {} 69 70 void SetUp() override { 71 // Register decoder. 72 receiver_.RegisterExternalDecoder(&decoder_, kUnusedPayloadType); 73 VideoDecoder::Settings settings; 74 settings.set_codec_type(kVideoCodecVP8); 75 receiver_.RegisterReceiveCodec(kUnusedPayloadType, settings); 76 77 // Set protection mode. 78 const size_t kMaxNackListSize = 250; 79 const int kMaxPacketAgeToNack = 450; 80 receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, 0); 81 EXPECT_EQ( 82 0, receiver_.RegisterPacketRequestCallback(&packet_request_callback_)); 83 84 // Since we call Decode, we need to provide a valid receive callback. 85 // However, for the purposes of these tests, we ignore the callbacks. 86 EXPECT_CALL(receive_callback_, OnIncomingPayloadType(_)).Times(AnyNumber()); 87 EXPECT_CALL(receive_callback_, OnDecoderInfoChanged).Times(AnyNumber()); 88 receiver_.RegisterReceiveCallback(&receive_callback_); 89 } 90 91 RTPHeader GetDefaultRTPHeader() const { 92 RTPHeader header; 93 header.markerBit = false; 94 header.payloadType = kUnusedPayloadType; 95 header.ssrc = 1; 96 header.headerLength = 12; 97 return header; 98 } 99 100 RTPVideoHeader GetDefaultVp8Header() const { 101 RTPVideoHeader video_header = {}; 102 video_header.frame_type = VideoFrameType::kEmptyFrame; 103 video_header.codec = kVideoCodecVP8; 104 return video_header; 105 } 106 107 void InsertAndVerifyPaddingFrame(const uint8_t* payload, 108 RTPHeader* header, 109 const RTPVideoHeader& video_header) { 110 for (int j = 0; j < 5; ++j) { 111 // Padding only packets are passed to the VCM with payload size 0. 112 EXPECT_EQ(0, receiver_.IncomingPacket(payload, 0, *header, video_header)); 113 ++header->sequenceNumber; 114 } 115 receiver_.Process(); 116 EXPECT_CALL(decoder_, Decode(_, _)).Times(0); 117 EXPECT_EQ(VCM_FRAME_NOT_READY, receiver_.Decode(kMaxWaitTimeMs)); 118 } 119 120 void InsertAndVerifyDecodableFrame(const uint8_t* payload, 121 size_t length, 122 RTPHeader* header, 123 const RTPVideoHeader& video_header) { 124 EXPECT_EQ(0, 125 receiver_.IncomingPacket(payload, length, *header, video_header)); 126 ++header->sequenceNumber; 127 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0); 128 129 receiver_.Process(); 130 EXPECT_CALL(decoder_, Decode(_, _)).Times(1); 131 EXPECT_EQ(0, receiver_.Decode(kMaxWaitTimeMs)); 132 } 133 134 FieldTrials field_trials_; 135 SimulatedClock clock_; 136 NiceMock<MockVideoDecoder> decoder_; 137 NiceMock<MockPacketRequestCallback> packet_request_callback_; 138 VCMTiming timing_; 139 MockVCMReceiveCallback receive_callback_; 140 VideoReceiver receiver_; 141 }; 142 143 TEST_F(TestVideoReceiver, PaddingOnlyFrames) { 144 const size_t kPaddingSize = 220; 145 const uint8_t kPayload[kPaddingSize] = {0}; 146 RTPHeader header = GetDefaultRTPHeader(); 147 RTPVideoHeader video_header = GetDefaultVp8Header(); 148 header.paddingLength = kPaddingSize; 149 for (int i = 0; i < 10; ++i) { 150 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0); 151 InsertAndVerifyPaddingFrame(kPayload, &header, video_header); 152 clock_.AdvanceTimeMilliseconds(33); 153 header.timestamp += 3000; 154 } 155 } 156 157 TEST_F(TestVideoReceiver, PaddingOnlyFramesWithLosses) { 158 const size_t kFrameSize = 1200; 159 const size_t kPaddingSize = 220; 160 const uint8_t kPayload[kFrameSize] = {0}; 161 RTPHeader header = GetDefaultRTPHeader(); 162 RTPVideoHeader video_header = GetDefaultVp8Header(); 163 header.paddingLength = kPaddingSize; 164 video_header.video_type_header.emplace<RTPVideoHeaderVP8>(); 165 166 // Insert one video frame to get one frame decoded. 167 video_header.frame_type = VideoFrameType::kVideoFrameKey; 168 video_header.is_first_packet_in_frame = true; 169 header.markerBit = true; 170 InsertAndVerifyDecodableFrame(kPayload, kFrameSize, &header, video_header); 171 172 clock_.AdvanceTimeMilliseconds(33); 173 header.timestamp += 3000; 174 video_header.frame_type = VideoFrameType::kEmptyFrame; 175 video_header.is_first_packet_in_frame = false; 176 header.markerBit = false; 177 // Insert padding frames. 178 for (int i = 0; i < 10; ++i) { 179 // Lose one packet from the 6th frame. 180 if (i == 5) { 181 ++header.sequenceNumber; 182 } 183 // Lose the 4th frame. 184 if (i == 3) { 185 header.sequenceNumber += 5; 186 } else { 187 if (i > 3 && i < 5) { 188 EXPECT_CALL(packet_request_callback_, ResendPackets(_, 5)).Times(1); 189 } else if (i >= 5) { 190 EXPECT_CALL(packet_request_callback_, ResendPackets(_, 6)).Times(1); 191 } else { 192 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0); 193 } 194 InsertAndVerifyPaddingFrame(kPayload, &header, video_header); 195 } 196 clock_.AdvanceTimeMilliseconds(33); 197 header.timestamp += 3000; 198 } 199 } 200 201 TEST_F(TestVideoReceiver, PaddingOnlyAndVideo) { 202 const size_t kFrameSize = 1200; 203 const size_t kPaddingSize = 220; 204 const uint8_t kPayload[kFrameSize] = {0}; 205 RTPHeader header = GetDefaultRTPHeader(); 206 RTPVideoHeader video_header = GetDefaultVp8Header(); 207 video_header.is_first_packet_in_frame = false; 208 header.paddingLength = kPaddingSize; 209 auto& vp8_header = 210 video_header.video_type_header.emplace<RTPVideoHeaderVP8>(); 211 vp8_header.pictureId = -1; 212 vp8_header.tl0PicIdx = -1; 213 214 for (int i = 0; i < 3; ++i) { 215 // Insert 2 video frames. 216 for (int j = 0; j < 2; ++j) { 217 if (i == 0 && j == 0) // First frame should be a key frame. 218 video_header.frame_type = VideoFrameType::kVideoFrameKey; 219 else 220 video_header.frame_type = VideoFrameType::kVideoFrameDelta; 221 video_header.is_first_packet_in_frame = true; 222 header.markerBit = true; 223 InsertAndVerifyDecodableFrame(kPayload, kFrameSize, &header, 224 video_header); 225 clock_.AdvanceTimeMilliseconds(33); 226 header.timestamp += 3000; 227 } 228 229 // Insert 2 padding only frames. 230 video_header.frame_type = VideoFrameType::kEmptyFrame; 231 video_header.is_first_packet_in_frame = false; 232 header.markerBit = false; 233 for (int j = 0; j < 2; ++j) { 234 // InsertAndVerifyPaddingFrame(kPayload, &header); 235 clock_.AdvanceTimeMilliseconds(33); 236 header.timestamp += 3000; 237 } 238 } 239 } 240 241 } // namespace 242 } // namespace vcm 243 } // namespace webrtc