OLD | NEW |
| (Empty) |
1 /* | |
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" | |
28 #include "webrtc/video/rtp_stream_receiver.h" | |
29 | |
30 using testing::_; | |
31 | |
32 namespace webrtc { | |
33 | |
34 namespace { | |
35 | |
36 const char kNewJitterBufferFieldTrialEnabled[] = | |
37 "WebRTC-NewVideoJitterBuffer/Enabled/"; | |
38 const uint8_t kH264StartCode[] = {0x00, 0x00, 0x00, 0x01}; | |
39 | |
40 class 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 | |
49 class MockNackSender : public NackSender { | |
50 public: | |
51 MOCK_METHOD1(SendNack, void(const std::vector<uint16_t>& sequence_numbers)); | |
52 }; | |
53 | |
54 class MockKeyFrameRequestSender : public KeyFrameRequestSender { | |
55 public: | |
56 MOCK_METHOD0(RequestKeyFrame, void()); | |
57 }; | |
58 | |
59 class 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 | |
98 class RtpStreamReceiverTest : public testing::Test { | |
99 public: | |
100 RtpStreamReceiverTest() | |
101 : config_(CreateConfig()), | |
102 timing_(Clock::GetRealTimeClock()), | |
103 process_thread_(ProcessThread::Create("TestThread")) {} | |
104 | |
105 void SetUp() { | |
106 rtp_stream_receiver_.reset(new RtpStreamReceiver( | |
107 &mock_transport_, nullptr, &packet_router_, &config_, | |
108 nullptr, process_thread_.get(), &mock_nack_sender_, | |
109 &mock_key_frame_request_sender_, &mock_on_complete_frame_callback_, | |
110 &timing_)); | |
111 } | |
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. | |
122 void AddSps(WebRtcRTPHeader* packet, int sps_id, std::vector<uint8_t>* data) { | |
123 NaluInfo info; | |
124 info.type = H264::NaluType::kSps; | |
125 info.sps_id = sps_id; | |
126 info.pps_id = -1; | |
127 info.offset = data->size(); | |
128 info.size = 2; | |
129 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, | |
136 int sps_id, | |
137 int pps_id, | |
138 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; | |
143 info.offset = data->size(); | |
144 info.size = 2; | |
145 data->push_back(H264::NaluType::kPps); | |
146 data->push_back(pps_id); | |
147 packet->type.Video.codecHeader.H264 | |
148 .nalus[packet->type.Video.codecHeader.H264.nalus_length++] = info; | |
149 } | |
150 | |
151 void AddIdr(WebRtcRTPHeader* packet, int pps_id) { | |
152 NaluInfo info; | |
153 info.type = H264::NaluType::kIdr; | |
154 info.sps_id = -1; | |
155 info.pps_id = pps_id; | |
156 packet->type.Video.codecHeader.H264 | |
157 .nalus[packet->type.Video.codecHeader.H264.nalus_length++] = info; | |
158 } | |
159 | |
160 protected: | |
161 static VideoReceiveStream::Config CreateConfig() { | |
162 VideoReceiveStream::Config config(nullptr); | |
163 config.rtp.remote_ssrc = 1111; | |
164 config.rtp.local_ssrc = 2222; | |
165 return config; | |
166 } | |
167 | |
168 webrtc::test::ScopedFieldTrials override_field_trials_{ | |
169 kNewJitterBufferFieldTrialEnabled}; | |
170 VideoReceiveStream::Config config_; | |
171 MockNackSender mock_nack_sender_; | |
172 MockKeyFrameRequestSender mock_key_frame_request_sender_; | |
173 MockTransport mock_transport_; | |
174 MockOnCompleteFrameCallback mock_on_complete_frame_callback_; | |
175 PacketRouter packet_router_; | |
176 VCMTiming timing_; | |
177 std::unique_ptr<ProcessThread> process_thread_; | |
178 std::unique_ptr<RtpStreamReceiver> rtp_stream_receiver_; | |
179 }; | |
180 | |
181 TEST_F(RtpStreamReceiverTest, GenericKeyFrame) { | |
182 WebRtcRTPHeader rtp_header; | |
183 const std::vector<uint8_t> data({1, 2, 3, 4}); | |
184 memset(&rtp_header, 0, sizeof(rtp_header)); | |
185 rtp_header.header.sequenceNumber = 1; | |
186 rtp_header.header.markerBit = 1; | |
187 rtp_header.type.Video.is_first_packet_in_frame = true; | |
188 rtp_header.frameType = kVideoFrameKey; | |
189 rtp_header.type.Video.codec = kRtpVideoGeneric; | |
190 mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data(), | |
191 data.size()); | |
192 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_)); | |
193 rtp_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(), | |
194 &rtp_header); | |
195 } | |
196 | |
197 TEST_F(RtpStreamReceiverTest, GenericKeyFrameBitstreamError) { | |
198 WebRtcRTPHeader rtp_header; | |
199 const std::vector<uint8_t> data({1, 2, 3, 4}); | |
200 memset(&rtp_header, 0, sizeof(rtp_header)); | |
201 rtp_header.header.sequenceNumber = 1; | |
202 rtp_header.header.markerBit = 1; | |
203 rtp_header.type.Video.is_first_packet_in_frame = true; | |
204 rtp_header.frameType = kVideoFrameKey; | |
205 rtp_header.type.Video.codec = kRtpVideoGeneric; | |
206 constexpr uint8_t expected_bitsteam[] = {1, 2, 3, 0xff}; | |
207 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
208 expected_bitsteam, sizeof(expected_bitsteam)); | |
209 EXPECT_CALL(mock_on_complete_frame_callback_, | |
210 DoOnCompleteFrameFailBitstream(_)); | |
211 rtp_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(), | |
212 &rtp_header); | |
213 } | |
214 | |
215 TEST_F(RtpStreamReceiverTest, InBandSpsPps) { | |
216 std::vector<uint8_t> sps_data; | |
217 WebRtcRTPHeader sps_packet = GetDefaultPacket(); | |
218 AddSps(&sps_packet, 0, &sps_data); | |
219 sps_packet.header.sequenceNumber = 0; | |
220 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
221 kH264StartCode, sizeof(kH264StartCode)); | |
222 mock_on_complete_frame_callback_.AppendExpectedBitstream(sps_data.data(), | |
223 sps_data.size()); | |
224 rtp_stream_receiver_->OnReceivedPayloadData(sps_data.data(), sps_data.size(), | |
225 &sps_packet); | |
226 | |
227 std::vector<uint8_t> pps_data; | |
228 WebRtcRTPHeader pps_packet = GetDefaultPacket(); | |
229 AddPps(&pps_packet, 0, 1, &pps_data); | |
230 pps_packet.header.sequenceNumber = 1; | |
231 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
232 kH264StartCode, sizeof(kH264StartCode)); | |
233 mock_on_complete_frame_callback_.AppendExpectedBitstream(pps_data.data(), | |
234 pps_data.size()); | |
235 rtp_stream_receiver_->OnReceivedPayloadData(pps_data.data(), pps_data.size(), | |
236 &pps_packet); | |
237 | |
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; | |
244 idr_packet.type.Video.is_first_packet_in_frame = true; | |
245 idr_packet.frameType = kVideoFrameKey; | |
246 idr_packet.type.Video.codec = kRtpVideoH264; | |
247 idr_data.insert(idr_data.end(), {0x65, 1, 2, 3}); | |
248 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
249 kH264StartCode, sizeof(kH264StartCode)); | |
250 mock_on_complete_frame_callback_.AppendExpectedBitstream(idr_data.data(), | |
251 idr_data.size()); | |
252 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_)); | |
253 rtp_stream_receiver_->OnReceivedPayloadData(idr_data.data(), idr_data.size(), | |
254 &idr_packet); | |
255 } | |
256 | |
257 TEST_F(RtpStreamReceiverTest, OutOfBandFmtpSpsPps) { | |
258 constexpr int kPayloadType = 99; | |
259 VideoCodec codec; | |
260 codec.plType = kPayloadType; | |
261 std::map<std::string, std::string> codec_params; | |
262 // Example parameter sets from https://tools.ietf.org/html/rfc3984#section-8.2 | |
263 // . | |
264 codec_params.insert( | |
265 {cricket::kH264FmtpSpropParameterSets, "Z0IACpZTBYmI,aMljiA=="}); | |
266 rtp_stream_receiver_->AddReceiveCodec(codec, codec_params); | |
267 const uint8_t binary_sps[] = {0x67, 0x42, 0x00, 0x0a, 0x96, | |
268 0x53, 0x05, 0x89, 0x88}; | |
269 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
270 kH264StartCode, sizeof(kH264StartCode)); | |
271 mock_on_complete_frame_callback_.AppendExpectedBitstream(binary_sps, | |
272 sizeof(binary_sps)); | |
273 const uint8_t binary_pps[] = {0x68, 0xc9, 0x63, 0x88}; | |
274 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
275 kH264StartCode, sizeof(kH264StartCode)); | |
276 mock_on_complete_frame_callback_.AppendExpectedBitstream(binary_pps, | |
277 sizeof(binary_pps)); | |
278 | |
279 std::vector<uint8_t> data; | |
280 WebRtcRTPHeader idr_packet = GetDefaultPacket(); | |
281 AddIdr(&idr_packet, 0); | |
282 idr_packet.header.payloadType = kPayloadType; | |
283 idr_packet.type.Video.is_first_packet_in_frame = true; | |
284 idr_packet.header.sequenceNumber = 2; | |
285 idr_packet.header.markerBit = 1; | |
286 idr_packet.type.Video.is_first_packet_in_frame = true; | |
287 idr_packet.frameType = kVideoFrameKey; | |
288 idr_packet.type.Video.codec = kRtpVideoH264; | |
289 data.insert(data.end(), {1, 2, 3}); | |
290 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
291 kH264StartCode, sizeof(kH264StartCode)); | |
292 mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data(), | |
293 data.size()); | |
294 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_)); | |
295 rtp_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(), | |
296 &idr_packet); | |
297 } | |
298 | |
299 TEST_F(RtpStreamReceiverTest, PaddingInMediaStream) { | |
300 WebRtcRTPHeader header = GetDefaultPacket(); | |
301 std::vector<uint8_t> data; | |
302 data.insert(data.end(), {1, 2, 3}); | |
303 header.header.payloadType = 99; | |
304 header.type.Video.is_first_packet_in_frame = true; | |
305 header.header.sequenceNumber = 2; | |
306 header.header.markerBit = true; | |
307 header.frameType = kVideoFrameKey; | |
308 header.type.Video.codec = kRtpVideoGeneric; | |
309 mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data(), | |
310 data.size()); | |
311 | |
312 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_)); | |
313 rtp_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(), | |
314 &header); | |
315 | |
316 header.header.sequenceNumber = 3; | |
317 rtp_stream_receiver_->OnReceivedPayloadData(nullptr, 0, &header); | |
318 | |
319 header.frameType = kVideoFrameDelta; | |
320 header.header.sequenceNumber = 4; | |
321 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_)); | |
322 rtp_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(), | |
323 &header); | |
324 | |
325 header.header.sequenceNumber = 6; | |
326 rtp_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(), | |
327 &header); | |
328 | |
329 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_)); | |
330 header.header.sequenceNumber = 5; | |
331 rtp_stream_receiver_->OnReceivedPayloadData(nullptr, 0, &header); | |
332 } | |
333 | |
334 TEST_F(RtpStreamReceiverTest, RequestKeyframeIfFirstFrameIsDelta) { | |
335 WebRtcRTPHeader rtp_header; | |
336 const std::vector<uint8_t> data({1, 2, 3, 4}); | |
337 memset(&rtp_header, 0, sizeof(rtp_header)); | |
338 rtp_header.header.sequenceNumber = 1; | |
339 rtp_header.header.markerBit = 1; | |
340 rtp_header.type.Video.is_first_packet_in_frame = true; | |
341 rtp_header.frameType = kVideoFrameDelta; | |
342 rtp_header.type.Video.codec = kRtpVideoGeneric; | |
343 | |
344 EXPECT_CALL(mock_key_frame_request_sender_, RequestKeyFrame()); | |
345 rtp_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(), | |
346 &rtp_header); | |
347 } | |
348 | |
349 } // namespace webrtc | |
OLD | NEW |