/*
 *  Copyright (c) 2013 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 <algorithm>  // max
#include <memory>
#include <vector>

#include "webrtc/base/bind.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/event.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/platform_thread.h"
#include "webrtc/base/rate_limiter.h"
#include "webrtc/call/call.h"
#include "webrtc/common_video/include/frame_callback.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h"
#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
#include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
#include "webrtc/system_wrappers/include/sleep.h"
#include "webrtc/test/call_test.h"
#include "webrtc/test/configurable_frame_size_encoder.h"
#include "webrtc/test/fake_texture_frame.h"
#include "webrtc/test/frame_generator.h"
#include "webrtc/test/frame_utils.h"
#include "webrtc/test/gtest.h"
#include "webrtc/test/null_transport.h"
#include "webrtc/test/rtcp_packet_parser.h"
#include "webrtc/test/testsupport/perf_test.h"
#include "webrtc/test/field_trial.h"

#include "webrtc/video/send_statistics_proxy.h"
#include "webrtc/video/transport_adapter.h"
#include "webrtc/video_frame.h"
#include "webrtc/video_send_stream.h"

namespace webrtc {

enum VideoFormat { kGeneric, kVP8, };

void ExpectEqualFramesVector(const std::vector<VideoFrame>& frames1,
                             const std::vector<VideoFrame>& frames2);
VideoFrame CreateVideoFrame(int width, int height, uint8_t data);

class VideoSendStreamTest : public test::CallTest {
 protected:
  void TestNackRetransmission(uint32_t retransmit_ssrc,
                              uint8_t retransmit_payload_type);
  void TestPacketFragmentationSize(VideoFormat format, bool with_fec);

  void TestVp9NonFlexMode(uint8_t num_temporal_layers,
                          uint8_t num_spatial_layers);

  void TestRequestSourceRotateVideo(bool support_orientation_ext);
};

TEST_F(VideoSendStreamTest, CanStartStartedStream) {
  CreateSenderCall(Call::Config(&event_log_));

  test::NullTransport transport;
  CreateSendConfig(1, 0, 0, &transport);
  CreateVideoStreams();
  video_send_stream_->Start();
  video_send_stream_->Start();
  DestroyStreams();
}

TEST_F(VideoSendStreamTest, CanStopStoppedStream) {
  CreateSenderCall(Call::Config(&event_log_));

  test::NullTransport transport;
  CreateSendConfig(1, 0, 0, &transport);
  CreateVideoStreams();
  video_send_stream_->Stop();
  video_send_stream_->Stop();
  DestroyStreams();
}

TEST_F(VideoSendStreamTest, SupportsCName) {
  static std::string kCName = "PjQatC14dGfbVwGPUOA9IH7RlsFDbWl4AhXEiDsBizo=";
  class CNameObserver : public test::SendTest {
   public:
    CNameObserver() : SendTest(kDefaultTimeoutMs) {}

   private:
    Action OnSendRtcp(const uint8_t* packet, size_t length) override {
      test::RtcpPacketParser parser;
      EXPECT_TRUE(parser.Parse(packet, length));
      if (parser.sdes()->num_packets() > 0) {
        EXPECT_EQ(1u, parser.sdes()->chunks().size());
        EXPECT_EQ(kCName, parser.sdes()->chunks()[0].cname);

        observation_complete_.Set();
      }

      return SEND_PACKET;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->rtp.c_name = kCName;
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait()) << "Timed out while waiting for RTCP with CNAME.";
    }
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, SupportsAbsoluteSendTime) {
  class AbsoluteSendTimeObserver : public test::SendTest {
   public:
    AbsoluteSendTimeObserver() : SendTest(kDefaultTimeoutMs) {
      EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
          kRtpExtensionAbsoluteSendTime, test::kAbsSendTimeExtensionId));
    }

    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      RTPHeader header;
      EXPECT_TRUE(parser_->Parse(packet, length, &header));

      EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
      EXPECT_TRUE(header.extension.hasAbsoluteSendTime);
      EXPECT_EQ(header.extension.transmissionTimeOffset, 0);
      if (header.extension.absoluteSendTime != 0) {
        // Wait for at least one packet with a non-zero send time. The send time
        // is a 16-bit value derived from the system clock, and it is valid
        // for a packet to have a zero send time. To tell that from an
        // unpopulated value we'll wait for a packet with non-zero send time.
        observation_complete_.Set();
      } else {
        LOG(LS_WARNING) << "Got a packet with zero absoluteSendTime, waiting"
                           " for another packet...";
      }

      return SEND_PACKET;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->rtp.extensions.clear();
      send_config->rtp.extensions.push_back(RtpExtension(
          RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait()) << "Timed out while waiting for single RTP packet.";
    }
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, SupportsTransmissionTimeOffset) {
  static const int kEncodeDelayMs = 5;
  class TransmissionTimeOffsetObserver : public test::SendTest {
   public:
    TransmissionTimeOffsetObserver()
        : SendTest(kDefaultTimeoutMs),
          encoder_(Clock::GetRealTimeClock(), kEncodeDelayMs) {
      EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
          kRtpExtensionTransmissionTimeOffset, test::kTOffsetExtensionId));
    }

   private:
    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      RTPHeader header;
      EXPECT_TRUE(parser_->Parse(packet, length, &header));

      EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
      EXPECT_FALSE(header.extension.hasAbsoluteSendTime);
      EXPECT_GT(header.extension.transmissionTimeOffset, 0);
      EXPECT_EQ(header.extension.absoluteSendTime, 0u);
      observation_complete_.Set();

      return SEND_PACKET;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->encoder_settings.encoder = &encoder_;
      send_config->rtp.extensions.clear();
      send_config->rtp.extensions.push_back(RtpExtension(
          RtpExtension::kTimestampOffsetUri, test::kTOffsetExtensionId));
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait()) << "Timed out while waiting for a single RTP packet.";
    }

    test::DelayedEncoder encoder_;
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, SupportsTransportWideSequenceNumbers) {
  static const uint8_t kExtensionId = test::kTransportSequenceNumberExtensionId;
  class TransportWideSequenceNumberObserver : public test::SendTest {
   public:
    TransportWideSequenceNumberObserver()
        : SendTest(kDefaultTimeoutMs), encoder_(Clock::GetRealTimeClock()) {
      EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
          kRtpExtensionTransportSequenceNumber, kExtensionId));
    }

   private:
    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      RTPHeader header;
      EXPECT_TRUE(parser_->Parse(packet, length, &header));

      EXPECT_TRUE(header.extension.hasTransportSequenceNumber);
      EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
      EXPECT_FALSE(header.extension.hasAbsoluteSendTime);

      observation_complete_.Set();

      return SEND_PACKET;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->encoder_settings.encoder = &encoder_;
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait()) << "Timed out while waiting for a single RTP packet.";
    }

    test::FakeEncoder encoder_;
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, SupportsVideoRotation) {
  class VideoRotationObserver : public test::SendTest {
   public:
    VideoRotationObserver() : SendTest(kDefaultTimeoutMs) {
      EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
          kRtpExtensionVideoRotation, test::kVideoRotationExtensionId));
    }

    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      RTPHeader header;
      EXPECT_TRUE(parser_->Parse(packet, length, &header));
      EXPECT_TRUE(header.extension.hasVideoRotation);
      EXPECT_EQ(kVideoRotation_90, header.extension.videoRotation);
      observation_complete_.Set();
      return SEND_PACKET;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->rtp.extensions.clear();
      send_config->rtp.extensions.push_back(RtpExtension(
          RtpExtension::kVideoRotationUri, test::kVideoRotationExtensionId));
    }

    void OnFrameGeneratorCapturerCreated(
        test::FrameGeneratorCapturer* frame_generator_capturer) override {
      frame_generator_capturer->SetFakeRotation(kVideoRotation_90);
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait()) << "Timed out while waiting for single RTP packet.";
    }
  } test;

  RunBaseTest(&test);
}

class FakeReceiveStatistics : public NullReceiveStatistics {
 public:
  FakeReceiveStatistics(uint32_t send_ssrc,
                        uint32_t last_sequence_number,
                        uint32_t cumulative_lost,
                        uint8_t fraction_lost)
      : lossy_stats_(new LossyStatistician(last_sequence_number,
                                           cumulative_lost,
                                           fraction_lost)) {
    stats_map_[send_ssrc] = lossy_stats_.get();
  }

  StatisticianMap GetActiveStatisticians() const override { return stats_map_; }

  StreamStatistician* GetStatistician(uint32_t ssrc) const override {
    return lossy_stats_.get();
  }

 private:
  class LossyStatistician : public StreamStatistician {
   public:
    LossyStatistician(uint32_t extended_max_sequence_number,
                      uint32_t cumulative_lost,
                      uint8_t fraction_lost) {
      stats_.fraction_lost = fraction_lost;
      stats_.cumulative_lost = cumulative_lost;
      stats_.extended_max_sequence_number = extended_max_sequence_number;
    }
    bool GetStatistics(RtcpStatistics* statistics, bool reset) override {
      *statistics = stats_;
      return true;
    }
    void GetDataCounters(size_t* bytes_received,
                         uint32_t* packets_received) const override {
      *bytes_received = 0;
      *packets_received = 0;
    }
    void GetReceiveStreamDataCounters(
        StreamDataCounters* data_counters) const override {}
    uint32_t BitrateReceived() const override { return 0; }
    bool IsRetransmitOfOldPacket(const RTPHeader& header,
                                 int64_t min_rtt) const override {
      return false;
    }

    bool IsPacketInOrder(uint16_t sequence_number) const override {
      return true;
    }

    RtcpStatistics stats_;
  };

  std::unique_ptr<LossyStatistician> lossy_stats_;
  StatisticianMap stats_map_;
};

class UlpfecObserver : public test::EndToEndTest {
 public:
  UlpfecObserver(bool header_extensions_enabled,
                 bool use_nack,
                 bool expect_red,
                 bool expect_ulpfec,
                 const std::string& codec,
                 VideoEncoder* encoder)
      : EndToEndTest(kTimeoutMs),
        encoder_(encoder),
        payload_name_(codec),
        use_nack_(use_nack),
        expect_red_(expect_red),
        expect_ulpfec_(expect_ulpfec),
        sent_media_(false),
        sent_ulpfec_(false),
        header_extensions_enabled_(header_extensions_enabled) {}

  // Some of the test cases are expected to time out and thus we are using
  // a shorter timeout window than the default here.
  static constexpr size_t kTimeoutMs = 10000;

 private:
  Action OnSendRtp(const uint8_t* packet, size_t length) override {
    RTPHeader header;
    EXPECT_TRUE(parser_->Parse(packet, length, &header));

    int encapsulated_payload_type = -1;
    if (header.payloadType == VideoSendStreamTest::kRedPayloadType) {
      EXPECT_TRUE(expect_red_);
      encapsulated_payload_type = static_cast<int>(packet[header.headerLength]);
      if (encapsulated_payload_type !=
          VideoSendStreamTest::kFakeVideoSendPayloadType) {
        EXPECT_EQ(VideoSendStreamTest::kUlpfecPayloadType,
                  encapsulated_payload_type);
      }
    } else {
      EXPECT_EQ(VideoSendStreamTest::kFakeVideoSendPayloadType,
                header.payloadType);
      if (static_cast<size_t>(header.headerLength + header.paddingLength) <
          length) {
        // Not padding-only, media received outside of RED.
        EXPECT_FALSE(expect_red_);
        sent_media_ = true;
      }
    }

    if (header_extensions_enabled_) {
      EXPECT_TRUE(header.extension.hasAbsoluteSendTime);
      uint32_t kHalf24BitsSpace = 0xFFFFFF / 2;
      if (header.extension.absoluteSendTime <= kHalf24BitsSpace &&
          prev_header_.extension.absoluteSendTime > kHalf24BitsSpace) {
        // 24 bits wrap.
        EXPECT_GT(prev_header_.extension.absoluteSendTime,
                  header.extension.absoluteSendTime);
      } else {
        EXPECT_GE(header.extension.absoluteSendTime,
                  prev_header_.extension.absoluteSendTime);
      }
      EXPECT_TRUE(header.extension.hasTransportSequenceNumber);
      uint16_t seq_num_diff = header.extension.transportSequenceNumber -
                              prev_header_.extension.transportSequenceNumber;
      EXPECT_EQ(1, seq_num_diff);
    }

    if (encapsulated_payload_type != -1) {
      if (encapsulated_payload_type ==
          VideoSendStreamTest::kUlpfecPayloadType) {
        EXPECT_TRUE(expect_ulpfec_);
        sent_ulpfec_ = true;
      } else {
        sent_media_ = true;
      }
    }

    if (sent_media_ && sent_ulpfec_) {
      observation_complete_.Set();
    }

    prev_header_ = header;

    return SEND_PACKET;
  }

  test::PacketTransport* CreateSendTransport(Call* sender_call) override {
    // At low RTT (< kLowRttNackMs) -> NACK only, no FEC.
    // Configure some network delay.
    const int kNetworkDelayMs = 100;
    FakeNetworkPipe::Config config;
    config.loss_percent = 5;
    config.queue_delay_ms = kNetworkDelayMs;
    return new test::PacketTransport(sender_call, this,
                                     test::PacketTransport::kSender, config);
  }

  void ModifyVideoConfigs(
      VideoSendStream::Config* send_config,
      std::vector<VideoReceiveStream::Config>* receive_configs,
      VideoEncoderConfig* encoder_config) override {
    if (use_nack_) {
      send_config->rtp.nack.rtp_history_ms =
          (*receive_configs)[0].rtp.nack.rtp_history_ms =
              VideoSendStreamTest::kNackRtpHistoryMs;
    }
    send_config->encoder_settings.encoder = encoder_;
    send_config->encoder_settings.payload_name = payload_name_;
    send_config->rtp.ulpfec.red_payload_type =
        VideoSendStreamTest::kRedPayloadType;
    send_config->rtp.ulpfec.ulpfec_payload_type =
        VideoSendStreamTest::kUlpfecPayloadType;
    EXPECT_FALSE(send_config->rtp.extensions.empty());
    if (!header_extensions_enabled_) {
      send_config->rtp.extensions.clear();
    } else {
      send_config->rtp.extensions.push_back(RtpExtension(
          RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
    }
    (*receive_configs)[0].rtp.ulpfec.red_payload_type =
        send_config->rtp.ulpfec.red_payload_type;
    (*receive_configs)[0].rtp.ulpfec.ulpfec_payload_type =
        send_config->rtp.ulpfec.ulpfec_payload_type;
  }

  void PerformTest() override {
    EXPECT_EQ(expect_ulpfec_, Wait())
        << "Timed out waiting for ULPFEC and/or media packets.";
  }

  VideoEncoder* const encoder_;
  std::string payload_name_;
  const bool use_nack_;
  const bool expect_red_;
  const bool expect_ulpfec_;
  bool sent_media_;
  bool sent_ulpfec_;
  bool header_extensions_enabled_;
  RTPHeader prev_header_;
};

TEST_F(VideoSendStreamTest, SupportsUlpfecWithExtensions) {
  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
  UlpfecObserver test(true, false, true, true, "VP8", encoder.get());
  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, SupportsUlpfecWithoutExtensions) {
  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
  UlpfecObserver test(false, false, true, true, "VP8", encoder.get());
  RunBaseTest(&test);
}

// The FEC scheme used is not efficient for H264, so we should not use RED/FEC
// since we'll still have to re-request FEC packets, effectively wasting
// bandwidth since the receiver has to wait for FEC retransmissions to determine
// that the received state is actually decodable.
TEST_F(VideoSendStreamTest, DoesNotUtilizeUlpfecForH264WithNackEnabled) {
  std::unique_ptr<VideoEncoder> encoder(
      new test::FakeH264Encoder(Clock::GetRealTimeClock()));
  UlpfecObserver test(false, true, true, false, "H264", encoder.get());
  RunBaseTest(&test);
}

// Without retransmissions FEC for H264 is fine.
TEST_F(VideoSendStreamTest, DoesUtilizeUlpfecForH264WithoutNackEnabled) {
  std::unique_ptr<VideoEncoder> encoder(
      new test::FakeH264Encoder(Clock::GetRealTimeClock()));
  UlpfecObserver test(false, false, true, true, "H264", encoder.get());
  RunBaseTest(&test);
}

// Disabled as flaky, see https://crbug.com/webrtc/7285 for details.
TEST_F(VideoSendStreamTest, DISABLED_DoesUtilizeUlpfecForVp8WithNackEnabled) {
  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
  UlpfecObserver test(false, true, true, true, "VP8", encoder.get());
  RunBaseTest(&test);
}

#if !defined(RTC_DISABLE_VP9)
// Disabled as flaky, see https://crbug.com/webrtc/7285 for details.
TEST_F(VideoSendStreamTest, DISABLED_DoesUtilizeUlpfecForVp9WithNackEnabled) {
  std::unique_ptr<VideoEncoder> encoder(VP9Encoder::Create());
  UlpfecObserver test(false, true, true, true, "VP9", encoder.get());
  RunBaseTest(&test);
}
#endif  // !defined(RTC_DISABLE_VP9)

TEST_F(VideoSendStreamTest, SupportsUlpfecWithMultithreadedH264) {
  std::unique_ptr<VideoEncoder> encoder(
      new test::MultithreadedFakeH264Encoder(Clock::GetRealTimeClock()));
  UlpfecObserver test(false, false, true, true, "H264", encoder.get());
  RunBaseTest(&test);
}

// TODO(brandtr): Move these FlexFEC tests when we have created
// FlexfecSendStream.
class FlexfecObserver : public test::EndToEndTest {
 public:
  FlexfecObserver(bool header_extensions_enabled,
                  bool use_nack,
                  const std::string& codec,
                  VideoEncoder* encoder)
      : EndToEndTest(VideoSendStreamTest::kDefaultTimeoutMs),
        encoder_(encoder),
        payload_name_(codec),
        use_nack_(use_nack),
        sent_media_(false),
        sent_flexfec_(false),
        header_extensions_enabled_(header_extensions_enabled) {}

  size_t GetNumFlexfecStreams() const override { return 1; }

 private:
  Action OnSendRtp(const uint8_t* packet, size_t length) override {
    RTPHeader header;
    EXPECT_TRUE(parser_->Parse(packet, length, &header));

    if (header.payloadType == VideoSendStreamTest::kFlexfecPayloadType) {
      EXPECT_EQ(VideoSendStreamTest::kFlexfecSendSsrc, header.ssrc);
      sent_flexfec_ = true;
    } else {
      EXPECT_EQ(VideoSendStreamTest::kFakeVideoSendPayloadType,
                header.payloadType);
      EXPECT_EQ(VideoSendStreamTest::kVideoSendSsrcs[0], header.ssrc);
      sent_media_ = true;
    }

    if (header_extensions_enabled_) {
      EXPECT_TRUE(header.extension.hasAbsoluteSendTime);
      EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
      EXPECT_TRUE(header.extension.hasTransportSequenceNumber);
    }

    if (sent_media_ && sent_flexfec_) {
      observation_complete_.Set();
    }

    return SEND_PACKET;
  }

  test::PacketTransport* CreateSendTransport(Call* sender_call) override {
    // At low RTT (< kLowRttNackMs) -> NACK only, no FEC.
    // Therefore we need some network delay.
    const int kNetworkDelayMs = 100;
    FakeNetworkPipe::Config config;
    config.loss_percent = 5;
    config.queue_delay_ms = kNetworkDelayMs;
    return new test::PacketTransport(sender_call, this,
                                     test::PacketTransport::kSender, config);
  }

  void ModifyVideoConfigs(
      VideoSendStream::Config* send_config,
      std::vector<VideoReceiveStream::Config>* receive_configs,
      VideoEncoderConfig* encoder_config) override {
    if (use_nack_) {
      send_config->rtp.nack.rtp_history_ms =
          (*receive_configs)[0].rtp.nack.rtp_history_ms =
              VideoSendStreamTest::kNackRtpHistoryMs;
    }
    send_config->encoder_settings.encoder = encoder_;
    send_config->encoder_settings.payload_name = payload_name_;
    if (header_extensions_enabled_) {
      send_config->rtp.extensions.push_back(RtpExtension(
          RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
      send_config->rtp.extensions.push_back(RtpExtension(
          RtpExtension::kTimestampOffsetUri, test::kTOffsetExtensionId));
    } else {
      send_config->rtp.extensions.clear();
    }
  }

  void PerformTest() override {
    EXPECT_TRUE(Wait())
        << "Timed out waiting for FlexFEC and/or media packets.";
  }

  VideoEncoder* const encoder_;
  std::string payload_name_;
  const bool use_nack_;
  bool sent_media_;
  bool sent_flexfec_;
  bool header_extensions_enabled_;
};

TEST_F(VideoSendStreamTest, SupportsFlexfecVp8) {
  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
  FlexfecObserver test(false, false, "VP8", encoder.get());
  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, SupportsFlexfecWithNackVp8) {
  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
  FlexfecObserver test(false, true, "VP8", encoder.get());
  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, SupportsFlexfecWithRtpExtensionsVp8) {
  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
  FlexfecObserver test(true, false, "VP8", encoder.get());
  RunBaseTest(&test);
}

#if !defined(RTC_DISABLE_VP9)
TEST_F(VideoSendStreamTest, SupportsFlexfecVp9) {
  std::unique_ptr<VideoEncoder> encoder(VP9Encoder::Create());
  FlexfecObserver test(false, false, "VP9", encoder.get());
  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, SupportsFlexfecWithNackVp9) {
  std::unique_ptr<VideoEncoder> encoder(VP9Encoder::Create());
  FlexfecObserver test(false, true, "VP9", encoder.get());
  RunBaseTest(&test);
}
#endif  // defined(RTC_DISABLE_VP9)

TEST_F(VideoSendStreamTest, SupportsFlexfecH264) {
  std::unique_ptr<VideoEncoder> encoder(
      new test::FakeH264Encoder(Clock::GetRealTimeClock()));
  FlexfecObserver test(false, false, "H264", encoder.get());
  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, SupportsFlexfecWithNackH264) {
  std::unique_ptr<VideoEncoder> encoder(
      new test::FakeH264Encoder(Clock::GetRealTimeClock()));
  FlexfecObserver test(false, true, "H264", encoder.get());
  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, SupportsFlexfecWithMultithreadedH264) {
  std::unique_ptr<VideoEncoder> encoder(
      new test::MultithreadedFakeH264Encoder(Clock::GetRealTimeClock()));
  FlexfecObserver test(false, false, "H264", encoder.get());
  RunBaseTest(&test);
}

void VideoSendStreamTest::TestNackRetransmission(
    uint32_t retransmit_ssrc,
    uint8_t retransmit_payload_type) {
  class NackObserver : public test::SendTest {
   public:
    explicit NackObserver(uint32_t retransmit_ssrc,
                          uint8_t retransmit_payload_type)
        : SendTest(kDefaultTimeoutMs),
          send_count_(0),
          retransmit_ssrc_(retransmit_ssrc),
          retransmit_payload_type_(retransmit_payload_type),
          nacked_sequence_number_(-1) {
    }

   private:
    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      RTPHeader header;
      EXPECT_TRUE(parser_->Parse(packet, length, &header));

      // Nack second packet after receiving the third one.
      if (++send_count_ == 3) {
        uint16_t nack_sequence_number = header.sequenceNumber - 1;
        nacked_sequence_number_ = nack_sequence_number;
        NullReceiveStatistics null_stats;
        RTCPSender rtcp_sender(false, Clock::GetRealTimeClock(), &null_stats,
                               nullptr, nullptr, transport_adapter_.get());

        rtcp_sender.SetRTCPStatus(RtcpMode::kReducedSize);
        rtcp_sender.SetRemoteSSRC(kVideoSendSsrcs[0]);

        RTCPSender::FeedbackState feedback_state;

        EXPECT_EQ(0,
                  rtcp_sender.SendRTCP(
                      feedback_state, kRtcpNack, 1, &nack_sequence_number));
      }

      uint16_t sequence_number = header.sequenceNumber;

      if (header.ssrc == retransmit_ssrc_ &&
          retransmit_ssrc_ != kVideoSendSsrcs[0]) {
        // Not kVideoSendSsrcs[0], assume correct RTX packet. Extract sequence
        // number.
        const uint8_t* rtx_header = packet + header.headerLength;
        sequence_number = (rtx_header[0] << 8) + rtx_header[1];
      }

      if (sequence_number == nacked_sequence_number_) {
        EXPECT_EQ(retransmit_ssrc_, header.ssrc);
        EXPECT_EQ(retransmit_payload_type_, header.payloadType);
        observation_complete_.Set();
      }

      return SEND_PACKET;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      transport_adapter_.reset(
          new internal::TransportAdapter(send_config->send_transport));
      transport_adapter_->Enable();
      send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
      send_config->rtp.rtx.payload_type = retransmit_payload_type_;
      if (retransmit_ssrc_ != kVideoSendSsrcs[0])
        send_config->rtp.rtx.ssrcs.push_back(retransmit_ssrc_);
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait()) << "Timed out while waiting for NACK retransmission.";
    }

    std::unique_ptr<internal::TransportAdapter> transport_adapter_;
    int send_count_;
    uint32_t retransmit_ssrc_;
    uint8_t retransmit_payload_type_;
    int nacked_sequence_number_;
  } test(retransmit_ssrc, retransmit_payload_type);

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, RetransmitsNack) {
  // Normal NACKs should use the send SSRC.
  TestNackRetransmission(kVideoSendSsrcs[0], kFakeVideoSendPayloadType);
}

TEST_F(VideoSendStreamTest, RetransmitsNackOverRtx) {
  // NACKs over RTX should use a separate SSRC.
  TestNackRetransmission(kSendRtxSsrcs[0], kSendRtxPayloadType);
}

void VideoSendStreamTest::TestPacketFragmentationSize(VideoFormat format,
                                                      bool with_fec) {
  // Use a fake encoder to output a frame of every size in the range [90, 290],
  // for each size making sure that the exact number of payload bytes received
  // is correct and that packets are fragmented to respect max packet size.
  static const size_t kMaxPacketSize = 128;
  static const size_t start = 90;
  static const size_t stop = 290;

  // Observer that verifies that the expected number of packets and bytes
  // arrive for each frame size, from start_size to stop_size.
  class FrameFragmentationTest : public test::SendTest,
                                 public EncodedFrameObserver {
   public:
    FrameFragmentationTest(size_t max_packet_size,
                           size_t start_size,
                           size_t stop_size,
                           bool test_generic_packetization,
                           bool use_fec)
        : SendTest(kLongTimeoutMs),
          encoder_(stop),
          max_packet_size_(max_packet_size),
          stop_size_(stop_size),
          test_generic_packetization_(test_generic_packetization),
          use_fec_(use_fec),
          packet_count_(0),
          accumulated_size_(0),
          accumulated_payload_(0),
          fec_packet_received_(false),
          current_size_rtp_(start_size),
          current_size_frame_(static_cast<int32_t>(start_size)) {
      // Fragmentation required, this test doesn't make sense without it.
      encoder_.SetFrameSize(start_size);
      RTC_DCHECK_GT(stop_size, max_packet_size);
    }

   private:
    Action OnSendRtp(const uint8_t* packet, size_t size) override {
      size_t length = size;
      RTPHeader header;
      EXPECT_TRUE(parser_->Parse(packet, length, &header));

      EXPECT_LE(length, max_packet_size_);

      if (use_fec_) {
        uint8_t payload_type = packet[header.headerLength];
        bool is_fec = header.payloadType == kRedPayloadType &&
                      payload_type == kUlpfecPayloadType;
        if (is_fec) {
          fec_packet_received_ = true;
          return SEND_PACKET;
        }
      }

      accumulated_size_ += length;

      if (use_fec_)
        TriggerLossReport(header);

      if (test_generic_packetization_) {
        size_t overhead = header.headerLength + header.paddingLength;
        // Only remove payload header and RED header if the packet actually
        // contains payload.
        if (length > overhead) {
          overhead += (1 /* Generic header */);
          if (use_fec_)
            overhead += 1;  // RED for FEC header.
        }
        EXPECT_GE(length, overhead);
        accumulated_payload_ += length - overhead;
      }

      // Marker bit set indicates last packet of a frame.
      if (header.markerBit) {
        if (use_fec_ && accumulated_payload_ == current_size_rtp_ - 1) {
          // With FEC enabled, frame size is incremented asynchronously, so
          // "old" frames one byte too small may arrive. Accept, but don't
          // increase expected frame size.
          accumulated_size_ = 0;
          accumulated_payload_ = 0;
          return SEND_PACKET;
        }

        EXPECT_GE(accumulated_size_, current_size_rtp_);
        if (test_generic_packetization_) {
          EXPECT_EQ(current_size_rtp_, accumulated_payload_);
        }

        // Last packet of frame; reset counters.
        accumulated_size_ = 0;
        accumulated_payload_ = 0;
        if (current_size_rtp_ == stop_size_) {
          // Done! (Don't increase size again, might arrive more @ stop_size).
          observation_complete_.Set();
        } else {
          // Increase next expected frame size. If testing with FEC, make sure
          // a FEC packet has been received for this frame size before
          // proceeding, to make sure that redundancy packets don't exceed
          // size limit.
          if (!use_fec_) {
            ++current_size_rtp_;
          } else if (fec_packet_received_) {
            fec_packet_received_ = false;
            ++current_size_rtp_;
            ++current_size_frame_;
          }
        }
      }

      return SEND_PACKET;
    }

    void TriggerLossReport(const RTPHeader& header) {
      // Send lossy receive reports to trigger FEC enabling.
      if (packet_count_++ % 2 != 0) {
        // Receive statistics reporting having lost 50% of the packets.
        FakeReceiveStatistics lossy_receive_stats(
            kVideoSendSsrcs[0], header.sequenceNumber, packet_count_ / 2, 127);
        RTCPSender rtcp_sender(false, Clock::GetRealTimeClock(),
                               &lossy_receive_stats, nullptr, nullptr,
                               transport_adapter_.get());

        rtcp_sender.SetRTCPStatus(RtcpMode::kReducedSize);
        rtcp_sender.SetRemoteSSRC(kVideoSendSsrcs[0]);

        RTCPSender::FeedbackState feedback_state;

        EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpRr));
      }
    }

    void EncodedFrameCallback(const EncodedFrame& encoded_frame) override {
      // Increase frame size for next encoded frame, in the context of the
      // encoder thread.
      if (!use_fec_ &&
          current_size_frame_.Value() < static_cast<int32_t>(stop_size_)) {
        ++current_size_frame_;
      }
      encoder_.SetFrameSize(static_cast<size_t>(current_size_frame_.Value()));
    }

    Call::Config GetSenderCallConfig() override {
      Call::Config config(&event_log_);
      const int kMinBitrateBps = 30000;
      config.bitrate_config.min_bitrate_bps = kMinBitrateBps;
      return config;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      transport_adapter_.reset(
          new internal::TransportAdapter(send_config->send_transport));
      transport_adapter_->Enable();
      if (use_fec_) {
        send_config->rtp.ulpfec.red_payload_type = kRedPayloadType;
        send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
      }

      if (!test_generic_packetization_)
        send_config->encoder_settings.payload_name = "VP8";

      send_config->encoder_settings.encoder = &encoder_;
      send_config->rtp.max_packet_size = kMaxPacketSize;
      send_config->post_encode_callback = this;

      // Make sure there is at least one extension header, to make the RTP
      // header larger than the base length of 12 bytes.
      EXPECT_FALSE(send_config->rtp.extensions.empty());
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait()) << "Timed out while observing incoming RTP packets.";
    }

    std::unique_ptr<internal::TransportAdapter> transport_adapter_;
    test::ConfigurableFrameSizeEncoder encoder_;

    const size_t max_packet_size_;
    const size_t stop_size_;
    const bool test_generic_packetization_;
    const bool use_fec_;

    uint32_t packet_count_;
    size_t accumulated_size_;
    size_t accumulated_payload_;
    bool fec_packet_received_;

    size_t current_size_rtp_;
    Atomic32 current_size_frame_;
  };

  // Don't auto increment if FEC is used; continue sending frame size until
  // a FEC packet has been received.
  FrameFragmentationTest test(
      kMaxPacketSize, start, stop, format == kGeneric, with_fec);

  RunBaseTest(&test);
}

