Let ViEEncoder tell VideoSendStream about reconfigurations.

This cl change so that all encoder configuration changes are reported to VideoSendStream through the ViEEncoder.
Also, the PayLoadRouter is changed to never stop sending on a an ssrc due to the encoder video frame size changes. Instead, the number of sending streams is only decided by the number of sending ssrc.

This cl is a preparation for moving encoder reconfiguration due to input video frame size changes from WebRtcVideoSendStream to ViEEncoder.

BUG=webrtc:5687, webrtc:6371
R=mflodman@webrtc.org

Review URL: https://codereview.webrtc.org/2338133003 .

Cr-Commit-Position: refs/heads/master@{#14371}
diff --git a/webrtc/video/payload_router.cc b/webrtc/video/payload_router.cc
index 5bcf705..2cc3e88 100644
--- a/webrtc/video/payload_router.cc
+++ b/webrtc/video/payload_router.cc
@@ -90,10 +90,8 @@
 PayloadRouter::PayloadRouter(const std::vector<RtpRtcp*>& rtp_modules,
                              int payload_type)
     : active_(false),
-      num_sending_modules_(1),
       rtp_modules_(rtp_modules),
       payload_type_(payload_type) {
-  UpdateModuleSendingState();
 }
 
 PayloadRouter::~PayloadRouter() {}
@@ -108,7 +106,11 @@
   if (active_ == active)
     return;
   active_ = active;
-  UpdateModuleSendingState();
+
+  for (auto& module : rtp_modules_) {
+    module->SetSendingStatus(active_);
+    module->SetSendingMediaStatus(active_);
+  }
 }
 
 bool PayloadRouter::active() {
@@ -116,34 +118,13 @@
   return active_ && !rtp_modules_.empty();
 }
 
-void PayloadRouter::SetSendStreams(const std::vector<VideoStream>& streams) {
-  RTC_DCHECK_LE(streams.size(), rtp_modules_.size());
-  rtc::CritScope lock(&crit_);
-  num_sending_modules_ = streams.size();
-  streams_ = streams;
-  // TODO(perkj): Should SetSendStreams also call SetTargetSendBitrate?
-  UpdateModuleSendingState();
-}
-
-void PayloadRouter::UpdateModuleSendingState() {
-  for (size_t i = 0; i < num_sending_modules_; ++i) {
-    rtp_modules_[i]->SetSendingStatus(active_);
-    rtp_modules_[i]->SetSendingMediaStatus(active_);
-  }
-  // Disable inactive modules.
-  for (size_t i = num_sending_modules_; i < rtp_modules_.size(); ++i) {
-    rtp_modules_[i]->SetSendingStatus(false);
-    rtp_modules_[i]->SetSendingMediaStatus(false);
-  }
-}
-
 EncodedImageCallback::Result PayloadRouter::OnEncodedImage(
     const EncodedImage& encoded_image,
     const CodecSpecificInfo* codec_specific_info,
     const RTPFragmentationHeader* fragmentation) {
   rtc::CritScope lock(&crit_);
   RTC_DCHECK(!rtp_modules_.empty());
-  if (!active_ || num_sending_modules_ == 0)
+  if (!active_)
     return Result(Result::ERROR_SEND_FAILED);
 
   int stream_index = 0;
@@ -154,12 +135,6 @@
     CopyCodecSpecific(codec_specific_info, &rtp_video_header);
   rtp_video_header.rotation = encoded_image.rotation_;
   rtp_video_header.playout_delay = encoded_image.playout_delay_;
-
-  RTC_DCHECK_LT(rtp_video_header.simulcastIdx, rtp_modules_.size());
-  // The simulcast index might actually be larger than the number of modules
-  // in case the encoder was processing a frame during a codec reconfig.
-  if (rtp_video_header.simulcastIdx >= num_sending_modules_)
-    return Result(Result::ERROR_SEND_FAILED);
   stream_index = rtp_video_header.simulcastIdx;
 
   uint32_t frame_id;
@@ -168,6 +143,7 @@
       encoded_image.capture_time_ms_, encoded_image._buffer,
       encoded_image._length, fragmentation, &rtp_video_header, &frame_id);
 
