blob: f99dac49200a3bc955a8875bec7b6dafdf6da074 [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
kwiberg3f55dea2016-02-29 05:51:59 -080011#include <memory>
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000012#include <vector>
13
Erik Språngc84cd952018-10-15 11:55:13 +020014#include "api/test/mock_video_decoder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "modules/video_coding/include/mock/mock_vcm_callbacks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "modules/video_coding/include/video_coding.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/video_coding/timing.h"
18#include "modules/video_coding/video_coding_impl.h"
19#include "system_wrappers/include/clock.h"
20#include "test/gtest.h"
21#include "test/video_codec_settings.h"
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000022
23using ::testing::_;
tommid0a71ba2017-03-14 04:16:20 -070024using ::testing::AnyNumber;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000025using ::testing::NiceMock;
26
27namespace webrtc {
28namespace vcm {
29namespace {
30
31class TestVideoReceiver : public ::testing::Test {
32 protected:
33 static const int kUnusedPayloadType = 10;
34
35 TestVideoReceiver() : clock_(0) {}
36
37 virtual void SetUp() {
philipel721d4022016-12-15 07:10:57 -080038 timing_.reset(new VCMTiming(&clock_));
Niels Möller689983f2018-11-07 16:36:22 +010039 receiver_.reset(new VideoReceiver(&clock_, timing_.get()));
perkj796cfaf2015-12-10 09:27:38 -080040 receiver_->RegisterExternalDecoder(&decoder_, kUnusedPayloadType);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000041 const size_t kMaxNackListSize = 250;
42 const int kMaxPacketAgeToNack = 450;
43 receiver_->SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, 0);
44
mflodman351424e2017-08-10 02:43:14 -070045 webrtc::test::CodecSettings(kVideoCodecVP8, &settings_);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000046 settings_.plType = kUnusedPayloadType; // Use the mocked encoder.
47 EXPECT_EQ(0, receiver_->RegisterReceiveCodec(&settings_, 1, true));
tommid0a71ba2017-03-14 04:16:20 -070048
49 // Since we call Decode, we need to provide a valid receive callback.
50 // However, for the purposes of these tests, we ignore the callbacks.
51 EXPECT_CALL(receive_callback_, OnIncomingPayloadType(_)).Times(AnyNumber());
52 EXPECT_CALL(receive_callback_, OnDecoderImplementationName(_))
53 .Times(AnyNumber());
54 receiver_->RegisterReceiveCallback(&receive_callback_);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000055 }
56
57 void InsertAndVerifyPaddingFrame(const uint8_t* payload,
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000058 WebRtcRTPHeader* header) {
59 ASSERT_TRUE(header != NULL);
60 for (int j = 0; j < 5; ++j) {
61 // Padding only packets are passed to the VCM with payload size 0.
62 EXPECT_EQ(0, receiver_->IncomingPacket(payload, 0, *header));
63 ++header->header.sequenceNumber;
64 }
pbosa26ac922016-02-25 04:50:01 -080065 receiver_->Process();
Niels Möller8df3a382018-05-07 16:10:01 +020066 EXPECT_CALL(decoder_, Decode(_, _, _, _)).Times(0);
perkj796cfaf2015-12-10 09:27:38 -080067 EXPECT_EQ(VCM_FRAME_NOT_READY, receiver_->Decode(100));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000068 }
69
70 void InsertAndVerifyDecodableFrame(const uint8_t* payload,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000071 size_t length,
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000072 WebRtcRTPHeader* header) {
73 ASSERT_TRUE(header != NULL);
74 EXPECT_EQ(0, receiver_->IncomingPacket(payload, length, *header));
75 ++header->header.sequenceNumber;
76 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0);
Yves Gerey665174f2018-06-19 15:03:05 +020077 receiver_->Process();
Niels Möller8df3a382018-05-07 16:10:01 +020078 EXPECT_CALL(decoder_, Decode(_, _, _, _)).Times(1);
perkj796cfaf2015-12-10 09:27:38 -080079 EXPECT_EQ(0, receiver_->Decode(100));
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000080 }
81
82 SimulatedClock clock_;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000083 VideoCodec settings_;
84 NiceMock<MockVideoDecoder> decoder_;
85 NiceMock<MockPacketRequestCallback> packet_request_callback_;
86
philipel721d4022016-12-15 07:10:57 -080087 std::unique_ptr<VCMTiming> timing_;
tommid0a71ba2017-03-14 04:16:20 -070088 MockVCMReceiveCallback receive_callback_;
kwiberg3f55dea2016-02-29 05:51:59 -080089 std::unique_ptr<VideoReceiver> receiver_;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000090};
91
92TEST_F(TestVideoReceiver, PaddingOnlyFrames) {
93 EXPECT_EQ(0, receiver_->SetVideoProtection(kProtectionNack, true));
94 EXPECT_EQ(
95 0, receiver_->RegisterPacketRequestCallback(&packet_request_callback_));
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000096 const size_t kPaddingSize = 220;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +000097 const uint8_t payload[kPaddingSize] = {0};
philipel7d745e52018-08-02 14:03:53 +020098 WebRtcRTPHeader header = {};
pbos22993e12015-10-19 02:39:06 -070099 header.frameType = kEmptyFrame;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000100 header.header.markerBit = false;
101 header.header.paddingLength = kPaddingSize;
102 header.header.payloadType = kUnusedPayloadType;
103 header.header.ssrc = 1;
104 header.header.headerLength = 12;
philipelcb96ad82018-07-02 14:41:58 +0200105 header.video_header().codec = kVideoCodecVP8;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000106 for (int i = 0; i < 10; ++i) {
107 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000108 InsertAndVerifyPaddingFrame(payload, &header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000109 clock_.AdvanceTimeMilliseconds(33);
110 header.header.timestamp += 3000;
111 }
112}
113
114TEST_F(TestVideoReceiver, PaddingOnlyFramesWithLosses) {
115 EXPECT_EQ(0, receiver_->SetVideoProtection(kProtectionNack, true));
116 EXPECT_EQ(
117 0, receiver_->RegisterPacketRequestCallback(&packet_request_callback_));
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000118 const size_t kFrameSize = 1200;
119 const size_t kPaddingSize = 220;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000120 const uint8_t payload[kFrameSize] = {0};
philipel7d745e52018-08-02 14:03:53 +0200121 WebRtcRTPHeader header = {};
pbos22993e12015-10-19 02:39:06 -0700122 header.frameType = kEmptyFrame;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000123 header.header.markerBit = false;
124 header.header.paddingLength = kPaddingSize;
125 header.header.payloadType = kUnusedPayloadType;
126 header.header.ssrc = 1;
127 header.header.headerLength = 12;
philipelcb96ad82018-07-02 14:41:58 +0200128 header.video_header().codec = kVideoCodecVP8;
Philip Eliassond52a1a62018-09-07 13:03:55 +0000129 header.video_header().video_type_header.emplace<RTPVideoHeaderVP8>();
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000130 // Insert one video frame to get one frame decoded.
131 header.frameType = kVideoFrameKey;
philipelcb96ad82018-07-02 14:41:58 +0200132 header.video_header().is_first_packet_in_frame = true;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000133 header.header.markerBit = true;
134 InsertAndVerifyDecodableFrame(payload, kFrameSize, &header);
135 clock_.AdvanceTimeMilliseconds(33);
136 header.header.timestamp += 3000;
137
pbos22993e12015-10-19 02:39:06 -0700138 header.frameType = kEmptyFrame;
philipelcb96ad82018-07-02 14:41:58 +0200139 header.video_header().is_first_packet_in_frame = false;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000140 header.header.markerBit = false;
141 // Insert padding frames.
142 for (int i = 0; i < 10; ++i) {
143 // Lose one packet from the 6th frame.
144 if (i == 5) {
145 ++header.header.sequenceNumber;
146 }
147 // Lose the 4th frame.
148 if (i == 3) {
149 header.header.sequenceNumber += 5;
150 } else {
151 if (i > 3 && i < 5) {
152 EXPECT_CALL(packet_request_callback_, ResendPackets(_, 5)).Times(1);
153 } else if (i >= 5) {
154 EXPECT_CALL(packet_request_callback_, ResendPackets(_, 6)).Times(1);
155 } else {
156 EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0);
157 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000158 InsertAndVerifyPaddingFrame(payload, &header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000159 }
160 clock_.AdvanceTimeMilliseconds(33);
161 header.header.timestamp += 3000;
162 }
163}
164
165TEST_F(TestVideoReceiver, PaddingOnlyAndVideo) {
166 EXPECT_EQ(0, receiver_->SetVideoProtection(kProtectionNack, true));
167 EXPECT_EQ(
168 0, receiver_->RegisterPacketRequestCallback(&packet_request_callback_));
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000169 const size_t kFrameSize = 1200;
170 const size_t kPaddingSize = 220;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000171 const uint8_t payload[kFrameSize] = {0};
philipel7d745e52018-08-02 14:03:53 +0200172 WebRtcRTPHeader header = {};
pbos22993e12015-10-19 02:39:06 -0700173 header.frameType = kEmptyFrame;
philipelcb96ad82018-07-02 14:41:58 +0200174 header.video_header().is_first_packet_in_frame = false;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000175 header.header.markerBit = false;
176 header.header.paddingLength = kPaddingSize;
177 header.header.payloadType = kUnusedPayloadType;
178 header.header.ssrc = 1;
179 header.header.headerLength = 12;
philipelcb96ad82018-07-02 14:41:58 +0200180 header.video_header().codec = kVideoCodecVP8;
Philip Eliassond52a1a62018-09-07 13:03:55 +0000181 auto& vp8_header =
182 header.video.video_type_header.emplace<RTPVideoHeaderVP8>();
183 vp8_header.pictureId = -1;
184 vp8_header.tl0PicIdx = -1;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000185 for (int i = 0; i < 3; ++i) {
186 // Insert 2 video frames.
187 for (int j = 0; j < 2; ++j) {
188 if (i == 0 && j == 0) // First frame should be a key frame.
189 header.frameType = kVideoFrameKey;
190 else
191 header.frameType = kVideoFrameDelta;
philipelcb96ad82018-07-02 14:41:58 +0200192 header.video_header().is_first_packet_in_frame = true;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000193 header.header.markerBit = true;
194 InsertAndVerifyDecodableFrame(payload, kFrameSize, &header);
195 clock_.AdvanceTimeMilliseconds(33);
196 header.header.timestamp += 3000;
197 }
198
199 // Insert 2 padding only frames.
pbos22993e12015-10-19 02:39:06 -0700200 header.frameType = kEmptyFrame;
philipelcb96ad82018-07-02 14:41:58 +0200201 header.video_header().is_first_packet_in_frame = false;
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000202 header.header.markerBit = false;
203 for (int j = 0; j < 2; ++j) {
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000204 // InsertAndVerifyPaddingFrame(payload, &header);
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000205 clock_.AdvanceTimeMilliseconds(33);
206 header.header.timestamp += 3000;
207 }
208 }
209}
210
andresp@webrtc.orge401c2e2013-09-16 20:29:13 +0000211} // namespace
212} // namespace vcm
213} // namespace webrtc