// TODO(sprang): Is there any way of speeding up these tests?
TEST_F(VideoSendStreamTest, FragmentsGenericAccordingToMaxPacketSize) {
  TestPacketFragmentationSize(kGeneric, false);
}

TEST_F(VideoSendStreamTest, FragmentsGenericAccordingToMaxPacketSizeWithFec) {
  TestPacketFragmentationSize(kGeneric, true);
}

TEST_F(VideoSendStreamTest, FragmentsVp8AccordingToMaxPacketSize) {
  TestPacketFragmentationSize(kVP8, false);
}

TEST_F(VideoSendStreamTest, FragmentsVp8AccordingToMaxPacketSizeWithFec) {
  TestPacketFragmentationSize(kVP8, true);
}

// The test will go through a number of phases.
// 1. Start sending packets.
// 2. As soon as the RTP stream has been detected, signal a low REMB value to
//    suspend the stream.
// 3. Wait until |kSuspendTimeFrames| have been captured without seeing any RTP
//    packets.
// 4. Signal a high REMB and then wait for the RTP stream to start again.
//    When the stream is detected again, and the stats show that the stream
//    is no longer suspended, the test ends.
TEST_F(VideoSendStreamTest, SuspendBelowMinBitrate) {
  static const int kSuspendTimeFrames = 60;  // Suspend for 2 seconds @ 30 fps.

  class RembObserver : public test::SendTest,
                       public rtc::VideoSinkInterface<VideoFrame> {
   public:
    RembObserver()
        : SendTest(kDefaultTimeoutMs),
          clock_(Clock::GetRealTimeClock()),
          stream_(nullptr),
          test_state_(kBeforeSuspend),
          rtp_count_(0),
          last_sequence_number_(0),
          suspended_frame_count_(0),
          low_remb_bps_(0),
          high_remb_bps_(0) {}

   private:
    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      rtc::CritScope lock(&crit_);
      ++rtp_count_;
      RTPHeader header;
      EXPECT_TRUE(parser_->Parse(packet, length, &header));
      last_sequence_number_ = header.sequenceNumber;

      if (test_state_ == kBeforeSuspend) {
        // The stream has started. Try to suspend it.
        SendRtcpFeedback(low_remb_bps_);
        test_state_ = kDuringSuspend;
      } else if (test_state_ == kDuringSuspend) {
        if (header.paddingLength == 0) {
          // Received non-padding packet during suspension period. Reset the
          // counter.
          suspended_frame_count_ = 0;
        }
        SendRtcpFeedback(0);  // REMB is only sent if value is > 0.
      } else if (test_state_ == kWaitingForPacket) {
        if (header.paddingLength == 0) {
          // Non-padding packet observed. Test is almost complete. Will just
          // have to wait for the stats to change.
          test_state_ = kWaitingForStats;
        }
        SendRtcpFeedback(0);  // REMB is only sent if value is > 0.
      } else if (test_state_ == kWaitingForStats) {
        VideoSendStream::Stats stats = stream_->GetStats();
        if (stats.suspended == false) {
          // Stats flipped to false. Test is complete.
          observation_complete_.Set();
        }
        SendRtcpFeedback(0);  // REMB is only sent if value is > 0.
      }

      return SEND_PACKET;
    }

    // This method implements the rtc::VideoSinkInterface. This is called when
    // a frame is provided to the VideoSendStream.
    void OnFrame(const VideoFrame& video_frame) override {
      rtc::CritScope lock(&crit_);
      if (test_state_ == kDuringSuspend &&
          ++suspended_frame_count_ > kSuspendTimeFrames) {
        VideoSendStream::Stats stats = stream_->GetStats();
        EXPECT_TRUE(stats.suspended);
        SendRtcpFeedback(high_remb_bps_);
        test_state_ = kWaitingForPacket;
      }
    }

    void set_low_remb_bps(int value) {
      rtc::CritScope lock(&crit_);
      low_remb_bps_ = value;
    }

    void set_high_remb_bps(int value) {
      rtc::CritScope lock(&crit_);
      high_remb_bps_ = value;
    }

    void OnVideoStreamsCreated(
        VideoSendStream* send_stream,
        const std::vector<VideoReceiveStream*>& receive_streams) override {
      stream_ = send_stream;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      RTC_DCHECK_EQ(1, encoder_config->number_of_streams);
      transport_adapter_.reset(
          new internal::TransportAdapter(send_config->send_transport));
      transport_adapter_->Enable();
      send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
      send_config->pre_encode_callback = this;
      send_config->suspend_below_min_bitrate = true;
      int min_bitrate_bps =
          test::DefaultVideoStreamFactory::kDefaultMinBitratePerStream[0];
      set_low_remb_bps(min_bitrate_bps - 10000);
      int threshold_window = std::max(min_bitrate_bps / 10, 20000);
      ASSERT_GT(encoder_config->max_bitrate_bps,
                min_bitrate_bps + threshold_window + 5000);
      set_high_remb_bps(min_bitrate_bps + threshold_window + 5000);
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait()) << "Timed out during suspend-below-min-bitrate test.";
    }

    enum TestState {
      kBeforeSuspend,
      kDuringSuspend,
      kWaitingForPacket,
      kWaitingForStats
    };

    virtual void SendRtcpFeedback(int remb_value)
        EXCLUSIVE_LOCKS_REQUIRED(crit_) {
      FakeReceiveStatistics receive_stats(kVideoSendSsrcs[0],
                                          last_sequence_number_, rtp_count_, 0);
      RTCPSender rtcp_sender(false, clock_, &receive_stats, nullptr, nullptr,
                             transport_adapter_.get());

      rtcp_sender.SetRTCPStatus(RtcpMode::kReducedSize);
      rtcp_sender.SetRemoteSSRC(kVideoSendSsrcs[0]);
      if (remb_value > 0) {
        rtcp_sender.SetREMBStatus(true);
        rtcp_sender.SetREMBData(remb_value, std::vector<uint32_t>());
      }
      RTCPSender::FeedbackState feedback_state;
      EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpRr));
    }

    std::unique_ptr<internal::TransportAdapter> transport_adapter_;
    Clock* const clock_;
    VideoSendStream* stream_;

    rtc::CriticalSection crit_;
    TestState test_state_ GUARDED_BY(crit_);
    int rtp_count_ GUARDED_BY(crit_);
    int last_sequence_number_ GUARDED_BY(crit_);
    int suspended_frame_count_ GUARDED_BY(crit_);
    int low_remb_bps_ GUARDED_BY(crit_);
    int high_remb_bps_ GUARDED_BY(crit_);
  } test;

  RunBaseTest(&test);
}