+  RTC_DCHECK_LT(rtp_video_header.simulcastIdx, rtp_modules_.size());
   if (send_result < 0)
     return Result(Result::ERROR_SEND_FAILED);
 
@@ -177,7 +153,7 @@
 size_t PayloadRouter::MaxPayloadLength() const {
   size_t min_payload_length = DefaultMaxPayloadLength();
   rtc::CritScope lock(&crit_);
-  for (size_t i = 0; i < num_sending_modules_; ++i) {
+  for (size_t i = 0; i < rtp_modules_.size(); ++i) {
     size_t module_payload_length = rtp_modules_[i]->MaxDataPayloadLength();
     if (module_payload_length < min_payload_length)
       min_payload_length = module_payload_length;
diff --git a/webrtc/video/payload_router.h b/webrtc/video/payload_router.h
index 24aee74..6426b00 100644
--- a/webrtc/video/payload_router.h
+++ b/webrtc/video/payload_router.h
@@ -37,7 +37,6 @@
   ~PayloadRouter();
 
   static size_t DefaultMaxPayloadLength();
-  void SetSendStreams(const std::vector<VideoStream>& streams);
 
   // PayloadRouter will only route packets if being active, all packets will be
   // dropped otherwise.
@@ -60,8 +59,6 @@
 
   rtc::CriticalSection crit_;
   bool active_ GUARDED_BY(crit_);
-  std::vector<VideoStream> streams_ GUARDED_BY(crit_);
-  size_t num_sending_modules_ GUARDED_BY(crit_);
 
   // Rtp modules are assumed to be sorted in simulcast index order. Not owned.
   const std::vector<RtpRtcp*> rtp_modules_;
diff --git a/webrtc/video/payload_router_unittest.cc b/webrtc/video/payload_router_unittest.cc
index def76b7..b5255d3 100644
--- a/webrtc/video/payload_router_unittest.cc
+++ b/webrtc/video/payload_router_unittest.cc
@@ -39,7 +39,6 @@
   encoded_image._length = 1;
 
   PayloadRouter payload_router(modules, payload_type);
-  payload_router.SetSendStreams(streams);
 
   EXPECT_CALL(rtp, SendOutgoingData(encoded_image._frameType, payload_type,
                                     encoded_image._timeStamp,
@@ -71,15 +70,6 @@
                                     encoded_image._length, nullptr, _, _))
       .Times(1);
   EXPECT_EQ(0, payload_router.Encoded(encoded_image, nullptr, nullptr));
-
-  streams.clear();
-  payload_router.SetSendStreams(streams);
-  EXPECT_CALL(rtp, SendOutgoingData(encoded_image._frameType, payload_type,
-                                    encoded_image._timeStamp,
-                                    encoded_image.capture_time_ms_, &payload,
-                                    encoded_image._length, nullptr, _, _))
-      .Times(0);
-  EXPECT_EQ(-1, payload_router.Encoded(encoded_image, nullptr, nullptr));
 }
 
 TEST(PayloadRouterTest, SendSimulcast) {
@@ -100,7 +90,6 @@
   encoded_image._length = 1;
 
   PayloadRouter payload_router(modules, payload_type);
-  payload_router.SetSendStreams(streams);
 
   CodecSpecificInfo codec_info_1;
   memset(&codec_info_1, 0, sizeof(CodecSpecificInfo));
@@ -138,17 +127,6 @@
       .Times(0);
   EXPECT_EQ(-1, payload_router.Encoded(encoded_image, &codec_info_1, nullptr));
   EXPECT_EQ(-1, payload_router.Encoded(encoded_image, &codec_info_2, nullptr));
-
-  // Invalid simulcast index.
-  streams.pop_back();  // Remove a stream.
-  payload_router.SetSendStreams(streams);
-  payload_router.set_active(true);
-  EXPECT_CALL(rtp_1, SendOutgoingData(_, _, _, _, _, _, _, _, _))
-      .Times(0);
-  EXPECT_CALL(rtp_2, SendOutgoingData(_, _, _, _, _, _, _, _, _))
-      .Times(0);
-  codec_info_2.codecSpecific.VP8.simulcastIdx = 1;
-  EXPECT_EQ(-1, payload_router.Encoded(encoded_image, &codec_info_2, nullptr));
 }
 
 TEST(PayloadRouterTest, MaxPayloadLength) {
@@ -164,7 +142,6 @@
 
   EXPECT_EQ(kDefaultMaxLength, PayloadRouter::DefaultMaxPayloadLength());
   std::vector<VideoStream> streams(2);
-  payload_router.SetSendStreams(streams);
 
   // Modules return a higher length than the default value.
   EXPECT_CALL(rtp_1, MaxDataPayloadLength())
diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc
index e9654dd..c8541fe 100644
--- a/webrtc/video/video_send_stream.cc
+++ b/webrtc/video/video_send_stream.cc
@@ -202,23 +202,23 @@
   return false;
 }
 
-int CalculateMaxPadBitrateBps(const VideoEncoderConfig& config,
+int CalculateMaxPadBitrateBps(std::vector<VideoStream> streams,
+                              int min_transmit_bitrate_bps,
                               bool pad_to_min_bitrate) {
   int pad_up_to_bitrate_bps = 0;
   // Calculate max padding bitrate for a multi layer codec.
-  if (config.streams.size() > 1) {
+  if (streams.size() > 1) {
     // Pad to min bitrate of the highest layer.
-    pad_up_to_bitrate_bps =
-        config.streams[config.streams.size() - 1].min_bitrate_bps;
+    pad_up_to_bitrate_bps = streams[streams.size() - 1].min_bitrate_bps;
     // Add target_bitrate_bps of the lower layers.
-    for (size_t i = 0; i < config.streams.size() - 1; ++i)
-      pad_up_to_bitrate_bps += config.streams[i].target_bitrate_bps;
+    for (size_t i = 0; i < streams.size() - 1; ++i)
+      pad_up_to_bitrate_bps += streams[i].target_bitrate_bps;
   } else if (pad_to_min_bitrate) {
-    pad_up_to_bitrate_bps = config.streams[0].min_bitrate_bps;
+    pad_up_to_bitrate_bps = streams[0].min_bitrate_bps;
   }
 
   pad_up_to_bitrate_bps =
-      std::max(pad_up_to_bitrate_bps, config.min_transmit_bitrate_bps);
+      std::max(pad_up_to_bitrate_bps, min_transmit_bitrate_bps);
 
   return pad_up_to_bitrate_bps;
 }
@@ -236,7 +236,7 @@
 // arbitrary thread.
 class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
                             public webrtc::VCMProtectionCallback,
-                            public EncodedImageCallback {
+                            public ViEEncoder::EncoderSink {
  public:
   VideoSendStreamImpl(SendStatisticsProxy* stats_proxy,
                       rtc::TaskQueue* worker_queue,
@@ -248,6 +248,7 @@
                       ViEEncoder* vie_encoder,
                       RtcEventLog* event_log,
                       const VideoSendStream::Config* config,
+                      int initial_encoder_max_bitrate,
                       std::map<uint32_t, RtpState> suspended_ssrcs);
   ~VideoSendStreamImpl() override;
 
@@ -264,11 +265,11 @@
   void Start();
   void Stop();
 
-  void SignalEncoderConfigurationChanged(const VideoEncoderConfig& config);
   VideoSendStream::RtpStateMap GetRtpStates() const;
 
  private:
   class CheckEncoderActivityTask;
+  class EncoderReconfiguredTask;
 
   // Implements BitrateAllocatorObserver.
   uint32_t OnBitrateUpdated(uint32_t bitrate_bps,
@@ -282,6 +283,9 @@
                         uint32_t* sent_nack_rate_bps,
                         uint32_t* sent_fec_rate_bps) override;
 
+  void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
+                                     int min_transmit_bitrate_bps) override;
+
   // Implements EncodedImageCallback. The implementation routes encoded frames
   // to the |payload_router_| and |config.pre_encode_callback| if set.
   // Called on an arbitrary encoder callback thread.
@@ -306,6 +310,7 @@
   rtc::CriticalSection encoder_activity_crit_sect_;
   CheckEncoderActivityTask* check_encoder_activity_task_
       GUARDED_BY(encoder_activity_crit_sect_);
+
   CallStats* const call_stats_;
   CongestionController* const congestion_controller_;
   BitrateAllocator* const bitrate_allocator_;
@@ -346,6 +351,7 @@
                    VieRemb* remb,
                    RtcEventLog* event_log,
                    const VideoSendStream::Config* config,
+                   int initial_encoder_max_bitrate,
                    const std::map<uint32_t, RtpState>& suspended_ssrcs)
       : send_stream_(send_stream),
         done_event_(done_event),
@@ -358,6 +364,7 @@
         remb_(remb),
         event_log_(event_log),
         config_(config),
+        initial_encoder_max_bitrate_(initial_encoder_max_bitrate),
         suspended_ssrcs_(suspended_ssrcs) {}
 
   ~ConstructionTask() override { done_event_->Set(); }
@@ -367,7 +374,8 @@
     send_stream_->reset(new VideoSendStreamImpl(
         stats_proxy_, rtc::TaskQueue::Current(), call_stats_,
         congestion_controller_, bitrate_allocator_, send_delay_stats_, remb_,
-        vie_encoder_, event_log_, config_, std::move(suspended_ssrcs_)));
+        vie_encoder_, event_log_, config_, initial_encoder_max_bitrate_,
+        std::move(suspended_ssrcs_)));
     return true;
   }
 
@@ -382,6 +390,7 @@
   VieRemb* const remb_;
   RtcEventLog* const event_log_;
   const VideoSendStream::Config* config_;
+  int initial_encoder_max_bitrate_;
   std::map<uint32_t, RtpState> suspended_ssrcs_;
 };
 
