SimulcastEncoderAdapter, don't start streams without enough bitrate

Currently a bug in InitEncode() sets all stream initially to active.
This CL actually bases the active-flag on available start bitrate.

Bug: webrtc:9747
Change-Id: If197b0c69376d96c717f2a391fba8108895018f3
Reviewed-on: https://webrtc-review.googlesource.com/99960
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24711}
diff --git a/media/engine/simulcast_encoder_adapter.cc b/media/engine/simulcast_encoder_adapter.cc
index 5827fc5..30da68e 100644
--- a/media/engine/simulcast_encoder_adapter.cc
+++ b/media/engine/simulcast_encoder_adapter.cc
@@ -208,12 +208,13 @@
   for (int i = 0; i < number_of_streams; ++i) {
     VideoCodec stream_codec;
     uint32_t start_bitrate_kbps = start_bitrates[i];
+    const bool send_stream = start_bitrate_kbps > 0;
     if (!doing_simulcast) {
       stream_codec = codec_;
       stream_codec.numberOfSimulcastStreams = 1;
     } else {
       // Cap start bitrate to the min bitrate in order to avoid strange codec
-      // behavior. Since sending sending will be false, this should not matter.
+      // behavior. Since sending will be false, this should not matter.
       start_bitrate_kbps =
           std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
       bool highest_resolution_stream = (i == (number_of_streams - 1));
@@ -251,7 +252,7 @@
     encoder->RegisterEncodeCompleteCallback(callback.get());
     streaminfos_.emplace_back(std::move(encoder), std::move(callback),
                               stream_codec.width, stream_codec.height,
-                              start_bitrate_kbps > 0);
+                              send_stream);
 
     if (i != 0) {
       implementation_name += ", ";
diff --git a/media/engine/simulcast_encoder_adapter_unittest.cc b/media/engine/simulcast_encoder_adapter_unittest.cc
index 8ab73834..5b7d185 100644
--- a/media/engine/simulcast_encoder_adapter_unittest.cc
+++ b/media/engine/simulcast_encoder_adapter_unittest.cc
@@ -513,6 +513,10 @@
       kVideoCodecVP8);
   rate_allocator_.reset(new SimulcastRateAllocator(codec_));
   adapter_->RegisterEncodeCompleteCallback(this);
+  const uint32_t target_bitrate =
+      1000 * (codec_.simulcastStream[0].targetBitrate +
+              codec_.simulcastStream[1].targetBitrate +
+              codec_.simulcastStream[2].minBitrate);
 
   // Input data.
   rtc::scoped_refptr<VideoFrameBuffer> buffer(I420Buffer::Create(1280, 720));
@@ -522,6 +526,9 @@
   // Encode with three streams.
   EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
   VerifyCodecSettings();
+  adapter_->SetRateAllocation(
+      rate_allocator_->GetAllocation(target_bitrate, 30), 30);
+
   std::vector<MockVideoEncoder*> original_encoders =
       helper_->factory()->encoders();
   ASSERT_EQ(3u, original_encoders.size());
@@ -546,6 +553,8 @@
   codec_.height /= 2;
   codec_.numberOfSimulcastStreams = 2;
   EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
+  adapter_->SetRateAllocation(
+      rate_allocator_->GetAllocation(target_bitrate, 30), 30);
   std::vector<MockVideoEncoder*> new_encoders = helper_->factory()->encoders();
   ASSERT_EQ(2u, new_encoders.size());
   ASSERT_EQ(original_encoders[0], new_encoders[0]);
@@ -567,6 +576,8 @@
   codec_.height /= 2;
   codec_.numberOfSimulcastStreams = 1;
   EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
+  adapter_->SetRateAllocation(
+      rate_allocator_->GetAllocation(target_bitrate, 30), 30);
   new_encoders = helper_->factory()->encoders();
   ASSERT_EQ(1u, new_encoders.size());
   ASSERT_EQ(original_encoders[0], new_encoders[0]);
@@ -583,6 +594,8 @@
   codec_.height *= 4;
   codec_.numberOfSimulcastStreams = 3;
   EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
+  adapter_->SetRateAllocation(
+      rate_allocator_->GetAllocation(target_bitrate, 30), 30);
   new_encoders = helper_->factory()->encoders();
   ASSERT_EQ(3u, new_encoders.size());
   // The first encoder is reused.
@@ -902,5 +915,38 @@
   ref_codec.qpMax = kLowMaxQp;
   VerifyCodec(ref_codec, 0);
 }
+
+TEST_F(TestSimulcastEncoderAdapterFake, ActivatesCorrectStreamsInInitEncode) {
+  // Set up common settings for three streams.
+  SimulcastTestFixtureImpl::DefaultSettings(
+      &codec_, static_cast<const int*>(kTestTemporalLayerProfile),
+      kVideoCodecVP8);
+  rate_allocator_.reset(new SimulcastRateAllocator(codec_));
+  adapter_->RegisterEncodeCompleteCallback(this);
+
+  // Only enough start bitrate for the lowest stream.
+  ASSERT_EQ(3u, codec_.numberOfSimulcastStreams);
+  codec_.startBitrate = codec_.simulcastStream[0].targetBitrate +
+                        codec_.simulcastStream[1].minBitrate - 1;
+
+  // Input data.
+  rtc::scoped_refptr<VideoFrameBuffer> buffer(I420Buffer::Create(1280, 720));
+  VideoFrame input_frame(buffer, 100, 1000, kVideoRotation_180);
+
+  // Encode with three streams.
+  EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
+  std::vector<MockVideoEncoder*> original_encoders =
+      helper_->factory()->encoders();
+  ASSERT_EQ(3u, original_encoders.size());
+  // Only first encoder will be active and called.
+  EXPECT_CALL(*original_encoders[0], Encode(_, _, _))
+      .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
+  EXPECT_CALL(*original_encoders[1], Encode(_, _, _)).Times(0);
+  EXPECT_CALL(*original_encoders[2], Encode(_, _, _)).Times(0);
+
+  std::vector<FrameType> frame_types;
+  frame_types.resize(3, kVideoFrameKey);
+  EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types));
+}
 }  // namespace test
 }  // namespace webrtc