OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2014 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 <array> | |
12 #include <memory> | |
13 #include <vector> | |
14 | |
15 #include "webrtc/common_video/include/video_frame_buffer.h" | |
16 #include "webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h" | |
17 #include "webrtc/modules/video_coding/codecs/vp8/simulcast_unittest.h" | |
18 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | |
19 #include "webrtc/test/gmock.h" | |
20 | |
21 namespace webrtc { | |
22 namespace testing { | |
23 | |
24 class TestSimulcastEncoderAdapter : public TestVp8Simulcast { | |
25 public: | |
26 TestSimulcastEncoderAdapter() | |
27 : TestVp8Simulcast(new SimulcastEncoderAdapter(new Vp8EncoderFactory()), | |
28 VP8Decoder::Create()) {} | |
29 | |
30 protected: | |
31 class Vp8EncoderFactory : public VideoEncoderFactory { | |
32 public: | |
33 VideoEncoder* Create() override { return VP8Encoder::Create(); } | |
34 | |
35 void Destroy(VideoEncoder* encoder) override { delete encoder; } | |
36 | |
37 virtual ~Vp8EncoderFactory() {} | |
38 }; | |
39 | |
40 virtual void SetUp() { TestVp8Simulcast::SetUp(); } | |
41 virtual void TearDown() { TestVp8Simulcast::TearDown(); } | |
42 }; | |
43 | |
44 TEST_F(TestSimulcastEncoderAdapter, TestKeyFrameRequestsOnAllStreams) { | |
45 TestVp8Simulcast::TestKeyFrameRequestsOnAllStreams(); | |
46 } | |
47 | |
48 TEST_F(TestSimulcastEncoderAdapter, TestPaddingAllStreams) { | |
49 TestVp8Simulcast::TestPaddingAllStreams(); | |
50 } | |
51 | |
52 TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreams) { | |
53 TestVp8Simulcast::TestPaddingTwoStreams(); | |
54 } | |
55 | |
56 TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreamsOneMaxedOut) { | |
57 TestVp8Simulcast::TestPaddingTwoStreamsOneMaxedOut(); | |
58 } | |
59 | |
60 TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStream) { | |
61 TestVp8Simulcast::TestPaddingOneStream(); | |
62 } | |
63 | |
64 TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStreamTwoMaxedOut) { | |
65 TestVp8Simulcast::TestPaddingOneStreamTwoMaxedOut(); | |
66 } | |
67 | |
68 TEST_F(TestSimulcastEncoderAdapter, TestSendAllStreams) { | |
69 TestVp8Simulcast::TestSendAllStreams(); | |
70 } | |
71 | |
72 TEST_F(TestSimulcastEncoderAdapter, TestDisablingStreams) { | |
73 TestVp8Simulcast::TestDisablingStreams(); | |
74 } | |
75 | |
76 TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneStream) { | |
77 TestVp8Simulcast::TestSwitchingToOneStream(); | |
78 } | |
79 | |
80 TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneOddStream) { | |
81 TestVp8Simulcast::TestSwitchingToOneOddStream(); | |
82 } | |
83 | |
84 TEST_F(TestSimulcastEncoderAdapter, TestStrideEncodeDecode) { | |
85 TestVp8Simulcast::TestStrideEncodeDecode(); | |
86 } | |
87 | |
88 TEST_F(TestSimulcastEncoderAdapter, TestSaptioTemporalLayers333PatternEncoder) { | |
89 TestVp8Simulcast::TestSaptioTemporalLayers333PatternEncoder(); | |
90 } | |
91 | |
92 TEST_F(TestSimulcastEncoderAdapter, TestSpatioTemporalLayers321PatternEncoder) { | |
93 TestVp8Simulcast::TestSpatioTemporalLayers321PatternEncoder(); | |
94 } | |
95 | |
96 class MockVideoEncoder : public VideoEncoder { | |
97 public: | |
98 // TODO(nisse): Valid overrides commented out, because the gmock | |
99 // methods don't use any override declarations, and we want to avoid | |
100 // warnings from -Winconsistent-missing-override. See | |
101 // http://crbug.com/428099. | |
102 int32_t InitEncode(const VideoCodec* codecSettings, | |
103 int32_t numberOfCores, | |
104 size_t maxPayloadSize) /* override */ { | |
105 codec_ = *codecSettings; | |
106 return init_encode_return_value_; | |
107 } | |
108 | |
109 MOCK_METHOD3( | |
110 Encode, | |
111 int32_t(const VideoFrame& inputImage, | |
112 const CodecSpecificInfo* codecSpecificInfo, | |
113 const std::vector<FrameType>* frame_types) /* override */); | |
114 | |
115 int32_t RegisterEncodeCompleteCallback( | |
116 EncodedImageCallback* callback) /* override */ { | |
117 callback_ = callback; | |
118 return 0; | |
119 } | |
120 | |
121 MOCK_METHOD0(Release, int32_t()); | |
122 | |
123 int32_t SetRateAllocation(const BitrateAllocation& bitrate_allocation, | |
124 uint32_t framerate) { | |
125 last_set_bitrate_ = bitrate_allocation; | |
126 return 0; | |
127 } | |
128 | |
129 MOCK_METHOD2(SetChannelParameters, int32_t(uint32_t packetLoss, int64_t rtt)); | |
130 | |
131 bool SupportsNativeHandle() const /* override */ { | |
132 return supports_native_handle_; | |
133 } | |
134 | |
135 virtual ~MockVideoEncoder() {} | |
136 | |
137 const VideoCodec& codec() const { return codec_; } | |
138 | |
139 void SendEncodedImage(int width, int height) { | |
140 // Sends a fake image of the given width/height. | |
141 EncodedImage image; | |
142 image._encodedWidth = width; | |
143 image._encodedHeight = height; | |
144 CodecSpecificInfo codec_specific_info; | |
145 memset(&codec_specific_info, 0, sizeof(codec_specific_info)); | |
146 callback_->OnEncodedImage(image, &codec_specific_info, nullptr); | |
147 } | |
148 | |
149 void set_supports_native_handle(bool enabled) { | |
150 supports_native_handle_ = enabled; | |
151 } | |
152 | |
153 void set_init_encode_return_value(int32_t value) { | |
154 init_encode_return_value_ = value; | |
155 } | |
156 | |
157 BitrateAllocation last_set_bitrate() const { return last_set_bitrate_; } | |
158 | |
159 MOCK_CONST_METHOD0(ImplementationName, const char*()); | |
160 | |
161 private: | |
162 bool supports_native_handle_ = false; | |
163 int32_t init_encode_return_value_ = 0; | |
164 BitrateAllocation last_set_bitrate_; | |
165 | |
166 VideoCodec codec_; | |
167 EncodedImageCallback* callback_; | |
168 }; | |
169 | |
170 class MockVideoEncoderFactory : public VideoEncoderFactory { | |
171 public: | |
172 VideoEncoder* Create() override { | |
173 MockVideoEncoder* encoder = new | |
174 ::testing::NiceMock<MockVideoEncoder>(); | |
175 encoder->set_init_encode_return_value(init_encode_return_value_); | |
176 const char* encoder_name = encoder_names_.empty() | |
177 ? "codec_implementation_name" | |
178 : encoder_names_[encoders_.size()]; | |
179 ON_CALL(*encoder, ImplementationName()).WillByDefault(Return(encoder_name)); | |
180 encoders_.push_back(encoder); | |
181 return encoder; | |
182 } | |
183 | |
184 void Destroy(VideoEncoder* encoder) override { | |
185 for (size_t i = 0; i < encoders_.size(); ++i) { | |
186 if (encoders_[i] == encoder) { | |
187 encoders_.erase(encoders_.begin() + i); | |
188 break; | |
189 } | |
190 } | |
191 delete encoder; | |
192 } | |
193 | |
194 virtual ~MockVideoEncoderFactory() {} | |
195 | |
196 const std::vector<MockVideoEncoder*>& encoders() const { return encoders_; } | |
197 void SetEncoderNames(const std::vector<const char*>& encoder_names) { | |
198 encoder_names_ = encoder_names; | |
199 } | |
200 void set_init_encode_return_value(int32_t value) { | |
201 init_encode_return_value_ = value; | |
202 } | |
203 | |
204 private: | |
205 int32_t init_encode_return_value_ = 0; | |
206 std::vector<MockVideoEncoder*> encoders_; | |
207 std::vector<const char*> encoder_names_; | |
208 }; | |
209 | |
210 class TestSimulcastEncoderAdapterFakeHelper { | |
211 public: | |
212 TestSimulcastEncoderAdapterFakeHelper() | |
213 : factory_(new MockVideoEncoderFactory()) {} | |
214 | |
215 // Can only be called once as the SimulcastEncoderAdapter will take the | |
216 // ownership of |factory_|. | |
217 VP8Encoder* CreateMockEncoderAdapter() { | |
218 return new SimulcastEncoderAdapter(factory_); | |
219 } | |
220 | |
221 void ExpectCallSetChannelParameters(uint32_t packetLoss, int64_t rtt) { | |
222 EXPECT_TRUE(!factory_->encoders().empty()); | |
223 for (size_t i = 0; i < factory_->encoders().size(); ++i) { | |
224 EXPECT_CALL(*factory_->encoders()[i], | |
225 SetChannelParameters(packetLoss, rtt)) | |
226 .Times(1); | |
227 } | |
228 } | |
229 | |
230 MockVideoEncoderFactory* factory() { return factory_; } | |
231 | |
232 private: | |
233 MockVideoEncoderFactory* factory_; | |
234 }; | |
235 | |
236 static const int kTestTemporalLayerProfile[3] = {3, 2, 1}; | |
237 | |
238 class TestSimulcastEncoderAdapterFake : public ::testing::Test, | |
239 public EncodedImageCallback { | |
240 public: | |
241 TestSimulcastEncoderAdapterFake() | |
242 : helper_(new TestSimulcastEncoderAdapterFakeHelper()), | |
243 adapter_(helper_->CreateMockEncoderAdapter()), | |
244 last_encoded_image_width_(-1), | |
245 last_encoded_image_height_(-1), | |
246 last_encoded_image_simulcast_index_(-1) {} | |
247 virtual ~TestSimulcastEncoderAdapterFake() { | |
248 if (adapter_) { | |
249 adapter_->Release(); | |
250 } | |
251 } | |
252 | |
253 Result OnEncodedImage(const EncodedImage& encoded_image, | |
254 const CodecSpecificInfo* codec_specific_info, | |
255 const RTPFragmentationHeader* fragmentation) override { | |
256 last_encoded_image_width_ = encoded_image._encodedWidth; | |
257 last_encoded_image_height_ = encoded_image._encodedHeight; | |
258 if (codec_specific_info) { | |
259 last_encoded_image_simulcast_index_ = | |
260 codec_specific_info->codecSpecific.VP8.simulcastIdx; | |
261 } | |
262 return Result(Result::OK, encoded_image._timeStamp); | |
263 } | |
264 | |
265 bool GetLastEncodedImageInfo(int* out_width, | |
266 int* out_height, | |
267 int* out_simulcast_index) { | |
268 if (last_encoded_image_width_ == -1) { | |
269 return false; | |
270 } | |
271 *out_width = last_encoded_image_width_; | |
272 *out_height = last_encoded_image_height_; | |
273 *out_simulcast_index = last_encoded_image_simulcast_index_; | |
274 return true; | |
275 } | |
276 | |
277 void SetupCodec() { | |
278 TestVp8Simulcast::DefaultSettings( | |
279 &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); | |
280 rate_allocator_.reset(new SimulcastRateAllocator(codec_, nullptr)); | |
281 tl_factory_.SetListener(rate_allocator_.get()); | |
282 codec_.VP8()->tl_factory = &tl_factory_; | |
283 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
284 adapter_->RegisterEncodeCompleteCallback(this); | |
285 } | |
286 | |
287 void VerifyCodec(const VideoCodec& ref, int stream_index) { | |
288 const VideoCodec& target = | |
289 helper_->factory()->encoders()[stream_index]->codec(); | |
290 EXPECT_EQ(ref.codecType, target.codecType); | |
291 EXPECT_EQ(0, strcmp(ref.plName, target.plName)); | |
292 EXPECT_EQ(ref.plType, target.plType); | |
293 EXPECT_EQ(ref.width, target.width); | |
294 EXPECT_EQ(ref.height, target.height); | |
295 EXPECT_EQ(ref.startBitrate, target.startBitrate); | |
296 EXPECT_EQ(ref.maxBitrate, target.maxBitrate); | |
297 EXPECT_EQ(ref.minBitrate, target.minBitrate); | |
298 EXPECT_EQ(ref.maxFramerate, target.maxFramerate); | |
299 EXPECT_EQ(ref.VP8().pictureLossIndicationOn, | |
300 target.VP8().pictureLossIndicationOn); | |
301 EXPECT_EQ(ref.VP8().complexity, target.VP8().complexity); | |
302 EXPECT_EQ(ref.VP8().resilience, target.VP8().resilience); | |
303 EXPECT_EQ(ref.VP8().numberOfTemporalLayers, | |
304 target.VP8().numberOfTemporalLayers); | |
305 EXPECT_EQ(ref.VP8().denoisingOn, target.VP8().denoisingOn); | |
306 EXPECT_EQ(ref.VP8().errorConcealmentOn, target.VP8().errorConcealmentOn); | |
307 EXPECT_EQ(ref.VP8().automaticResizeOn, target.VP8().automaticResizeOn); | |
308 EXPECT_EQ(ref.VP8().frameDroppingOn, target.VP8().frameDroppingOn); | |
309 EXPECT_EQ(ref.VP8().keyFrameInterval, target.VP8().keyFrameInterval); | |
310 EXPECT_EQ(ref.qpMax, target.qpMax); | |
311 EXPECT_EQ(0, target.numberOfSimulcastStreams); | |
312 EXPECT_EQ(ref.mode, target.mode); | |
313 | |
314 // No need to compare simulcastStream as numberOfSimulcastStreams should | |
315 // always be 0. | |
316 } | |
317 | |
318 void InitRefCodec(int stream_index, VideoCodec* ref_codec) { | |
319 *ref_codec = codec_; | |
320 ref_codec->VP8()->numberOfTemporalLayers = | |
321 kTestTemporalLayerProfile[stream_index]; | |
322 ref_codec->VP8()->tl_factory = &tl_factory_; | |
323 ref_codec->width = codec_.simulcastStream[stream_index].width; | |
324 ref_codec->height = codec_.simulcastStream[stream_index].height; | |
325 ref_codec->maxBitrate = codec_.simulcastStream[stream_index].maxBitrate; | |
326 ref_codec->minBitrate = codec_.simulcastStream[stream_index].minBitrate; | |
327 ref_codec->qpMax = codec_.simulcastStream[stream_index].qpMax; | |
328 } | |
329 | |
330 void VerifyCodecSettings() { | |
331 EXPECT_EQ(3u, helper_->factory()->encoders().size()); | |
332 VideoCodec ref_codec; | |
333 | |
334 // stream 0, the lowest resolution stream. | |
335 InitRefCodec(0, &ref_codec); | |
336 ref_codec.qpMax = 45; | |
337 ref_codec.VP8()->complexity = webrtc::kComplexityHigher; | |
338 ref_codec.VP8()->denoisingOn = false; | |
339 ref_codec.startBitrate = 100; // Should equal to the target bitrate. | |
340 VerifyCodec(ref_codec, 0); | |
341 | |
342 // stream 1 | |
343 InitRefCodec(1, &ref_codec); | |
344 ref_codec.VP8()->denoisingOn = false; | |
345 // The start bitrate (300kbit) minus what we have for the lower layers | |
346 // (100kbit). | |
347 ref_codec.startBitrate = 200; | |
348 VerifyCodec(ref_codec, 1); | |
349 | |
350 // stream 2, the biggest resolution stream. | |
351 InitRefCodec(2, &ref_codec); | |
352 // We don't have enough bits to send this, so the adapter should have | |
353 // configured it to use the min bitrate for this layer (600kbit) but turn | |
354 // off sending. | |
355 ref_codec.startBitrate = 600; | |
356 VerifyCodec(ref_codec, 2); | |
357 } | |
358 | |
359 protected: | |
360 std::unique_ptr<TestSimulcastEncoderAdapterFakeHelper> helper_; | |
361 std::unique_ptr<VP8Encoder> adapter_; | |
362 VideoCodec codec_; | |
363 int last_encoded_image_width_; | |
364 int last_encoded_image_height_; | |
365 int last_encoded_image_simulcast_index_; | |
366 TemporalLayersFactory tl_factory_; | |
367 std::unique_ptr<SimulcastRateAllocator> rate_allocator_; | |
368 }; | |
369 | |
370 TEST_F(TestSimulcastEncoderAdapterFake, InitEncode) { | |
371 SetupCodec(); | |
372 VerifyCodecSettings(); | |
373 } | |
374 | |
375 TEST_F(TestSimulcastEncoderAdapterFake, ReleaseWithoutInitEncode) { | |
376 EXPECT_EQ(0, adapter_->Release()); | |
377 } | |
378 | |
379 TEST_F(TestSimulcastEncoderAdapterFake, Reinit) { | |
380 SetupCodec(); | |
381 EXPECT_EQ(0, adapter_->Release()); | |
382 | |
383 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
384 } | |
385 | |
386 TEST_F(TestSimulcastEncoderAdapterFake, SetChannelParameters) { | |
387 SetupCodec(); | |
388 const uint32_t packetLoss = 5; | |
389 const int64_t rtt = 30; | |
390 helper_->ExpectCallSetChannelParameters(packetLoss, rtt); | |
391 adapter_->SetChannelParameters(packetLoss, rtt); | |
392 } | |
393 | |
394 TEST_F(TestSimulcastEncoderAdapterFake, EncodedCallbackForDifferentEncoders) { | |
395 SetupCodec(); | |
396 | |
397 // Set bitrates so that we send all layers. | |
398 adapter_->SetRateAllocation(rate_allocator_->GetAllocation(1200, 30), 30); | |
399 | |
400 // At this point, the simulcast encoder adapter should have 3 streams: HD, | |
401 // quarter HD, and quarter quarter HD. We're going to mostly ignore the exact | |
402 // resolutions, to test that the adapter forwards on the correct resolution | |
403 // and simulcast index values, going only off the encoder that generates the | |
404 // image. | |
405 std::vector<MockVideoEncoder*> encoders = helper_->factory()->encoders(); | |
406 ASSERT_EQ(3u, encoders.size()); | |
407 encoders[0]->SendEncodedImage(1152, 704); | |
408 int width; | |
409 int height; | |
410 int simulcast_index; | |
411 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); | |
412 EXPECT_EQ(1152, width); | |
413 EXPECT_EQ(704, height); | |
414 EXPECT_EQ(0, simulcast_index); | |
415 | |
416 encoders[1]->SendEncodedImage(300, 620); | |
417 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); | |
418 EXPECT_EQ(300, width); | |
419 EXPECT_EQ(620, height); | |
420 EXPECT_EQ(1, simulcast_index); | |
421 | |
422 encoders[2]->SendEncodedImage(120, 240); | |
423 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); | |
424 EXPECT_EQ(120, width); | |
425 EXPECT_EQ(240, height); | |
426 EXPECT_EQ(2, simulcast_index); | |
427 } | |
428 | |
429 // This test verifies that the underlying encoders are reused, when the adapter | |
430 // is reinited with different number of simulcast streams. It further checks | |
431 // that the allocated encoders are reused in the same order as before, starting | |
432 // with the lowest stream. | |
433 TEST_F(TestSimulcastEncoderAdapterFake, ReusesEncodersInOrder) { | |
434 // Set up common settings for three streams. | |
435 TestVp8Simulcast::DefaultSettings( | |
436 &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); | |
437 rate_allocator_.reset(new SimulcastRateAllocator(codec_, nullptr)); | |
438 tl_factory_.SetListener(rate_allocator_.get()); | |
439 codec_.VP8()->tl_factory = &tl_factory_; | |
440 adapter_->RegisterEncodeCompleteCallback(this); | |
441 | |
442 // Input data. | |
443 rtc::scoped_refptr<VideoFrameBuffer> buffer(I420Buffer::Create(1280, 720)); | |
444 VideoFrame input_frame(buffer, 100, 1000, kVideoRotation_180); | |
445 std::vector<FrameType> frame_types; | |
446 | |
447 // Encode with three streams. | |
448 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
449 VerifyCodecSettings(); | |
450 std::vector<MockVideoEncoder*> original_encoders = | |
451 helper_->factory()->encoders(); | |
452 ASSERT_EQ(3u, original_encoders.size()); | |
453 EXPECT_CALL(*original_encoders[0], Encode(_, _, _)) | |
454 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
455 EXPECT_CALL(*original_encoders[1], Encode(_, _, _)) | |
456 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
457 EXPECT_CALL(*original_encoders[2], Encode(_, _, _)) | |
458 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
459 frame_types.resize(3, kVideoFrameKey); | |
460 EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); | |
461 EXPECT_CALL(*original_encoders[0], Release()) | |
462 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
463 EXPECT_CALL(*original_encoders[1], Release()) | |
464 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
465 EXPECT_CALL(*original_encoders[2], Release()) | |
466 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
467 EXPECT_EQ(0, adapter_->Release()); | |
468 | |
469 // Encode with two streams. | |
470 codec_.width /= 2; | |
471 codec_.height /= 2; | |
472 codec_.numberOfSimulcastStreams = 2; | |
473 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
474 std::vector<MockVideoEncoder*> new_encoders = helper_->factory()->encoders(); | |
475 ASSERT_EQ(2u, new_encoders.size()); | |
476 ASSERT_EQ(original_encoders[0], new_encoders[0]); | |
477 EXPECT_CALL(*original_encoders[0], Encode(_, _, _)) | |
478 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
479 ASSERT_EQ(original_encoders[1], new_encoders[1]); | |
480 EXPECT_CALL(*original_encoders[1], Encode(_, _, _)) | |
481 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
482 frame_types.resize(2, kVideoFrameKey); | |
483 EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); | |
484 EXPECT_CALL(*original_encoders[0], Release()) | |
485 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
486 EXPECT_CALL(*original_encoders[1], Release()) | |
487 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
488 EXPECT_EQ(0, adapter_->Release()); | |
489 | |
490 // Encode with single stream. | |
491 codec_.width /= 2; | |
492 codec_.height /= 2; | |
493 codec_.numberOfSimulcastStreams = 1; | |
494 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
495 new_encoders = helper_->factory()->encoders(); | |
496 ASSERT_EQ(1u, new_encoders.size()); | |
497 ASSERT_EQ(original_encoders[0], new_encoders[0]); | |
498 EXPECT_CALL(*original_encoders[0], Encode(_, _, _)) | |
499 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
500 frame_types.resize(1, kVideoFrameKey); | |
501 EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); | |
502 EXPECT_CALL(*original_encoders[0], Release()) | |
503 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
504 EXPECT_EQ(0, adapter_->Release()); | |
505 | |
506 // Encode with three streams, again. | |
507 codec_.width *= 4; | |
508 codec_.height *= 4; | |
509 codec_.numberOfSimulcastStreams = 3; | |
510 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
511 new_encoders = helper_->factory()->encoders(); | |
512 ASSERT_EQ(3u, new_encoders.size()); | |
513 // The first encoder is reused. | |
514 ASSERT_EQ(original_encoders[0], new_encoders[0]); | |
515 EXPECT_CALL(*original_encoders[0], Encode(_, _, _)) | |
516 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
517 // The second and third encoders are new. | |
518 EXPECT_CALL(*new_encoders[1], Encode(_, _, _)) | |
519 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
520 EXPECT_CALL(*new_encoders[2], Encode(_, _, _)) | |
521 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
522 frame_types.resize(3, kVideoFrameKey); | |
523 EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); | |
524 EXPECT_CALL(*original_encoders[0], Release()) | |
525 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
526 EXPECT_CALL(*new_encoders[1], Release()) | |
527 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
528 EXPECT_CALL(*new_encoders[2], Release()) | |
529 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
530 EXPECT_EQ(0, adapter_->Release()); | |
531 } | |
532 | |
533 TEST_F(TestSimulcastEncoderAdapterFake, DoesNotLeakEncoders) { | |
534 SetupCodec(); | |
535 VerifyCodecSettings(); | |
536 | |
537 EXPECT_EQ(3u, helper_->factory()->encoders().size()); | |
538 | |
539 // The adapter should destroy all encoders it has allocated. Since | |
540 // |helper_->factory()| is owned by |adapter_|, however, we need to rely on | |
541 // lsan to find leaks here. | |
542 EXPECT_EQ(0, adapter_->Release()); | |
543 adapter_.reset(); | |
544 } | |
545 | |
546 // This test verifies that an adapter reinit with the same codec settings as | |
547 // before does not change the underlying encoder codec settings. | |
548 TEST_F(TestSimulcastEncoderAdapterFake, ReinitDoesNotReorderEncoderSettings) { | |
549 SetupCodec(); | |
550 VerifyCodecSettings(); | |
551 | |
552 // Capture current codec settings. | |
553 std::vector<MockVideoEncoder*> encoders = helper_->factory()->encoders(); | |
554 ASSERT_EQ(3u, encoders.size()); | |
555 std::array<VideoCodec, 3> codecs_before; | |
556 for (int i = 0; i < 3; ++i) { | |
557 codecs_before[i] = encoders[i]->codec(); | |
558 } | |
559 | |
560 // Reinitialize and verify that the new codec settings are the same. | |
561 EXPECT_EQ(0, adapter_->Release()); | |
562 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
563 for (int i = 0; i < 3; ++i) { | |
564 const VideoCodec& codec_before = codecs_before[i]; | |
565 const VideoCodec& codec_after = encoders[i]->codec(); | |
566 | |
567 // webrtc::VideoCodec does not implement operator==. | |
568 EXPECT_EQ(codec_before.codecType, codec_after.codecType); | |
569 EXPECT_EQ(codec_before.plType, codec_after.plType); | |
570 EXPECT_EQ(codec_before.width, codec_after.width); | |
571 EXPECT_EQ(codec_before.height, codec_after.height); | |
572 EXPECT_EQ(codec_before.startBitrate, codec_after.startBitrate); | |
573 EXPECT_EQ(codec_before.maxBitrate, codec_after.maxBitrate); | |
574 EXPECT_EQ(codec_before.minBitrate, codec_after.minBitrate); | |
575 EXPECT_EQ(codec_before.targetBitrate, codec_after.targetBitrate); | |
576 EXPECT_EQ(codec_before.maxFramerate, codec_after.maxFramerate); | |
577 EXPECT_EQ(codec_before.qpMax, codec_after.qpMax); | |
578 EXPECT_EQ(codec_before.numberOfSimulcastStreams, | |
579 codec_after.numberOfSimulcastStreams); | |
580 EXPECT_EQ(codec_before.mode, codec_after.mode); | |
581 EXPECT_EQ(codec_before.expect_encode_from_texture, | |
582 codec_after.expect_encode_from_texture); | |
583 } | |
584 } | |
585 | |
586 // This test is similar to the one above, except that it tests the simulcastIdx | |
587 // from the CodecSpecificInfo that is connected to an encoded frame. The | |
588 // PayloadRouter demuxes the incoming encoded frames on different RTP modules | |
589 // using the simulcastIdx, so it's important that there is no corresponding | |
590 // encoder reordering in between adapter reinits as this would lead to PictureID | |
591 // discontinuities. | |
592 TEST_F(TestSimulcastEncoderAdapterFake, ReinitDoesNotReorderFrameSimulcastIdx) { | |
593 SetupCodec(); | |
594 adapter_->SetRateAllocation(rate_allocator_->GetAllocation(1200, 30), 30); | |
595 VerifyCodecSettings(); | |
596 | |
597 // Send frames on all streams. | |
598 std::vector<MockVideoEncoder*> encoders = helper_->factory()->encoders(); | |
599 ASSERT_EQ(3u, encoders.size()); | |
600 encoders[0]->SendEncodedImage(1152, 704); | |
601 int width; | |
602 int height; | |
603 int simulcast_index; | |
604 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); | |
605 EXPECT_EQ(0, simulcast_index); | |
606 | |
607 encoders[1]->SendEncodedImage(300, 620); | |
608 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); | |
609 EXPECT_EQ(1, simulcast_index); | |
610 | |
611 encoders[2]->SendEncodedImage(120, 240); | |
612 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); | |
613 EXPECT_EQ(2, simulcast_index); | |
614 | |
615 // Reinitialize. | |
616 EXPECT_EQ(0, adapter_->Release()); | |
617 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
618 adapter_->SetRateAllocation(rate_allocator_->GetAllocation(1200, 30), 30); | |
619 | |
620 // Verify that the same encoder sends out frames on the same simulcast index. | |
621 encoders[0]->SendEncodedImage(1152, 704); | |
622 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); | |
623 EXPECT_EQ(0, simulcast_index); | |
624 | |
625 encoders[1]->SendEncodedImage(300, 620); | |
626 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); | |
627 EXPECT_EQ(1, simulcast_index); | |
628 | |
629 encoders[2]->SendEncodedImage(120, 240); | |
630 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index)); | |
631 EXPECT_EQ(2, simulcast_index); | |
632 } | |
633 | |
634 TEST_F(TestSimulcastEncoderAdapterFake, SupportsNativeHandleForSingleStreams) { | |
635 TestVp8Simulcast::DefaultSettings( | |
636 &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); | |
637 codec_.VP8()->tl_factory = &tl_factory_; | |
638 codec_.numberOfSimulcastStreams = 1; | |
639 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
640 adapter_->RegisterEncodeCompleteCallback(this); | |
641 ASSERT_EQ(1u, helper_->factory()->encoders().size()); | |
642 helper_->factory()->encoders()[0]->set_supports_native_handle(true); | |
643 EXPECT_TRUE(adapter_->SupportsNativeHandle()); | |
644 helper_->factory()->encoders()[0]->set_supports_native_handle(false); | |
645 EXPECT_FALSE(adapter_->SupportsNativeHandle()); | |
646 } | |
647 | |
648 TEST_F(TestSimulcastEncoderAdapterFake, SetRatesUnderMinBitrate) { | |
649 TestVp8Simulcast::DefaultSettings( | |
650 &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); | |
651 codec_.VP8()->tl_factory = &tl_factory_; | |
652 codec_.minBitrate = 50; | |
653 codec_.numberOfSimulcastStreams = 1; | |
654 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
655 rate_allocator_.reset(new SimulcastRateAllocator(codec_, nullptr)); | |
656 | |
657 // Above min should be respected. | |
658 BitrateAllocation target_bitrate = | |
659 rate_allocator_->GetAllocation(codec_.minBitrate * 1000, 30); | |
660 adapter_->SetRateAllocation(target_bitrate, 30); | |
661 EXPECT_EQ(target_bitrate, | |
662 helper_->factory()->encoders()[0]->last_set_bitrate()); | |
663 | |
664 // Below min but non-zero should be replaced with the min bitrate. | |
665 BitrateAllocation too_low_bitrate = | |
666 rate_allocator_->GetAllocation((codec_.minBitrate - 1) * 1000, 30); | |
667 adapter_->SetRateAllocation(too_low_bitrate, 30); | |
668 EXPECT_EQ(target_bitrate, | |
669 helper_->factory()->encoders()[0]->last_set_bitrate()); | |
670 | |
671 // Zero should be passed on as is, since it means "pause". | |
672 adapter_->SetRateAllocation(BitrateAllocation(), 30); | |
673 EXPECT_EQ(BitrateAllocation(), | |
674 helper_->factory()->encoders()[0]->last_set_bitrate()); | |
675 } | |
676 | |
677 TEST_F(TestSimulcastEncoderAdapterFake, SupportsImplementationName) { | |
678 EXPECT_STREQ("SimulcastEncoderAdapter", adapter_->ImplementationName()); | |
679 TestVp8Simulcast::DefaultSettings( | |
680 &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); | |
681 codec_.VP8()->tl_factory = &tl_factory_; | |
682 std::vector<const char*> encoder_names; | |
683 encoder_names.push_back("codec1"); | |
684 encoder_names.push_back("codec2"); | |
685 encoder_names.push_back("codec3"); | |
686 helper_->factory()->SetEncoderNames(encoder_names); | |
687 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
688 EXPECT_STREQ("SimulcastEncoderAdapter (codec1, codec2, codec3)", | |
689 adapter_->ImplementationName()); | |
690 | |
691 // Single streams should not expose "SimulcastEncoderAdapter" in name. | |
692 EXPECT_EQ(0, adapter_->Release()); | |
693 codec_.numberOfSimulcastStreams = 1; | |
694 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
695 adapter_->RegisterEncodeCompleteCallback(this); | |
696 ASSERT_EQ(1u, helper_->factory()->encoders().size()); | |
697 EXPECT_STREQ("codec1", adapter_->ImplementationName()); | |
698 } | |
699 | |
700 TEST_F(TestSimulcastEncoderAdapterFake, | |
701 SupportsNativeHandleForMultipleStreams) { | |
702 TestVp8Simulcast::DefaultSettings( | |
703 &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); | |
704 codec_.VP8()->tl_factory = &tl_factory_; | |
705 codec_.numberOfSimulcastStreams = 3; | |
706 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
707 adapter_->RegisterEncodeCompleteCallback(this); | |
708 ASSERT_EQ(3u, helper_->factory()->encoders().size()); | |
709 for (MockVideoEncoder* encoder : helper_->factory()->encoders()) | |
710 encoder->set_supports_native_handle(true); | |
711 // If one encoder doesn't support it, then overall support is disabled. | |
712 helper_->factory()->encoders()[0]->set_supports_native_handle(false); | |
713 EXPECT_FALSE(adapter_->SupportsNativeHandle()); | |
714 // Once all do, then the adapter claims support. | |
715 helper_->factory()->encoders()[0]->set_supports_native_handle(true); | |
716 EXPECT_TRUE(adapter_->SupportsNativeHandle()); | |
717 } | |
718 | |
719 // TODO(nisse): Reuse definition in webrtc/test/fake_texture_handle.h. | |
720 class FakeNativeBuffer : public VideoFrameBuffer { | |
721 public: | |
722 FakeNativeBuffer(int width, int height) : width_(width), height_(height) {} | |
723 | |
724 Type type() const override { return Type::kNative; } | |
725 int width() const override { return width_; } | |
726 int height() const override { return height_; } | |
727 | |
728 rtc::scoped_refptr<I420BufferInterface> ToI420() override { | |
729 RTC_NOTREACHED(); | |
730 return nullptr; | |
731 } | |
732 | |
733 private: | |
734 const int width_; | |
735 const int height_; | |
736 }; | |
737 | |
738 TEST_F(TestSimulcastEncoderAdapterFake, | |
739 NativeHandleForwardingForMultipleStreams) { | |
740 TestVp8Simulcast::DefaultSettings( | |
741 &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); | |
742 codec_.VP8()->tl_factory = &tl_factory_; | |
743 codec_.numberOfSimulcastStreams = 3; | |
744 // High start bitrate, so all streams are enabled. | |
745 codec_.startBitrate = 3000; | |
746 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
747 adapter_->RegisterEncodeCompleteCallback(this); | |
748 ASSERT_EQ(3u, helper_->factory()->encoders().size()); | |
749 for (MockVideoEncoder* encoder : helper_->factory()->encoders()) | |
750 encoder->set_supports_native_handle(true); | |
751 EXPECT_TRUE(adapter_->SupportsNativeHandle()); | |
752 | |
753 rtc::scoped_refptr<VideoFrameBuffer> buffer( | |
754 new rtc::RefCountedObject<FakeNativeBuffer>(1280, 720)); | |
755 VideoFrame input_frame(buffer, 100, 1000, kVideoRotation_180); | |
756 // Expect calls with the given video frame verbatim, since it's a texture | |
757 // frame and can't otherwise be modified/resized. | |
758 for (MockVideoEncoder* encoder : helper_->factory()->encoders()) | |
759 EXPECT_CALL(*encoder, Encode(::testing::Ref(input_frame), _, _)).Times(1); | |
760 std::vector<FrameType> frame_types(3, kVideoFrameKey); | |
761 EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); | |
762 } | |
763 | |
764 TEST_F(TestSimulcastEncoderAdapterFake, TestFailureReturnCodesFromEncodeCalls) { | |
765 TestVp8Simulcast::DefaultSettings( | |
766 &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); | |
767 codec_.VP8()->tl_factory = &tl_factory_; | |
768 codec_.numberOfSimulcastStreams = 3; | |
769 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); | |
770 adapter_->RegisterEncodeCompleteCallback(this); | |
771 ASSERT_EQ(3u, helper_->factory()->encoders().size()); | |
772 // Tell the 2nd encoder to request software fallback. | |
773 EXPECT_CALL(*helper_->factory()->encoders()[1], Encode(_, _, _)) | |
774 .WillOnce(Return(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE)); | |
775 | |
776 // Send a fake frame and assert the return is software fallback. | |
777 rtc::scoped_refptr<I420Buffer> input_buffer = | |
778 I420Buffer::Create(kDefaultWidth, kDefaultHeight); | |
779 input_buffer->InitializeData(); | |
780 VideoFrame input_frame(input_buffer, 0, 0, webrtc::kVideoRotation_0); | |
781 std::vector<FrameType> frame_types(3, kVideoFrameKey); | |
782 EXPECT_EQ(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE, | |
783 adapter_->Encode(input_frame, nullptr, &frame_types)); | |
784 } | |
785 | |
786 TEST_F(TestSimulcastEncoderAdapterFake, TestInitFailureCleansUpEncoders) { | |
787 TestVp8Simulcast::DefaultSettings( | |
788 &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); | |
789 codec_.VP8()->tl_factory = &tl_factory_; | |
790 codec_.numberOfSimulcastStreams = 3; | |
791 helper_->factory()->set_init_encode_return_value( | |
792 WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE); | |
793 EXPECT_EQ(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE, | |
794 adapter_->InitEncode(&codec_, 1, 1200)); | |
795 EXPECT_TRUE(helper_->factory()->encoders().empty()); | |
796 } | |
797 | |
798 } // namespace testing | |
799 } // namespace webrtc | |
OLD | NEW |