// This test that padding stops being send after a while if the Camera stops
// producing video frames and that padding resumes if the camera restarts.
TEST_F(VideoSendStreamTest, NoPaddingWhenVideoIsMuted) {
  class NoPaddingWhenVideoIsMuted : public test::SendTest {
   public:
    NoPaddingWhenVideoIsMuted()
        : SendTest(kDefaultTimeoutMs),
          clock_(Clock::GetRealTimeClock()),
          last_packet_time_ms_(-1),
          capturer_(nullptr) {
    }

   private:
    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      rtc::CritScope lock(&crit_);
      last_packet_time_ms_ = clock_->TimeInMilliseconds();

      RTPHeader header;
      parser_->Parse(packet, length, &header);
      const bool only_padding =
          header.headerLength + header.paddingLength == length;

      if (test_state_ == kBeforeStopCapture) {
        capturer_->Stop();
        test_state_ = kWaitingForPadding;
      } else if (test_state_ == kWaitingForPadding && only_padding) {
        test_state_ = kWaitingForNoPackets;
      } else if (test_state_ == kWaitingForPaddingAfterCameraRestart &&
                 only_padding) {
        observation_complete_.Set();
      }
      return SEND_PACKET;
    }

    Action OnSendRtcp(const uint8_t* packet, size_t length) override {
      rtc::CritScope lock(&crit_);
      const int kNoPacketsThresholdMs = 2000;
      if (test_state_ == kWaitingForNoPackets &&
          (last_packet_time_ms_ > 0 &&
           clock_->TimeInMilliseconds() - last_packet_time_ms_ >
               kNoPacketsThresholdMs)) {
        capturer_->Start();
        test_state_ = kWaitingForPaddingAfterCameraRestart;
      }
      return SEND_PACKET;
    }

    size_t GetNumVideoStreams() const override { return 3; }

    void OnFrameGeneratorCapturerCreated(
        test::FrameGeneratorCapturer* frame_generator_capturer) override {
      rtc::CritScope lock(&crit_);
      capturer_ = frame_generator_capturer;
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait())
          << "Timed out while waiting for RTP packets to stop being sent.";
    }

    enum TestState {
      kBeforeStopCapture,
      kWaitingForPadding,
      kWaitingForNoPackets,
      kWaitingForPaddingAfterCameraRestart
    };

    TestState test_state_ = kBeforeStopCapture;
    Clock* const clock_;
    std::unique_ptr<internal::TransportAdapter> transport_adapter_;
    rtc::CriticalSection crit_;
    int64_t last_packet_time_ms_ GUARDED_BY(crit_);
    test::FrameGeneratorCapturer* capturer_ GUARDED_BY(crit_);
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, PaddingIsPrimarilyRetransmissions) {
  const int kCapacityKbps = 10000;  // 10 Mbps
  class PaddingIsPrimarilyRetransmissions : public test::EndToEndTest {
   public:
    PaddingIsPrimarilyRetransmissions()
        : EndToEndTest(kDefaultTimeoutMs),
          clock_(Clock::GetRealTimeClock()),
          padding_length_(0),
          total_length_(0),
          call_(nullptr) {}

   private:
    void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
      call_ = sender_call;
    }

    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      rtc::CritScope lock(&crit_);

      RTPHeader header;
      parser_->Parse(packet, length, &header);
      padding_length_ += header.paddingLength;
      total_length_ += length;
      return SEND_PACKET;
    }

    test::PacketTransport* CreateSendTransport(Call* sender_call) override {
      const int kNetworkDelayMs = 50;
      FakeNetworkPipe::Config config;
      config.loss_percent = 10;
      config.link_capacity_kbps = kCapacityKbps;
      config.queue_delay_ms = kNetworkDelayMs;
      return new test::PacketTransport(sender_call, this,
                                       test::PacketTransport::kSender, config);
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      // Turn on RTX.
      send_config->rtp.rtx.payload_type = kFakeVideoSendPayloadType;
      send_config->rtp.rtx.ssrcs.push_back(kVideoSendSsrcs[0]);
    }

    void PerformTest() override {
      // TODO(isheriff): Some platforms do not ramp up as expected to full
      // capacity due to packet scheduling delays. Fix that before getting
      // rid of this.
      SleepMs(5000);
      {
        rtc::CritScope lock(&crit_);
        // Expect padding to be a small percentage of total bytes sent.
        EXPECT_LT(padding_length_, .1 * total_length_);
      }
    }

    rtc::CriticalSection crit_;
    Clock* const clock_;
    size_t padding_length_ GUARDED_BY(crit_);
    size_t total_length_ GUARDED_BY(crit_);
    Call* call_;
  } test;

  RunBaseTest(&test);
}