@@ -461,20 +470,25 @@
   bool timed_out_;
 };
 
-class ReconfigureVideoEncoderTask : public rtc::QueuedTask {
+class VideoSendStreamImpl::EncoderReconfiguredTask : public rtc::QueuedTask {
  public:
-  ReconfigureVideoEncoderTask(VideoSendStreamImpl* send_stream,
-                              VideoEncoderConfig config)
-      : send_stream_(send_stream), config_(std::move(config)) {}
+  EncoderReconfiguredTask(VideoSendStreamImpl* send_stream,
+                          std::vector<VideoStream> streams,
+                          int min_transmit_bitrate_bps)
+      : send_stream_(send_stream),
+        streams_(std::move(streams)),
+        min_transmit_bitrate_bps_(min_transmit_bitrate_bps) {}
 
  private:
   bool Run() override {
-    send_stream_->SignalEncoderConfigurationChanged(std::move(config_));
+    send_stream_->OnEncoderConfigurationChanged(std::move(streams_),
+                                                min_transmit_bitrate_bps_);
     return true;
   }
 
   VideoSendStreamImpl* send_stream_;
-  VideoEncoderConfig config_;
+  std::vector<VideoStream> streams_;
+  int min_transmit_bitrate_bps_;
 };
 
 VideoSendStream::VideoSendStream(
@@ -501,11 +515,18 @@
                      config_.pre_encode_callback, config_.overuse_callback,
                      config_.post_encode_callback));
 
