OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2016 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/video/rtp_stream_receiver.h" | |
28 | |
29 using testing::_; | |
30 | |
31 namespace webrtc { | |
32 | |
33 namespace { | |
34 | |
35 const char kNewJitterBufferFieldTrialEnabled[] = | |
36 "WebRTC-NewVideoJitterBuffer/Enabled/"; | |
37 const uint8_t kH264StartCode[] = {0x00, 0x00, 0x00, 0x01}; | |
38 | |
39 class MockTransport : public Transport { | |
40 public: | |
41 MOCK_METHOD3(SendRtp, | |
42 bool(const uint8_t* packet, | |
43 size_t length, | |
44 const PacketOptions& options)); | |
45 MOCK_METHOD2(SendRtcp, bool(const uint8_t* packet, size_t length)); | |
46 }; | |
47 | |
48 class MockNackSender : public NackSender { | |
49 public: | |
50 MOCK_METHOD1(SendNack, void(const std::vector<uint16_t>& sequence_numbers)); | |
51 }; | |
52 | |
53 class MockKeyFrameRequestSender : public KeyFrameRequestSender { | |
54 public: | |
55 MOCK_METHOD0(RequestKeyFrame, void()); | |
56 }; | |
57 | |
58 class MockOnCompleteFrameCallback | |
59 : public video_coding::OnCompleteFrameCallback { | |
60 public: | |
61 MockOnCompleteFrameCallback() : buffer_(rtc::ByteBuffer::ORDER_NETWORK) {} | |
62 | |
63 MOCK_METHOD1(DoOnCompleteFrame, void(video_coding::FrameObject* frame)); | |
64 MOCK_METHOD1(DoOnCompleteFrameFailNullptr, | |
65 void(video_coding::FrameObject* frame)); | |
66 MOCK_METHOD1(DoOnCompleteFrameFailLength, | |
67 void(video_coding::FrameObject* frame)); | |
68 MOCK_METHOD1(DoOnCompleteFrameFailBitstream, | |
69 void(video_coding::FrameObject* frame)); | |
70 void OnCompleteFrame(std::unique_ptr<video_coding::FrameObject> frame) { | |
71 if (!frame) { | |
72 DoOnCompleteFrameFailNullptr(nullptr); | |
73 return; | |
74 } | |
75 if (buffer_.Length() != frame->size()) { | |
76 LOG(LS_WARNING) << "length not equal " << buffer_.Length() << " " | |
77 << frame->size(); | |
sprang_webrtc
2017/01/23 12:57:09
Are you expecting this to happen? I think no one w
| |
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 field_trial::InitFieldTrialsFromString(kNewJitterBufferFieldTrialEnabled); | |
107 rtp_stream_receiver_.reset(new RtpStreamReceiver( | |
108 nullptr, nullptr, &mock_transport_, nullptr, nullptr, &packet_router_, | |
109 nullptr, &config_, nullptr, process_thread_.get(), nullptr, | |
110 &mock_nack_sender_, &mock_key_frame_request_sender_, | |
111 &mock_on_complete_frame_callback_, &timing_)); | |
112 } | |
113 | |
114 WebRtcRTPHeader GetDefaultPacket() { | |
115 WebRtcRTPHeader packet; | |
116 memset(&packet, 0, sizeof(packet)); | |
117 packet.type.Video.codec = kRtpVideoH264; | |
118 return packet; | |
119 } | |
120 | |
121 // TODO(Johan): refactor h264_sps_pps_tracker_unittests.cc to avoid duplicate | |
122 // code. | |
123 void AddSps(WebRtcRTPHeader* packet, int sps_id, std::vector<uint8_t>* data) { | |
124 NaluInfo info; | |
125 info.type = H264::NaluType::kSps; | |
126 info.sps_id = sps_id; | |
127 info.pps_id = -1; | |
128 info.offset = data->size(); | |
129 info.size = 2; | |
130 data->push_back(H264::NaluType::kSps); | |
131 data->push_back(sps_id); | |
132 packet->type.Video.codecHeader.H264 | |
133 .nalus[packet->type.Video.codecHeader.H264.nalus_length++] = info; | |
134 } | |
135 | |
136 void AddPps(WebRtcRTPHeader* packet, | |
137 int sps_id, | |
138 int pps_id, | |
139 std::vector<uint8_t>* data) { | |
140 NaluInfo info; | |
141 info.type = H264::NaluType::kPps; | |
142 info.sps_id = sps_id; | |
143 info.pps_id = pps_id; | |
144 info.offset = data->size(); | |
145 info.size = 2; | |
146 data->push_back(H264::NaluType::kPps); | |
147 data->push_back(pps_id); | |
148 packet->type.Video.codecHeader.H264 | |
149 .nalus[packet->type.Video.codecHeader.H264.nalus_length++] = info; | |
150 } | |
151 | |
152 void AddIdr(WebRtcRTPHeader* packet, int pps_id) { | |
153 NaluInfo info; | |
154 info.type = H264::NaluType::kIdr; | |
155 info.sps_id = -1; | |
156 info.pps_id = pps_id; | |
157 packet->type.Video.codecHeader.H264 | |
158 .nalus[packet->type.Video.codecHeader.H264.nalus_length++] = info; | |
159 } | |
160 | |
161 protected: | |
162 static VideoReceiveStream::Config CreateConfig() { | |
163 VideoReceiveStream::Config config(nullptr); | |
164 config.rtp.remote_ssrc = 1111; | |
165 config.rtp.local_ssrc = 2222; | |
166 return config; | |
167 } | |
168 | |
169 VideoReceiveStream::Config config_; | |
170 MockNackSender mock_nack_sender_; | |
171 MockKeyFrameRequestSender mock_key_frame_request_sender_; | |
172 MockTransport mock_transport_; | |
173 MockOnCompleteFrameCallback mock_on_complete_frame_callback_; | |
174 PacketRouter packet_router_; | |
175 VCMTiming timing_; | |
176 std::unique_ptr<ProcessThread> process_thread_; | |
177 std::unique_ptr<RtpStreamReceiver> rtp_stream_receiver_; | |
178 }; | |
179 | |
180 TEST_F(RtpStreamReceiverTest, GenericKeyFrame) { | |
181 WebRtcRTPHeader rtp_header; | |
182 const std::vector<uint8_t> data({1, 2, 3, 4}); | |
183 memset(&rtp_header, 0, sizeof(rtp_header)); | |
184 rtp_header.header.sequenceNumber = 1; | |
185 rtp_header.header.markerBit = 1; | |
186 rtp_header.type.Video.is_first_packet_in_frame = true; | |
187 rtp_header.frameType = kVideoFrameKey; | |
188 rtp_header.type.Video.codec = kRtpVideoGeneric; | |
189 mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data(), | |
190 data.size()); | |
191 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_)); | |
192 rtp_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(), | |
193 &rtp_header); | |
194 } | |
195 | |
196 TEST_F(RtpStreamReceiverTest, GenericKeyFrameBitstreamError) { | |
197 WebRtcRTPHeader rtp_header; | |
198 const std::vector<uint8_t> data({1, 2, 3, 4}); | |
199 memset(&rtp_header, 0, sizeof(rtp_header)); | |
200 rtp_header.header.sequenceNumber = 1; | |
201 rtp_header.header.markerBit = 1; | |
202 rtp_header.type.Video.is_first_packet_in_frame = true; | |
203 rtp_header.frameType = kVideoFrameKey; | |
204 rtp_header.type.Video.codec = kRtpVideoGeneric; | |
205 constexpr uint8_t expected_bitsteam[] = {1, 2, 3, 0xff}; | |
206 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
207 expected_bitsteam, sizeof(expected_bitsteam)); | |
208 EXPECT_CALL(mock_on_complete_frame_callback_, | |
209 DoOnCompleteFrameFailBitstream(_)); | |
210 rtp_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(), | |
211 &rtp_header); | |
212 } | |
213 | |
214 TEST_F(RtpStreamReceiverTest, InBandSpsPps) { | |
215 std::vector<uint8_t> sps_data; | |
216 WebRtcRTPHeader sps_packet = GetDefaultPacket(); | |
217 AddSps(&sps_packet, 0, &sps_data); | |
218 sps_packet.header.sequenceNumber = 0; | |
219 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
220 kH264StartCode, sizeof(kH264StartCode)); | |
221 mock_on_complete_frame_callback_.AppendExpectedBitstream(sps_data.data(), | |
222 sps_data.size()); | |
223 rtp_stream_receiver_->OnReceivedPayloadData(sps_data.data(), sps_data.size(), | |
224 &sps_packet); | |
225 | |
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; | |
230 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
231 kH264StartCode, sizeof(kH264StartCode)); | |
232 mock_on_complete_frame_callback_.AppendExpectedBitstream(pps_data.data(), | |
233 pps_data.size()); | |
234 rtp_stream_receiver_->OnReceivedPayloadData(pps_data.data(), pps_data.size(), | |
235 &pps_packet); | |
236 | |
237 std::vector<uint8_t> idr_data; | |
238 WebRtcRTPHeader idr_packet = GetDefaultPacket(); | |
239 AddIdr(&idr_packet, 1); | |
240 idr_packet.type.Video.is_first_packet_in_frame = true; | |
241 idr_packet.header.sequenceNumber = 2; | |
242 idr_packet.header.markerBit = 1; | |
243 idr_packet.type.Video.is_first_packet_in_frame = true; | |
244 idr_packet.frameType = kVideoFrameKey; | |
245 idr_packet.type.Video.codec = kRtpVideoH264; | |
246 idr_data.insert(idr_data.end(), {0x65, 1, 2, 3}); | |
247 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
248 kH264StartCode, sizeof(kH264StartCode)); | |
249 mock_on_complete_frame_callback_.AppendExpectedBitstream(idr_data.data(), | |
250 idr_data.size()); | |
251 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_)); | |
252 rtp_stream_receiver_->OnReceivedPayloadData(idr_data.data(), idr_data.size(), | |
253 &idr_packet); | |
254 } | |
255 | |
256 TEST_F(RtpStreamReceiverTest, OutOfBandFmtpSpsPps) { | |
257 constexpr int kPayloadType = 99; | |
258 VideoCodec codec; | |
259 codec.plType = kPayloadType; | |
260 std::map<std::string, std::string> codec_params; | |
261 // Example parameter sets from https://tools.ietf.org/html/rfc3984#section-8.2 | |
262 // . | |
263 codec_params.insert( | |
264 {cricket::kH264FmtpSpropParameterSets, "Z0IACpZTBYmI,aMljiA=="}); | |
265 rtp_stream_receiver_->AddReceiveCodec(codec, codec_params); | |
266 const uint8_t binary_sps[] = {0x67, 0x42, 0x00, 0x0a, 0x96, | |
267 0x53, 0x05, 0x89, 0x88}; | |
268 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
269 kH264StartCode, sizeof(kH264StartCode)); | |
270 mock_on_complete_frame_callback_.AppendExpectedBitstream(binary_sps, | |
271 sizeof(binary_sps)); | |
272 const uint8_t binary_pps[] = {0x68, 0xc9, 0x63, 0x88}; | |
273 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
274 kH264StartCode, sizeof(kH264StartCode)); | |
275 mock_on_complete_frame_callback_.AppendExpectedBitstream(binary_pps, | |
276 sizeof(binary_pps)); | |
277 | |
278 std::vector<uint8_t> data; | |
279 WebRtcRTPHeader idr_packet = GetDefaultPacket(); | |
280 AddIdr(&idr_packet, 0); | |
281 idr_packet.header.payloadType = kPayloadType; | |
282 idr_packet.type.Video.is_first_packet_in_frame = true; | |
283 idr_packet.header.sequenceNumber = 2; | |
284 idr_packet.header.markerBit = 1; | |
285 idr_packet.type.Video.is_first_packet_in_frame = true; | |
286 idr_packet.frameType = kVideoFrameKey; | |
287 idr_packet.type.Video.codec = kRtpVideoH264; | |
288 data.insert(data.end(), {1, 2, 3}); | |
289 mock_on_complete_frame_callback_.AppendExpectedBitstream( | |
290 kH264StartCode, sizeof(kH264StartCode)); | |
291 mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data(), | |
292 data.size()); | |
293 EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_)); | |
294 rtp_stream_receiver_->OnReceivedPayloadData(data.data(), data.size(), | |
295 &idr_packet); | |
296 } | |
297 | |
298 } // namespace webrtc | |
OLD | NEW |