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