// This test first observes "high" bitrate use at which point it sends a REMB to
// indicate that it should be lowered significantly. The test then observes that
// the bitrate observed is sinking well below the min-transmit-bitrate threshold
// to verify that the min-transmit bitrate respects incoming REMB.
//
// Note that the test starts at "high" bitrate and does not ramp up to "higher"
// bitrate since no receiver block or remb is sent in the initial phase.
TEST_F(VideoSendStreamTest, MinTransmitBitrateRespectsRemb) {
  static const int kMinTransmitBitrateBps = 400000;
  static const int kHighBitrateBps = 150000;
  static const int kRembBitrateBps = 80000;
  static const int kRembRespectedBitrateBps = 100000;
  class BitrateObserver : public test::SendTest {
   public:
    BitrateObserver()
        : SendTest(kDefaultTimeoutMs),
          retranmission_rate_limiter_(Clock::GetRealTimeClock(), 1000),
          stream_(nullptr),
          bitrate_capped_(false) {}

   private:
    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      if (RtpHeaderParser::IsRtcp(packet, length))
        return DROP_PACKET;

      RTPHeader header;
      if (!parser_->Parse(packet, length, &header))
        return DROP_PACKET;
      RTC_DCHECK(stream_);
      VideoSendStream::Stats stats = stream_->GetStats();
      if (!stats.substreams.empty()) {
        EXPECT_EQ(1u, stats.substreams.size());
        int total_bitrate_bps =
            stats.substreams.begin()->second.total_bitrate_bps;
        test::PrintResult("bitrate_stats_",
                          "min_transmit_bitrate_low_remb",
                          "bitrate_bps",
                          static_cast<size_t>(total_bitrate_bps),
                          "bps",
                          false);
        if (total_bitrate_bps > kHighBitrateBps) {
          rtp_rtcp_->SetREMBData(kRembBitrateBps,
                                 std::vector<uint32_t>(1, header.ssrc));
          rtp_rtcp_->Process();
          bitrate_capped_ = true;
        } else if (bitrate_capped_ &&
                   total_bitrate_bps < kRembRespectedBitrateBps) {
          observation_complete_.Set();
        }
      }
      // Packets don't have to be delivered since the test is the receiver.
      return DROP_PACKET;
    }

    void OnVideoStreamsCreated(
        VideoSendStream* send_stream,
        const std::vector<VideoReceiveStream*>& receive_streams) override {
      stream_ = send_stream;
      RtpRtcp::Configuration config;
      config.outgoing_transport = feedback_transport_.get();
      config.retransmission_rate_limiter = &retranmission_rate_limiter_;
      rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
      rtp_rtcp_->SetREMBStatus(true);
      rtp_rtcp_->SetRTCPStatus(RtcpMode::kReducedSize);
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      feedback_transport_.reset(
          new internal::TransportAdapter(send_config->send_transport));
      feedback_transport_->Enable();
      encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps;
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait())
          << "Timeout while waiting for low bitrate stats after REMB.";
    }

    std::unique_ptr<RtpRtcp> rtp_rtcp_;
    std::unique_ptr<internal::TransportAdapter> feedback_transport_;
    RateLimiter retranmission_rate_limiter_;
    VideoSendStream* stream_;
    bool bitrate_capped_;
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, ChangingNetworkRoute) {
  static const int kStartBitrateBps = 300000;
  static const int kNewMaxBitrateBps = 1234567;
  static const uint8_t kExtensionId = test::kTransportSequenceNumberExtensionId;
  class ChangingNetworkRouteTest : public test::EndToEndTest {
   public:
    ChangingNetworkRouteTest()
        : EndToEndTest(test::CallTest::kDefaultTimeoutMs), call_(nullptr) {
      EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
          kRtpExtensionTransportSequenceNumber, kExtensionId));
    }

    void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
      call_ = sender_call;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->rtp.extensions.clear();
      send_config->rtp.extensions.push_back(RtpExtension(
          RtpExtension::kTransportSequenceNumberUri, kExtensionId));
      (*receive_configs)[0].rtp.extensions = send_config->rtp.extensions;
      (*receive_configs)[0].rtp.transport_cc = true;
    }

    void ModifyAudioConfigs(
        AudioSendStream::Config* send_config,
        std::vector<AudioReceiveStream::Config>* receive_configs) override {
      send_config->rtp.extensions.clear();
      send_config->rtp.extensions.push_back(RtpExtension(
          RtpExtension::kTransportSequenceNumberUri, kExtensionId));
      (*receive_configs)[0].rtp.extensions.clear();
      (*receive_configs)[0].rtp.extensions = send_config->rtp.extensions;
      (*receive_configs)[0].rtp.transport_cc = true;
    }

    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      if (call_->GetStats().send_bandwidth_bps > kStartBitrateBps) {
        observation_complete_.Set();
      }

      return SEND_PACKET;
    }

    void PerformTest() override {
      rtc::NetworkRoute new_route(true, 10, 20, -1);
      call_->OnNetworkRouteChanged("transport", new_route);
      Call::Config::BitrateConfig bitrate_config;
      bitrate_config.start_bitrate_bps = kStartBitrateBps;
      call_->SetBitrateConfig(bitrate_config);
      EXPECT_TRUE(Wait())
          << "Timed out while waiting for start bitrate to be exceeded.";

      bitrate_config.start_bitrate_bps = -1;
      bitrate_config.max_bitrate_bps = kNewMaxBitrateBps;
      call_->SetBitrateConfig(bitrate_config);
      // TODO(holmer): We should set the last sent packet id here and verify
      // that we correctly ignore any packet loss reported prior to that id.
      ++new_route.local_network_id;
      call_->OnNetworkRouteChanged("transport", new_route);
      EXPECT_GE(call_->GetStats().send_bandwidth_bps, kStartBitrateBps);
    }

   private:
    Call* call_;
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, ChangingTransportOverhead) {
  class ChangingTransportOverheadTest : public test::EndToEndTest {
   public:
    ChangingTransportOverheadTest()
        : EndToEndTest(test::CallTest::kDefaultTimeoutMs),
          call_(nullptr),
          packets_sent_(0),
          transport_overhead_(0) {}

    void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
      call_ = sender_call;
    }

    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      EXPECT_LE(length, kMaxRtpPacketSize);
      rtc::CritScope cs(&lock_);
      if (++packets_sent_ < 100)
        return SEND_PACKET;
      observation_complete_.Set();
      return SEND_PACKET;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->rtp.max_packet_size = kMaxRtpPacketSize;
    }

    void PerformTest() override {
      transport_overhead_ = 100;
      call_->OnTransportOverheadChanged(webrtc::MediaType::VIDEO,
                                        transport_overhead_);
      EXPECT_TRUE(Wait());
      {
        rtc::CritScope cs(&lock_);
        packets_sent_ = 0;
      }
      transport_overhead_ = 500;
      call_->OnTransportOverheadChanged(webrtc::MediaType::VIDEO,
                                        transport_overhead_);
      EXPECT_TRUE(Wait());
    }

   private:
    Call* call_;
    rtc::CriticalSection lock_;
    int packets_sent_ GUARDED_BY(lock_);
    int transport_overhead_;
    const size_t kMaxRtpPacketSize = 1000;
  } test;

  RunBaseTest(&test);
}

// Test class takes takes as argument a switch selecting if type switch should
// occur and a function pointer to reset the send stream. This is necessary
// since you cannot change the content type of a VideoSendStream, you need to
// recreate it. Stopping and recreating the stream can only be done on the main
// thread and in the context of VideoSendStreamTest (not BaseTest).
template <typename T>
class MaxPaddingSetTest : public test::SendTest {
 public:
  static const uint32_t kMinTransmitBitrateBps = 400000;
  static const uint32_t kActualEncodeBitrateBps = 40000;
  static const uint32_t kMinPacketsToSend = 50;

  explicit MaxPaddingSetTest(bool test_switch_content_type, T* stream_reset_fun)
      : SendTest(test::CallTest::kDefaultTimeoutMs),
        content_switch_event_(false, false),
        call_(nullptr),
        send_stream_(nullptr),
        send_stream_config_(nullptr),
        packets_sent_(0),
        running_without_padding_(test_switch_content_type),
        stream_resetter_(stream_reset_fun) {}

  void OnVideoStreamsCreated(
      VideoSendStream* send_stream,
      const std::vector<VideoReceiveStream*>& receive_streams) override {
    rtc::CritScope lock(&crit_);
    send_stream_ = send_stream;
  }

  void ModifyVideoConfigs(
      VideoSendStream::Config* send_config,
      std::vector<VideoReceiveStream::Config>* receive_configs,
      VideoEncoderConfig* encoder_config) override {
    RTC_DCHECK_EQ(1, encoder_config->number_of_streams);
    if (RunningWithoutPadding()) {
      encoder_config->min_transmit_bitrate_bps = 0;
      encoder_config->content_type =
          VideoEncoderConfig::ContentType::kRealtimeVideo;
    } else {
      encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps;
      encoder_config->content_type = VideoEncoderConfig::ContentType::kScreen;
    }
    send_stream_config_ = send_config->Copy();
    encoder_config_ = encoder_config->Copy();
  }

  void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
    call_ = sender_call;
  }

  Action OnSendRtp(const uint8_t* packet, size_t length) override {
    rtc::CritScope lock(&crit_);
    if (running_without_padding_)
      EXPECT_EQ(0, call_->GetStats().max_padding_bitrate_bps);

    // Wait until at least kMinPacketsToSend frames have been encoded, so that
    // we have reliable data.
    if (++packets_sent_ < kMinPacketsToSend)
      return SEND_PACKET;

    if (running_without_padding_) {
      // We've sent kMinPacketsToSend packets with default configuration, switch
      // to enabling screen content and setting min transmit bitrate.
      // Note that we need to recreate the stream if changing content type.
      packets_sent_ = 0;
      encoder_config_.min_transmit_bitrate_bps = kMinTransmitBitrateBps;
      encoder_config_.content_type = VideoEncoderConfig::ContentType::kScreen;
      running_without_padding_ = false;
      content_switch_event_.Set();
      return SEND_PACKET;
    }

    // Make sure the pacer has been configured with a min transmit bitrate.
    if (call_->GetStats().max_padding_bitrate_bps > 0)
      observation_complete_.Set();

    return SEND_PACKET;
  }

  void PerformTest() override {
    if (RunningWithoutPadding()) {
      ASSERT_TRUE(
          content_switch_event_.Wait(test::CallTest::kDefaultTimeoutMs));
      rtc::CritScope lock(&crit_);
      RTC_DCHECK(stream_resetter_);
      (*stream_resetter_)(send_stream_config_, encoder_config_);
    }

    ASSERT_TRUE(Wait()) << "Timed out waiting for a valid padding bitrate.";
  }

 private:
  bool RunningWithoutPadding() const {
    rtc::CritScope lock(&crit_);
    return running_without_padding_;
  }

  rtc::CriticalSection crit_;
  rtc::Event content_switch_event_;
  Call* call_;
  VideoSendStream* send_stream_ GUARDED_BY(crit_);
  VideoSendStream::Config send_stream_config_;
  VideoEncoderConfig encoder_config_;
  uint32_t packets_sent_ GUARDED_BY(crit_);
  bool running_without_padding_;
  T* const stream_resetter_;
};

TEST_F(VideoSendStreamTest, RespectsMinTransmitBitrate) {
  auto reset_fun = [](const VideoSendStream::Config& send_stream_config,
                      const VideoEncoderConfig& encoder_config) {};
  MaxPaddingSetTest<decltype(reset_fun)> test(false, &reset_fun);
  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, RespectsMinTransmitBitrateAfterContentSwitch) {
  // Function for removing and recreating the send stream with a new config.
  auto reset_fun = [this](const VideoSendStream::Config& send_stream_config,
                          const VideoEncoderConfig& encoder_config) {
    Stop();
    sender_call_->DestroyVideoSendStream(video_send_stream_);
    video_send_config_ = send_stream_config.Copy();
    video_encoder_config_ = encoder_config.Copy();
    video_send_stream_ = sender_call_->CreateVideoSendStream(
        video_send_config_.Copy(), video_encoder_config_.Copy());
    video_send_stream_->SetSource(
        frame_generator_capturer_.get(),
        VideoSendStream::DegradationPreference::kMaintainResolution);
    Start();
  };
  MaxPaddingSetTest<decltype(reset_fun)> test(true, &reset_fun);
  RunBaseTest(&test);
}

// This test verifies that new frame sizes reconfigures encoders even though not
// (yet) sending. The purpose of this is to permit encoding as quickly as
// possible once we start sending. Likely the frames being input are from the
// same source that will be sent later, which just means that we're ready
// earlier.
TEST_F(VideoSendStreamTest,
       EncoderReconfigureOnResolutionChangeWhenNotSending) {
  class EncoderObserver : public test::FakeEncoder {
   public:
    EncoderObserver()
        : FakeEncoder(Clock::GetRealTimeClock()),
          init_encode_called_(false, false),
          number_of_initializations_(0),
          last_initialized_frame_width_(0),
          last_initialized_frame_height_(0) {}

    void WaitForResolution(int width, int height) {
      {
        rtc::CritScope lock(&crit_);
        if (last_initialized_frame_width_ == width &&
            last_initialized_frame_height_ == height) {
          return;
        }
      }
      EXPECT_TRUE(
          init_encode_called_.Wait(VideoSendStreamTest::kDefaultTimeoutMs));
      {
        rtc::CritScope lock(&crit_);
        EXPECT_EQ(width, last_initialized_frame_width_);
        EXPECT_EQ(height, last_initialized_frame_height_);
      }
    }

   private:
    int32_t InitEncode(const VideoCodec* config,
                       int32_t number_of_cores,
                       size_t max_payload_size) override {
      rtc::CritScope lock(&crit_);
      last_initialized_frame_width_ = config->width;
      last_initialized_frame_height_ = config->height;
      ++number_of_initializations_;
      init_encode_called_.Set();
      return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
    }

    int32_t Encode(const VideoFrame& input_image,
                   const CodecSpecificInfo* codec_specific_info,
                   const std::vector<FrameType>* frame_types) override {
      ADD_FAILURE()
          << "Unexpected Encode call since the send stream is not started";
      return 0;
    }

    rtc::CriticalSection crit_;
    rtc::Event init_encode_called_;
    size_t number_of_initializations_ GUARDED_BY(&crit_);
    int last_initialized_frame_width_ GUARDED_BY(&crit_);
    int last_initialized_frame_height_ GUARDED_BY(&crit_);
  };

  CreateSenderCall(Call::Config(&event_log_));
  test::NullTransport transport;
  CreateSendConfig(1, 0, 0, &transport);
  EncoderObserver encoder;
  video_send_config_.encoder_settings.encoder = &encoder;
  CreateVideoStreams();
  CreateFrameGeneratorCapturer(kDefaultFramerate, kDefaultWidth,
                               kDefaultHeight);
  frame_generator_capturer_->Start();

  encoder.WaitForResolution(kDefaultWidth, kDefaultHeight);
  frame_generator_capturer_->ChangeResolution(kDefaultWidth * 2,
                                              kDefaultHeight * 2);
  encoder.WaitForResolution(kDefaultWidth * 2, kDefaultHeight * 2);
  DestroyStreams();
}