+  // TODO(perkj): Remove vector<VideoStreams> from VideoEncoderConfig and
+  // replace with max_bitrate. The VideoStream should be created by ViEEncoder
+  // when the video resolution is known.
+  int initial_max_encoder_bitrate = 0;
+  for (const auto& stream : encoder_config.streams)
+    initial_max_encoder_bitrate += stream.max_bitrate_bps;
+
   worker_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(new ConstructionTask(
       &send_stream_, &thread_sync_event_, &stats_proxy_, vie_encoder_.get(),
       module_process_thread, call_stats, congestion_controller,
       bitrate_allocator, send_delay_stats, remb, event_log, &config_,
-      suspended_ssrcs)));
+      initial_max_encoder_bitrate, suspended_ssrcs)));
 
   // Wait for ConstructionTask to complete so that |send_stream_| can be used.
   // |module_process_thread| must be registered and deregistered on the thread
@@ -558,10 +579,8 @@
   // TODO(perkj): Move logic for reconfiguration the encoder due to frame size
   // change from WebRtcVideoChannel2::WebRtcVideoSendStream::OnFrame to
   // be internally handled by ViEEncoder.
-  vie_encoder_->ConfigureEncoder(config, config_.rtp.max_packet_size);
-
-  worker_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(
-      new ReconfigureVideoEncoderTask(send_stream_.get(), std::move(config))));
+  vie_encoder_->ConfigureEncoder(std::move(config),
+                                 config_.rtp.max_packet_size);
 }
 
 VideoSendStream::Stats VideoSendStream::GetStats() {
@@ -607,6 +626,7 @@
     ViEEncoder* vie_encoder,
     RtcEventLog* event_log,
     const VideoSendStream::Config* config,
+    int initial_encoder_max_bitrate,
     std::map<uint32_t, RtpState> suspended_ssrcs)
     : stats_proxy_(stats_proxy),
       config_(config),
