• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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