TEST_F(VideoSendStreamTest, CanReconfigureToUseStartBitrateAbovePreviousMax) {
  class StartBitrateObserver : public test::FakeEncoder {
   public:
    StartBitrateObserver()
        : FakeEncoder(Clock::GetRealTimeClock()),
          start_bitrate_changed_(false, false),
          start_bitrate_kbps_(0) {}
    int32_t InitEncode(const VideoCodec* config,
                       int32_t number_of_cores,
                       size_t max_payload_size) override {
      rtc::CritScope lock(&crit_);
      start_bitrate_kbps_ = config->startBitrate;
      start_bitrate_changed_.Set();
      return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
    }

    int32_t SetRates(uint32_t new_target_bitrate, uint32_t framerate) override {
      rtc::CritScope lock(&crit_);
      start_bitrate_kbps_ = new_target_bitrate;
      start_bitrate_changed_.Set();
      return FakeEncoder::SetRates(new_target_bitrate, framerate);
    }

    int GetStartBitrateKbps() const {
      rtc::CritScope lock(&crit_);
      return start_bitrate_kbps_;
    }

    bool WaitForStartBitrate() {
      return start_bitrate_changed_.Wait(
          VideoSendStreamTest::kDefaultTimeoutMs);
    }

   private:
    rtc::CriticalSection crit_;
    rtc::Event start_bitrate_changed_;
    int start_bitrate_kbps_ GUARDED_BY(crit_);
  };

  CreateSenderCall(Call::Config(&event_log_));

  test::NullTransport transport;
  CreateSendConfig(1, 0, 0, &transport);

  Call::Config::BitrateConfig bitrate_config;
  bitrate_config.start_bitrate_bps = 2 * video_encoder_config_.max_bitrate_bps;
  sender_call_->SetBitrateConfig(bitrate_config);

  StartBitrateObserver encoder;
  video_send_config_.encoder_settings.encoder = &encoder;
  // Since this test does not use a capturer, set |internal_source| = true.
  // Encoder configuration is otherwise updated on the next video frame.
  video_send_config_.encoder_settings.internal_source = true;

  CreateVideoStreams();

  EXPECT_TRUE(encoder.WaitForStartBitrate());
  EXPECT_EQ(video_encoder_config_.max_bitrate_bps / 1000,
            encoder.GetStartBitrateKbps());

  video_encoder_config_.max_bitrate_bps = 2 * bitrate_config.start_bitrate_bps;
  video_send_stream_->ReconfigureVideoEncoder(video_encoder_config_.Copy());

  // New bitrate should be reconfigured above the previous max. As there's no
  // network connection this shouldn't be flaky, as no bitrate should've been
  // reported in between.
  EXPECT_TRUE(encoder.WaitForStartBitrate());
  EXPECT_EQ(bitrate_config.start_bitrate_bps / 1000,
            encoder.GetStartBitrateKbps());

  DestroyStreams();
}

// This test that if the encoder use an internal source, VideoEncoder::SetRates
// will be called with zero bitrate during initialization and that
// VideoSendStream::Stop also triggers VideoEncoder::SetRates Start to be called
// with zero bitrate.
TEST_F(VideoSendStreamTest, VideoSendStreamStopSetEncoderRateToZero) {
  class StartStopBitrateObserver : public test::FakeEncoder {
   public:
    StartStopBitrateObserver()
        : FakeEncoder(Clock::GetRealTimeClock()),
          encoder_init_(false, false),
          bitrate_changed_(false, false) {}
    int32_t InitEncode(const VideoCodec* config,
                       int32_t number_of_cores,
                       size_t max_payload_size) override {
      rtc::CritScope lock(&crit_);
      encoder_init_.Set();
      return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
    }

    int32_t SetRateAllocation(const BitrateAllocation& bitrate,
                              uint32_t framerate) override {
      rtc::CritScope lock(&crit_);
      bitrate_kbps_ = rtc::Optional<int>(bitrate.get_sum_kbps());
      bitrate_changed_.Set();
      return FakeEncoder::SetRateAllocation(bitrate, framerate);
    }

    bool WaitForEncoderInit() {
      return encoder_init_.Wait(VideoSendStreamTest::kDefaultTimeoutMs);
    }

    bool WaitBitrateChanged(bool non_zero) {
      do {
        rtc::Optional<int> bitrate_kbps;
        {
          rtc::CritScope lock(&crit_);
          bitrate_kbps = bitrate_kbps_;
        }
        if (!bitrate_kbps)
          continue;

        if ((non_zero && *bitrate_kbps > 0) ||
            (!non_zero && *bitrate_kbps == 0)) {
          return true;
        }
      } while (bitrate_changed_.Wait(VideoSendStreamTest::kDefaultTimeoutMs));
      return false;
    }

   private:
    rtc::CriticalSection crit_;
    rtc::Event encoder_init_;
    rtc::Event bitrate_changed_;
    rtc::Optional<int> bitrate_kbps_ GUARDED_BY(crit_);
  };

  CreateSenderCall(Call::Config(&event_log_));

  test::NullTransport transport;
  CreateSendConfig(1, 0, 0, &transport);

  sender_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);

  StartStopBitrateObserver encoder;
  video_send_config_.encoder_settings.encoder = &encoder;
  video_send_config_.encoder_settings.internal_source = true;

  CreateVideoStreams();

  EXPECT_TRUE(encoder.WaitForEncoderInit());

  video_send_stream_->Start();
  EXPECT_TRUE(encoder.WaitBitrateChanged(true));

  video_send_stream_->Stop();
  EXPECT_TRUE(encoder.WaitBitrateChanged(false));

  video_send_stream_->Start();
  EXPECT_TRUE(encoder.WaitBitrateChanged(true));

  DestroyStreams();
}

TEST_F(VideoSendStreamTest, CapturesTextureAndVideoFrames) {
  class FrameObserver : public rtc::VideoSinkInterface<VideoFrame> {
   public:
    FrameObserver() : output_frame_event_(false, false) {}

    void OnFrame(const VideoFrame& video_frame) override {
      output_frames_.push_back(video_frame);
      output_frame_event_.Set();
    }

    void WaitOutputFrame() {
      const int kWaitFrameTimeoutMs = 3000;
      EXPECT_TRUE(output_frame_event_.Wait(kWaitFrameTimeoutMs))
          << "Timeout while waiting for output frames.";
    }

    const std::vector<VideoFrame>& output_frames() const {
      return output_frames_;
    }

   private:
    // Delivered output frames.
    std::vector<VideoFrame> output_frames_;

    // Indicate an output frame has arrived.
    rtc::Event output_frame_event_;
  };

  // Initialize send stream.
  CreateSenderCall(Call::Config(&event_log_));

  test::NullTransport transport;
  CreateSendConfig(1, 0, 0, &transport);
  FrameObserver observer;
  video_send_config_.pre_encode_callback = &observer;
  CreateVideoStreams();

  // Prepare five input frames. Send ordinary VideoFrame and texture frames
  // alternatively.
  std::vector<VideoFrame> input_frames;
  int width = 168;
  int height = 132;

  test::FakeNativeHandle* handle1 = new test::FakeNativeHandle();
  test::FakeNativeHandle* handle2 = new test::FakeNativeHandle();
  test::FakeNativeHandle* handle3 = new test::FakeNativeHandle();
  input_frames.push_back(test::FakeNativeHandle::CreateFrame(
      handle1, width, height, 1, 1, kVideoRotation_0));
  input_frames.push_back(test::FakeNativeHandle::CreateFrame(
      handle2, width, height, 2, 2, kVideoRotation_0));
  input_frames.push_back(CreateVideoFrame(width, height, 3));
  input_frames.push_back(CreateVideoFrame(width, height, 4));
  input_frames.push_back(test::FakeNativeHandle::CreateFrame(
      handle3, width, height, 5, 5, kVideoRotation_0));

  video_send_stream_->Start();
  test::FrameForwarder forwarder;
  video_send_stream_->SetSource(
      &forwarder, VideoSendStream::DegradationPreference::kBalanced);
  for (size_t i = 0; i < input_frames.size(); i++) {
    forwarder.IncomingCapturedFrame(input_frames[i]);
    // Wait until the output frame is received before sending the next input
    // frame. Or the previous input frame may be replaced without delivering.
    observer.WaitOutputFrame();
  }
  video_send_stream_->Stop();
  video_send_stream_->SetSource(
      nullptr, VideoSendStream::DegradationPreference::kBalanced);

  // Test if the input and output frames are the same. render_time_ms and
  // timestamp are not compared because capturer sets those values.
  ExpectEqualFramesVector(input_frames, observer.output_frames());

  DestroyStreams();
}

void ExpectEqualFramesVector(const std::vector<VideoFrame>& frames1,
                             const std::vector<VideoFrame>& frames2) {
  EXPECT_EQ(frames1.size(), frames2.size());
  for (size_t i = 0; i < std::min(frames1.size(), frames2.size()); ++i)
    // Compare frame buffers, since we don't care about differing timestamps.
    EXPECT_TRUE(test::FrameBufsEqual(frames1[i].video_frame_buffer(),
                                     frames2[i].video_frame_buffer()));
}

VideoFrame CreateVideoFrame(int width, int height, uint8_t data) {
  const int kSizeY = width * height * 2;
  std::unique_ptr<uint8_t[]> buffer(new uint8_t[kSizeY]);
  memset(buffer.get(), data, kSizeY);
  VideoFrame frame(
      I420Buffer::Create(width, height, width, width / 2, width / 2),
      kVideoRotation_0, data);
  frame.set_timestamp(data);
  // Use data as a ms timestamp.
  frame.set_timestamp_us(data * rtc::kNumMicrosecsPerMillisec);
  return frame;
}

TEST_F(VideoSendStreamTest, EncoderIsProperlyInitializedAndDestroyed) {
  class EncoderStateObserver : public test::SendTest, public VideoEncoder {
   public:
    EncoderStateObserver()
        : SendTest(kDefaultTimeoutMs),
          stream_(nullptr),
          initialized_(false),
          callback_registered_(false),
          num_releases_(0),
          released_(false) {}

    bool IsReleased() {
      rtc::CritScope lock(&crit_);
      return released_;
    }

    bool IsReadyForEncode() {
      rtc::CritScope lock(&crit_);
      return initialized_ && callback_registered_;
    }

    size_t num_releases() {
      rtc::CritScope lock(&crit_);
      return num_releases_;
    }

   private:
    int32_t InitEncode(const VideoCodec* codecSettings,
                       int32_t numberOfCores,
                       size_t maxPayloadSize) override {
      rtc::CritScope lock(&crit_);
      EXPECT_FALSE(initialized_);
      initialized_ = true;
      released_ = false;
      return 0;
    }

    int32_t Encode(const VideoFrame& inputImage,
                   const CodecSpecificInfo* codecSpecificInfo,
                   const std::vector<FrameType>* frame_types) override {
      EXPECT_TRUE(IsReadyForEncode());

      observation_complete_.Set();
      return 0;
    }

    int32_t RegisterEncodeCompleteCallback(
        EncodedImageCallback* callback) override {
      rtc::CritScope lock(&crit_);
      EXPECT_TRUE(initialized_);
      callback_registered_ = true;
      return 0;
    }

    int32_t Release() override {
      rtc::CritScope lock(&crit_);
      EXPECT_TRUE(IsReadyForEncode());
      EXPECT_FALSE(released_);
      initialized_ = false;
      callback_registered_ = false;
      released_ = true;
      ++num_releases_;
      return 0;
    }

    int32_t SetChannelParameters(uint32_t packetLoss, int64_t rtt) override {
      EXPECT_TRUE(IsReadyForEncode());
      return 0;
    }

    int32_t SetRates(uint32_t newBitRate, uint32_t frameRate) override {
      EXPECT_TRUE(IsReadyForEncode());
      return 0;
    }

    void OnVideoStreamsCreated(
        VideoSendStream* send_stream,
        const std::vector<VideoReceiveStream*>& receive_streams) override {
      stream_ = send_stream;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->encoder_settings.encoder = this;
      encoder_config_ = encoder_config->Copy();
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait()) << "Timed out while waiting for Encode.";
      EXPECT_EQ(0u, num_releases());
      stream_->ReconfigureVideoEncoder(std::move(encoder_config_));
      EXPECT_EQ(0u, num_releases());
      stream_->Stop();
      // Encoder should not be released before destroying the VideoSendStream.
      EXPECT_FALSE(IsReleased());
      EXPECT_TRUE(IsReadyForEncode());
      stream_->Start();
      // Sanity check, make sure we still encode frames with this encoder.
      EXPECT_TRUE(Wait()) << "Timed out while waiting for Encode.";
    }

    rtc::CriticalSection crit_;
    VideoSendStream* stream_;
    bool initialized_ GUARDED_BY(crit_);
    bool callback_registered_ GUARDED_BY(crit_);
    size_t num_releases_ GUARDED_BY(crit_);
    bool released_ GUARDED_BY(crit_);
    VideoEncoderConfig encoder_config_;
  } test_encoder;

  RunBaseTest(&test_encoder);

  EXPECT_TRUE(test_encoder.IsReleased());
  EXPECT_EQ(1u, test_encoder.num_releases());
}

TEST_F(VideoSendStreamTest, EncoderSetupPropagatesCommonEncoderConfigValues) {
  class VideoCodecConfigObserver : public test::SendTest,
                                   public test::FakeEncoder {
   public:
    VideoCodecConfigObserver()
        : SendTest(kDefaultTimeoutMs),
          FakeEncoder(Clock::GetRealTimeClock()),
          init_encode_event_(false, false),
          num_initializations_(0),
          stream_(nullptr) {}

   private:
    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->encoder_settings.encoder = this;
      encoder_config->max_bitrate_bps = kFirstMaxBitrateBps;
      encoder_config_ = encoder_config->Copy();
    }

    void OnVideoStreamsCreated(
        VideoSendStream* send_stream,
        const std::vector<VideoReceiveStream*>& receive_streams) override {
      stream_ = send_stream;
    }

    int32_t InitEncode(const VideoCodec* config,
                       int32_t number_of_cores,
                       size_t max_payload_size) override {
      if (num_initializations_ == 0) {
        // Verify default values.
        EXPECT_EQ(kFirstMaxBitrateBps / 1000, config->maxBitrate);
      } else {
        // Verify that changed values are propagated.
        EXPECT_EQ(kSecondMaxBitrateBps / 1000, config->maxBitrate);
      }
      ++num_initializations_;
      init_encode_event_.Set();
      return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
    }

    void PerformTest() override {
      EXPECT_TRUE(init_encode_event_.Wait(kDefaultTimeoutMs));
      EXPECT_EQ(1u, num_initializations_) << "VideoEncoder not initialized.";

      encoder_config_.max_bitrate_bps = kSecondMaxBitrateBps;
      stream_->ReconfigureVideoEncoder(std::move(encoder_config_));
      EXPECT_TRUE(init_encode_event_.Wait(kDefaultTimeoutMs));
      EXPECT_EQ(2u, num_initializations_)
          << "ReconfigureVideoEncoder did not reinitialize the encoder with "
             "new encoder settings.";
    }

    const uint32_t kFirstMaxBitrateBps = 1000000;
    const uint32_t kSecondMaxBitrateBps = 2000000;

    rtc::Event init_encode_event_;
    size_t num_initializations_;
    VideoSendStream* stream_;
    VideoEncoderConfig encoder_config_;
  } test;

  RunBaseTest(&test);
}