@@ -620,7 +640,7 @@
       remb_(remb),
       max_padding_bitrate_(0),
       encoder_min_bitrate_bps_(0),
-      encoder_max_bitrate_bps_(0),
+      encoder_max_bitrate_bps_(initial_encoder_max_bitrate),
       encoder_target_rate_bps_(0),
       vie_encoder_(vie_encoder),
       encoder_feedback_(Clock::GetRealTimeClock(),
@@ -801,35 +821,44 @@
       max_padding_bitrate_, !config_->suspend_below_min_bitrate);
 }
 
-void VideoSendStreamImpl::SignalEncoderConfigurationChanged(
-    const VideoEncoderConfig& config) {
-  RTC_DCHECK_GE(config_->rtp.ssrcs.size(), config.streams.size());
-  TRACE_EVENT0("webrtc", "VideoSendStream::SignalEncoderConfigurationChanged");
-  LOG(LS_INFO) << "SignalEncoderConfigurationChanged: " << config.ToString();
-  RTC_DCHECK_GE(config_->rtp.ssrcs.size(), config.streams.size());
+void VideoSendStreamImpl::OnEncoderConfigurationChanged(
+    std::vector<VideoStream> streams,
+    int min_transmit_bitrate_bps) {
+  if (!worker_queue_->IsCurrent()) {
+    // TODO(perkj): Using |this| in post is safe for now since destruction of
+    // VideoSendStreamImpl is synchronized in
+    // VideoSendStream::StopPermanentlyAndGetRtpStates. But we should really
+    // use some kind of weak_ptr to guarantee that VideoSendStreamImpl is still
+    // alive when this task runs.
+    worker_queue_->PostTask(
+        std::unique_ptr<rtc::QueuedTask>(new EncoderReconfiguredTask(
+            this, std::move(streams), min_transmit_bitrate_bps)));
+    return;
+  }
+  RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size());
+  TRACE_EVENT0("webrtc", "VideoSendStream::OnEncoderConfigurationChanged");
+  RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size());
   RTC_DCHECK_RUN_ON(worker_queue_);
 
   const int kEncoderMinBitrateBps = 30000;
   encoder_min_bitrate_bps_ =
-      std::max(config.streams[0].min_bitrate_bps, kEncoderMinBitrateBps);
+      std::max(streams[0].min_bitrate_bps, kEncoderMinBitrateBps);
   encoder_max_bitrate_bps_ = 0;
