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 <vector>
12
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "webrtc/modules/video_coding/include/video_codec_interface.h"
15 #include "webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h"
16 #include "webrtc/modules/video_coding/codecs/vp8/simulcast_unittest.h"
17 #include "webrtc/modules/video_coding/codecs/vp8/vp8_factory.h"
18
19 namespace webrtc {
20 namespace testing {
21
CreateTestEncoderAdapter()22 static VP8Encoder* CreateTestEncoderAdapter() {
23 VP8EncoderFactoryConfig::set_use_simulcast_adapter(true);
24 return VP8Encoder::Create();
25 }
26
27 class TestSimulcastEncoderAdapter : public TestVp8Simulcast {
28 public:
TestSimulcastEncoderAdapter()29 TestSimulcastEncoderAdapter()
30 : TestVp8Simulcast(CreateTestEncoderAdapter(), VP8Decoder::Create()) {}
31
32 protected:
SetUp()33 virtual void SetUp() { TestVp8Simulcast::SetUp(); }
TearDown()34 virtual void TearDown() {
35 TestVp8Simulcast::TearDown();
36 VP8EncoderFactoryConfig::set_use_simulcast_adapter(false);
37 }
38 };
39
TEST_F(TestSimulcastEncoderAdapter,TestKeyFrameRequestsOnAllStreams)40 TEST_F(TestSimulcastEncoderAdapter, TestKeyFrameRequestsOnAllStreams) {
41 TestVp8Simulcast::TestKeyFrameRequestsOnAllStreams();
42 }
43
TEST_F(TestSimulcastEncoderAdapter,TestPaddingAllStreams)44 TEST_F(TestSimulcastEncoderAdapter, TestPaddingAllStreams) {
45 TestVp8Simulcast::TestPaddingAllStreams();
46 }
47
TEST_F(TestSimulcastEncoderAdapter,TestPaddingTwoStreams)48 TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreams) {
49 TestVp8Simulcast::TestPaddingTwoStreams();
50 }
51
TEST_F(TestSimulcastEncoderAdapter,TestPaddingTwoStreamsOneMaxedOut)52 TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreamsOneMaxedOut) {
53 TestVp8Simulcast::TestPaddingTwoStreamsOneMaxedOut();
54 }
55
TEST_F(TestSimulcastEncoderAdapter,TestPaddingOneStream)56 TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStream) {
57 TestVp8Simulcast::TestPaddingOneStream();
58 }
59
TEST_F(TestSimulcastEncoderAdapter,TestPaddingOneStreamTwoMaxedOut)60 TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStreamTwoMaxedOut) {
61 TestVp8Simulcast::TestPaddingOneStreamTwoMaxedOut();
62 }
63
TEST_F(TestSimulcastEncoderAdapter,TestSendAllStreams)64 TEST_F(TestSimulcastEncoderAdapter, TestSendAllStreams) {
65 TestVp8Simulcast::TestSendAllStreams();
66 }
67
TEST_F(TestSimulcastEncoderAdapter,TestDisablingStreams)68 TEST_F(TestSimulcastEncoderAdapter, TestDisablingStreams) {
69 TestVp8Simulcast::TestDisablingStreams();
70 }
71
TEST_F(TestSimulcastEncoderAdapter,TestSwitchingToOneStream)72 TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneStream) {
73 TestVp8Simulcast::TestSwitchingToOneStream();
74 }
75
TEST_F(TestSimulcastEncoderAdapter,TestSwitchingToOneOddStream)76 TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneOddStream) {
77 TestVp8Simulcast::TestSwitchingToOneOddStream();
78 }
79
TEST_F(TestSimulcastEncoderAdapter,TestRPSIEncodeDecode)80 TEST_F(TestSimulcastEncoderAdapter, TestRPSIEncodeDecode) {
81 TestVp8Simulcast::TestRPSIEncodeDecode();
82 }
83
TEST_F(TestSimulcastEncoderAdapter,TestStrideEncodeDecode)84 TEST_F(TestSimulcastEncoderAdapter, TestStrideEncodeDecode) {
85 TestVp8Simulcast::TestStrideEncodeDecode();
86 }
87
TEST_F(TestSimulcastEncoderAdapter,TestSaptioTemporalLayers333PatternEncoder)88 TEST_F(TestSimulcastEncoderAdapter, TestSaptioTemporalLayers333PatternEncoder) {
89 TestVp8Simulcast::TestSaptioTemporalLayers333PatternEncoder();
90 }
91
TEST_F(TestSimulcastEncoderAdapter,TestSpatioTemporalLayers321PatternEncoder)92 TEST_F(TestSimulcastEncoderAdapter, TestSpatioTemporalLayers321PatternEncoder) {
93 TestVp8Simulcast::TestSpatioTemporalLayers321PatternEncoder();
94 }
95
96 // TODO(ronghuawu): Enable this test when SkipEncodingUnusedStreams option is
97 // implemented for SimulcastEncoderAdapter.
TEST_F(TestSimulcastEncoderAdapter,DISABLED_TestSkipEncodingUnusedStreams)98 TEST_F(TestSimulcastEncoderAdapter, DISABLED_TestSkipEncodingUnusedStreams) {
99 TestVp8Simulcast::TestSkipEncodingUnusedStreams();
100 }
101
TEST_F(TestSimulcastEncoderAdapter,DISABLED_TestRPSIEncoder)102 TEST_F(TestSimulcastEncoderAdapter, DISABLED_TestRPSIEncoder) {
103 TestVp8Simulcast::TestRPSIEncoder();
104 }
105
106 class MockVideoEncoder : public VideoEncoder {
107 public:
InitEncode(const VideoCodec * codecSettings,int32_t numberOfCores,size_t maxPayloadSize)108 int32_t InitEncode(const VideoCodec* codecSettings,
109 int32_t numberOfCores,
110 size_t maxPayloadSize) override {
111 codec_ = *codecSettings;
112 return 0;
113 }
114
Encode(const VideoFrame & inputImage,const CodecSpecificInfo * codecSpecificInfo,const std::vector<FrameType> * frame_types)115 int32_t Encode(const VideoFrame& inputImage,
116 const CodecSpecificInfo* codecSpecificInfo,
117 const std::vector<FrameType>* frame_types) override {
118 return 0;
119 }
120
RegisterEncodeCompleteCallback(EncodedImageCallback * callback)121 int32_t RegisterEncodeCompleteCallback(
122 EncodedImageCallback* callback) override {
123 callback_ = callback;
124 return 0;
125 }
126
Release()127 int32_t Release() override { return 0; }
128
SetRates(uint32_t newBitRate,uint32_t frameRate)129 int32_t SetRates(uint32_t newBitRate, uint32_t frameRate) override {
130 return 0;
131 }
132
133 MOCK_METHOD2(SetChannelParameters, int32_t(uint32_t packetLoss, int64_t rtt));
134
SupportsNativeHandle() const135 bool SupportsNativeHandle() const override { return supports_native_handle_; }
136
~MockVideoEncoder()137 virtual ~MockVideoEncoder() {}
138
codec() const139 const VideoCodec& codec() const { return codec_; }
140
SendEncodedImage(int width,int height)141 void SendEncodedImage(int width, int height) {
142 // Sends a fake image of the given width/height.
143 EncodedImage image;
144 image._encodedWidth = width;
145 image._encodedHeight = height;
146 CodecSpecificInfo codecSpecificInfo;
147 memset(&codecSpecificInfo, 0, sizeof(codecSpecificInfo));
148 callback_->Encoded(image, &codecSpecificInfo, NULL);
149 }
150
set_supports_native_handle(bool enabled)151 void set_supports_native_handle(bool enabled) {
152 supports_native_handle_ = enabled;
153 }
154
155 private:
156 bool supports_native_handle_ = false;
157 VideoCodec codec_;
158 EncodedImageCallback* callback_;
159 };
160
161 class MockVideoEncoderFactory : public VideoEncoderFactory {
162 public:
Create()163 VideoEncoder* Create() override {
164 MockVideoEncoder* encoder = new MockVideoEncoder();
165 encoders_.push_back(encoder);
166 return encoder;
167 }
168
Destroy(VideoEncoder * encoder)169 void Destroy(VideoEncoder* encoder) override { delete encoder; }
170
~MockVideoEncoderFactory()171 virtual ~MockVideoEncoderFactory() {}
172
encoders() const173 const std::vector<MockVideoEncoder*>& encoders() const { return encoders_; }
174
175 private:
176 std::vector<MockVideoEncoder*> encoders_;
177 };
178
179 class TestSimulcastEncoderAdapterFakeHelper {
180 public:
TestSimulcastEncoderAdapterFakeHelper()181 TestSimulcastEncoderAdapterFakeHelper()
182 : factory_(new MockVideoEncoderFactory()) {}
183
184 // Can only be called once as the SimulcastEncoderAdapter will take the
185 // ownership of |factory_|.
CreateMockEncoderAdapter()186 VP8Encoder* CreateMockEncoderAdapter() {
187 return new SimulcastEncoderAdapter(factory_);
188 }
189
ExpectCallSetChannelParameters(uint32_t packetLoss,int64_t rtt)190 void ExpectCallSetChannelParameters(uint32_t packetLoss, int64_t rtt) {
191 EXPECT_TRUE(!factory_->encoders().empty());
192 for (size_t i = 0; i < factory_->encoders().size(); ++i) {
193 EXPECT_CALL(*factory_->encoders()[i],
194 SetChannelParameters(packetLoss, rtt))
195 .Times(1);
196 }
197 }
198
factory()199 MockVideoEncoderFactory* factory() { return factory_; }
200
201 private:
202 MockVideoEncoderFactory* factory_;
203 };
204
205 static const int kTestTemporalLayerProfile[3] = {3, 2, 1};
206
207 class TestSimulcastEncoderAdapterFake : public ::testing::Test,
208 public EncodedImageCallback {
209 public:
TestSimulcastEncoderAdapterFake()210 TestSimulcastEncoderAdapterFake()
211 : helper_(new TestSimulcastEncoderAdapterFakeHelper()),
212 adapter_(helper_->CreateMockEncoderAdapter()),
213 last_encoded_image_width_(-1),
214 last_encoded_image_height_(-1),
215 last_encoded_image_simulcast_index_(-1) {}
~TestSimulcastEncoderAdapterFake()216 virtual ~TestSimulcastEncoderAdapterFake() {}
217
Encoded(const EncodedImage & encodedImage,const CodecSpecificInfo * codecSpecificInfo=NULL,const RTPFragmentationHeader * fragmentation=NULL)218 int32_t Encoded(const EncodedImage& encodedImage,
219 const CodecSpecificInfo* codecSpecificInfo = NULL,
220 const RTPFragmentationHeader* fragmentation = NULL) override {
221 last_encoded_image_width_ = encodedImage._encodedWidth;
222 last_encoded_image_height_ = encodedImage._encodedHeight;
223 if (codecSpecificInfo) {
224 last_encoded_image_simulcast_index_ =
225 codecSpecificInfo->codecSpecific.VP8.simulcastIdx;
226 }
227 return 0;
228 }
229
GetLastEncodedImageInfo(int * out_width,int * out_height,int * out_simulcast_index)230 bool GetLastEncodedImageInfo(int* out_width,
231 int* out_height,
232 int* out_simulcast_index) {
233 if (last_encoded_image_width_ == -1) {
234 return false;
235 }
236 *out_width = last_encoded_image_width_;
237 *out_height = last_encoded_image_height_;
238 *out_simulcast_index = last_encoded_image_simulcast_index_;
239 return true;
240 }
241
SetupCodec()242 void SetupCodec() {
243 TestVp8Simulcast::DefaultSettings(
244 &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
245 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
246 adapter_->RegisterEncodeCompleteCallback(this);
247 }
248
VerifyCodec(const VideoCodec & ref,int stream_index)249 void VerifyCodec(const VideoCodec& ref, int stream_index) {
250 const VideoCodec& target =
251 helper_->factory()->encoders()[stream_index]->codec();
252 EXPECT_EQ(ref.codecType, target.codecType);
253 EXPECT_EQ(0, strcmp(ref.plName, target.plName));
254 EXPECT_EQ(ref.plType, target.plType);
255 EXPECT_EQ(ref.width, target.width);
256 EXPECT_EQ(ref.height, target.height);
257 EXPECT_EQ(ref.startBitrate, target.startBitrate);
258 EXPECT_EQ(ref.maxBitrate, target.maxBitrate);
259 EXPECT_EQ(ref.minBitrate, target.minBitrate);
260 EXPECT_EQ(ref.maxFramerate, target.maxFramerate);
261 EXPECT_EQ(ref.codecSpecific.VP8.pictureLossIndicationOn,
262 target.codecSpecific.VP8.pictureLossIndicationOn);
263 EXPECT_EQ(ref.codecSpecific.VP8.feedbackModeOn,
264 target.codecSpecific.VP8.feedbackModeOn);
265 EXPECT_EQ(ref.codecSpecific.VP8.complexity,
266 target.codecSpecific.VP8.complexity);
267 EXPECT_EQ(ref.codecSpecific.VP8.resilience,
268 target.codecSpecific.VP8.resilience);
269 EXPECT_EQ(ref.codecSpecific.VP8.numberOfTemporalLayers,
270 target.codecSpecific.VP8.numberOfTemporalLayers);
271 EXPECT_EQ(ref.codecSpecific.VP8.denoisingOn,
272 target.codecSpecific.VP8.denoisingOn);
273 EXPECT_EQ(ref.codecSpecific.VP8.errorConcealmentOn,
274 target.codecSpecific.VP8.errorConcealmentOn);
275 EXPECT_EQ(ref.codecSpecific.VP8.automaticResizeOn,
276 target.codecSpecific.VP8.automaticResizeOn);
277 EXPECT_EQ(ref.codecSpecific.VP8.frameDroppingOn,
278 target.codecSpecific.VP8.frameDroppingOn);
279 EXPECT_EQ(ref.codecSpecific.VP8.keyFrameInterval,
280 target.codecSpecific.VP8.keyFrameInterval);
281 EXPECT_EQ(ref.qpMax, target.qpMax);
282 EXPECT_EQ(0, target.numberOfSimulcastStreams);
283 EXPECT_EQ(ref.mode, target.mode);
284 EXPECT_EQ(ref.extra_options, target.extra_options);
285
286 // No need to compare simulcastStream as numberOfSimulcastStreams should
287 // always be 0.
288 }
289
InitRefCodec(int stream_index,VideoCodec * ref_codec)290 void InitRefCodec(int stream_index, VideoCodec* ref_codec) {
291 *ref_codec = codec_;
292 ref_codec->codecSpecific.VP8.numberOfTemporalLayers =
293 kTestTemporalLayerProfile[stream_index];
294 ref_codec->width = codec_.simulcastStream[stream_index].width;
295 ref_codec->height = codec_.simulcastStream[stream_index].height;
296 ref_codec->maxBitrate = codec_.simulcastStream[stream_index].maxBitrate;
297 ref_codec->minBitrate = codec_.simulcastStream[stream_index].minBitrate;
298 ref_codec->qpMax = codec_.simulcastStream[stream_index].qpMax;
299 }
300
VerifyCodecSettings()301 void VerifyCodecSettings() {
302 EXPECT_EQ(3u, helper_->factory()->encoders().size());
303 VideoCodec ref_codec;
304
305 // stream 0, the lowest resolution stream.
306 InitRefCodec(0, &ref_codec);
307 ref_codec.qpMax = 45;
308 ref_codec.codecSpecific.VP8.complexity = webrtc::kComplexityHigher;
309 ref_codec.codecSpecific.VP8.denoisingOn = false;
310 ref_codec.startBitrate = 100; // Should equal to the target bitrate.
311 VerifyCodec(ref_codec, 0);
312
313 // stream 1
314 InitRefCodec(1, &ref_codec);
315 ref_codec.codecSpecific.VP8.denoisingOn = false;
316 // The start bitrate (300kbit) minus what we have for the lower layers
317 // (100kbit).
318 ref_codec.startBitrate = 200;
319 VerifyCodec(ref_codec, 1);
320
321 // stream 2, the biggest resolution stream.
322 InitRefCodec(2, &ref_codec);
323 // We don't have enough bits to send this, so the adapter should have
324 // configured it to use the min bitrate for this layer (600kbit) but turn
325 // off sending.
326 ref_codec.startBitrate = 600;
327 VerifyCodec(ref_codec, 2);
328 }
329
330 protected:
331 rtc::scoped_ptr<TestSimulcastEncoderAdapterFakeHelper> helper_;
332 rtc::scoped_ptr<VP8Encoder> adapter_;
333 VideoCodec codec_;
334 int last_encoded_image_width_;
335 int last_encoded_image_height_;
336 int last_encoded_image_simulcast_index_;
337 };
338
TEST_F(TestSimulcastEncoderAdapterFake,InitEncode)339 TEST_F(TestSimulcastEncoderAdapterFake, InitEncode) {
340 SetupCodec();
341 VerifyCodecSettings();
342 }
343
TEST_F(TestSimulcastEncoderAdapterFake,SetChannelParameters)344 TEST_F(TestSimulcastEncoderAdapterFake, SetChannelParameters) {
345 SetupCodec();
346 const uint32_t packetLoss = 5;
347 const int64_t rtt = 30;
348 helper_->ExpectCallSetChannelParameters(packetLoss, rtt);
349 adapter_->SetChannelParameters(packetLoss, rtt);
350 }
351
TEST_F(TestSimulcastEncoderAdapterFake,EncodedCallbackForDifferentEncoders)352 TEST_F(TestSimulcastEncoderAdapterFake, EncodedCallbackForDifferentEncoders) {
353 SetupCodec();
354
355 // Set bitrates so that we send all layers.
356 adapter_->SetRates(1200, 30);
357
358 // At this point, the simulcast encoder adapter should have 3 streams: HD,
359 // quarter HD, and quarter quarter HD. We're going to mostly ignore the exact
360 // resolutions, to test that the adapter forwards on the correct resolution
361 // and simulcast index values, going only off the encoder that generates the
362 // image.
363 EXPECT_EQ(3u, helper_->factory()->encoders().size());
364 helper_->factory()->encoders()[0]->SendEncodedImage(1152, 704);
365 int width;
366 int height;
367 int simulcast_index;
368 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
369 EXPECT_EQ(1152, width);
370 EXPECT_EQ(704, height);
371 EXPECT_EQ(0, simulcast_index);
372
373 helper_->factory()->encoders()[1]->SendEncodedImage(300, 620);
374 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
375 EXPECT_EQ(300, width);
376 EXPECT_EQ(620, height);
377 EXPECT_EQ(1, simulcast_index);
378
379 helper_->factory()->encoders()[2]->SendEncodedImage(120, 240);
380 EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
381 EXPECT_EQ(120, width);
382 EXPECT_EQ(240, height);
383 EXPECT_EQ(2, simulcast_index);
384 }
385
TEST_F(TestSimulcastEncoderAdapterFake,SupportsNativeHandleForSingleStreams)386 TEST_F(TestSimulcastEncoderAdapterFake, SupportsNativeHandleForSingleStreams) {
387 TestVp8Simulcast::DefaultSettings(
388 &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
389 codec_.numberOfSimulcastStreams = 1;
390 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
391 adapter_->RegisterEncodeCompleteCallback(this);
392 ASSERT_EQ(1u, helper_->factory()->encoders().size());
393 helper_->factory()->encoders()[0]->set_supports_native_handle(true);
394 EXPECT_TRUE(adapter_->SupportsNativeHandle());
395 helper_->factory()->encoders()[0]->set_supports_native_handle(false);
396 EXPECT_FALSE(adapter_->SupportsNativeHandle());
397 }
398
TEST_F(TestSimulcastEncoderAdapterFake,SupportsNativeHandleDisabledForMultipleStreams)399 TEST_F(TestSimulcastEncoderAdapterFake,
400 SupportsNativeHandleDisabledForMultipleStreams) {
401 // TODO(pbos): Implement actual test (verify that it works) when implemented
402 // for multiple streams.
403 TestVp8Simulcast::DefaultSettings(
404 &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
405 codec_.numberOfSimulcastStreams = 3;
406 EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
407 adapter_->RegisterEncodeCompleteCallback(this);
408 ASSERT_EQ(3u, helper_->factory()->encoders().size());
409 for (MockVideoEncoder* encoder : helper_->factory()->encoders())
410 encoder->set_supports_native_handle(true);
411 EXPECT_FALSE(adapter_->SupportsNativeHandle());
412 }
413
414 } // namespace testing
415 } // namespace webrtc
416