static const size_t kVideoCodecConfigObserverNumberOfTemporalLayers = 4;
template <typename T>
class VideoCodecConfigObserver : public test::SendTest,
                                 public test::FakeEncoder {
 public:
  VideoCodecConfigObserver(VideoCodecType video_codec_type,
                           const char* codec_name)
      : SendTest(VideoSendStreamTest::kDefaultTimeoutMs),
        FakeEncoder(Clock::GetRealTimeClock()),
        video_codec_type_(video_codec_type),
        codec_name_(codec_name),
        init_encode_event_(false, false),
        num_initializations_(0),
        stream_(nullptr) {
    memset(&encoder_settings_, 0, sizeof(encoder_settings_));
  }

 private:
  class VideoStreamFactory
      : public VideoEncoderConfig::VideoStreamFactoryInterface {
   public:
    VideoStreamFactory() {}

   private:
    std::vector<VideoStream> CreateEncoderStreams(
        int width,
        int height,
        const VideoEncoderConfig& encoder_config) override {
      std::vector<VideoStream> streams =
          test::CreateVideoStreams(width, height, encoder_config);
      for (size_t i = 0; i < streams.size(); ++i) {
        streams[i].temporal_layer_thresholds_bps.resize(
            kVideoCodecConfigObserverNumberOfTemporalLayers - 1);
      }
      return streams;
    }
  };

  void ModifyVideoConfigs(
      VideoSendStream::Config* send_config,
      std::vector<VideoReceiveStream::Config>* receive_configs,
      VideoEncoderConfig* encoder_config) override {
    send_config->encoder_settings.encoder = this;
    send_config->encoder_settings.payload_name = codec_name_;

    encoder_config->encoder_specific_settings = GetEncoderSpecificSettings();
    encoder_config->video_stream_factory =
        new rtc::RefCountedObject<VideoStreamFactory>();
    encoder_config_ = encoder_config->Copy();
  }

  void OnVideoStreamsCreated(
      VideoSendStream* send_stream,
      const std::vector<VideoReceiveStream*>& receive_streams) override {
    stream_ = send_stream;
  }

  int32_t InitEncode(const VideoCodec* config,
                     int32_t number_of_cores,
                     size_t max_payload_size) override {
    EXPECT_EQ(video_codec_type_, config->codecType);
    VerifyCodecSpecifics(*config);
    ++num_initializations_;
    init_encode_event_.Set();
    return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
  }

  void VerifyCodecSpecifics(const VideoCodec& config) const;
  rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
  GetEncoderSpecificSettings() const;

  void PerformTest() override {
    EXPECT_TRUE(
        init_encode_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs));
    ASSERT_EQ(1u, num_initializations_) << "VideoEncoder not initialized.";

    encoder_settings_.frameDroppingOn = true;
    encoder_config_.encoder_specific_settings = GetEncoderSpecificSettings();
    stream_->ReconfigureVideoEncoder(std::move(encoder_config_));
    ASSERT_TRUE(
        init_encode_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs));
    EXPECT_EQ(2u, num_initializations_)
        << "ReconfigureVideoEncoder did not reinitialize the encoder with "
           "new encoder settings.";
  }

  int32_t Encode(const VideoFrame& input_image,
                 const CodecSpecificInfo* codec_specific_info,
                 const std::vector<FrameType>* frame_types) override {
    // Silently skip the encode, FakeEncoder::Encode doesn't produce VP8.
    return 0;
  }

  T encoder_settings_;
  const VideoCodecType video_codec_type_;
  const char* const codec_name_;
  rtc::Event init_encode_event_;
  size_t num_initializations_;
  VideoSendStream* stream_;
  VideoEncoderConfig encoder_config_;
};

template <>
void VideoCodecConfigObserver<VideoCodecH264>::VerifyCodecSpecifics(
    const VideoCodec& config) const {
  EXPECT_EQ(
      0, memcmp(&config.H264(), &encoder_settings_, sizeof(encoder_settings_)));
}

template <>
rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
VideoCodecConfigObserver<VideoCodecH264>::GetEncoderSpecificSettings() const {
  return new rtc::RefCountedObject<
      VideoEncoderConfig::H264EncoderSpecificSettings>(encoder_settings_);
}

template <>
void VideoCodecConfigObserver<VideoCodecVP8>::VerifyCodecSpecifics(
    const VideoCodec& config) const {
  // Check that the number of temporal layers has propagated properly to
  // VideoCodec.
  EXPECT_EQ(kVideoCodecConfigObserverNumberOfTemporalLayers,
            config.VP8().numberOfTemporalLayers);

  for (unsigned char i = 0; i < config.numberOfSimulcastStreams; ++i) {
    EXPECT_EQ(kVideoCodecConfigObserverNumberOfTemporalLayers,
              config.simulcastStream[i].numberOfTemporalLayers);
  }

  // Set expected temporal layers as they should have been set when
  // reconfiguring the encoder and not match the set config. Also copy the
  // TemporalLayersFactory pointer that has been injected by ViEEncoder.
  VideoCodecVP8 encoder_settings = encoder_settings_;
  encoder_settings.numberOfTemporalLayers =
      kVideoCodecConfigObserverNumberOfTemporalLayers;
  encoder_settings.tl_factory = config.VP8().tl_factory;
  EXPECT_EQ(
      0, memcmp(&config.VP8(), &encoder_settings, sizeof(encoder_settings_)));
}

template <>
rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
VideoCodecConfigObserver<VideoCodecVP8>::GetEncoderSpecificSettings() const {
  return new rtc::RefCountedObject<
      VideoEncoderConfig::Vp8EncoderSpecificSettings>(encoder_settings_);
}

template <>
void VideoCodecConfigObserver<VideoCodecVP9>::VerifyCodecSpecifics(
    const VideoCodec& config) const {
  // Check that the number of temporal layers has propagated properly to
  // VideoCodec.
  EXPECT_EQ(kVideoCodecConfigObserverNumberOfTemporalLayers,
            config.VP9().numberOfTemporalLayers);

  for (unsigned char i = 0; i < config.numberOfSimulcastStreams; ++i) {
    EXPECT_EQ(kVideoCodecConfigObserverNumberOfTemporalLayers,
              config.simulcastStream[i].numberOfTemporalLayers);
  }

  // Set expected temporal layers as they should have been set when
  // reconfiguring the encoder and not match the set config.
  VideoCodecVP9 encoder_settings = encoder_settings_;
  encoder_settings.numberOfTemporalLayers =
      kVideoCodecConfigObserverNumberOfTemporalLayers;
  EXPECT_EQ(
      0, memcmp(&(config.VP9()), &encoder_settings, sizeof(encoder_settings_)));
}

template <>
rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
VideoCodecConfigObserver<VideoCodecVP9>::GetEncoderSpecificSettings() const {
  return new rtc::RefCountedObject<
      VideoEncoderConfig::Vp9EncoderSpecificSettings>(encoder_settings_);
}

TEST_F(VideoSendStreamTest, EncoderSetupPropagatesVp8Config) {
  VideoCodecConfigObserver<VideoCodecVP8> test(kVideoCodecVP8, "VP8");
  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, EncoderSetupPropagatesVp9Config) {
  VideoCodecConfigObserver<VideoCodecVP9> test(kVideoCodecVP9, "VP9");
  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, EncoderSetupPropagatesH264Config) {
  VideoCodecConfigObserver<VideoCodecH264> test(kVideoCodecH264, "H264");
  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, RtcpSenderReportContainsMediaBytesSent) {
  class RtcpSenderReportTest : public test::SendTest {
   public:
    RtcpSenderReportTest() : SendTest(kDefaultTimeoutMs),
                             rtp_packets_sent_(0),
                             media_bytes_sent_(0) {}

   private:
    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      rtc::CritScope lock(&crit_);
      RTPHeader header;
      EXPECT_TRUE(parser_->Parse(packet, length, &header));
      ++rtp_packets_sent_;
      media_bytes_sent_ += length - header.headerLength - header.paddingLength;
      return SEND_PACKET;
    }

    Action OnSendRtcp(const uint8_t* packet, size_t length) override {
      rtc::CritScope lock(&crit_);
      test::RtcpPacketParser parser;
      EXPECT_TRUE(parser.Parse(packet, length));

      if (parser.sender_report()->num_packets() > 0) {
        // Only compare sent media bytes if SenderPacketCount matches the
        // number of sent rtp packets (a new rtp packet could be sent before
        // the rtcp packet).
        if (parser.sender_report()->sender_octet_count() > 0 &&
            parser.sender_report()->sender_packet_count() ==
                rtp_packets_sent_) {
          EXPECT_EQ(media_bytes_sent_,
                    parser.sender_report()->sender_octet_count());
          observation_complete_.Set();
        }
      }

      return SEND_PACKET;
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait()) << "Timed out while waiting for RTCP sender report.";
    }

    rtc::CriticalSection crit_;
    size_t rtp_packets_sent_ GUARDED_BY(&crit_);
    size_t media_bytes_sent_ GUARDED_BY(&crit_);
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, TranslatesTwoLayerScreencastToTargetBitrate) {
  static const int kScreencastTargetBitrateKbps = 200;

  class VideoStreamFactory
      : public VideoEncoderConfig::VideoStreamFactoryInterface {
   public:
    VideoStreamFactory() {}

   private:
    std::vector<VideoStream> CreateEncoderStreams(
        int width,
        int height,
        const VideoEncoderConfig& encoder_config) override {
      std::vector<VideoStream> streams =
          test::CreateVideoStreams(width, height, encoder_config);
      EXPECT_TRUE(streams[0].temporal_layer_thresholds_bps.empty());
      streams[0].temporal_layer_thresholds_bps.push_back(
          kScreencastTargetBitrateKbps * 1000);
      return streams;
    }
  };

  class ScreencastTargetBitrateTest : public test::SendTest,
                                      public test::FakeEncoder {
   public:
    ScreencastTargetBitrateTest()
        : SendTest(kDefaultTimeoutMs),
          test::FakeEncoder(Clock::GetRealTimeClock()) {}

   private:
    int32_t InitEncode(const VideoCodec* config,
                       int32_t number_of_cores,
                       size_t max_payload_size) override {
      EXPECT_EQ(static_cast<unsigned int>(kScreencastTargetBitrateKbps),
                config->targetBitrate);
      observation_complete_.Set();
      return test::FakeEncoder::InitEncode(
          config, number_of_cores, max_payload_size);
    }
    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->encoder_settings.encoder = this;
      EXPECT_EQ(1u, encoder_config->number_of_streams);
      encoder_config->video_stream_factory =
          new rtc::RefCountedObject<VideoStreamFactory>();
      encoder_config->content_type = VideoEncoderConfig::ContentType::kScreen;
    }

    void PerformTest() override {
      EXPECT_TRUE(Wait())
          << "Timed out while waiting for the encoder to be initialized.";
    }
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, ReconfigureBitratesSetsEncoderBitratesCorrectly) {
  // These are chosen to be "kind of odd" to not be accidentally checked against
  // default values.
  static const int kMinBitrateKbps = 137;
  static const int kStartBitrateKbps = 345;
  static const int kLowerMaxBitrateKbps = 312;
  static const int kMaxBitrateKbps = 413;
  static const int kIncreasedStartBitrateKbps = 451;
  static const int kIncreasedMaxBitrateKbps = 597;
  class EncoderBitrateThresholdObserver : public test::SendTest,
                                          public test::FakeEncoder {
   public:
    EncoderBitrateThresholdObserver()
        : SendTest(kDefaultTimeoutMs),
          FakeEncoder(Clock::GetRealTimeClock()),
          init_encode_event_(false, false),
          bitrate_changed_event_(false, false),
          target_bitrate_(0),
          num_initializations_(0),
          call_(nullptr),
          send_stream_(nullptr) {}

   private:
    int32_t InitEncode(const VideoCodec* codecSettings,
                       int32_t numberOfCores,
                       size_t maxPayloadSize) override {
      EXPECT_GE(codecSettings->startBitrate, codecSettings->minBitrate);
      EXPECT_LE(codecSettings->startBitrate, codecSettings->maxBitrate);
      if (num_initializations_ == 0) {
        EXPECT_EQ(static_cast<unsigned int>(kMinBitrateKbps),
                  codecSettings->minBitrate);
        EXPECT_EQ(static_cast<unsigned int>(kStartBitrateKbps),
                  codecSettings->startBitrate);
        EXPECT_EQ(static_cast<unsigned int>(kMaxBitrateKbps),
                  codecSettings->maxBitrate);
        observation_complete_.Set();
      } else if (num_initializations_ == 1) {
        EXPECT_EQ(static_cast<unsigned int>(kLowerMaxBitrateKbps),
                  codecSettings->maxBitrate);
        // The start bitrate should be kept (-1) and capped to the max bitrate.
        // Since this is not an end-to-end call no receiver should have been
        // returning a REMB that could lower this estimate.
        EXPECT_EQ(codecSettings->startBitrate, codecSettings->maxBitrate);
      } else if (num_initializations_ == 2) {
        EXPECT_EQ(static_cast<unsigned int>(kIncreasedMaxBitrateKbps),
                  codecSettings->maxBitrate);
        // The start bitrate will be whatever the rate BitRateController
        // has currently configured but in the span of the set max and min
        // bitrate.
      }
      ++num_initializations_;
      init_encode_event_.Set();

      return FakeEncoder::InitEncode(codecSettings, numberOfCores,
                                     maxPayloadSize);
    }

    int32_t SetRateAllocation(const BitrateAllocation& bitrate,
                              uint32_t frameRate) override {
      {
        rtc::CritScope lock(&crit_);
        if (target_bitrate_ == bitrate.get_sum_kbps()) {
          return FakeEncoder::SetRateAllocation(bitrate, frameRate);
        }
        target_bitrate_ = bitrate.get_sum_kbps();
      }
      bitrate_changed_event_.Set();
      return FakeEncoder::SetRateAllocation(bitrate, frameRate);
    }

    void WaitForSetRates(uint32_t expected_bitrate) {
      EXPECT_TRUE(
          bitrate_changed_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs))
          << "Timed out while waiting encoder rate to be set.";
      rtc::CritScope lock(&crit_);
      EXPECT_EQ(expected_bitrate, target_bitrate_);
    }

    Call::Config GetSenderCallConfig() override {
      Call::Config config(&event_log_);
      config.bitrate_config.min_bitrate_bps = kMinBitrateKbps * 1000;
      config.bitrate_config.start_bitrate_bps = kStartBitrateKbps * 1000;
      config.bitrate_config.max_bitrate_bps = kMaxBitrateKbps * 1000;
      return config;
    }

    class VideoStreamFactory
        : public VideoEncoderConfig::VideoStreamFactoryInterface {
     public:
      explicit VideoStreamFactory(int min_bitrate_bps)
          : min_bitrate_bps_(min_bitrate_bps) {}

     private:
      std::vector<VideoStream> CreateEncoderStreams(
          int width,
          int height,
          const VideoEncoderConfig& encoder_config) override {
        std::vector<VideoStream> streams =
            test::CreateVideoStreams(width, height, encoder_config);
        streams[0].min_bitrate_bps = min_bitrate_bps_;
        return streams;
      }

      const int min_bitrate_bps_;
    };

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->encoder_settings.encoder = this;
      // Set bitrates lower/higher than min/max to make sure they are properly
      // capped.
      encoder_config->max_bitrate_bps = kMaxBitrateKbps * 1000;
      // Create a new StreamFactory to be able to set
      // |VideoStream.min_bitrate_bps|.
      encoder_config->video_stream_factory =
          new rtc::RefCountedObject<VideoStreamFactory>(kMinBitrateKbps * 1000);
      encoder_config_ = encoder_config->Copy();
    }

    void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
      call_ = sender_call;
    }

    void OnVideoStreamsCreated(
        VideoSendStream* send_stream,
        const std::vector<VideoReceiveStream*>& receive_streams) override {
      send_stream_ = send_stream;
    }

    void PerformTest() override {
      ASSERT_TRUE(
          init_encode_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs))
          << "Timed out while waiting for encoder to be configured.";
      WaitForSetRates(kStartBitrateKbps);
      Call::Config::BitrateConfig bitrate_config;
      bitrate_config.start_bitrate_bps = kIncreasedStartBitrateKbps * 1000;
      bitrate_config.max_bitrate_bps = kIncreasedMaxBitrateKbps * 1000;
      call_->SetBitrateConfig(bitrate_config);
      // Encoder rate is capped by EncoderConfig max_bitrate_bps.
      WaitForSetRates(kMaxBitrateKbps);
      encoder_config_.max_bitrate_bps = kLowerMaxBitrateKbps * 1000;
      send_stream_->ReconfigureVideoEncoder(encoder_config_.Copy());
      ASSERT_TRUE(
          init_encode_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs));
      EXPECT_EQ(2, num_initializations_)
          << "Encoder should have been reconfigured with the new value.";
      WaitForSetRates(kLowerMaxBitrateKbps);

      encoder_config_.max_bitrate_bps = kIncreasedMaxBitrateKbps * 1000;
      send_stream_->ReconfigureVideoEncoder(encoder_config_.Copy());
      ASSERT_TRUE(
          init_encode_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs));
      EXPECT_EQ(3, num_initializations_)
          << "Encoder should have been reconfigured with the new value.";
      // Expected target bitrate is the start bitrate set in the call to
      // call_->SetBitrateConfig.
      WaitForSetRates(kIncreasedStartBitrateKbps);
    }

    rtc::Event init_encode_event_;
    rtc::Event bitrate_changed_event_;
    rtc::CriticalSection crit_;
    uint32_t target_bitrate_ GUARDED_BY(&crit_);

    int num_initializations_;
    webrtc::Call* call_;
    webrtc::VideoSendStream* send_stream_;
    webrtc::VideoEncoderConfig encoder_config_;
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, ReportsSentResolution) {
  static const size_t kNumStreams = 3;
  // Unusual resolutions to make sure that they are the ones being reported.
  static const struct {
    int width;
    int height;
  } kEncodedResolution[kNumStreams] = {
      {241, 181}, {300, 121}, {121, 221}};
  class ScreencastTargetBitrateTest : public test::SendTest,
                                      public test::FakeEncoder {
   public:
    ScreencastTargetBitrateTest()
        : SendTest(kDefaultTimeoutMs),
          test::FakeEncoder(Clock::GetRealTimeClock()),
          send_stream_(nullptr) {}

   private:
    int32_t Encode(const VideoFrame& input_image,
                   const CodecSpecificInfo* codecSpecificInfo,
                   const std::vector<FrameType>* frame_types) override {
      CodecSpecificInfo specifics;
      specifics.codecType = kVideoCodecGeneric;

      uint8_t buffer[16] = {0};
      EncodedImage encoded(buffer, sizeof(buffer), sizeof(buffer));
      encoded._timeStamp = input_image.timestamp();
      encoded.capture_time_ms_ = input_image.render_time_ms();

      for (size_t i = 0; i < kNumStreams; ++i) {
        specifics.codecSpecific.generic.simulcast_idx = static_cast<uint8_t>(i);
        encoded._frameType = (*frame_types)[i];
        encoded._encodedWidth = kEncodedResolution[i].width;
        encoded._encodedHeight = kEncodedResolution[i].height;
        EncodedImageCallback* callback;
        {
          rtc::CritScope cs(&crit_sect_);
          callback = callback_;
        }
        RTC_DCHECK(callback);
        if (callback->OnEncodedImage(encoded, &specifics, nullptr).error !=
            EncodedImageCallback::Result::OK) {
          return -1;
        }
      }

      observation_complete_.Set();
      return 0;
    }
    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->encoder_settings.encoder = this;
      EXPECT_EQ(kNumStreams, encoder_config->number_of_streams);
    }

    size_t GetNumVideoStreams() const override { return kNumStreams; }

    void PerformTest() override {
      EXPECT_TRUE(Wait())
          << "Timed out while waiting for the encoder to send one frame.";
      VideoSendStream::Stats stats = send_stream_->GetStats();

      for (size_t i = 0; i < kNumStreams; ++i) {
        ASSERT_TRUE(stats.substreams.find(kVideoSendSsrcs[i]) !=
                    stats.substreams.end())
            << "No stats for SSRC: " << kVideoSendSsrcs[i]
            << ", stats should exist as soon as frames have been encoded.";
        VideoSendStream::StreamStats ssrc_stats =
            stats.substreams[kVideoSendSsrcs[i]];
        EXPECT_EQ(kEncodedResolution[i].width, ssrc_stats.width);
        EXPECT_EQ(kEncodedResolution[i].height, ssrc_stats.height);
      }
    }

    void OnVideoStreamsCreated(
        VideoSendStream* send_stream,
        const std::vector<VideoReceiveStream*>& receive_streams) override {
      send_stream_ = send_stream;
    }

    VideoSendStream* send_stream_;
  } test;

  RunBaseTest(&test);
}

