blob: 363838b846ea80f4078887d4921ce409fc1b239d [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"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020012#include "modules/video_coding/include/video_coding.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#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"
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000018
19using ::testing::_;
tommid0a71ba2017-03-14 04:16:20 -070020using ::testing::AnyNumber;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000021using ::testing::NiceMock;
22
23namespace webrtc {
24namespace vcm {
25namespace {
26
Niels Möller2fca9712020-02-04 10:46:37 +010027class MockPacketRequestCallback : public VCMPacketRequestCallback {
28 public:
29 MOCK_METHOD2(ResendPackets,
30 int32_t(const uint16_t* sequenceNumbers, uint16_t length));
31};
32
33class MockVCMReceiveCallback : public VCMReceiveCallback {
34 public:
35 MockVCMReceiveCallback() {}
36 virtual ~MockVCMReceiveCallback() {}
37
38 MOCK_METHOD4(
39 FrameToRender,
40 int32_t(VideoFrame&, absl::optional<uint8_t>, int32_t, VideoContentType));
41 MOCK_METHOD1(OnIncomingPayloadType, void(int));
42 MOCK_METHOD1(OnDecoderImplementationName, void(const char*));
43};
44
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000045class TestVideoReceiver : public ::testing::Test {
46 protected:
47 static const int kUnusedPayloadType = 10;
Åsa Persson86202532019-01-09 14:03:59 +010048 static const uint16_t kMaxWaitTimeMs = 100;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000049
Åsa Persson86202532019-01-09 14:03:59 +010050 TestVideoReceiver()
51 : clock_(0), timing_(&clock_), receiver_(&clock_, &timing_) {}
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000052
53 virtual void SetUp() {
Åsa Persson86202532019-01-09 14:03:59 +010054 // Register decoder.
55 receiver_.RegisterExternalDecoder(&decoder_, kUnusedPayloadType);
56 webrtc::test::CodecSettings(kVideoCodecVP8, &settings_);
57 settings_.plType = kUnusedPayloadType;
58 EXPECT_EQ(0, receiver_.RegisterReceiveCodec(&settings_, 1, true));
59
60 // Set protection mode.
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000061 const size_t kMaxNackListSize = 250;
62 const int kMaxPacketAgeToNack = 450;
Åsa Persson86202532019-01-09 14:03:59 +010063 receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, 0);
Åsa Persson86202532019-01-09 14:03:59 +010064 EXPECT_EQ(
65 0, receiver_.RegisterPacketRequestCallback(&packet_request_callback_));
tommid0a71ba2017-03-14 04:16:20 -070066
67 // Since we call Decode, we need to provide a valid receive callback.
68 // However, for the purposes of these tests, we ignore the callbacks.
69 EXPECT_CALL(receive_callback_, OnIncomingPayloadType(_)).Times(AnyNumber());
70 EXPECT_CALL(receive_callback_, OnDecoderImplementationName(_))
71 .Times(AnyNumber());
Åsa Persson86202532019-01-09 14:03:59 +010072 receiver_.RegisterReceiveCallback(&receive_callback_);
73 }
74
Niels Möllerbe7a0ec2019-04-25 10:02:52 +020075 RTPHeader GetDefaultRTPHeader() const {
76 RTPHeader header;
77 header.markerBit = false;
78 header.payloadType = kUnusedPayloadType;
79 header.ssrc = 1;
80 header.headerLength = 12;
Åsa Persson86202532019-01-09 14:03:59 +010081 return header;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000082 }
83
Niels Möllerbe7a0ec2019-04-25 10:02:52 +020084 RTPVideoHeader GetDefaultVp8Header() const {
85 RTPVideoHeader video_header = {};
86 video_header.frame_type = VideoFrameType::kEmptyFrame;
87 video_header.codec = kVideoCodecVP8;
88 return video_header;
89 }
90
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000091 void InsertAndVerifyPaddingFrame(const uint8_t* payload,
Niels Möllerbe7a0ec2019-04-25 10:02:52 +020092 RTPHeader* header,
93 const RTPVideoHeader& video_header) {
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000094 for (int j = 0; j < 5; ++j) {
95 // Padding only packets are passed to the VCM with payload size 0.
Niels Möllerbe7a0ec2019-04-25 10:02:52 +020096 EXPECT_EQ(0, receiver_.IncomingPacket(payload, 0, *header, video_header));
97 ++header->sequenceNumber;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000098 }
Åsa Persson86202532019-01-09 14:03:59 +010099 receiver_.Process();
Niels Möller7aacdd92019-03-25 09:11:40 +0100100 EXPECT_CALL(decoder_, Decode(_, _, _)).Times(0);
Åsa Persson86202532019-01-09 14:03:59 +0100101 EXPECT_EQ(VCM_FRAME_NOT_READY, receiver_.Decode(kMaxWaitTimeMs));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000102 }
103
104 void InsertAndVerifyDecodableFrame(const uint8_t* payload,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000105 size_t length,
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200106 RTPHeader* header,
107 const RTPVideoHeader& video_header) {
108 EXPECT_EQ(0,
109 receiver_.IncomingPacket(payload, length, *header, video_header));
110 ++header->sequenceNumber;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000111 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0);
Åsa Persson86202532019-01-09 14:03:59 +0100112
113 receiver_.Process();
Niels Möller7aacdd92019-03-25 09:11:40 +0100114 EXPECT_CALL(decoder_, Decode(_, _, _)).Times(1);
Åsa Persson86202532019-01-09 14:03:59 +0100115 EXPECT_EQ(0, receiver_.Decode(kMaxWaitTimeMs));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000116 }
117
118 SimulatedClock clock_;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000119 VideoCodec settings_;
120 NiceMock<MockVideoDecoder> decoder_;
121 NiceMock<MockPacketRequestCallback> packet_request_callback_;
Åsa Persson86202532019-01-09 14:03:59 +0100122 VCMTiming timing_;
tommid0a71ba2017-03-14 04:16:20 -0700123 MockVCMReceiveCallback receive_callback_;
Åsa Persson86202532019-01-09 14:03:59 +0100124 VideoReceiver receiver_;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000125};
126
127TEST_F(TestVideoReceiver, PaddingOnlyFrames) {
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000128 const size_t kPaddingSize = 220;
Åsa Persson86202532019-01-09 14:03:59 +0100129 const uint8_t kPayload[kPaddingSize] = {0};
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200130 RTPHeader header = GetDefaultRTPHeader();
131 RTPVideoHeader video_header = GetDefaultVp8Header();
132 header.paddingLength = kPaddingSize;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000133 for (int i = 0; i < 10; ++i) {
134 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200135 InsertAndVerifyPaddingFrame(kPayload, &header, video_header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000136 clock_.AdvanceTimeMilliseconds(33);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200137 header.timestamp += 3000;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000138 }
139}
140
141TEST_F(TestVideoReceiver, PaddingOnlyFramesWithLosses) {
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000142 const size_t kFrameSize = 1200;
143 const size_t kPaddingSize = 220;
Åsa Persson86202532019-01-09 14:03:59 +0100144 const uint8_t kPayload[kFrameSize] = {0};
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200145 RTPHeader header = GetDefaultRTPHeader();
146 RTPVideoHeader video_header = GetDefaultVp8Header();
147 header.paddingLength = kPaddingSize;
148 video_header.video_type_header.emplace<RTPVideoHeaderVP8>();
Åsa Persson86202532019-01-09 14:03:59 +0100149
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000150 // Insert one video frame to get one frame decoded.
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200151 video_header.frame_type = VideoFrameType::kVideoFrameKey;
152 video_header.is_first_packet_in_frame = true;
153 header.markerBit = true;
154 InsertAndVerifyDecodableFrame(kPayload, kFrameSize, &header, video_header);
Åsa Persson86202532019-01-09 14:03:59 +0100155
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000156 clock_.AdvanceTimeMilliseconds(33);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200157 header.timestamp += 3000;
158 video_header.frame_type = VideoFrameType::kEmptyFrame;
159 video_header.is_first_packet_in_frame = false;
160 header.markerBit = false;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000161 // Insert padding frames.
162 for (int i = 0; i < 10; ++i) {
163 // Lose one packet from the 6th frame.
164 if (i == 5) {
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200165 ++header.sequenceNumber;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000166 }
167 // Lose the 4th frame.
168 if (i == 3) {
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200169 header.sequenceNumber += 5;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000170 } else {
171 if (i > 3 && i < 5) {
172 EXPECT_CALL(packet_request_callback_, ResendPackets(_, 5)).Times(1);
173 } else if (i >= 5) {
174 EXPECT_CALL(packet_request_callback_, ResendPackets(_, 6)).Times(1);
175 } else {
176 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0);
177 }
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200178 InsertAndVerifyPaddingFrame(kPayload, &header, video_header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000179 }
180 clock_.AdvanceTimeMilliseconds(33);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200181 header.timestamp += 3000;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000182 }
183}
184
185TEST_F(TestVideoReceiver, PaddingOnlyAndVideo) {
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000186 const size_t kFrameSize = 1200;
187 const size_t kPaddingSize = 220;
Åsa Persson86202532019-01-09 14:03:59 +0100188 const uint8_t kPayload[kFrameSize] = {0};
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200189 RTPHeader header = GetDefaultRTPHeader();
190 RTPVideoHeader video_header = GetDefaultVp8Header();
191 video_header.is_first_packet_in_frame = false;
192 header.paddingLength = kPaddingSize;
Philip Eliassond52a1a62018-09-07 13:03:55 +0000193 auto& vp8_header =
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200194 video_header.video_type_header.emplace<RTPVideoHeaderVP8>();
Philip Eliassond52a1a62018-09-07 13:03:55 +0000195 vp8_header.pictureId = -1;
196 vp8_header.tl0PicIdx = -1;
Åsa Persson86202532019-01-09 14:03:59 +0100197
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000198 for (int i = 0; i < 3; ++i) {
199 // Insert 2 video frames.
200 for (int j = 0; j < 2; ++j) {
201 if (i == 0 && j == 0) // First frame should be a key frame.
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200202 video_header.frame_type = VideoFrameType::kVideoFrameKey;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000203 else
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200204 video_header.frame_type = VideoFrameType::kVideoFrameDelta;
205 video_header.is_first_packet_in_frame = true;
206 header.markerBit = true;
207 InsertAndVerifyDecodableFrame(kPayload, kFrameSize, &header,
208 video_header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000209 clock_.AdvanceTimeMilliseconds(33);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200210 header.timestamp += 3000;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000211 }
212
213 // Insert 2 padding only frames.
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200214 video_header.frame_type = VideoFrameType::kEmptyFrame;
215 video_header.is_first_packet_in_frame = false;
216 header.markerBit = false;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000217 for (int j = 0; j < 2; ++j) {
Åsa Persson86202532019-01-09 14:03:59 +0100218 // InsertAndVerifyPaddingFrame(kPayload, &header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000219 clock_.AdvanceTimeMilliseconds(33);
Niels Möllerbe7a0ec2019-04-25 10:02:52 +0200220 header.timestamp += 3000;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000221 }
222 }
223}
224
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000225} // namespace
226} // namespace vcm
227} // namespace webrtc