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