xref: /aosp_15_r20/external/webrtc/modules/video_coding/video_receiver_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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