-  for (const auto& stream : config.streams)
+  for (const auto& stream : streams)
     encoder_max_bitrate_bps_ += stream.max_bitrate_bps;
-  max_padding_bitrate_ =
-      CalculateMaxPadBitrateBps(config, config_->suspend_below_min_bitrate);
-
-  payload_router_.SetSendStreams(config.streams);
+  max_padding_bitrate_ = CalculateMaxPadBitrateBps(
+      streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate);
 
   // Clear stats for disabled layers.
-  for (size_t i = config.streams.size(); i < config_->rtp.ssrcs.size(); ++i) {
+  for (size_t i = streams.size(); i < config_->rtp.ssrcs.size(); ++i) {
     stats_proxy_->OnInactiveSsrc(config_->rtp.ssrcs[i]);
   }
 
   size_t number_of_temporal_layers =
-      config.streams.back().temporal_layer_thresholds_bps.size() + 1;
+      streams.back().temporal_layer_thresholds_bps.size() + 1;
   protection_bitrate_calculator_.SetEncodingData(
-      config.streams[0].width, config.streams[0].height,
-      number_of_temporal_layers, config_->rtp.max_packet_size);
+      streams[0].width, streams[0].height, number_of_temporal_layers,
+      config_->rtp.max_packet_size);
 
   if (payload_router_.active()) {
     // The send stream is started already. Update the allocator with new bitrate
diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc
index cd6d88d..5e1d294d 100644
--- a/webrtc/video/vie_encoder.cc
+++ b/webrtc/video/vie_encoder.cc
@@ -12,6 +12,7 @@
 
 #include <algorithm>
 #include <limits>
+#include <utility>
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
@@ -367,7 +368,7 @@
   source_proxy_->SetSource(source);
 }
 
