blob: 8f42fbdfbd6f5a13768c4ef11bf8d60ae04902a1 [file] [log] [blame]
johan62d02c32017-01-24 04:38:27 -08001/*
2 * Copyright 2017 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 "webrtc/test/gtest.h"
12#include "webrtc/test/gmock.h"
13
14#include "webrtc/base/bytebuffer.h"
15#include "webrtc/base/logging.h"
16#include "webrtc/common_video/h264/h264_common.h"
17#include "webrtc/media/base/mediaconstants.h"
18#include "webrtc/modules/pacing/packet_router.h"
19#include "webrtc/modules/video_coding/include/video_coding_defines.h"
20#include "webrtc/modules/video_coding/frame_object.h"
21#include "webrtc/modules/video_coding/packet.h"
22#include "webrtc/modules/video_coding/rtp_frame_reference_finder.h"
23#include "webrtc/modules/video_coding/timing.h"
24#include "webrtc/modules/utility/include/process_thread.h"
25#include "webrtc/system_wrappers/include/clock.h"
26#include "webrtc/system_wrappers/include/field_trial_default.h"
27#include "webrtc/test/field_trial.h"
nisseb1f2ff92017-06-09 04:01:55 -070028#include "webrtc/video/rtp_video_stream_receiver.h"
johan62d02c32017-01-24 04:38:27 -080029
30using testing::_;
31
32namespace webrtc {
33
34namespace {
35
36const char kNewJitterBufferFieldTrialEnabled[] =
37 "WebRTC-NewVideoJitterBuffer/Enabled/";
38const uint8_t kH264StartCode[] = {0x00, 0x00, 0x00, 0x01};
39
40class MockTransport : public Transport {
41 public:
42 MOCK_METHOD3(SendRtp,
43 bool(const uint8_t* packet,
44 size_t length,
45 const PacketOptions& options));
46 MOCK_METHOD2(SendRtcp, bool(const uint8_t* packet, size_t length));
47};
48
49class MockNackSender : public NackSender {
50 public:
51 MOCK_METHOD1(SendNack, void(const std::vector<uint16_t>& sequence_numbers));
52};
53
54class MockKeyFrameRequestSender : public KeyFrameRequestSender {
55 public:
56 MOCK_METHOD0(RequestKeyFrame, void());
57};
58
59class MockOnCompleteFrameCallback
60 : public video_coding::OnCompleteFrameCallback {
61 public:
62 MockOnCompleteFrameCallback() : buffer_(rtc::ByteBuffer::ORDER_NETWORK) {}
63
64 MOCK_METHOD1(DoOnCompleteFrame, void(video_coding::FrameObject* frame));
65 MOCK_METHOD1(DoOnCompleteFrameFailNullptr,
66 void(video_coding::FrameObject* frame));
67 MOCK_METHOD1(DoOnCompleteFrameFailLength,
68 void(video_coding::FrameObject* frame));
69 MOCK_METHOD1(DoOnCompleteFrameFailBitstream,
70 void(video_coding::FrameObject* frame));
71 void OnCompleteFrame(std::unique_ptr<video_coding::FrameObject> frame) {
72 if (!frame) {
73 DoOnCompleteFrameFailNullptr(nullptr);
74 return;
75 }
76 EXPECT_EQ(buffer_.Length(), frame->size());
77 if (buffer_.Length() != frame->size()) {
78 DoOnCompleteFrameFailLength(frame.get());
79 return;
80 }
81 std::vector<uint8_t> actual_data(frame->size());
82 frame->GetBitstream(actual_data.data());
83 if (memcmp(buffer_.Data(), actual_data.data(), buffer_.Length()) != 0) {
84 DoOnCompleteFrameFailBitstream(frame.get());
85 return;
86 }
87 DoOnCompleteFrame(frame.get());
88 }
89 void AppendExpectedBitstream(const uint8_t data[], size_t size_in_bytes) {
90 // TODO(Johan): Let rtc::ByteBuffer handle uint8_t* instead of char*.
91 buffer_.WriteBytes(reinterpret_cast<const char*>(data), size_in_bytes);
92 }
93 rtc::ByteBufferWriter buffer_;
94};
95
96} // namespace
97
nisseb1f2ff92017-06-09 04:01:55 -070098class RtpVideoStreamReceiverTest : public testing::Test {
johan62d02c32017-01-24 04:38:27 -080099 public:
nisseb1f2ff92017-06-09 04:01:55 -0700100 RtpVideoStreamReceiverTest()
johan62d02c32017-01-24 04:38:27 -0800101 : config_(CreateConfig()),
102 timing_(Clock::GetRealTimeClock()),
103 process_thread_(ProcessThread::Create("TestThread")) {}
104
105 void SetUp() {
nisseb1f2ff92017-06-09 04:01:55 -0700106 rtp_video_stream_receiver_.reset(new RtpVideoStreamReceiver(
nisse05843312017-04-18 23:38:35 -0700107 &mock_transport_, nullptr, &packet_router_, &config_,
philipela45102f2017-02-22 05:30:39 -0800108 nullptr, process_thread_.get(), &mock_nack_sender_,
109 &mock_key_frame_request_sender_, &mock_on_complete_frame_callback_,
110 &timing_));
johan62d02c32017-01-24 04:38:27 -0800111 }
112
113 WebRtcRTPHeader GetDefaultPacket() {
114 WebRtcRTPHeader packet;
115 memset(&packet, 0, sizeof(packet));
116 packet.type.Video.codec = kRtpVideoH264;
117 return packet;
118 }
119
120 // TODO(Johan): refactor h264_sps_pps_tracker_unittests.cc to avoid duplicate
121 // code.
philipel83c97da2017-06-21 07:22:40 -0700122 void AddSps(WebRtcRTPHeader* packet,
123 uint8_t sps_id,
124 std::vector<uint8_t>* data) {
johan62d02c32017-01-24 04:38:27 -0800125 NaluInfo info;
126 info.type = H264::NaluType::kSps;
127 info.sps_id = sps_id;
128 info.pps_id = -1;
johan62d02c32017-01-24 04:38:27 -0800129 data->push_back(H264::NaluType::kSps);
130 data->push_back(sps_id);
131 packet->type.Video.codecHeader.H264
132 .nalus[packet->type.Video.codecHeader.H264.nalus_length++] = info;
133 }
134
135 void AddPps(WebRtcRTPHeader* packet,
philipel83c97da2017-06-21 07:22:40 -0700136 uint8_t sps_id,
137 uint8_t pps_id,
johan62d02c32017-01-24 04:38:27 -0800138 std::vector<uint8_t>* data) {
139 NaluInfo info;
140 info.type = H264::NaluType::kPps;
141 info.sps_id = sps_id;
142 info.pps_id = pps_id;
johan62d02c32017-01-24 04:38:27 -0800143 data->push_back(H264::NaluType::kPps);
144 data->push_back(pps_id);
145 packet->type.Video.codecHeader.H264
146 .nalus[packet->type.Video.codecHeader.H264.nalus_length++] = info;
147 }
148
149 void AddIdr(WebRtcRTPHeader* packet, int pps_id) {
150 NaluInfo info;
151 info.type = H264::NaluType::kIdr;
152 info.sps_id = -1;
153 info.pps_id = pps_id;
154 packet->type.Video.codecHeader.H264
155 .nalus[packet->type.Video.codecHeader.H264.nalus_length++] = info;
156 }
157
158 protected:
159 static VideoReceiveStream::Config CreateConfig() {
160 VideoReceiveStream::Config config(nullptr);
161 config.rtp.remote_ssrc = 1111;
162 config.rtp.local_ssrc = 2222;
163 return config;
164 }
165
166 webrtc::test::ScopedFieldTrials override_field_trials_{
167 kNewJitterBufferFieldTrialEnabled};
168 VideoReceiveStream::Config config_;
169 MockNackSender mock_nack_sender_;
170 MockKeyFrameRequestSender mock_key_frame_request_sender_;
171 MockTransport mock_transport_;
172 MockOnCompleteFrameCallback mock_on_complete_frame_callback_;
173 PacketRouter packet_router_;
174 VCMTiming timing_;
175 std::unique_ptr<ProcessThread> process_thread_;
nisseb1f2ff92017-06-09 04:01:55 -0700176 std::unique_ptr<RtpVideoStreamReceiver> rtp_video_stream_receiver_;
johan62d02c32017-01-24 04:38:27 -0800177};
178
nisseb1f2ff92017-06-09 04:01:55 -0700179TEST_F(RtpVideoStreamReceiverTest, GenericKeyFrame) {
johan62d02c32017-01-24 04:38:27 -0800180 WebRtcRTPHeader rtp_header;
181 const std::vector<uint8_t> data({1, 2, 3, 4});
182 memset(&rtp_header, 0, sizeof(rtp_header));
183 rtp_header.header.sequenceNumber = 1;
184 rtp_header.header.markerBit = 1;
185 rtp_header.type.Video.is_first_packet_in_frame = true;
186 rtp_header.frameType = kVideoFrameKey;
187 rtp_header.type.Video.codec = kRtpVideoGeneric;
188 mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data(),
189 data.size());
190 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_));
nisseb1f2ff92017-06-09 04:01:55 -0700191 rtp_video_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(),
192 &rtp_header);
johan62d02c32017-01-24 04:38:27 -0800193}
194
nisseb1f2ff92017-06-09 04:01:55 -0700195TEST_F(RtpVideoStreamReceiverTest, GenericKeyFrameBitstreamError) {
johan62d02c32017-01-24 04:38:27 -0800196 WebRtcRTPHeader rtp_header;
197 const std::vector<uint8_t> data({1, 2, 3, 4});
198 memset(&rtp_header, 0, sizeof(rtp_header));
199 rtp_header.header.sequenceNumber = 1;
200 rtp_header.header.markerBit = 1;
201 rtp_header.type.Video.is_first_packet_in_frame = true;
202 rtp_header.frameType = kVideoFrameKey;
203 rtp_header.type.Video.codec = kRtpVideoGeneric;
204 constexpr uint8_t expected_bitsteam[] = {1, 2, 3, 0xff};
205 mock_on_complete_frame_callback_.AppendExpectedBitstream(
206 expected_bitsteam, sizeof(expected_bitsteam));
207 EXPECT_CALL(mock_on_complete_frame_callback_,
208 DoOnCompleteFrameFailBitstream(_));
nisseb1f2ff92017-06-09 04:01:55 -0700209 rtp_video_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(),
210 &rtp_header);
johan62d02c32017-01-24 04:38:27 -0800211}
212
nisseb1f2ff92017-06-09 04:01:55 -0700213TEST_F(RtpVideoStreamReceiverTest, InBandSpsPps) {
johan62d02c32017-01-24 04:38:27 -0800214 std::vector<uint8_t> sps_data;
215 WebRtcRTPHeader sps_packet = GetDefaultPacket();
216 AddSps(&sps_packet, 0, &sps_data);
217 sps_packet.header.sequenceNumber = 0;
philipel83c97da2017-06-21 07:22:40 -0700218 sps_packet.type.Video.is_first_packet_in_frame = true;
johan62d02c32017-01-24 04:38:27 -0800219 mock_on_complete_frame_callback_.AppendExpectedBitstream(
220 kH264StartCode, sizeof(kH264StartCode));
221 mock_on_complete_frame_callback_.AppendExpectedBitstream(sps_data.data(),
222 sps_data.size());
nisseb1f2ff92017-06-09 04:01:55 -0700223 rtp_video_stream_receiver_->OnReceivedPayloadData(
224 sps_data.data(), sps_data.size(), &sps_packet);
johan62d02c32017-01-24 04:38:27 -0800225
226 std::vector<uint8_t> pps_data;
227 WebRtcRTPHeader pps_packet = GetDefaultPacket();
228 AddPps(&pps_packet, 0, 1, &pps_data);
229 pps_packet.header.sequenceNumber = 1;
philipel83c97da2017-06-21 07:22:40 -0700230 pps_packet.type.Video.is_first_packet_in_frame = true;
johan62d02c32017-01-24 04:38:27 -0800231 mock_on_complete_frame_callback_.AppendExpectedBitstream(
232 kH264StartCode, sizeof(kH264StartCode));
233 mock_on_complete_frame_callback_.AppendExpectedBitstream(pps_data.data(),
234 pps_data.size());
nisseb1f2ff92017-06-09 04:01:55 -0700235 rtp_video_stream_receiver_->OnReceivedPayloadData(
236 pps_data.data(), pps_data.size(), &pps_packet);
johan62d02c32017-01-24 04:38:27 -0800237
238 std::vector<uint8_t> idr_data;
239 WebRtcRTPHeader idr_packet = GetDefaultPacket();
240 AddIdr(&idr_packet, 1);
241 idr_packet.type.Video.is_first_packet_in_frame = true;
242 idr_packet.header.sequenceNumber = 2;
243 idr_packet.header.markerBit = 1;
johan62d02c32017-01-24 04:38:27 -0800244 idr_packet.frameType = kVideoFrameKey;
johan62d02c32017-01-24 04:38:27 -0800245 idr_data.insert(idr_data.end(), {0x65, 1, 2, 3});
246 mock_on_complete_frame_callback_.AppendExpectedBitstream(
247 kH264StartCode, sizeof(kH264StartCode));
248 mock_on_complete_frame_callback_.AppendExpectedBitstream(idr_data.data(),
249 idr_data.size());
250 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_));
nisseb1f2ff92017-06-09 04:01:55 -0700251 rtp_video_stream_receiver_->OnReceivedPayloadData(
252 idr_data.data(), idr_data.size(), &idr_packet);
johan62d02c32017-01-24 04:38:27 -0800253}
254
nisseb1f2ff92017-06-09 04:01:55 -0700255TEST_F(RtpVideoStreamReceiverTest, OutOfBandFmtpSpsPps) {
johan62d02c32017-01-24 04:38:27 -0800256 constexpr int kPayloadType = 99;
257 VideoCodec codec;
258 codec.plType = kPayloadType;
259 std::map<std::string, std::string> codec_params;
260 // Example parameter sets from https://tools.ietf.org/html/rfc3984#section-8.2
261 // .
262 codec_params.insert(
263 {cricket::kH264FmtpSpropParameterSets, "Z0IACpZTBYmI,aMljiA=="});
nisseb1f2ff92017-06-09 04:01:55 -0700264 rtp_video_stream_receiver_->AddReceiveCodec(codec, codec_params);
johan62d02c32017-01-24 04:38:27 -0800265 const uint8_t binary_sps[] = {0x67, 0x42, 0x00, 0x0a, 0x96,
266 0x53, 0x05, 0x89, 0x88};
267 mock_on_complete_frame_callback_.AppendExpectedBitstream(
268 kH264StartCode, sizeof(kH264StartCode));
269 mock_on_complete_frame_callback_.AppendExpectedBitstream(binary_sps,
270 sizeof(binary_sps));
271 const uint8_t binary_pps[] = {0x68, 0xc9, 0x63, 0x88};
272 mock_on_complete_frame_callback_.AppendExpectedBitstream(
273 kH264StartCode, sizeof(kH264StartCode));
274 mock_on_complete_frame_callback_.AppendExpectedBitstream(binary_pps,
275 sizeof(binary_pps));
276
277 std::vector<uint8_t> data;
278 WebRtcRTPHeader idr_packet = GetDefaultPacket();
279 AddIdr(&idr_packet, 0);
280 idr_packet.header.payloadType = kPayloadType;
281 idr_packet.type.Video.is_first_packet_in_frame = true;
282 idr_packet.header.sequenceNumber = 2;
283 idr_packet.header.markerBit = 1;
284 idr_packet.type.Video.is_first_packet_in_frame = true;
285 idr_packet.frameType = kVideoFrameKey;
286 idr_packet.type.Video.codec = kRtpVideoH264;
287 data.insert(data.end(), {1, 2, 3});
288 mock_on_complete_frame_callback_.AppendExpectedBitstream(
289 kH264StartCode, sizeof(kH264StartCode));
290 mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data(),
291 data.size());
292 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_));
nisseb1f2ff92017-06-09 04:01:55 -0700293 rtp_video_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(),
294 &idr_packet);
johan62d02c32017-01-24 04:38:27 -0800295}
296
nisseb1f2ff92017-06-09 04:01:55 -0700297TEST_F(RtpVideoStreamReceiverTest, PaddingInMediaStream) {
philipel54ca9192017-03-21 05:45:18 -0700298 WebRtcRTPHeader header = GetDefaultPacket();
299 std::vector<uint8_t> data;
300 data.insert(data.end(), {1, 2, 3});
301 header.header.payloadType = 99;
302 header.type.Video.is_first_packet_in_frame = true;
303 header.header.sequenceNumber = 2;
304 header.header.markerBit = true;
305 header.frameType = kVideoFrameKey;
306 header.type.Video.codec = kRtpVideoGeneric;
307 mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data(),
308 data.size());
309
310 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_));
nisseb1f2ff92017-06-09 04:01:55 -0700311 rtp_video_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(),
312 &header);
philipel54ca9192017-03-21 05:45:18 -0700313
314 header.header.sequenceNumber = 3;
nisseb1f2ff92017-06-09 04:01:55 -0700315 rtp_video_stream_receiver_->OnReceivedPayloadData(nullptr, 0, &header);
philipel54ca9192017-03-21 05:45:18 -0700316
317 header.frameType = kVideoFrameDelta;
318 header.header.sequenceNumber = 4;
319 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_));
nisseb1f2ff92017-06-09 04:01:55 -0700320 rtp_video_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(),
321 &header);
philipel54ca9192017-03-21 05:45:18 -0700322
323 header.header.sequenceNumber = 6;
nisseb1f2ff92017-06-09 04:01:55 -0700324 rtp_video_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(),
325 &header);
philipel54ca9192017-03-21 05:45:18 -0700326
327 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_));
328 header.header.sequenceNumber = 5;
nisseb1f2ff92017-06-09 04:01:55 -0700329 rtp_video_stream_receiver_->OnReceivedPayloadData(nullptr, 0, &header);
philipel54ca9192017-03-21 05:45:18 -0700330}
331
nisseb1f2ff92017-06-09 04:01:55 -0700332TEST_F(RtpVideoStreamReceiverTest, RequestKeyframeIfFirstFrameIsDelta) {
philipel2c53b132017-05-16 08:06:30 -0700333 WebRtcRTPHeader rtp_header;
334 const std::vector<uint8_t> data({1, 2, 3, 4});
335 memset(&rtp_header, 0, sizeof(rtp_header));
336 rtp_header.header.sequenceNumber = 1;
337 rtp_header.header.markerBit = 1;
338 rtp_header.type.Video.is_first_packet_in_frame = true;
339 rtp_header.frameType = kVideoFrameDelta;
340 rtp_header.type.Video.codec = kRtpVideoGeneric;
341
342 EXPECT_CALL(mock_key_frame_request_sender_, RequestKeyFrame());
nisseb1f2ff92017-06-09 04:01:55 -0700343 rtp_video_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(),
344 &rtp_header);
philipel2c53b132017-05-16 08:06:30 -0700345}
346
johan62d02c32017-01-24 04:38:27 -0800347} // namespace webrtc