text: /*
   *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
  
  #include <array>
  #include <memory>
  #include <vector>
  
  #include "api/video_codecs/sdp_video_format.h"
  #include "api/video_codecs/video_encoder_factory.h"
  #include "common_video/include/video_frame_buffer.h"
  #include "media/engine/internalencoderfactory.h"
  #include "media/engine/simulcast_encoder_adapter.h"
  #include "modules/video_coding/codecs/vp8/simulcast_test_utility.h"
  #include "modules/video_coding/include/video_codec_interface.h"
  #include "rtc_base/ptr_util.h"
  #include "test/gmock.h"
  
  namespace webrtc {
  namespace testing {
  
  class TestSimulcastEncoderAdapter : public TestVp8Simulcast {
   public:
    TestSimulcastEncoderAdapter() : factory_(new InternalEncoderFactory()) {}
  
   protected:
    std::unique_ptr<VP8Encoder> CreateEncoder() override {
      return rtc::MakeUnique<SimulcastEncoderAdapter>(factory_.get());
    }
    std::unique_ptr<VP8Decoder> CreateDecoder() override {
      return VP8Decoder::Create();
    }
  
   private:
    std::unique_ptr<VideoEncoderFactory> factory_;
  };
  
  TEST_F(TestSimulcastEncoderAdapter, TestKeyFrameRequestsOnAllStreams) {
    TestVp8Simulcast::TestKeyFrameRequestsOnAllStreams();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestPaddingAllStreams) {
    TestVp8Simulcast::TestPaddingAllStreams();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreams) {
    TestVp8Simulcast::TestPaddingTwoStreams();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreamsOneMaxedOut) {
    TestVp8Simulcast::TestPaddingTwoStreamsOneMaxedOut();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStream) {
    TestVp8Simulcast::TestPaddingOneStream();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStreamTwoMaxedOut) {
    TestVp8Simulcast::TestPaddingOneStreamTwoMaxedOut();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestSendAllStreams) {
    TestVp8Simulcast::TestSendAllStreams();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestDisablingStreams) {
    TestVp8Simulcast::TestDisablingStreams();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestActiveStreams) {
    TestVp8Simulcast::TestActiveStreams();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneStream) {
    TestVp8Simulcast::TestSwitchingToOneStream();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneOddStream) {
    TestVp8Simulcast::TestSwitchingToOneOddStream();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestStrideEncodeDecode) {
    TestVp8Simulcast::TestStrideEncodeDecode();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestSaptioTemporalLayers333PatternEncoder) {
    TestVp8Simulcast::TestSaptioTemporalLayers333PatternEncoder();
  }
  
  TEST_F(TestSimulcastEncoderAdapter, TestSpatioTemporalLayers321PatternEncoder) {
    TestVp8Simulcast::TestSpatioTemporalLayers321PatternEncoder();
  }
  
  class MockVideoEncoder;
  
  class MockVideoEncoderFactory : public VideoEncoderFactory {
   public:
    std::vector<SdpVideoFormat> GetSupportedFormats() const override;
  
    std::unique_ptr<VideoEncoder> CreateVideoEncoder(
        const SdpVideoFormat& format) override;
  
    CodecInfo QueryVideoEncoder(const SdpVideoFormat& format) const override;
  
    const std::vector<MockVideoEncoder*>& encoders() const;
    void SetEncoderNames(const std::vector<const char*>& encoder_names);
    void set_init_encode_return_value(int32_t value);
  
    void DestroyVideoEncoder(VideoEncoder* encoder);
  
   private:
    int32_t init_encode_return_value_ = 0;
    std::vector<MockVideoEncoder*> encoders_;
    std::vector<const char*> encoder_names_;
  };
  
  class MockVideoEncoder : public VideoEncoder {
   public:
    explicit MockVideoEncoder(MockVideoEncoderFactory* factory)
        : factory_(factory), callback_(nullptr) {}
  
    // TODO(nisse): Valid overrides commented out, because the gmock
    // methods don't use any override declarations, and we want to avoid
    // warnings from -Winconsistent-missing-override. See
    // http://crbug.com/428099.
    int32_t InitEncode(const VideoCodec* codecSettings,
                       int32_t numberOfCores,
                       size_t maxPayloadSize) /* override */ {
      codec_ = *codecSettings;
      return init_encode_return_value_;
    }
  
    MOCK_METHOD3(
        Encode,
        int32_t(const VideoFrame& inputImage,
                const CodecSpecificInfo* codecSpecificInfo,
                const std::vector<FrameType>* frame_types) /* override */);
  
    int32_t RegisterEncodeCompleteCallback(
        EncodedImageCallback* callback) /* override */ {
      callback_ = callback;
      return 0;
    }
  
    MOCK_METHOD0(Release, int32_t());
  
    int32_t SetRateAllocation(const BitrateAllocation& bitrate_allocation,
                              uint32_t framerate) {
      last_set_bitrate_ = bitrate_allocation;
      return 0;
    }
  
    MOCK_METHOD2(SetChannelParameters, int32_t(uint32_t packetLoss, int64_t rtt));
  
    bool SupportsNativeHandle() const /* override */ {
      return supports_native_handle_;
    }
  
    virtual ~MockVideoEncoder() { factory_->DestroyVideoEncoder(this); }
  
    const VideoCodec& codec() const { return codec_; }
  
    void SendEncodedImage(int width, int height) {
      // Sends a fake image of the given width/height.
      EncodedImage image;
      image._encodedWidth = width;
      image._encodedHeight = height;
      CodecSpecificInfo codec_specific_info;
      memset(&codec_specific_info, 0, sizeof(codec_specific_info));
      callback_->OnEncodedImage(image, &codec_specific_info, nullptr);
    }
  
    void set_supports_native_handle(bool enabled) {
      supports_native_handle_ = enabled;
    }
  
    void set_init_encode_return_value(int32_t value) {
      init_encode_return_value_ = value;
    }
  
    BitrateAllocation last_set_bitrate() const { return last_set_bitrate_; }
  
    MOCK_CONST_METHOD0(ImplementationName, const char*());
  
   private:
    MockVideoEncoderFactory* const factory_;
    bool supports_native_handle_ = false;
    int32_t init_encode_return_value_ = 0;
    BitrateAllocation last_set_bitrate_;
  
    VideoCodec codec_;
    EncodedImageCallback* callback_;
  };
  
  std::vector<SdpVideoFormat> MockVideoEncoderFactory::GetSupportedFormats()
      const {
    std::vector<SdpVideoFormat> formats = {SdpVideoFormat("VP8")};
    return formats;
  }
  
  std::unique_ptr<VideoEncoder> MockVideoEncoderFactory::CreateVideoEncoder(
      const SdpVideoFormat& format) {
    std::unique_ptr<MockVideoEncoder> encoder(
        new ::testing::NiceMock<MockVideoEncoder>(this));
    encoder->set_init_encode_return_value(init_encode_return_value_);
    const char* encoder_name = encoder_names_.empty()
                                   ? "codec_implementation_name"
                                   : encoder_names_[encoders_.size()];
    ON_CALL(*encoder, ImplementationName()).WillByDefault(Return(encoder_name));
    encoders_.push_back(encoder.get());
    return encoder;
  }
  
  void MockVideoEncoderFactory::DestroyVideoEncoder(VideoEncoder* encoder) {
    for (size_t i = 0; i < encoders_.size(); ++i) {
      if (encoders_[i] == encoder) {
        encoders_.erase(encoders_.begin() + i);
        break;
      }
    }
  }
  
  VideoEncoderFactory::CodecInfo MockVideoEncoderFactory::QueryVideoEncoder(
      const SdpVideoFormat& format) const {
    return CodecInfo();
  }
  
  const std::vector<MockVideoEncoder*>& MockVideoEncoderFactory::encoders()
      const {
    return encoders_;
  }
  void MockVideoEncoderFactory::SetEncoderNames(
      const std::vector<const char*>& encoder_names) {
    encoder_names_ = encoder_names;
  }
  void MockVideoEncoderFactory::set_init_encode_return_value(int32_t value) {
    init_encode_return_value_ = value;
  }
  
  class TestSimulcastEncoderAdapterFakeHelper {
   public:
    TestSimulcastEncoderAdapterFakeHelper()
        : factory_(new MockVideoEncoderFactory()) {}
  
    // Can only be called once as the SimulcastEncoderAdapter will take the
    // ownership of |factory_|.
    VP8Encoder* CreateMockEncoderAdapter() {
      return new SimulcastEncoderAdapter(factory_.get());
    }
  
    void ExpectCallSetChannelParameters(uint32_t packetLoss, int64_t rtt) {
      EXPECT_TRUE(!factory_->encoders().empty());
      for (size_t i = 0; i < factory_->encoders().size(); ++i) {
        EXPECT_CALL(*factory_->encoders()[i],
                    SetChannelParameters(packetLoss, rtt))
            .Times(1);
      }
    }
  
    MockVideoEncoderFactory* factory() { return factory_.get(); }
  
   private:
    std::unique_ptr<MockVideoEncoderFactory> factory_;
  };
  
  static const int kTestTemporalLayerProfile[3] = {3, 2, 1};
  
  class TestSimulcastEncoderAdapterFake : public ::testing::Test,
                                          public EncodedImageCallback {
   public:
    TestSimulcastEncoderAdapterFake()
        : helper_(new TestSimulcastEncoderAdapterFakeHelper()),
          adapter_(helper_->CreateMockEncoderAdapter()),
          last_encoded_image_width_(-1),
          last_encoded_image_height_(-1),
          last_encoded_image_simulcast_index_(-1) {}
    virtual ~TestSimulcastEncoderAdapterFake() {
      if (adapter_) {
        adapter_->Release();
      }
    }
  
    Result OnEncodedImage(const EncodedImage& encoded_image,
                          const CodecSpecificInfo* codec_specific_info,
                          const RTPFragmentationHeader* fragmentation) override {
      last_encoded_image_width_ = encoded_image._encodedWidth;
      last_encoded_image_height_ = encoded_image._encodedHeight;
      if (codec_specific_info) {
        last_encoded_image_simulcast_index_ =
            codec_specific_info->codecSpecific.VP8.simulcastIdx;
      }
      return Result(Result::OK, encoded_image._timeStamp);
    }
  
    bool GetLastEncodedImageInfo(int* out_width,
                                 int* out_height,
                                 int* out_simulcast_index) {
      if (last_encoded_image_width_ == -1) {
        return false;
      }
      *out_width = last_encoded_image_width_;
      *out_height = last_encoded_image_height_;
      *out_simulcast_index = last_encoded_image_simulcast_index_;
      return true;
    }
  
    void SetupCodec() {
      TestVp8Simulcast::DefaultSettings(
          &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
      rate_allocator_.reset(new SimulcastRateAllocator(codec_));
      EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
      adapter_->RegisterEncodeCompleteCallback(this);
    }
  
    void VerifyCodec(const VideoCodec& ref, int stream_index) {
      const VideoCodec& target =
          helper_->factory()->encoders()[stream_index]->codec();
      EXPECT_EQ(ref.codecType, target.codecType);
      EXPECT_EQ(ref.plType, target.plType);
      EXPECT_EQ(ref.width, target.width);
      EXPECT_EQ(ref.height, target.height);
      EXPECT_EQ(ref.startBitrate, target.startBitrate);
      EXPECT_EQ(ref.maxBitrate, target.maxBitrate);
      EXPECT_EQ(ref.minBitrate, target.minBitrate);
      EXPECT_EQ(ref.maxFramerate, target.maxFramerate);
      EXPECT_EQ(ref.VP8().complexity, target.VP8().complexity);
      EXPECT_EQ(ref.VP8().resilience, target.VP8().resilience);
      EXPECT_EQ(ref.VP8().numberOfTemporalLayers,
                target.VP8().numberOfTemporalLayers);
      EXPECT_EQ(ref.VP8().denoisingOn, target.VP8().denoisingOn);
      EXPECT_EQ(ref.VP8().automaticResizeOn, target.VP8().automaticResizeOn);
      EXPECT_EQ(ref.VP8().frameDroppingOn, target.VP8().frameDroppingOn);
      EXPECT_EQ(ref.VP8().keyFrameInterval, target.VP8().keyFrameInterval);
      EXPECT_EQ(ref.qpMax, target.qpMax);
      EXPECT_EQ(0, target.numberOfSimulcastStreams);
      EXPECT_EQ(ref.mode, target.mode);
  
      // No need to compare simulcastStream as numberOfSimulcastStreams should
      // always be 0.
    }
  
    void InitRefCodec(int stream_index, VideoCodec* ref_codec) {
      *ref_codec = codec_;
      ref_codec->VP8()->numberOfTemporalLayers =
          kTestTemporalLayerProfile[stream_index];
      ref_codec->width = codec_.simulcastStream[stream_index].width;
      ref_codec->height = codec_.simulcastStream[stream_index].height;
      ref_codec->maxBitrate = codec_.simulcastStream[stream_index].maxBitrate;
      ref_codec->minBitrate = codec_.simulcastStream[stream_index].minBitrate;
      ref_codec->qpMax = codec_.simulcastStream[stream_index].qpMax;
    }
  
    void VerifyCodecSettings() {
      EXPECT_EQ(3u, helper_->factory()->encoders().size());
      VideoCodec ref_codec;
  
      // stream 0, the lowest resolution stream.
      InitRefCodec(0, &ref_codec);
      ref_codec.qpMax = 45;
      ref_codec.VP8()->complexity = webrtc::kComplexityHigher;
      ref_codec.VP8()->denoisingOn = false;
      ref_codec.startBitrate = 100;  // Should equal to the target bitrate.
      VerifyCodec(ref_codec, 0);
  
      // stream 1
      InitRefCodec(1, &ref_codec);
      ref_codec.VP8()->denoisingOn = false;
      // The start bitrate (300kbit) minus what we have for the lower layers
      // (100kbit).
      ref_codec.startBitrate = 200;
      VerifyCodec(ref_codec, 1);
  
      // stream 2, the biggest resolution stream.
      InitRefCodec(2, &ref_codec);
      // We don't have enough bits to send this, so the adapter should have
      // configured it to use the min bitrate for this layer (600kbit) but turn
      // off sending.
      ref_codec.startBitrate = 600;
      VerifyCodec(ref_codec, 2);
    }
  
   protected:
    std::unique_ptr<TestSimulcastEncoderAdapterFakeHelper> helper_;
    std::unique_ptr<VP8Encoder> adapter_;
    VideoCodec codec_;
    int last_encoded_image_width_;
    int last_encoded_image_height_;
    int last_encoded_image_simulcast_index_;
    std::unique_ptr<SimulcastRateAllocator> rate_allocator_;
  };
  
  TEST_F(TestSimulcastEncoderAdapterFake, InitEncode) {
    SetupCodec();
    VerifyCodecSettings();
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake, ReleaseWithoutInitEncode) {
    EXPECT_EQ(0, adapter_->Release());
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake, Reinit) {
    SetupCodec();
    EXPECT_EQ(0, adapter_->Release());
  
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake, SetChannelParameters) {
    SetupCodec();
    const uint32_t packetLoss = 5;
    const int64_t rtt = 30;
    helper_->ExpectCallSetChannelParameters(packetLoss, rtt);
    adapter_->SetChannelParameters(packetLoss, rtt);
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake, EncodedCallbackForDifferentEncoders) {
    SetupCodec();
  
    // Set bitrates so that we send all layers.
    adapter_->SetRateAllocation(rate_allocator_->GetAllocation(1200, 30), 30);
  
    // At this point, the simulcast encoder adapter should have 3 streams: HD,
    // quarter HD, and quarter quarter HD. We're going to mostly ignore the exact
    // resolutions, to test that the adapter forwards on the correct resolution
    // and simulcast index values, going only off the encoder that generates the
    // image.
    std::vector<MockVideoEncoder*> encoders = helper_->factory()->encoders();
    ASSERT_EQ(3u, encoders.size());
    encoders[0]->SendEncodedImage(1152, 704);
    int width;
    int height;
    int simulcast_index;
    EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
    EXPECT_EQ(1152, width);
    EXPECT_EQ(704, height);
    EXPECT_EQ(0, simulcast_index);
  
    encoders[1]->SendEncodedImage(300, 620);
    EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
    EXPECT_EQ(300, width);
    EXPECT_EQ(620, height);
    EXPECT_EQ(1, simulcast_index);
  
    encoders[2]->SendEncodedImage(120, 240);
    EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
    EXPECT_EQ(120, width);
    EXPECT_EQ(240, height);
    EXPECT_EQ(2, simulcast_index);
  }
  
  // This test verifies that the underlying encoders are reused, when the adapter
  // is reinited with different number of simulcast streams. It further checks
  // that the allocated encoders are reused in the same order as before, starting
  // with the lowest stream.
  TEST_F(TestSimulcastEncoderAdapterFake, ReusesEncodersInOrder) {
    // Set up common settings for three streams.
    TestVp8Simulcast::DefaultSettings(
        &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
    rate_allocator_.reset(new SimulcastRateAllocator(codec_));
    adapter_->RegisterEncodeCompleteCallback(this);
  
    // Input data.
    rtc::scoped_refptr<VideoFrameBuffer> buffer(I420Buffer::Create(1280, 720));
    VideoFrame input_frame(buffer, 100, 1000, kVideoRotation_180);
    std::vector<FrameType> frame_types;
  
    // Encode with three streams.
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    VerifyCodecSettings();
    std::vector<MockVideoEncoder*> original_encoders =
        helper_->factory()->encoders();
    ASSERT_EQ(3u, original_encoders.size());
    EXPECT_CALL(*original_encoders[0], Encode(_, _, _))
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_CALL(*original_encoders[1], Encode(_, _, _))
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_CALL(*original_encoders[2], Encode(_, _, _))
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    frame_types.resize(3, kVideoFrameKey);
    EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types));
    EXPECT_CALL(*original_encoders[0], Release())
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_CALL(*original_encoders[1], Release())
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_CALL(*original_encoders[2], Release())
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_EQ(0, adapter_->Release());
  
    // Encode with two streams.
    codec_.width /= 2;
    codec_.height /= 2;
    codec_.numberOfSimulcastStreams = 2;
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    std::vector<MockVideoEncoder*> new_encoders = helper_->factory()->encoders();
    ASSERT_EQ(2u, new_encoders.size());
    ASSERT_EQ(original_encoders[0], new_encoders[0]);
    EXPECT_CALL(*original_encoders[0], Encode(_, _, _))
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    ASSERT_EQ(original_encoders[1], new_encoders[1]);
    EXPECT_CALL(*original_encoders[1], Encode(_, _, _))
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    frame_types.resize(2, kVideoFrameKey);
    EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types));
    EXPECT_CALL(*original_encoders[0], Release())
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_CALL(*original_encoders[1], Release())
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_EQ(0, adapter_->Release());
  
    // Encode with single stream.
    codec_.width /= 2;
    codec_.height /= 2;
    codec_.numberOfSimulcastStreams = 1;
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    new_encoders = helper_->factory()->encoders();
    ASSERT_EQ(1u, new_encoders.size());
    ASSERT_EQ(original_encoders[0], new_encoders[0]);
    EXPECT_CALL(*original_encoders[0], Encode(_, _, _))
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    frame_types.resize(1, kVideoFrameKey);
    EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types));
    EXPECT_CALL(*original_encoders[0], Release())
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_EQ(0, adapter_->Release());
  
    // Encode with three streams, again.
    codec_.width *= 4;
    codec_.height *= 4;
    codec_.numberOfSimulcastStreams = 3;
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    new_encoders = helper_->factory()->encoders();
    ASSERT_EQ(3u, new_encoders.size());
    // The first encoder is reused.
    ASSERT_EQ(original_encoders[0], new_encoders[0]);
    EXPECT_CALL(*original_encoders[0], Encode(_, _, _))
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    // The second and third encoders are new.
    EXPECT_CALL(*new_encoders[1], Encode(_, _, _))
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_CALL(*new_encoders[2], Encode(_, _, _))
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    frame_types.resize(3, kVideoFrameKey);
    EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types));
    EXPECT_CALL(*original_encoders[0], Release())
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_CALL(*new_encoders[1], Release())
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_CALL(*new_encoders[2], Release())
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
    EXPECT_EQ(0, adapter_->Release());
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake, DoesNotLeakEncoders) {
    SetupCodec();
    VerifyCodecSettings();
  
    EXPECT_EQ(3u, helper_->factory()->encoders().size());
  
    // The adapter should destroy all encoders it has allocated. Since
    // |helper_->factory()| is owned by |adapter_|, however, we need to rely on
    // lsan to find leaks here.
    EXPECT_EQ(0, adapter_->Release());
    adapter_.reset();
  }
  
  // This test verifies that an adapter reinit with the same codec settings as
  // before does not change the underlying encoder codec settings.
  TEST_F(TestSimulcastEncoderAdapterFake, ReinitDoesNotReorderEncoderSettings) {
    SetupCodec();
    VerifyCodecSettings();
  
    // Capture current codec settings.
    std::vector<MockVideoEncoder*> encoders = helper_->factory()->encoders();
    ASSERT_EQ(3u, encoders.size());
    std::array<VideoCodec, 3> codecs_before;
    for (int i = 0; i < 3; ++i) {
      codecs_before[i] = encoders[i]->codec();
    }
  
    // Reinitialize and verify that the new codec settings are the same.
    EXPECT_EQ(0, adapter_->Release());
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    for (int i = 0; i < 3; ++i) {
      const VideoCodec& codec_before = codecs_before[i];
      const VideoCodec& codec_after = encoders[i]->codec();
  
      // webrtc::VideoCodec does not implement operator==.
      EXPECT_EQ(codec_before.codecType, codec_after.codecType);
      EXPECT_EQ(codec_before.plType, codec_after.plType);
      EXPECT_EQ(codec_before.width, codec_after.width);
      EXPECT_EQ(codec_before.height, codec_after.height);
      EXPECT_EQ(codec_before.startBitrate, codec_after.startBitrate);
      EXPECT_EQ(codec_before.maxBitrate, codec_after.maxBitrate);
      EXPECT_EQ(codec_before.minBitrate, codec_after.minBitrate);
      EXPECT_EQ(codec_before.targetBitrate, codec_after.targetBitrate);
      EXPECT_EQ(codec_before.maxFramerate, codec_after.maxFramerate);
      EXPECT_EQ(codec_before.qpMax, codec_after.qpMax);
      EXPECT_EQ(codec_before.numberOfSimulcastStreams,
                codec_after.numberOfSimulcastStreams);
      EXPECT_EQ(codec_before.mode, codec_after.mode);
      EXPECT_EQ(codec_before.expect_encode_from_texture,
                codec_after.expect_encode_from_texture);
    }
  }
  
  // This test is similar to the one above, except that it tests the simulcastIdx
  // from the CodecSpecificInfo that is connected to an encoded frame. The
  // PayloadRouter demuxes the incoming encoded frames on different RTP modules
  // using the simulcastIdx, so it's important that there is no corresponding
  // encoder reordering in between adapter reinits as this would lead to PictureID
  // discontinuities.
  TEST_F(TestSimulcastEncoderAdapterFake, ReinitDoesNotReorderFrameSimulcastIdx) {
    SetupCodec();
    adapter_->SetRateAllocation(rate_allocator_->GetAllocation(1200, 30), 30);
    VerifyCodecSettings();
  
    // Send frames on all streams.
    std::vector<MockVideoEncoder*> encoders = helper_->factory()->encoders();
    ASSERT_EQ(3u, encoders.size());
    encoders[0]->SendEncodedImage(1152, 704);
    int width;
    int height;
    int simulcast_index;
    EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
    EXPECT_EQ(0, simulcast_index);
  
    encoders[1]->SendEncodedImage(300, 620);
    EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
    EXPECT_EQ(1, simulcast_index);
  
    encoders[2]->SendEncodedImage(120, 240);
    EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
    EXPECT_EQ(2, simulcast_index);
  
    // Reinitialize.
    EXPECT_EQ(0, adapter_->Release());
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    adapter_->SetRateAllocation(rate_allocator_->GetAllocation(1200, 30), 30);
  
    // Verify that the same encoder sends out frames on the same simulcast index.
    encoders[0]->SendEncodedImage(1152, 704);
    EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
    EXPECT_EQ(0, simulcast_index);
  
    encoders[1]->SendEncodedImage(300, 620);
    EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
    EXPECT_EQ(1, simulcast_index);
  
    encoders[2]->SendEncodedImage(120, 240);
    EXPECT_TRUE(GetLastEncodedImageInfo(&width, &height, &simulcast_index));
    EXPECT_EQ(2, simulcast_index);
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake, SupportsNativeHandleForSingleStreams) {
    TestVp8Simulcast::DefaultSettings(
        &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
    codec_.numberOfSimulcastStreams = 1;
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    adapter_->RegisterEncodeCompleteCallback(this);
    ASSERT_EQ(1u, helper_->factory()->encoders().size());
    helper_->factory()->encoders()[0]->set_supports_native_handle(true);
    EXPECT_TRUE(adapter_->SupportsNativeHandle());
    helper_->factory()->encoders()[0]->set_supports_native_handle(false);
    EXPECT_FALSE(adapter_->SupportsNativeHandle());
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake, SetRatesUnderMinBitrate) {
    TestVp8Simulcast::DefaultSettings(
        &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
    codec_.minBitrate = 50;
    codec_.numberOfSimulcastStreams = 1;
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    rate_allocator_.reset(new SimulcastRateAllocator(codec_));
  
    // Above min should be respected.
    BitrateAllocation target_bitrate =
        rate_allocator_->GetAllocation(codec_.minBitrate * 1000, 30);
    adapter_->SetRateAllocation(target_bitrate, 30);
    EXPECT_EQ(target_bitrate,
              helper_->factory()->encoders()[0]->last_set_bitrate());
  
    // Below min but non-zero should be replaced with the min bitrate.
    BitrateAllocation too_low_bitrate =
        rate_allocator_->GetAllocation((codec_.minBitrate - 1) * 1000, 30);
    adapter_->SetRateAllocation(too_low_bitrate, 30);
    EXPECT_EQ(target_bitrate,
              helper_->factory()->encoders()[0]->last_set_bitrate());
  
    // Zero should be passed on as is, since it means "pause".
    adapter_->SetRateAllocation(BitrateAllocation(), 30);
    EXPECT_EQ(BitrateAllocation(),
              helper_->factory()->encoders()[0]->last_set_bitrate());
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake, SupportsImplementationName) {
    EXPECT_STREQ("SimulcastEncoderAdapter", adapter_->ImplementationName());
    TestVp8Simulcast::DefaultSettings(
        &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
    std::vector<const char*> encoder_names;
    encoder_names.push_back("codec1");
    encoder_names.push_back("codec2");
    encoder_names.push_back("codec3");
    helper_->factory()->SetEncoderNames(encoder_names);
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    EXPECT_STREQ("SimulcastEncoderAdapter (codec1, codec2, codec3)",
                 adapter_->ImplementationName());
  
    // Single streams should not expose "SimulcastEncoderAdapter" in name.
    EXPECT_EQ(0, adapter_->Release());
    codec_.numberOfSimulcastStreams = 1;
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    adapter_->RegisterEncodeCompleteCallback(this);
    ASSERT_EQ(1u, helper_->factory()->encoders().size());
    EXPECT_STREQ("codec1", adapter_->ImplementationName());
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake,
         SupportsNativeHandleForMultipleStreams) {
    TestVp8Simulcast::DefaultSettings(
        &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
    codec_.numberOfSimulcastStreams = 3;
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    adapter_->RegisterEncodeCompleteCallback(this);
    ASSERT_EQ(3u, helper_->factory()->encoders().size());
    for (MockVideoEncoder* encoder : helper_->factory()->encoders())
      encoder->set_supports_native_handle(true);
    // If one encoder doesn't support it, then overall support is disabled.
    helper_->factory()->encoders()[0]->set_supports_native_handle(false);
    EXPECT_FALSE(adapter_->SupportsNativeHandle());
    // Once all do, then the adapter claims support.
    helper_->factory()->encoders()[0]->set_supports_native_handle(true);
    EXPECT_TRUE(adapter_->SupportsNativeHandle());
  }
  
  // TODO(nisse): Reuse definition in webrtc/test/fake_texture_handle.h.
  class FakeNativeBuffer : public VideoFrameBuffer {
   public:
    FakeNativeBuffer(int width, int height) : width_(width), height_(height) {}
  
    Type type() const override { return Type::kNative; }
    int width() const override { return width_; }
    int height() const override { return height_; }
  
    rtc::scoped_refptr<I420BufferInterface> ToI420() override {
      RTC_NOTREACHED();
      return nullptr;
    }
  
   private:
    const int width_;
    const int height_;
  };
  
  TEST_F(TestSimulcastEncoderAdapterFake,
         NativeHandleForwardingForMultipleStreams) {
    TestVp8Simulcast::DefaultSettings(
        &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
    codec_.numberOfSimulcastStreams = 3;
    // High start bitrate, so all streams are enabled.
    codec_.startBitrate = 3000;
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    adapter_->RegisterEncodeCompleteCallback(this);
    ASSERT_EQ(3u, helper_->factory()->encoders().size());
    for (MockVideoEncoder* encoder : helper_->factory()->encoders())
      encoder->set_supports_native_handle(true);
    EXPECT_TRUE(adapter_->SupportsNativeHandle());
  
    rtc::scoped_refptr<VideoFrameBuffer> buffer(
        new rtc::RefCountedObject<FakeNativeBuffer>(1280, 720));
    VideoFrame input_frame(buffer, 100, 1000, kVideoRotation_180);
    // Expect calls with the given video frame verbatim, since it's a texture
    // frame and can't otherwise be modified/resized.
    for (MockVideoEncoder* encoder : helper_->factory()->encoders())
      EXPECT_CALL(*encoder, Encode(::testing::Ref(input_frame), _, _)).Times(1);
    std::vector<FrameType> frame_types(3, kVideoFrameKey);
    EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types));
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake, TestFailureReturnCodesFromEncodeCalls) {
    TestVp8Simulcast::DefaultSettings(
        &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
    codec_.numberOfSimulcastStreams = 3;
    EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
    adapter_->RegisterEncodeCompleteCallback(this);
    ASSERT_EQ(3u, helper_->factory()->encoders().size());
    // Tell the 2nd encoder to request software fallback.
    EXPECT_CALL(*helper_->factory()->encoders()[1], Encode(_, _, _))
        .WillOnce(Return(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE));
  
    // Send a fake frame and assert the return is software fallback.
    rtc::scoped_refptr<I420Buffer> input_buffer =
        I420Buffer::Create(kDefaultWidth, kDefaultHeight);
    input_buffer->InitializeData();
    VideoFrame input_frame(input_buffer, 0, 0, webrtc::kVideoRotation_0);
    std::vector<FrameType> frame_types(3, kVideoFrameKey);
    EXPECT_EQ(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE,
              adapter_->Encode(input_frame, nullptr, &frame_types));
  }
  
  TEST_F(TestSimulcastEncoderAdapterFake, TestInitFailureCleansUpEncoders) {
    TestVp8Simulcast::DefaultSettings(
        &codec_, static_cast<const int*>(kTestTemporalLayerProfile));
    codec_.numberOfSimulcastStreams = 3;
    helper_->factory()->set_init_encode_return_value(
        WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE);
    EXPECT_EQ(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE,
              adapter_->InitEncode(&codec_, 1, 1200));
    EXPECT_TRUE(helper_->factory()->encoders().empty());
  }
  
  }  // namespace testing
  }  // namespace webrtc
  