Home | History | Annotate | Download | only in vp8
      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 
     22 static VP8Encoder* CreateTestEncoderAdapter() {
     23   VP8EncoderFactoryConfig::set_use_simulcast_adapter(true);
     24   return VP8Encoder::Create();
     25 }
     26 
     27 class TestSimulcastEncoderAdapter : public TestVp8Simulcast {
     28  public:
     29   TestSimulcastEncoderAdapter()
     30       : TestVp8Simulcast(CreateTestEncoderAdapter(), VP8Decoder::Create()) {}
     31 
     32  protected:
     33   virtual void SetUp() { TestVp8Simulcast::SetUp(); }
     34   virtual void TearDown() {
     35     TestVp8Simulcast::TearDown();
     36     VP8EncoderFactoryConfig::set_use_simulcast_adapter(false);
     37   }
     38 };
     39 
     40 TEST_F(TestSimulcastEncoderAdapter, TestKeyFrameRequestsOnAllStreams) {
     41   TestVp8Simulcast::TestKeyFrameRequestsOnAllStreams();
     42 }
     43 
     44 TEST_F(TestSimulcastEncoderAdapter, TestPaddingAllStreams) {
     45   TestVp8Simulcast::TestPaddingAllStreams();
     46 }
     47 
     48 TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreams) {
     49   TestVp8Simulcast::TestPaddingTwoStreams();
     50 }
     51 
     52 TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreamsOneMaxedOut) {
     53   TestVp8Simulcast::TestPaddingTwoStreamsOneMaxedOut();
     54 }
     55 
     56 TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStream) {
     57   TestVp8Simulcast::TestPaddingOneStream();
     58 }
     59 
     60 TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStreamTwoMaxedOut) {
     61   TestVp8Simulcast::TestPaddingOneStreamTwoMaxedOut();
     62 }
     63 
     64 TEST_F(TestSimulcastEncoderAdapter, TestSendAllStreams) {
     65   TestVp8Simulcast::TestSendAllStreams();
     66 }
     67 
     68 TEST_F(TestSimulcastEncoderAdapter, TestDisablingStreams) {
     69   TestVp8Simulcast::TestDisablingStreams();
     70 }
     71 
     72 TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneStream) {
     73   TestVp8Simulcast::TestSwitchingToOneStream();
     74 }
     75 
     76 TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneOddStream) {
     77   TestVp8Simulcast::TestSwitchingToOneOddStream();
     78 }
     79 
     80 TEST_F(TestSimulcastEncoderAdapter, TestRPSIEncodeDecode) {
     81   TestVp8Simulcast::TestRPSIEncodeDecode();
     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 // TODO(ronghuawu): Enable this test when SkipEncodingUnusedStreams option is
     97 // implemented for SimulcastEncoderAdapter.
     98 TEST_F(TestSimulcastEncoderAdapter, DISABLED_TestSkipEncodingUnusedStreams) {
     99   TestVp8Simulcast::TestSkipEncodingUnusedStreams();
    100 }
    101 
    102 TEST_F(TestSimulcastEncoderAdapter, DISABLED_TestRPSIEncoder) {
    103   TestVp8Simulcast::TestRPSIEncoder();
    104 }
    105 
    106 class MockVideoEncoder : public VideoEncoder {
    107  public:
    108   int32_t InitEncode(const VideoCodec* codecSettings,
    109                      int32_t numberOfCores,
    110                      size_t maxPayloadSize) override {
    111     codec_ = *codecSettings;
    112     return 0;
    113   }
    114 
    115   int32_t Encode(const VideoFrame& inputImage,
    116                  const CodecSpecificInfo* codecSpecificInfo,
    117                  const std::vector<FrameType>* frame_types) override {
    118     return 0;
    119   }
    120 
    121   int32_t RegisterEncodeCompleteCallback(
    122       EncodedImageCallback* callback) override {
    123     callback_ = callback;
    124     return 0;
    125   }
    126 
    127   int32_t Release() override { return 0; }
    128 
    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 
    135   bool SupportsNativeHandle() const override { return supports_native_handle_; }
    136 
    137   virtual ~MockVideoEncoder() {}
    138 
    139   const VideoCodec& codec() const { return codec_; }
    140 
    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 
    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:
    163   VideoEncoder* Create() override {
    164     MockVideoEncoder* encoder = new MockVideoEncoder();
    165     encoders_.push_back(encoder);
    166     return encoder;
    167   }
    168 
    169   void Destroy(VideoEncoder* encoder) override { delete encoder; }
    170 
    171   virtual ~MockVideoEncoderFactory() {}
    172 
    173   const std::vector<MockVideoEncoder*>& encoders() const { return encoders_; }
    174 
    175  private:
    176   std::vector<MockVideoEncoder*> encoders_;
    177 };
    178 
    179 class TestSimulcastEncoderAdapterFakeHelper {
    180  public:
    181   TestSimulcastEncoderAdapterFakeHelper()
    182       : factory_(new MockVideoEncoderFactory()) {}
    183 
    184   // Can only be called once as the SimulcastEncoderAdapter will take the
    185   // ownership of |factory_|.
    186   VP8Encoder* CreateMockEncoderAdapter() {
    187     return new SimulcastEncoderAdapter(factory_);
    188   }
    189 
    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 
    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:
    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) {}
    216   virtual ~TestSimulcastEncoderAdapterFake() {}
    217 
    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 
    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 
    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 
    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 
    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 
    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 
    339 TEST_F(TestSimulcastEncoderAdapterFake, InitEncode) {
    340   SetupCodec();
    341   VerifyCodecSettings();
    342 }
    343 
    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 
    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 
    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 
    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