blob: f2ebce8ec22afa2081376e68ee3024ab4a461264 [file] [log] [blame]
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +00001/*
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
Erik Språngc84cd952018-10-15 11:55:13 +020011#include "api/test/mock_video_decoder.h"
Danil Chapovalov355b8d22021-08-13 16:50:37 +020012#include "api/video_codecs/video_decoder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "modules/video_coding/include/video_coding.h"
Rasmus Brandtc4d253c2022-05-25 12:03:35 +020014#include "modules/video_coding/timing/timing.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "modules/video_coding/video_coding_impl.h"
16#include "system_wrappers/include/clock.h"
17#include "test/gtest.h"
Jonas Orelande02f9ee2022-03-25 12:43:14 +010018#include "test/scoped_key_value_config.h"
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000019
20using ::testing::_;
tommid0a71ba2017-03-14 04:16:20 -070021using ::testing::AnyNumber;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000022using ::testing::NiceMock;
23
24namespace webrtc {
25namespace vcm {
26namespace {
27
Niels Möller2fca9712020-02-04 10:46:37 +010028class MockPacketRequestCallback : public VCMPacketRequestCallback {
29 public:
Danil Chapovalovf2c0f152020-05-19 13:20:27 +020030 MOCK_METHOD(int32_t,
31 ResendPackets,
32 (const uint16_t* sequenceNumbers, uint16_t length),
33 (override));
Niels Möller2fca9712020-02-04 10:46:37 +010034};
35
36class MockVCMReceiveCallback : public VCMReceiveCallback {
37 public:
38 MockVCMReceiveCallback() {}
39 virtual ~MockVCMReceiveCallback() {}
40
Philipp Hancked970b092022-06-17 07:34:23 +020041 MOCK_METHOD(
42 int32_t,
43 FrameToRender,
44 (VideoFrame&, absl::optional<uint8_t>, TimeDelta, VideoContentType),
45 (override));
Danil Chapovalovf2c0f152020-05-19 13:20:27 +020046 MOCK_METHOD(void, OnIncomingPayloadType, (int), (override));
47 MOCK_METHOD(void, OnDecoderImplementationName, (const char*), (override));
Niels Möller2fca9712020-02-04 10:46:37 +010048};
49
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000050class TestVideoReceiver : public ::testing::Test {
51 protected:
52 static const int kUnusedPayloadType = 10;
Åsa Persson86202532019-01-09 14:03:59 +010053 static const uint16_t kMaxWaitTimeMs = 100;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000054
Åsa Persson86202532019-01-09 14:03:59 +010055 TestVideoReceiver()
Jonas Orelande02f9ee2022-03-25 12:43:14 +010056 : clock_(0),
57 timing_(&clock_, field_trials_),
58 receiver_(&clock_, &timing_, field_trials_) {}
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000059
60 virtual void SetUp() {
Åsa Persson86202532019-01-09 14:03:59 +010061 // Register decoder.
62 receiver_.RegisterExternalDecoder(&decoder_, kUnusedPayloadType);
Danil Chapovalov355b8d22021-08-13 16:50:37 +020063 VideoDecoder::Settings settings;
64 settings.set_codec_type(kVideoCodecVP8);
Danil Chapovalovba0a3062021-08-13 18:15:55 +020065 receiver_.RegisterReceiveCodec(kUnusedPayloadType, settings);
Åsa Persson86202532019-01-09 14:03:59 +010066
67 // Set protection mode.
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000068 const size_t kMaxNackListSize = 250;
69 const int kMaxPacketAgeToNack = 450;
Åsa Persson86202532019-01-09 14:03:59 +010070 receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, 0);
Åsa Persson86202532019-01-09 14:03:59 +010071 EXPECT_EQ(
72 0, receiver_.RegisterPacketRequestCallback(&packet_request_callback_));
tommid0a71ba2017-03-14 04:16:20 -070073
74 // Since we call Decode, we need to provide a valid receive callback.
75 // However, for the purposes of these tests, we ignore the callbacks.
76 EXPECT_CALL(receive_callback_, OnIncomingPayloadType(_)).Times(AnyNumber());
77 EXPECT_CALL(receive_callback_, OnDecoderImplementationName(_))
78 .Times(AnyNumber());
Åsa Persson86202532019-01-09 14:03:59 +010079 receiver_.RegisterReceiveCallback(&receive_callback_);
80 }
81
Niels Möllerbe7a0ec2019-04-25 10:02:52 +020082 RTPHeader GetDefaultRTPHeader() const {
83 RTPHeader header;
84 header.markerBit = false;
85 header.payloadType = kUnusedPayloadType;
86 header.ssrc = 1;
87 header.headerLength = 12;
Åsa Persson86202532019-01-09 14:03:59 +010088 return header;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000089 }
90
Niels Möllerbe7a0ec2019-04-25 10:02:52 +020091 RTPVideoHeader GetDefaultVp8Header() const {
92 RTPVideoHeader video_header = {};
93 video_header.frame_type = VideoFrameType::kEmptyFrame;
94 video_header.codec = kVideoCodecVP8;
95 return video_header;
96 }
97
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000098 void InsertAndVerifyPaddingFrame(const uint8_t* payload,
Niels Möllerbe7a0ec2019-04-25 10:02:52 +020099 RTPHeader* header,
100 const RTPVideoHeader& video_header) {
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000101 for (int j = 0; j < 5; ++j) {
102 // Padding only packets are passed to the VCM with payload size 0.
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200103 EXPECT_EQ(0, receiver_.IncomingPacket(payload, 0, *header, video_header));
104 ++header->sequenceNumber;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000105 }
Åsa Persson86202532019-01-09 14:03:59 +0100106 receiver_.Process();
Niels Möller7aacdd92019-03-25 09:11:40 +0100107 EXPECT_CALL(decoder_, Decode(_, _, _)).Times(0);
Åsa Persson86202532019-01-09 14:03:59 +0100108 EXPECT_EQ(VCM_FRAME_NOT_READY, receiver_.Decode(kMaxWaitTimeMs));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000109 }
110
111 void InsertAndVerifyDecodableFrame(const uint8_t* payload,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000112 size_t length,
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200113 RTPHeader* header,
114 const RTPVideoHeader& video_header) {
115 EXPECT_EQ(0,
116 receiver_.IncomingPacket(payload, length, *header, video_header));
117 ++header->sequenceNumber;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000118 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0);
Åsa Persson86202532019-01-09 14:03:59 +0100119
120 receiver_.Process();
Niels Möller7aacdd92019-03-25 09:11:40 +0100121 EXPECT_CALL(decoder_, Decode(_, _, _)).Times(1);
Åsa Persson86202532019-01-09 14:03:59 +0100122 EXPECT_EQ(0, receiver_.Decode(kMaxWaitTimeMs));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000123 }
124
Jonas Orelande02f9ee2022-03-25 12:43:14 +0100125 test::ScopedKeyValueConfig field_trials_;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000126 SimulatedClock clock_;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000127 NiceMock<MockVideoDecoder> decoder_;
128 NiceMock<MockPacketRequestCallback> packet_request_callback_;
Åsa Persson86202532019-01-09 14:03:59 +0100129 VCMTiming timing_;
tommid0a71ba2017-03-14 04:16:20 -0700130 MockVCMReceiveCallback receive_callback_;
Åsa Persson86202532019-01-09 14:03:59 +0100131 VideoReceiver receiver_;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000132};
133
134TEST_F(TestVideoReceiver, PaddingOnlyFrames) {
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000135 const size_t kPaddingSize = 220;
Åsa Persson86202532019-01-09 14:03:59 +0100136 const uint8_t kPayload[kPaddingSize] = {0};
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200137 RTPHeader header = GetDefaultRTPHeader();
138 RTPVideoHeader video_header = GetDefaultVp8Header();
139 header.paddingLength = kPaddingSize;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000140 for (int i = 0; i < 10; ++i) {
141 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200142 InsertAndVerifyPaddingFrame(kPayload, &header, video_header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000143 clock_.AdvanceTimeMilliseconds(33);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200144 header.timestamp += 3000;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000145 }
146}
147
148TEST_F(TestVideoReceiver, PaddingOnlyFramesWithLosses) {
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000149 const size_t kFrameSize = 1200;
150 const size_t kPaddingSize = 220;
Åsa Persson86202532019-01-09 14:03:59 +0100151 const uint8_t kPayload[kFrameSize] = {0};
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200152 RTPHeader header = GetDefaultRTPHeader();
153 RTPVideoHeader video_header = GetDefaultVp8Header();
154 header.paddingLength = kPaddingSize;
155 video_header.video_type_header.emplace<RTPVideoHeaderVP8>();
Åsa Persson86202532019-01-09 14:03:59 +0100156
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000157 // Insert one video frame to get one frame decoded.
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200158 video_header.frame_type = VideoFrameType::kVideoFrameKey;
159 video_header.is_first_packet_in_frame = true;
160 header.markerBit = true;
161 InsertAndVerifyDecodableFrame(kPayload, kFrameSize, &header, video_header);
Åsa Persson86202532019-01-09 14:03:59 +0100162
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000163 clock_.AdvanceTimeMilliseconds(33);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200164 header.timestamp += 3000;
165 video_header.frame_type = VideoFrameType::kEmptyFrame;
166 video_header.is_first_packet_in_frame = false;
167 header.markerBit = false;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000168 // Insert padding frames.
169 for (int i = 0; i < 10; ++i) {
170 // Lose one packet from the 6th frame.
171 if (i == 5) {
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200172 ++header.sequenceNumber;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000173 }
174 // Lose the 4th frame.
175 if (i == 3) {
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200176 header.sequenceNumber += 5;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000177 } else {
178 if (i > 3 && i < 5) {
179 EXPECT_CALL(packet_request_callback_, ResendPackets(_, 5)).Times(1);
180 } else if (i >= 5) {
181 EXPECT_CALL(packet_request_callback_, ResendPackets(_, 6)).Times(1);
182 } else {
183 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0);
184 }
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200185 InsertAndVerifyPaddingFrame(kPayload, &header, video_header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000186 }
187 clock_.AdvanceTimeMilliseconds(33);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200188 header.timestamp += 3000;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000189 }
190}
191
192TEST_F(TestVideoReceiver, PaddingOnlyAndVideo) {
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000193 const size_t kFrameSize = 1200;
194 const size_t kPaddingSize = 220;
Åsa Persson86202532019-01-09 14:03:59 +0100195 const uint8_t kPayload[kFrameSize] = {0};
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200196 RTPHeader header = GetDefaultRTPHeader();
197 RTPVideoHeader video_header = GetDefaultVp8Header();
198 video_header.is_first_packet_in_frame = false;
199 header.paddingLength = kPaddingSize;
Philip Eliassond52a1a62018-09-07 13:03:55 +0000200 auto& vp8_header =
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200201 video_header.video_type_header.emplace<RTPVideoHeaderVP8>();
Philip Eliassond52a1a62018-09-07 13:03:55 +0000202 vp8_header.pictureId = -1;
203 vp8_header.tl0PicIdx = -1;
Åsa Persson86202532019-01-09 14:03:59 +0100204
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000205 for (int i = 0; i < 3; ++i) {
206 // Insert 2 video frames.
207 for (int j = 0; j < 2; ++j) {
208 if (i == 0 && j == 0) // First frame should be a key frame.
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200209 video_header.frame_type = VideoFrameType::kVideoFrameKey;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000210 else
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200211 video_header.frame_type = VideoFrameType::kVideoFrameDelta;
212 video_header.is_first_packet_in_frame = true;
213 header.markerBit = true;
214 InsertAndVerifyDecodableFrame(kPayload, kFrameSize, &header,
215 video_header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000216 clock_.AdvanceTimeMilliseconds(33);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200217 header.timestamp += 3000;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000218 }
219
220 // Insert 2 padding only frames.
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200221 video_header.frame_type = VideoFrameType::kEmptyFrame;
222 video_header.is_first_packet_in_frame = false;
223 header.markerBit = false;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000224 for (int j = 0; j < 2; ++j) {
Åsa Persson86202532019-01-09 14:03:59 +0100225 // InsertAndVerifyPaddingFrame(kPayload, &header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000226 clock_.AdvanceTimeMilliseconds(33);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200227 header.timestamp += 3000;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000228 }
229 }
230}
231
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000232} // namespace
233} // namespace vcm
234} // namespace webrtc