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