#if !defined(RTC_DISABLE_VP9)
class Vp9HeaderObserver : public test::SendTest {
 public:
  Vp9HeaderObserver()
      : SendTest(VideoSendStreamTest::kLongTimeoutMs),
        vp9_encoder_(VP9Encoder::Create()),
        vp9_settings_(VideoEncoder::GetDefaultVp9Settings()),
        packets_sent_(0),
        frames_sent_(0),
        expected_width_(0),
        expected_height_(0) {}

  virtual void ModifyVideoConfigsHook(
      VideoSendStream::Config* send_config,
      std::vector<VideoReceiveStream::Config>* receive_configs,
      VideoEncoderConfig* encoder_config) {}

  virtual void InspectHeader(const RTPVideoHeaderVP9& vp9) = 0;

 private:
  const int kVp9PayloadType = 105;

  class VideoStreamFactory
      : public VideoEncoderConfig::VideoStreamFactoryInterface {
   public:
    explicit VideoStreamFactory(size_t number_of_temporal_layers)
        : number_of_temporal_layers_(number_of_temporal_layers) {}

   private:
    std::vector<VideoStream> CreateEncoderStreams(
        int width,
        int height,
        const VideoEncoderConfig& encoder_config) override {
      std::vector<VideoStream> streams =
          test::CreateVideoStreams(width, height, encoder_config);
      streams[0].temporal_layer_thresholds_bps.resize(
          number_of_temporal_layers_ - 1);
      return streams;
    }

    const size_t number_of_temporal_layers_;
  };

  void ModifyVideoConfigs(
      VideoSendStream::Config* send_config,
      std::vector<VideoReceiveStream::Config>* receive_configs,
      VideoEncoderConfig* encoder_config) override {
    send_config->encoder_settings.encoder = vp9_encoder_.get();
    send_config->encoder_settings.payload_name = "VP9";
    send_config->encoder_settings.payload_type = kVp9PayloadType;
    ModifyVideoConfigsHook(send_config, receive_configs, encoder_config);
    encoder_config->encoder_specific_settings = new rtc::RefCountedObject<
      VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings_);
    EXPECT_EQ(1u, encoder_config->number_of_streams);
    encoder_config->video_stream_factory =
        new rtc::RefCountedObject<VideoStreamFactory>(
            vp9_settings_.numberOfTemporalLayers);
    encoder_config_ = encoder_config->Copy();
  }

  void ModifyVideoCaptureStartResolution(int* width,
                                         int* height,
                                         int* frame_rate) override {
    expected_width_ = *width;
    expected_height_ = *height;
  }

  void PerformTest() override {
    EXPECT_TRUE(Wait()) << "Test timed out waiting for VP9 packet, num frames "
                        << frames_sent_;
  }

  Action OnSendRtp(const uint8_t* packet, size_t length) override {
    RTPHeader header;
    EXPECT_TRUE(parser_->Parse(packet, length, &header));

    EXPECT_EQ(kVp9PayloadType, header.payloadType);
    const uint8_t* payload = packet + header.headerLength;
    size_t payload_length = length - header.headerLength - header.paddingLength;

    bool new_packet = packets_sent_ == 0 ||
                      IsNewerSequenceNumber(header.sequenceNumber,
                                            last_header_.sequenceNumber);
    if (payload_length > 0 && new_packet) {
      RtpDepacketizer::ParsedPayload parsed;
      RtpDepacketizerVp9 depacketizer;
      EXPECT_TRUE(depacketizer.Parse(&parsed, payload, payload_length));
      EXPECT_EQ(RtpVideoCodecTypes::kRtpVideoVp9, parsed.type.Video.codec);
      // Verify common fields for all configurations.
      VerifyCommonHeader(parsed.type.Video.codecHeader.VP9);
      CompareConsecutiveFrames(header, parsed.type.Video);
      // Verify configuration specific settings.
      InspectHeader(parsed.type.Video.codecHeader.VP9);

      ++packets_sent_;
      if (header.markerBit) {
        ++frames_sent_;
      }
      last_header_ = header;
      last_vp9_ = parsed.type.Video.codecHeader.VP9;
    }
    return SEND_PACKET;
  }

 protected:
  bool ContinuousPictureId(const RTPVideoHeaderVP9& vp9) const {
    if (last_vp9_.picture_id > vp9.picture_id) {
      return vp9.picture_id == 0;  // Wrap.
    } else {
      return vp9.picture_id == last_vp9_.picture_id + 1;
    }
  }

  void VerifySpatialIdxWithinFrame(const RTPVideoHeaderVP9& vp9) const {
    bool new_layer = vp9.spatial_idx != last_vp9_.spatial_idx;
    EXPECT_EQ(new_layer, vp9.beginning_of_frame);
    EXPECT_EQ(new_layer, last_vp9_.end_of_frame);
    EXPECT_EQ(new_layer ? last_vp9_.spatial_idx + 1 : last_vp9_.spatial_idx,
              vp9.spatial_idx);
  }

  void VerifyFixedTemporalLayerStructure(const RTPVideoHeaderVP9& vp9,
                                         uint8_t num_layers) const {
    switch (num_layers) {
      case 0:
        VerifyTemporalLayerStructure0(vp9);
        break;
      case 1:
        VerifyTemporalLayerStructure1(vp9);
        break;
      case 2:
        VerifyTemporalLayerStructure2(vp9);
        break;
      case 3:
        VerifyTemporalLayerStructure3(vp9);
        break;
      default:
        RTC_NOTREACHED();
    }
  }

  void VerifyTemporalLayerStructure0(const RTPVideoHeaderVP9& vp9) const {
    EXPECT_EQ(kNoTl0PicIdx, vp9.tl0_pic_idx);
    EXPECT_EQ(kNoTemporalIdx, vp9.temporal_idx);  // no tid
    EXPECT_FALSE(vp9.temporal_up_switch);
  }

  void VerifyTemporalLayerStructure1(const RTPVideoHeaderVP9& vp9) const {
    EXPECT_NE(kNoTl0PicIdx, vp9.tl0_pic_idx);
    EXPECT_EQ(0, vp9.temporal_idx);  // 0,0,0,...
    EXPECT_FALSE(vp9.temporal_up_switch);
  }

  void VerifyTemporalLayerStructure2(const RTPVideoHeaderVP9& vp9) const {
    EXPECT_NE(kNoTl0PicIdx, vp9.tl0_pic_idx);
    EXPECT_GE(vp9.temporal_idx, 0);  // 0,1,0,1,... (tid reset on I-frames).
    EXPECT_LE(vp9.temporal_idx, 1);
    EXPECT_EQ(vp9.temporal_idx > 0, vp9.temporal_up_switch);
    if (IsNewPictureId(vp9)) {
      uint8_t expected_tid =
          (!vp9.inter_pic_predicted || last_vp9_.temporal_idx == 1) ? 0 : 1;
      EXPECT_EQ(expected_tid, vp9.temporal_idx);
    }
  }

  void VerifyTemporalLayerStructure3(const RTPVideoHeaderVP9& vp9) const {
    EXPECT_NE(kNoTl0PicIdx, vp9.tl0_pic_idx);
    EXPECT_GE(vp9.temporal_idx, 0);  // 0,2,1,2,... (tid reset on I-frames).
    EXPECT_LE(vp9.temporal_idx, 2);
    if (IsNewPictureId(vp9) && vp9.inter_pic_predicted) {
      EXPECT_NE(vp9.temporal_idx, last_vp9_.temporal_idx);
      switch (vp9.temporal_idx) {
        case 0:
          EXPECT_EQ(2, last_vp9_.temporal_idx);
          EXPECT_FALSE(vp9.temporal_up_switch);
          break;
        case 1:
          EXPECT_EQ(2, last_vp9_.temporal_idx);
          EXPECT_TRUE(vp9.temporal_up_switch);
          break;
        case 2:
          EXPECT_EQ(last_vp9_.temporal_idx == 0, vp9.temporal_up_switch);
          break;
      }
    }
  }

  void VerifyTl0Idx(const RTPVideoHeaderVP9& vp9) const {
    if (vp9.tl0_pic_idx == kNoTl0PicIdx)
      return;

    uint8_t expected_tl0_idx = last_vp9_.tl0_pic_idx;
    if (vp9.temporal_idx == 0)
      ++expected_tl0_idx;
    EXPECT_EQ(expected_tl0_idx, vp9.tl0_pic_idx);
  }

  bool IsNewPictureId(const RTPVideoHeaderVP9& vp9) const {
    return frames_sent_ > 0 && (vp9.picture_id != last_vp9_.picture_id);
  }

  // Flexible mode (F=1):    Non-flexible mode (F=0):
  //
  //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+
  //      |I|P|L|F|B|E|V|-|     |I|P|L|F|B|E|V|-|
  //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+
  // I:   |M| PICTURE ID  |  I: |M| PICTURE ID  |
  //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+
  // M:   | EXTENDED PID  |  M: | EXTENDED PID  |
  //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+
  // L:   |  T  |U|  S  |D|  L: |  T  |U|  S  |D|
  //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+
  // P,F: | P_DIFF    |X|N|     |   TL0PICIDX   |
  //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+
  // X:   |EXTENDED P_DIFF|  V: | SS  ..        |
  //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+
  // V:   | SS  ..        |
  //      +-+-+-+-+-+-+-+-+
  void VerifyCommonHeader(const RTPVideoHeaderVP9& vp9) const {
    EXPECT_EQ(kMaxTwoBytePictureId, vp9.max_picture_id);       // M:1
    EXPECT_NE(kNoPictureId, vp9.picture_id);                   // I:1
    EXPECT_EQ(vp9_settings_.flexibleMode, vp9.flexible_mode);  // F
    EXPECT_GE(vp9.spatial_idx, 0);                             // S
    EXPECT_LT(vp9.spatial_idx, vp9_settings_.numberOfSpatialLayers);
    if (vp9.ss_data_available)  // V
      VerifySsData(vp9);

    if (frames_sent_ == 0)
      EXPECT_FALSE(vp9.inter_pic_predicted);  // P

    if (!vp9.inter_pic_predicted) {
      EXPECT_TRUE(vp9.temporal_idx == 0 || vp9.temporal_idx == kNoTemporalIdx);
      EXPECT_FALSE(vp9.temporal_up_switch);
    }
  }

  // Scalability structure (SS).
  //
  //      +-+-+-+-+-+-+-+-+
  // V:   | N_S |Y|G|-|-|-|
  //      +-+-+-+-+-+-+-+-+
  // Y:   |    WIDTH      |  N_S + 1 times
  //      +-+-+-+-+-+-+-+-+
  //      |    HEIGHT     |
  //      +-+-+-+-+-+-+-+-+
  // G:   |      N_G      |
  //      +-+-+-+-+-+-+-+-+
  // N_G: |  T  |U| R |-|-|  N_G times
  //      +-+-+-+-+-+-+-+-+
  //      |    P_DIFF     |  R times
  //      +-+-+-+-+-+-+-+-+
  void VerifySsData(const RTPVideoHeaderVP9& vp9) const {
    EXPECT_TRUE(vp9.ss_data_available);             // V
    EXPECT_EQ(vp9_settings_.numberOfSpatialLayers,  // N_S + 1
              vp9.num_spatial_layers);
    EXPECT_TRUE(vp9.spatial_layer_resolution_present);  // Y:1
    int expected_width = expected_width_;
    int expected_height = expected_height_;
    for (int i = static_cast<int>(vp9.num_spatial_layers) - 1; i >= 0; --i) {
      EXPECT_EQ(expected_width, vp9.width[i]);    // WIDTH
      EXPECT_EQ(expected_height, vp9.height[i]);  // HEIGHT
      expected_width /= 2;
      expected_height /= 2;
    }
  }

  void CompareConsecutiveFrames(const RTPHeader& header,
                                const RTPVideoHeader& video) const {
    const RTPVideoHeaderVP9& vp9 = video.codecHeader.VP9;

    bool new_frame = packets_sent_ == 0 ||
                     IsNewerTimestamp(header.timestamp, last_header_.timestamp);
    EXPECT_EQ(new_frame, video.is_first_packet_in_frame);
    if (!new_frame) {
      EXPECT_FALSE(last_header_.markerBit);
      EXPECT_EQ(last_header_.timestamp, header.timestamp);
      EXPECT_EQ(last_vp9_.picture_id, vp9.picture_id);
      EXPECT_EQ(last_vp9_.temporal_idx, vp9.temporal_idx);
      EXPECT_EQ(last_vp9_.tl0_pic_idx, vp9.tl0_pic_idx);
      VerifySpatialIdxWithinFrame(vp9);
      return;
    }
    // New frame.
    EXPECT_TRUE(vp9.beginning_of_frame);

    // Compare with last packet in previous frame.
    if (frames_sent_ == 0)
      return;
    EXPECT_TRUE(last_vp9_.end_of_frame);
    EXPECT_TRUE(last_header_.markerBit);
    EXPECT_TRUE(ContinuousPictureId(vp9));
    VerifyTl0Idx(vp9);
  }

  std::unique_ptr<VP9Encoder> vp9_encoder_;
  VideoCodecVP9 vp9_settings_;
  webrtc::VideoEncoderConfig encoder_config_;
  RTPHeader last_header_;
  RTPVideoHeaderVP9 last_vp9_;
  size_t packets_sent_;
  size_t frames_sent_;
  int expected_width_;
  int expected_height_;
};