-void ViEEncoder::SetSink(EncodedImageCallback* sink) {
+void ViEEncoder::SetSink(EncoderSink* sink) {
   encoder_queue_.PostTask([this, sink] {
     RTC_DCHECK_RUN_ON(&encoder_queue_);
     sink_ = sink;
@@ -381,18 +382,25 @@
   });
 }
 
-void ViEEncoder::ConfigureEncoder(const VideoEncoderConfig& config,
+void ViEEncoder::ConfigureEncoder(VideoEncoderConfig config,
                                   size_t max_data_payload_length) {
   VideoCodec video_codec = VideoEncoderConfigToVideoCodec(
       config, settings_.payload_name, settings_.payload_type);
-  encoder_queue_.PostTask([this, video_codec, max_data_payload_length] {
-    ConfigureEncoderInternal(video_codec, max_data_payload_length);
+  LOG(LS_INFO) << "ConfigureEncoder: " << config.ToString();
+  std::vector<VideoStream> stream = std::move(config.streams);
+  int min_transmit_bitrate = config.min_transmit_bitrate_bps;
+  encoder_queue_.PostTask([this, video_codec, max_data_payload_length, stream,
+                           min_transmit_bitrate] {
+    ConfigureEncoderInternal(video_codec, max_data_payload_length, stream,
+                             min_transmit_bitrate);
   });
   return;
 }
 
 void ViEEncoder::ConfigureEncoderInternal(const VideoCodec& video_codec,
-                                          size_t max_data_payload_length) {
+                                          size_t max_data_payload_length,
+                                          std::vector<VideoStream> stream,
+                                          int min_transmit_bitrate) {
   RTC_DCHECK_RUN_ON(&encoder_queue_);
   RTC_DCHECK_GE(encoder_start_bitrate_bps_, 0);
   RTC_DCHECK(sink_);
@@ -434,6 +442,8 @@
     }
     stats_proxy_->SetContentType(content_type);
   }
+
+  sink_->OnEncoderConfigurationChanged(stream, min_transmit_bitrate);
 }
 
 void ViEEncoder::OnFrame(const VideoFrame& video_frame) {
diff --git a/webrtc/video/vie_encoder.h b/webrtc/video/vie_encoder.h
index eaf2536..15fd9cf 100644
--- a/webrtc/video/vie_encoder.h
+++ b/webrtc/video/vie_encoder.h
@@ -49,6 +49,15 @@
                    public VCMSendStatisticsCallback,
                    public CpuOveruseObserver {
  public:
+  // Interface for receiving encoded video frames and notifications about
+  // configuration changes.
+  class EncoderSink : public EncodedImageCallback {
+   public:
+    virtual void OnEncoderConfigurationChanged(
+        std::vector<VideoStream> streams,
+        int min_transmit_bitrate_bps) = 0;
+  };
+
   ViEEncoder(uint32_t number_of_cores,
              SendStatisticsProxy* stats_proxy,
              const webrtc::VideoSendStream::Config::EncoderSettings& settings,
@@ -64,12 +73,12 @@
   void DeRegisterProcessThread();
 
   void SetSource(rtc::VideoSourceInterface<VideoFrame>* source);
-  void SetSink(EncodedImageCallback* sink);
+  void SetSink(EncoderSink* sink);
 
   // TODO(perkj): Can we remove VideoCodec.startBitrate ?
   void SetStartBitrate(int start_bitrate_bps);
 
-  void ConfigureEncoder(const VideoEncoderConfig& config,
+  void ConfigureEncoder(VideoEncoderConfig config,
                         size_t max_data_payload_length);
 
   // Permanently stop encoding. After this method has returned, it is
@@ -92,7 +101,9 @@
   class VideoSourceProxy;
 
   void ConfigureEncoderInternal(const VideoCodec& video_codec,
-                                size_t max_data_payload_length);
+                                size_t max_data_payload_length,
+                                std::vector<VideoStream> stream,
+                                int min_transmit_bitrate);
 
   // Implements VideoSinkInterface.
   void OnFrame(const VideoFrame& video_frame) override;
@@ -123,7 +134,7 @@
   const uint32_t number_of_cores_;
 
   const std::unique_ptr<VideoSourceProxy> source_proxy_;
-  EncodedImageCallback* sink_;
+  EncoderSink* sink_;
   const VideoSendStream::Config::EncoderSettings settings_;
 
   const std::unique_ptr<VideoProcessing> vp_;
diff --git a/webrtc/video/vie_encoder_unittest.cc b/webrtc/video/vie_encoder_unittest.cc
index ba25a1d..8c43fe5 100644
--- a/webrtc/video/vie_encoder_unittest.cc
+++ b/webrtc/video/vie_encoder_unittest.cc
@@ -8,6 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include <utility>
+
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/test/encoder_settings.h"
@@ -36,7 +38,10 @@
     video_send_config_.encoder_settings.payload_name = "FAKE";
     video_send_config_.encoder_settings.payload_type = 125;
 
-    video_encoder_config_.streams = test::CreateVideoStreams(1);
+    VideoEncoderConfig video_encoder_config;
+    video_encoder_config.streams = test::CreateVideoStreams(1);
+    codec_width_ = static_cast<int>(video_encoder_config.streams[0].width);
+    codec_height_ = static_cast<int>(video_encoder_config.streams[0].height);
 
     vie_encoder_.reset(new ViEEncoder(
         1 /* number_of_cores */, &stats_proxy_,
@@ -45,7 +50,7 @@
     vie_encoder_->SetSink(&sink_);
     vie_encoder_->SetSource(&video_source_);
     vie_encoder_->SetStartBitrate(10000);
-    vie_encoder_->ConfigureEncoder(video_encoder_config_, 1440);
+    vie_encoder_->ConfigureEncoder(std::move(video_encoder_config), 1440);
   }
 
   VideoFrame CreateFrame(int64_t ntp_ts, rtc::Event* destruction_event) const {
@@ -63,12 +68,9 @@
       rtc::Event* const event_;
     };
 
-    VideoFrame frame(
-        new rtc::RefCountedObject<TestBuffer>(
-            destruction_event,
-            static_cast<int>(video_encoder_config_.streams[0].width),
-            static_cast<int>(video_encoder_config_.streams[0].height)),
-        99, 99, kVideoRotation_0);
+    VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
+                         destruction_event, codec_width_, codec_height_),
+                     99, 99, kVideoRotation_0);
     frame.set_ntp_time_ms(ntp_ts);
     return frame;
   }
@@ -123,21 +125,11 @@
     int64_t ntp_time_ms_ = 0;
   };
 
-  class TestSink : public EncodedImageCallback {
+  class TestSink : public ViEEncoder::EncoderSink {
    public:
     explicit TestSink(TestEncoder* test_encoder)
         : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
 
-    int32_t Encoded(const EncodedImage& encoded_image,
-                    const CodecSpecificInfo* codec_specific_info,
-                    const RTPFragmentationHeader* fragmentation) override {
-      rtc::CritScope lock(&crit_);
-      EXPECT_TRUE(expect_frames_);
-      timestamp_ = encoded_image._timeStamp;
-      encoded_frame_event_.Set();
-      return 0;
-    }
-
     void WaitForEncodedFrame(int64_t expected_ntp_time) {
       uint32_t timestamp = 0;
       EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
@@ -153,16 +145,46 @@
       expect_frames_ = false;
     }
 
+    int number_of_reconfigurations() {
+      rtc::CritScope lock(&crit_);
+      return number_of_reconfigurations_;
+    }
+
+    int last_min_transmit_bitrate() {
+      rtc::CritScope lock(&crit_);
+      return min_transmit_bitrate_bps_;
+    }
+
    private:
+    int32_t Encoded(const EncodedImage& encoded_image,
+                    const CodecSpecificInfo* codec_specific_info,
+                    const RTPFragmentationHeader* fragmentation) override {
+      rtc::CritScope lock(&crit_);
+      EXPECT_TRUE(expect_frames_);
+      timestamp_ = encoded_image._timeStamp;
+      encoded_frame_event_.Set();
+      return 0;
+    }
+
+    void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
+                                       int min_transmit_bitrate_bps) override {
+      rtc::CriticalSection crit_;
+      ++number_of_reconfigurations_;
+      min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
+    }
+
     rtc::CriticalSection crit_;
     TestEncoder* test_encoder_;
     rtc::Event encoded_frame_event_;
     uint32_t timestamp_ = 0;
     bool expect_frames_ = true;
+    int number_of_reconfigurations_ = 0;
+    int min_transmit_bitrate_bps_ = 0;
   };
 
   VideoSendStream::Config video_send_config_;
-  VideoEncoderConfig video_encoder_config_;
+  int codec_width_;
+  int codec_height_;
   TestEncoder fake_encoder_;
   SendStatisticsProxy stats_proxy_;
   TestSink sink_;
@@ -255,4 +277,27 @@
   vie_encoder_->Stop();
 }
 
+TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
+  const int kTargetBitrateBps = 100000;
+  vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+
+  // Capture a frame and wait for it to synchronize with the encoder thread.
+  vie_encoder_->IncomingCapturedFrame(CreateFrame(1, nullptr));
+  sink_.WaitForEncodedFrame(1);
+  EXPECT_EQ(1, sink_.number_of_reconfigurations());
+
+  VideoEncoderConfig video_encoder_config;
+  video_encoder_config.streams = test::CreateVideoStreams(1);
+  video_encoder_config.min_transmit_bitrate_bps = 9999;
+  vie_encoder_->ConfigureEncoder(std::move(video_encoder_config), 1440);
+
+  // Capture a frame and wait for it to synchronize with the encoder thread.
+  vie_encoder_->IncomingCapturedFrame(CreateFrame(2, nullptr));
+  sink_.WaitForEncodedFrame(2);
+  EXPECT_EQ(2, sink_.number_of_reconfigurations());
+  EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
+
+  vie_encoder_->Stop();
+}
+
 }  // namespace webrtc