TEST_F(VideoSendStreamTest, Vp9NonFlexMode_1Tl1SLayers) {
  const uint8_t kNumTemporalLayers = 1;
  const uint8_t kNumSpatialLayers = 1;
  TestVp9NonFlexMode(kNumTemporalLayers, kNumSpatialLayers);
}

TEST_F(VideoSendStreamTest, Vp9NonFlexMode_2Tl1SLayers) {
  const uint8_t kNumTemporalLayers = 2;
  const uint8_t kNumSpatialLayers = 1;
  TestVp9NonFlexMode(kNumTemporalLayers, kNumSpatialLayers);
}

TEST_F(VideoSendStreamTest, Vp9NonFlexMode_3Tl1SLayers) {
  const uint8_t kNumTemporalLayers = 3;
  const uint8_t kNumSpatialLayers = 1;
  TestVp9NonFlexMode(kNumTemporalLayers, kNumSpatialLayers);
}

TEST_F(VideoSendStreamTest, Vp9NonFlexMode_1Tl2SLayers) {
  const uint8_t kNumTemporalLayers = 1;
  const uint8_t kNumSpatialLayers = 2;
  TestVp9NonFlexMode(kNumTemporalLayers, kNumSpatialLayers);
}

TEST_F(VideoSendStreamTest, Vp9NonFlexMode_2Tl2SLayers) {
  const uint8_t kNumTemporalLayers = 2;
  const uint8_t kNumSpatialLayers = 2;
  TestVp9NonFlexMode(kNumTemporalLayers, kNumSpatialLayers);
}

TEST_F(VideoSendStreamTest, Vp9NonFlexMode_3Tl2SLayers) {
  const uint8_t kNumTemporalLayers = 3;
  const uint8_t kNumSpatialLayers = 2;
  TestVp9NonFlexMode(kNumTemporalLayers, kNumSpatialLayers);
}

void VideoSendStreamTest::TestVp9NonFlexMode(uint8_t num_temporal_layers,
                                             uint8_t num_spatial_layers) {
  static const size_t kNumFramesToSend = 100;
  // Set to < kNumFramesToSend and coprime to length of temporal layer
  // structures to verify temporal id reset on key frame.
  static const int kKeyFrameInterval = 31;
  class NonFlexibleMode : public Vp9HeaderObserver {
   public:
    NonFlexibleMode(uint8_t num_temporal_layers, uint8_t num_spatial_layers)
        : num_temporal_layers_(num_temporal_layers),
          num_spatial_layers_(num_spatial_layers),
          l_field_(num_temporal_layers > 1 || num_spatial_layers > 1) {}
    void ModifyVideoConfigsHook(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      vp9_settings_.flexibleMode = false;
      vp9_settings_.frameDroppingOn = false;
      vp9_settings_.keyFrameInterval = kKeyFrameInterval;
      vp9_settings_.numberOfTemporalLayers = num_temporal_layers_;
      vp9_settings_.numberOfSpatialLayers = num_spatial_layers_;
    }

    void InspectHeader(const RTPVideoHeaderVP9& vp9) override {
      bool ss_data_expected = !vp9.inter_pic_predicted &&
                              vp9.beginning_of_frame && vp9.spatial_idx == 0;
      EXPECT_EQ(ss_data_expected, vp9.ss_data_available);
      EXPECT_EQ(vp9.spatial_idx > 0, vp9.inter_layer_predicted);  // D
      EXPECT_EQ(!vp9.inter_pic_predicted,
                frames_sent_ % kKeyFrameInterval == 0);

      if (IsNewPictureId(vp9)) {
        EXPECT_EQ(0, vp9.spatial_idx);
        EXPECT_EQ(num_spatial_layers_ - 1, last_vp9_.spatial_idx);
      }

      VerifyFixedTemporalLayerStructure(vp9,
                                        l_field_ ? num_temporal_layers_ : 0);

      if (frames_sent_ > kNumFramesToSend)
        observation_complete_.Set();
    }
    const uint8_t num_temporal_layers_;
    const uint8_t num_spatial_layers_;
    const bool l_field_;
  } test(num_temporal_layers, num_spatial_layers);

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, Vp9NonFlexModeSmallResolution) {
  static const size_t kNumFramesToSend = 50;
  static const int kWidth = 4;
  static const int kHeight = 4;
  class NonFlexibleModeResolution : public Vp9HeaderObserver {
    void ModifyVideoConfigsHook(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      vp9_settings_.flexibleMode = false;
      vp9_settings_.numberOfTemporalLayers = 1;
      vp9_settings_.numberOfSpatialLayers = 1;

      EXPECT_EQ(1u, encoder_config->number_of_streams);
    }

    void InspectHeader(const RTPVideoHeaderVP9& vp9_header) override {
      if (frames_sent_ > kNumFramesToSend)
        observation_complete_.Set();
    }

    void ModifyVideoCaptureStartResolution(int* width,
                                           int* height,
                                           int* frame_rate) override {
      expected_width_ = kWidth;
      expected_height_ = kHeight;
      *width = kWidth;
      *height = kHeight;
    }
  } test;

  RunBaseTest(&test);
}

TEST_F(VideoSendStreamTest, Vp9FlexModeRefCount) {
  class FlexibleMode : public Vp9HeaderObserver {
    void ModifyVideoConfigsHook(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      encoder_config->content_type = VideoEncoderConfig::ContentType::kScreen;
      vp9_settings_.flexibleMode = true;
      vp9_settings_.numberOfTemporalLayers = 1;
      vp9_settings_.numberOfSpatialLayers = 2;
    }

    void InspectHeader(const RTPVideoHeaderVP9& vp9_header) override {
      EXPECT_TRUE(vp9_header.flexible_mode);
      EXPECT_EQ(kNoTl0PicIdx, vp9_header.tl0_pic_idx);
      if (vp9_header.inter_pic_predicted) {
        EXPECT_GT(vp9_header.num_ref_pics, 0u);
        observation_complete_.Set();
      }
    }
  } test;

  RunBaseTest(&test);
}
#endif  // !defined(RTC_DISABLE_VP9)

void VideoSendStreamTest::TestRequestSourceRotateVideo(
    bool support_orientation_ext) {
  CreateSenderCall(Call::Config(&event_log_));

  test::NullTransport transport;
  CreateSendConfig(1, 0, 0, &transport);
  video_send_config_.rtp.extensions.clear();
  if (support_orientation_ext) {
    video_send_config_.rtp.extensions.push_back(
        RtpExtension(RtpExtension::kVideoRotationUri, 1));
  }

  CreateVideoStreams();
  test::FrameForwarder forwarder;
  video_send_stream_->SetSource(
      &forwarder, VideoSendStream::DegradationPreference::kBalanced);

  EXPECT_TRUE(forwarder.sink_wants().rotation_applied !=
              support_orientation_ext);

  DestroyStreams();
}

TEST_F(VideoSendStreamTest,
       RequestSourceRotateIfVideoOrientationExtensionNotSupported) {
  TestRequestSourceRotateVideo(false);
}

TEST_F(VideoSendStreamTest,
       DoNotRequestsRotationIfVideoOrientationExtensionSupported) {
  TestRequestSourceRotateVideo(true);
}

// This test verifies that overhead is removed from the bandwidth estimate by
// testing that the maximum possible target payload rate is smaller than the
// maximum bandwidth estimate by the overhead rate.
TEST_F(VideoSendStreamTest, RemoveOverheadFromBandwidth) {
  test::ScopedFieldTrials override_field_trials(
      "WebRTC-SendSideBwe-WithOverhead/Enabled/");
  class RemoveOverheadFromBandwidthTest : public test::EndToEndTest,
                                          public test::FakeEncoder {
   public:
    RemoveOverheadFromBandwidthTest()
        : EndToEndTest(test::CallTest::kDefaultTimeoutMs),
          FakeEncoder(Clock::GetRealTimeClock()),
          call_(nullptr),
          max_bitrate_bps_(0),
          first_packet_sent_(false),
          bitrate_changed_event_(false, false) {}

    int32_t SetRateAllocation(const BitrateAllocation& bitrate,
                              uint32_t frameRate) override {
      rtc::CritScope lock(&crit_);
      // Wait for the first sent packet so that videosendstream knows
      // rtp_overhead.
      if (first_packet_sent_) {
        max_bitrate_bps_ = bitrate.get_sum_bps();
        bitrate_changed_event_.Set();
      }
      return FakeEncoder::SetRateAllocation(bitrate, frameRate);
    }

    void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
      call_ = sender_call;
    }

    void ModifyVideoConfigs(
        VideoSendStream::Config* send_config,
        std::vector<VideoReceiveStream::Config>* receive_configs,
        VideoEncoderConfig* encoder_config) override {
      send_config->rtp.max_packet_size = 1200;
      send_config->encoder_settings.encoder = this;
      EXPECT_FALSE(send_config->rtp.extensions.empty());
    }

    Action OnSendRtp(const uint8_t* packet, size_t length) override {
      rtc::CritScope lock(&crit_);
      first_packet_sent_ = true;
      return SEND_PACKET;
    }

    void PerformTest() override {
      Call::Config::BitrateConfig bitrate_config;
      constexpr int kStartBitrateBps = 60000;
      constexpr int kMaxBitrateBps = 60000;
      constexpr int kMinBitrateBps = 10000;
      bitrate_config.start_bitrate_bps = kStartBitrateBps;
      bitrate_config.max_bitrate_bps = kMaxBitrateBps;
      bitrate_config.min_bitrate_bps = kMinBitrateBps;
      call_->SetBitrateConfig(bitrate_config);
      call_->OnTransportOverheadChanged(webrtc::MediaType::VIDEO, 40);

      // At a bitrate of 60kbps with a packet size of 1200B video and an
      // overhead of 40B per packet video produces 2240bps overhead.
      // So the encoder BW should be set to 57760bps.
      bitrate_changed_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs);
      {
        rtc::CritScope lock(&crit_);
        EXPECT_LE(max_bitrate_bps_, 57760u);
      }
    }

   private:
    Call* call_;
    rtc::CriticalSection crit_;
    uint32_t max_bitrate_bps_ GUARDED_BY(&crit_);
    bool first_packet_sent_ GUARDED_BY(&crit_);
    rtc::Event bitrate_changed_event_;
  } test;

  RunBaseTest(&test);
}

}  // namespace webrtc
