Reland "Enables/disables simulcast streams by allocating a bitrate of 0 to the spatial layer."

This is a reland of 18c4261339dc76b220e7c805e36b4ea6f3dd161d
Original change's description:
> Enables/disables simulcast streams by allocating a bitrate of 0 to the spatial layer.
>
> Creates VideoStreams & VideoCodec.simulcastStreams with an active field, and then allocates 0 bitrate to simulcast streams that are inactive. This turns off the encoder for specific simulcast streams.
>
> Bug: webrtc:8653
> Change-Id: Id93b03dcd8d1191a7d3300bd77882c8af96ee469
> Reviewed-on: https://webrtc-review.googlesource.com/37740
> Reviewed-by: Stefan Holmer <stefan@webrtc.org>
> Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
> Reviewed-by: Erik Språng <sprang@webrtc.org>
> Commit-Queue: Seth Hampson <shampson@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#21646}

TBR=sprang@webrtc.org,stefan@webrtc.org,deadbeef@webrtc.org

Bug: webrtc:8630
Change-Id: Ib3df6f9b7158bff362a7ec66fc57e368682c5846
Reviewed-on: https://webrtc-review.googlesource.com/40980
Reviewed-by: Seth Hampson <shampson@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Seth Hampson <shampson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21688}
diff --git a/media/engine/simulcast_encoder_adapter_unittest.cc b/media/engine/simulcast_encoder_adapter_unittest.cc
index 8087d7b..d8fc4b6 100644
--- a/media/engine/simulcast_encoder_adapter_unittest.cc
+++ b/media/engine/simulcast_encoder_adapter_unittest.cc
@@ -73,6 +73,10 @@
   TestVp8Simulcast::TestDisablingStreams();
 }
 
+TEST_F(TestSimulcastEncoderAdapter, TestActiveStreams) {
+  TestVp8Simulcast::TestActiveStreams();
+}
+
 TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneStream) {
   TestVp8Simulcast::TestSwitchingToOneStream();
 }
diff --git a/modules/video_coding/codecs/vp8/simulcast_rate_allocator.cc b/modules/video_coding/codecs/vp8/simulcast_rate_allocator.cc
index b2b3334..b865f5e 100644
--- a/modules/video_coding/codecs/vp8/simulcast_rate_allocator.cc
+++ b/modules/video_coding/codecs/vp8/simulcast_rate_allocator.cc
@@ -37,56 +37,92 @@
 BitrateAllocation SimulcastRateAllocator::GetAllocation(
     uint32_t total_bitrate_bps,
     uint32_t framerate) {
+  BitrateAllocation allocated_bitrates_bps;
+  DistributeAllocationToSimulcastLayers(total_bitrate_bps,
+                                        &allocated_bitrates_bps);
+  DistributeAllocationToTemporalLayers(framerate, &allocated_bitrates_bps);
+  return allocated_bitrates_bps;
+}
+
+void SimulcastRateAllocator::DistributeAllocationToSimulcastLayers(
+    uint32_t total_bitrate_bps,
+    BitrateAllocation* allocated_bitrates_bps) {
   uint32_t left_to_allocate = total_bitrate_bps;
   if (codec_.maxBitrate && codec_.maxBitrate * 1000 < left_to_allocate)
     left_to_allocate = codec_.maxBitrate * 1000;
 
-  BitrateAllocation allocated_bitrates_bps;
   if (codec_.numberOfSimulcastStreams == 0) {
     // No simulcast, just set the target as this has been capped already.
-    allocated_bitrates_bps.SetBitrate(
-        0, 0, std::max(codec_.minBitrate * 1000, left_to_allocate));
-  } else {
-    // Always allocate enough bitrate for the minimum bitrate of the first
-    // layer. Suspending below min bitrate is controlled outside the codec
-    // implementation and is not overridden by this.
-    left_to_allocate =
-        std::max(codec_.simulcastStream[0].minBitrate * 1000, left_to_allocate);
-
-    // Begin by allocating bitrate to simulcast streams, putting all bitrate in
-    // temporal layer 0. We'll then distribute this bitrate, across potential
-    // temporal layers, when stream allocation is done.
-
-    // Allocate up to the target bitrate for each simulcast layer.
-    size_t layer = 0;
-    for (; layer < codec_.numberOfSimulcastStreams; ++layer) {
-      const SimulcastStream& stream = codec_.simulcastStream[layer];
-      if (left_to_allocate < stream.minBitrate * 1000)
-        break;
-      uint32_t allocation =
-          std::min(left_to_allocate, stream.targetBitrate * 1000);
-      allocated_bitrates_bps.SetBitrate(layer, 0, allocation);
-      RTC_DCHECK_LE(allocation, left_to_allocate);
-      left_to_allocate -= allocation;
+    if (codec_.active) {
+      allocated_bitrates_bps->SetBitrate(
+          0, 0, std::max(codec_.minBitrate * 1000, left_to_allocate));
     }
-
-    // Next, try allocate remaining bitrate, up to max bitrate, in top stream.
-    // TODO(sprang): Allocate up to max bitrate for all layers once we have a
-    //               better idea of possible performance implications.
-    if (left_to_allocate > 0) {
-      size_t active_layer = layer - 1;
-      const SimulcastStream& stream = codec_.simulcastStream[active_layer];
-      uint32_t bitrate_bps =
-          allocated_bitrates_bps.GetSpatialLayerSum(active_layer);
-      uint32_t allocation =
-          std::min(left_to_allocate, stream.maxBitrate * 1000 - bitrate_bps);
-      bitrate_bps += allocation;
-      RTC_DCHECK_LE(allocation, left_to_allocate);
-      left_to_allocate -= allocation;
-      allocated_bitrates_bps.SetBitrate(active_layer, 0, bitrate_bps);
+    return;
+  }
+  // Find the first active layer. We don't allocate to inactive layers.
+  size_t active_layer = 0;
+  for (; active_layer < codec_.numberOfSimulcastStreams; ++active_layer) {
+    if (codec_.simulcastStream[active_layer].active) {
+      // Found the first active layer.
+      break;
     }
   }
+  // All streams could be inactive, and nothing more to do.
+  if (active_layer == codec_.numberOfSimulcastStreams) {
+    return;
+  }
 
+  // Always allocate enough bitrate for the minimum bitrate of the first
+  // active layer. Suspending below min bitrate is controlled outside the
+  // codec implementation and is not overridden by this.
+  left_to_allocate = std::max(
+      codec_.simulcastStream[active_layer].minBitrate * 1000, left_to_allocate);
+
+  // Begin by allocating bitrate to simulcast streams, putting all bitrate in
+  // temporal layer 0. We'll then distribute this bitrate, across potential
+  // temporal layers, when stream allocation is done.
+
+  size_t top_active_layer = active_layer;
+  // Allocate up to the target bitrate for each active simulcast layer.
+  for (; active_layer < codec_.numberOfSimulcastStreams; ++active_layer) {
+    const SimulcastStream& stream = codec_.simulcastStream[active_layer];
+    if (!stream.active) {
+      continue;
+    }
+    // If we can't allocate to the current layer we can't allocate to higher
+    // layers because they require a higher minimum bitrate.
+    if (left_to_allocate < stream.minBitrate * 1000) {
+      break;
+    }
+    // We are allocating to this layer so it is the current active allocation.
+    top_active_layer = active_layer;
+    uint32_t allocation =
+        std::min(left_to_allocate, stream.targetBitrate * 1000);
+    allocated_bitrates_bps->SetBitrate(active_layer, 0, allocation);
+    RTC_DCHECK_LE(allocation, left_to_allocate);
+    left_to_allocate -= allocation;
+  }
+
+  // Next, try allocate remaining bitrate, up to max bitrate, in top active
+  // stream.
+  // TODO(sprang): Allocate up to max bitrate for all layers once we have a
+  //               better idea of possible performance implications.
+  if (left_to_allocate > 0) {
+    const SimulcastStream& stream = codec_.simulcastStream[top_active_layer];
+    uint32_t bitrate_bps =
+        allocated_bitrates_bps->GetSpatialLayerSum(top_active_layer);
+    uint32_t allocation =
+        std::min(left_to_allocate, stream.maxBitrate * 1000 - bitrate_bps);
+    bitrate_bps += allocation;
+    RTC_DCHECK_LE(allocation, left_to_allocate);
+    left_to_allocate -= allocation;
+    allocated_bitrates_bps->SetBitrate(top_active_layer, 0, bitrate_bps);
+  }
+}
+
+void SimulcastRateAllocator::DistributeAllocationToTemporalLayers(
+    uint32_t framerate,
+    BitrateAllocation* allocated_bitrates_bps) {
   const int num_spatial_streams =
       std::max(1, static_cast<int>(codec_.numberOfSimulcastStreams));
 
@@ -94,16 +130,21 @@
   // available temporal layers.
   for (int simulcast_id = 0; simulcast_id < num_spatial_streams;
        ++simulcast_id) {
+    // TODO(shampson): Consider adding a continue here if the simulcast stream
+    //                 is inactive. Currently this is not added because the call
+    //                 below to OnRatesUpdated changes the TemporalLayer's
+    //                 state.
     auto tl_it = temporal_layers_.find(simulcast_id);
     if (tl_it == temporal_layers_.end())
       continue;  // TODO(sprang): If > 1 SS, assume default TL alloc?
 
     uint32_t target_bitrate_kbps =
-        allocated_bitrates_bps.GetBitrate(simulcast_id, 0) / 1000;
+        allocated_bitrates_bps->GetBitrate(simulcast_id, 0) / 1000;
+
     const uint32_t expected_allocated_bitrate_kbps = target_bitrate_kbps;
     RTC_DCHECK_EQ(
         target_bitrate_kbps,
-        allocated_bitrates_bps.GetSpatialLayerSum(simulcast_id) / 1000);
+        allocated_bitrates_bps->GetSpatialLayerSum(simulcast_id) / 1000);
     const int num_temporal_streams = std::max<uint8_t>(
         1, codec_.numberOfSimulcastStreams == 0
                ? codec_.VP8().numberOfTemporalLayers
@@ -137,14 +178,14 @@
     uint64_t tl_allocation_sum_kbps = 0;
     for (size_t tl_index = 0; tl_index < tl_allocation.size(); ++tl_index) {
       uint32_t layer_rate_kbps = tl_allocation[tl_index];
-      allocated_bitrates_bps.SetBitrate(simulcast_id, tl_index,
-                                        layer_rate_kbps * 1000);
+      if (layer_rate_kbps > 0) {
+        allocated_bitrates_bps->SetBitrate(simulcast_id, tl_index,
+                                           layer_rate_kbps * 1000);
+      }
       tl_allocation_sum_kbps += layer_rate_kbps;
     }
     RTC_DCHECK_LE(tl_allocation_sum_kbps, expected_allocated_bitrate_kbps);
   }
-
-  return allocated_bitrates_bps;
 }
 
 uint32_t SimulcastRateAllocator::GetPreferredBitrateBps(uint32_t framerate) {
diff --git a/modules/video_coding/codecs/vp8/simulcast_rate_allocator.h b/modules/video_coding/codecs/vp8/simulcast_rate_allocator.h
index 929abba..b4b6f31 100644
--- a/modules/video_coding/codecs/vp8/simulcast_rate_allocator.h
+++ b/modules/video_coding/codecs/vp8/simulcast_rate_allocator.h
@@ -39,6 +39,12 @@
   const VideoCodec& GetCodec() const;
 
  private:
+  void DistributeAllocationToSimulcastLayers(
+      uint32_t total_bitrate_bps,
+      BitrateAllocation* allocated_bitrates_bps);
+  void DistributeAllocationToTemporalLayers(
+      uint32_t framerate,
+      BitrateAllocation* allocated_bitrates_bps);
   const VideoCodec codec_;
   std::map<uint32_t, TemporalLayers*> temporal_layers_;
   std::unique_ptr<TemporalLayersFactory> tl_factory_;
diff --git a/modules/video_coding/codecs/vp8/simulcast_test_utility.h b/modules/video_coding/codecs/vp8/simulcast_test_utility.h
index 7f32ad2..e13bad4 100644
--- a/modules/video_coding/codecs/vp8/simulcast_test_utility.h
+++ b/modules/video_coding/codecs/vp8/simulcast_test_utility.h
@@ -203,6 +203,7 @@
     settings->width = kDefaultWidth;
     settings->height = kDefaultHeight;
     settings->numberOfSimulcastStreams = kNumberOfSimulcastStreams;
+    settings->active = true;
     ASSERT_EQ(3, kNumberOfSimulcastStreams);
     settings->timing_frame_thresholds = {kDefaultTimingFramesDelayMs,
                                          kDefaultOutlierFrameSizePercent};
@@ -238,6 +239,7 @@
     stream->targetBitrate = target_bitrate;
     stream->numberOfTemporalLayers = num_temporal_layers;
     stream->qpMax = 45;
+    stream->active = true;
   }
 
  protected:
@@ -282,10 +284,22 @@
         rate_allocator_->GetAllocation(bitrate_kbps * 1000, fps), fps);
   }
 
-  void ExpectStreams(FrameType frame_type, int expected_video_streams) {
-    ASSERT_GE(expected_video_streams, 0);
-    ASSERT_LE(expected_video_streams, kNumberOfSimulcastStreams);
-    if (expected_video_streams >= 1) {
+  void UpdateActiveStreams(const std::vector<bool> active_streams) {
+    ASSERT_EQ(static_cast<int>(active_streams.size()),
+              kNumberOfSimulcastStreams);
+    for (size_t i = 0; i < active_streams.size(); ++i) {
+      settings_.simulcastStream[i].active = active_streams[i];
+    }
+    // Re initialize the allocator and encoder with the new settings.
+    SetUpRateAllocator();
+    EXPECT_EQ(0, encoder_->InitEncode(&settings_, 1, 1200));
+  }
+
+  void ExpectStreams(FrameType frame_type,
+                     const std::vector<bool> expected_streams_active) {
+    ASSERT_EQ(static_cast<int>(expected_streams_active.size()),
+              kNumberOfSimulcastStreams);
+    if (expected_streams_active[0]) {
       EXPECT_CALL(
           encoder_callback_,
           OnEncodedImage(
@@ -297,7 +311,7 @@
           .WillRepeatedly(Return(EncodedImageCallback::Result(
               EncodedImageCallback::Result::OK, 0)));
     }
-    if (expected_video_streams >= 2) {
+    if (expected_streams_active[1]) {
       EXPECT_CALL(
           encoder_callback_,
           OnEncodedImage(
@@ -309,7 +323,7 @@
           .WillRepeatedly(Return(EncodedImageCallback::Result(
               EncodedImageCallback::Result::OK, 0)));
     }
-    if (expected_video_streams >= 3) {
+    if (expected_streams_active[2]) {
       EXPECT_CALL(
           encoder_callback_,
           OnEncodedImage(
@@ -323,6 +337,16 @@
     }
   }
 
+  void ExpectStreams(FrameType frame_type, int expected_video_streams) {
+    ASSERT_GE(expected_video_streams, 0);
+    ASSERT_LE(expected_video_streams, kNumberOfSimulcastStreams);
+    std::vector<bool> expected_streams_active(kNumberOfSimulcastStreams, false);
+    for (int i = 0; i < expected_video_streams; ++i) {
+      expected_streams_active[i] = true;
+    }
+    ExpectStreams(frame_type, expected_streams_active);
+  }
+
   void VerifyTemporalIdxAndSyncForAllSpatialLayers(
       Vp8TestEncodedImageCallback* encoder_callback,
       const int* expected_temporal_idx,
@@ -501,6 +525,43 @@
     EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
   }
 
+  void TestActiveStreams() {
+    const int kEnoughBitrateAllStreams =
+        kMaxBitrates[0] + kMaxBitrates[1] + kMaxBitrates[2];
+    std::vector<FrameType> frame_types(kNumberOfSimulcastStreams,
+                                       kVideoFrameDelta);
+    // TODO(shampson): Currently turning off the base stream causes unexpected
+    // behavior in the libvpx encoder. The libvpx encoder labels key frames
+    // based upon the base stream. If the base stream is never enabled, it
+    // will continue to spit out encoded images labeled as key frames for the
+    // other streams that are enabled. Once this is fixed in libvpx, update this
+    // test to reflect that change.
+
+    // Only turn on the the base stream.
+    std::vector<bool> active_streams = {true, false, false};
+    UpdateActiveStreams(active_streams);
+    SetRates(kEnoughBitrateAllStreams, 30);
+    ExpectStreams(kVideoFrameKey, active_streams);
+    input_frame_->set_timestamp(input_frame_->timestamp() + 3000);
+    EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
+
+    ExpectStreams(kVideoFrameDelta, active_streams);
+    input_frame_->set_timestamp(input_frame_->timestamp() + 3000);
+    EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
+
+    // Turn off only the middle stream.
+    active_streams = {true, false, true};
+    UpdateActiveStreams(active_streams);
+    SetRates(kEnoughBitrateAllStreams, 30);
+    ExpectStreams(kVideoFrameKey, active_streams);
+    input_frame_->set_timestamp(input_frame_->timestamp() + 3000);
+    EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
+
+    ExpectStreams(kVideoFrameDelta, active_streams);
+    input_frame_->set_timestamp(input_frame_->timestamp() + 3000);
+    EXPECT_EQ(0, encoder_->Encode(*input_frame_, NULL, &frame_types));
+  }
+
   void SwitchingToOneStream(int width, int height) {
     // Disable all streams except the last and set the bitrate of the last to
     // 100 kbps. This verifies the way GTP switches to screenshare mode.
diff --git a/modules/video_coding/codecs/vp8/simulcast_unittest.cc b/modules/video_coding/codecs/vp8/simulcast_unittest.cc
index b1dd794..f72d880 100644
--- a/modules/video_coding/codecs/vp8/simulcast_unittest.cc
+++ b/modules/video_coding/codecs/vp8/simulcast_unittest.cc
@@ -55,6 +55,10 @@
   TestVp8Simulcast::TestDisablingStreams();
 }
 
+TEST_F(TestVp8Impl, TestActiveStreams) {
+  TestVp8Simulcast::TestActiveStreams();
+}
+
 TEST_F(TestVp8Impl, TestSwitchingToOneStream) {
   TestVp8Simulcast::TestSwitchingToOneStream();
 }
diff --git a/modules/video_coding/utility/default_video_bitrate_allocator.cc b/modules/video_coding/utility/default_video_bitrate_allocator.cc
index 5e3b3a2..0c4ae9b 100644
--- a/modules/video_coding/utility/default_video_bitrate_allocator.cc
+++ b/modules/video_coding/utility/default_video_bitrate_allocator.cc
@@ -24,7 +24,7 @@
     uint32_t total_bitrate_bps,
     uint32_t framerate) {
   BitrateAllocation allocation;
-  if (total_bitrate_bps == 0)
+  if (total_bitrate_bps == 0 || !codec_.active)
     return allocation;
 
   if (total_bitrate_bps < codec_.minBitrate * 1000) {
diff --git a/modules/video_coding/utility/default_video_bitrate_allocator_unittest.cc b/modules/video_coding/utility/default_video_bitrate_allocator_unittest.cc
index 695ac68..e27b3d3 100644
--- a/modules/video_coding/utility/default_video_bitrate_allocator_unittest.cc
+++ b/modules/video_coding/utility/default_video_bitrate_allocator_unittest.cc
@@ -45,6 +45,13 @@
   EXPECT_EQ(0u, allocation.get_sum_bps());
 }
 
+TEST_F(DefaultVideoBitrateAllocatorTest, Inactive) {
+  codec_.active = false;
+  allocator_.reset(new DefaultVideoBitrateAllocator(codec_));
+  BitrateAllocation allocation = allocator_->GetAllocation(1, kMaxFramerate);
+  EXPECT_EQ(0u, allocation.get_sum_bps());
+}
+
 TEST_F(DefaultVideoBitrateAllocatorTest, CapsToMin) {
   BitrateAllocation allocation = allocator_->GetAllocation(1, kMaxFramerate);
   EXPECT_EQ(kMinBitrateBps, allocation.get_sum_bps());
diff --git a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
index 15ac938..44d0081 100644
--- a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
+++ b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
@@ -51,6 +51,7 @@
     codec_.minBitrate = kMinBitrateKbps;
     codec_.targetBitrate = kTargetBitrateKbps;
     codec_.maxBitrate = kMaxBitrateKbps;
+    codec_.active = true;
     CreateAllocator();
   }
   virtual ~SimulcastRateAllocatorTest() {}
@@ -69,6 +70,9 @@
     uint32_t sum = 0;
     for (size_t i = 0; i < S; ++i) {
       uint32_t layer_bitrate = actual.GetSpatialLayerSum(i);
+      if (layer_bitrate == 0) {
+        EXPECT_FALSE(actual.IsSpatialLayerUsed(i));
+      }
       EXPECT_EQ(expected[i] * 1000U, layer_bitrate) << "Mismatch at index "
                                                     << i;
       sum += layer_bitrate;
@@ -96,6 +100,34 @@
     }
   }
 
+  void SetupCodecThreeSimulcastStreams(
+      const std::vector<bool>& active_streams) {
+    size_t num_streams = 3;
+    RTC_DCHECK_GE(active_streams.size(), num_streams);
+    SetupCodecTwoSimulcastStreams(active_streams);
+    codec_.numberOfSimulcastStreams = num_streams;
+    codec_.simulcastStream[2].minBitrate = 2000;
+    codec_.simulcastStream[2].targetBitrate = 3000;
+    codec_.simulcastStream[2].maxBitrate = 4000;
+    codec_.simulcastStream[2].active = active_streams[2];
+  }
+
+  void SetupCodecTwoSimulcastStreams(const std::vector<bool>& active_streams) {
+    size_t num_streams = 2;
+    RTC_DCHECK_GE(active_streams.size(), num_streams);
+    codec_.numberOfSimulcastStreams = num_streams;
+    codec_.maxBitrate = 0;
+    codec_.simulcastStream[0].minBitrate = 10;
+    codec_.simulcastStream[0].targetBitrate = 100;
+    codec_.simulcastStream[0].maxBitrate = 500;
+    codec_.simulcastStream[1].minBitrate = 50;
+    codec_.simulcastStream[1].targetBitrate = 500;
+    codec_.simulcastStream[1].maxBitrate = 1000;
+    for (size_t i = 0; i < num_streams; ++i) {
+      codec_.simulcastStream[i].active = active_streams[i];
+    }
+  }
+
   virtual std::unique_ptr<TemporalLayersFactory> GetTlFactory() {
     return std::unique_ptr<TemporalLayersFactory>(new TemporalLayersFactory());
   }
@@ -113,6 +145,7 @@
 
 TEST_F(SimulcastRateAllocatorTest, NoSimulcastBelowMin) {
   uint32_t expected[] = {codec_.minBitrate};
+  codec_.active = true;
   ExpectEqual(expected, GetAllocation(codec_.minBitrate - 1));
   ExpectEqual(expected, GetAllocation(1));
   ExpectEqual(expected, GetAllocation(0));
@@ -120,12 +153,14 @@
 
 TEST_F(SimulcastRateAllocatorTest, NoSimulcastAboveMax) {
   uint32_t expected[] = {codec_.maxBitrate};
+  codec_.active = true;
   ExpectEqual(expected, GetAllocation(codec_.maxBitrate + 1));
   ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
 }
 
 TEST_F(SimulcastRateAllocatorTest, NoSimulcastNoMax) {
   const uint32_t kMax = BitrateAllocation::kMaxBitrateBps / 1000;
+  codec_.active = true;
   codec_.maxBitrate = 0;
   CreateAllocator();
 
@@ -134,6 +169,7 @@
 }
 
 TEST_F(SimulcastRateAllocatorTest, NoSimulcastWithinLimits) {
+  codec_.active = true;
   for (uint32_t bitrate = codec_.minBitrate; bitrate <= codec_.maxBitrate;
        ++bitrate) {
     uint32_t expected[] = {bitrate};
@@ -141,12 +177,25 @@
   }
 }
 
+// Tests that when we aren't using simulcast and the codec is marked inactive no
+// bitrate will be allocated.
+TEST_F(SimulcastRateAllocatorTest, NoSimulcastInactive) {
+  codec_.active = false;
+  uint32_t expected[] = {0};
+  CreateAllocator();
+
+  ExpectEqual(expected, GetAllocation(kMinBitrateKbps - 10));
+  ExpectEqual(expected, GetAllocation(kTargetBitrateKbps));
+  ExpectEqual(expected, GetAllocation(kMaxBitrateKbps + 10));
+}
+
 TEST_F(SimulcastRateAllocatorTest, SingleSimulcastBelowMin) {
   // With simulcast, use the min bitrate from the ss spec instead of the global.
   codec_.numberOfSimulcastStreams = 1;
   const uint32_t kMin = codec_.minBitrate - 10;
   codec_.simulcastStream[0].minBitrate = kMin;
   codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
+  codec_.simulcastStream[0].active = true;
   CreateAllocator();
 
   uint32_t expected[] = {kMin};
@@ -160,6 +209,7 @@
   codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
   const uint32_t kMax = codec_.simulcastStream[0].maxBitrate + 1000;
   codec_.simulcastStream[0].maxBitrate = kMax;
+  codec_.simulcastStream[0].active = true;
   CreateAllocator();
 
   uint32_t expected[] = {kMax};
@@ -173,6 +223,7 @@
   codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
   codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
   codec_.simulcastStream[0].maxBitrate = kMaxBitrateKbps;
+  codec_.simulcastStream[0].active = true;
   CreateAllocator();
 
   for (uint32_t bitrate = kMinBitrateKbps; bitrate <= kMaxBitrateKbps;
@@ -182,18 +233,23 @@
   }
 }
 
+TEST_F(SimulcastRateAllocatorTest, SingleSimulcastInactive) {
+  codec_.numberOfSimulcastStreams = 1;
+  codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
+  codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
+  codec_.simulcastStream[0].maxBitrate = kMaxBitrateKbps;
+  codec_.simulcastStream[0].active = false;
+  CreateAllocator();
+
+  uint32_t expected[] = {0};
+  ExpectEqual(expected, GetAllocation(kMinBitrateKbps - 10));
+  ExpectEqual(expected, GetAllocation(kTargetBitrateKbps));
+  ExpectEqual(expected, GetAllocation(kMaxBitrateKbps + 10));
+}
+
 TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) {
-  codec_.numberOfSimulcastStreams = 3;
-  codec_.maxBitrate = 0;
-  codec_.simulcastStream[0].minBitrate = 10;
-  codec_.simulcastStream[0].targetBitrate = 100;
-  codec_.simulcastStream[0].maxBitrate = 500;
-  codec_.simulcastStream[1].minBitrate = 50;
-  codec_.simulcastStream[1].targetBitrate = 500;
-  codec_.simulcastStream[1].maxBitrate = 1000;
-  codec_.simulcastStream[2].minBitrate = 2000;
-  codec_.simulcastStream[2].targetBitrate = 3000;
-  codec_.simulcastStream[2].maxBitrate = 4000;
+  const std::vector<bool> active_streams(3, true);
+  SetupCodecThreeSimulcastStreams(active_streams);
   CreateAllocator();
 
   {
@@ -267,6 +323,164 @@
                            codec_.simulcastStream[2].maxBitrate};
     ExpectEqual(expected, GetAllocation(bitrate));
   }
+
+  {
+    // Enough to max out all streams which will allocate the target amount to
+    // the lower streams.
+    const uint32_t bitrate = codec_.simulcastStream[0].maxBitrate +
+                             codec_.simulcastStream[1].maxBitrate +
+                             codec_.simulcastStream[2].maxBitrate;
+    uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate,
+                           codec_.simulcastStream[1].targetBitrate,
+                           codec_.simulcastStream[2].maxBitrate};
+    ExpectEqual(expected, GetAllocation(bitrate));
+  }
+}
+
+// If three simulcast streams that are all inactive, none of them should be
+// allocated bitrate.
+TEST_F(SimulcastRateAllocatorTest, ThreeStreamsInactive) {
+  const std::vector<bool> active_streams(3, false);
+  SetupCodecThreeSimulcastStreams(active_streams);
+  CreateAllocator();
+
+  // Just enough to allocate the min.
+  const uint32_t min_bitrate = codec_.simulcastStream[0].minBitrate +
+                               codec_.simulcastStream[1].minBitrate +
+                               codec_.simulcastStream[2].minBitrate;
+  // Enough bitrate to allocate target to all streams.
+  const uint32_t target_bitrate = codec_.simulcastStream[0].targetBitrate +
+                                  codec_.simulcastStream[1].targetBitrate +
+                                  codec_.simulcastStream[2].targetBitrate;
+  // Enough bitrate to allocate max to all streams.
+  const uint32_t max_bitrate = codec_.simulcastStream[0].maxBitrate +
+                               codec_.simulcastStream[1].maxBitrate +
+                               codec_.simulcastStream[2].maxBitrate;
+  uint32_t expected[] = {0, 0, 0};
+  ExpectEqual(expected, GetAllocation(0));
+  ExpectEqual(expected, GetAllocation(min_bitrate));
+  ExpectEqual(expected, GetAllocation(target_bitrate));
+  ExpectEqual(expected, GetAllocation(max_bitrate));
+}
+
+// If there are two simulcast streams, we expect the high active stream to be
+// allocated as if it is a single active stream.
+TEST_F(SimulcastRateAllocatorTest, TwoStreamsLowInactive) {
+  const std::vector<bool> active_streams({false, true});
+  SetupCodecTwoSimulcastStreams(active_streams);
+  CreateAllocator();
+
+  const uint32_t kActiveStreamMinBitrate = codec_.simulcastStream[1].minBitrate;
+  const uint32_t kActiveStreamTargetBitrate =
+      codec_.simulcastStream[1].targetBitrate;
+  const uint32_t kActiveStreamMaxBitrate = codec_.simulcastStream[1].maxBitrate;
+  {
+    // Expect that the stream is always allocated its min bitrate.
+    uint32_t expected[] = {0, kActiveStreamMinBitrate};
+    ExpectEqual(expected, GetAllocation(0));
+    ExpectEqual(expected, GetAllocation(kActiveStreamMinBitrate - 10));
+    ExpectEqual(expected, GetAllocation(kActiveStreamMinBitrate));
+  }
+
+  {
+    // The stream should be allocated its target bitrate.
+    uint32_t expected[] = {0, kActiveStreamTargetBitrate};
+    ExpectEqual(expected, GetAllocation(kActiveStreamTargetBitrate));
+  }
+
+  {
+    // The stream should be allocated its max if the target input is sufficient.
+    uint32_t expected[] = {0, kActiveStreamMaxBitrate};
+    ExpectEqual(expected, GetAllocation(kActiveStreamMaxBitrate));
+    ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
+  }
+}
+
+// If there are two simulcast streams, we expect the low active stream to be
+// allocated as if it is a single active stream.
+TEST_F(SimulcastRateAllocatorTest, TwoStreamsHighInactive) {
+  const std::vector<bool> active_streams({true, false});
+  SetupCodecTwoSimulcastStreams(active_streams);
+  CreateAllocator();
+
+  const uint32_t kActiveStreamMinBitrate = codec_.simulcastStream[0].minBitrate;
+  const uint32_t kActiveStreamTargetBitrate =
+      codec_.simulcastStream[0].targetBitrate;
+  const uint32_t kActiveStreamMaxBitrate = codec_.simulcastStream[0].maxBitrate;
+  {
+    // Expect that the stream is always allocated its min bitrate.
+    uint32_t expected[] = {kActiveStreamMinBitrate, 0};
+    ExpectEqual(expected, GetAllocation(0));
+    ExpectEqual(expected, GetAllocation(kActiveStreamMinBitrate - 10));
+    ExpectEqual(expected, GetAllocation(kActiveStreamMinBitrate));
+  }
+
+  {
+    // The stream should be allocated its target bitrate.
+    uint32_t expected[] = {kActiveStreamTargetBitrate, 0};
+    ExpectEqual(expected, GetAllocation(kActiveStreamTargetBitrate));
+  }
+
+  {
+    // The stream should be allocated its max if the target input is sufficent.
+    uint32_t expected[] = {kActiveStreamMaxBitrate, 0};
+    ExpectEqual(expected, GetAllocation(kActiveStreamMaxBitrate));
+    ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
+  }
+}
+
+// If there are three simulcast streams and the middle stream is inactive, the
+// other two streams should be allocated bitrate the same as if they are two
+// active simulcast streams.
+TEST_F(SimulcastRateAllocatorTest, ThreeStreamsMiddleInactive) {
+  const std::vector<bool> active_streams({true, false, true});
+  SetupCodecThreeSimulcastStreams(active_streams);
+  CreateAllocator();
+
+  {
+    const uint32_t kLowStreamMinBitrate = codec_.simulcastStream[0].minBitrate;
+    // The lowest stream should always be allocated its minimum bitrate.
+    uint32_t expected[] = {kLowStreamMinBitrate, 0, 0};
+    ExpectEqual(expected, GetAllocation(0));
+    ExpectEqual(expected, GetAllocation(kLowStreamMinBitrate - 10));
+    ExpectEqual(expected, GetAllocation(kLowStreamMinBitrate));
+  }
+
+  {
+    // The lowest stream gets its target bitrate.
+    uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate, 0, 0};
+    ExpectEqual(expected,
+                GetAllocation(codec_.simulcastStream[0].targetBitrate));
+  }
+
+  {
+    // The lowest stream gets its max bitrate, but not enough for the high
+    // stream.
+    const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
+                             codec_.simulcastStream[2].minBitrate - 1;
+    uint32_t expected[] = {codec_.simulcastStream[0].maxBitrate, 0, 0};
+    ExpectEqual(expected, GetAllocation(bitrate));
+  }
+
+  {
+    // Both active streams get allocated target bitrate.
+    const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
+                             codec_.simulcastStream[2].targetBitrate;
+    uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate, 0,
+                           codec_.simulcastStream[2].targetBitrate};
+    ExpectEqual(expected, GetAllocation(bitrate));
+  }
+
+  {
+    // Lowest stream gets its target bitrate, high stream gets its max bitrate.
+    uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
+                       codec_.simulcastStream[2].maxBitrate;
+    uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate, 0,
+                           codec_.simulcastStream[2].maxBitrate};
+    ExpectEqual(expected, GetAllocation(bitrate));
+    ExpectEqual(expected, GetAllocation(bitrate + 10));
+    ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
+  }
 }
 
 TEST_F(SimulcastRateAllocatorTest, GetPreferredBitrateBps) {
@@ -283,15 +497,18 @@
   codec_.maxBitrate = 999999;
   codec_.simulcastStream[0].minBitrate = 10;
   codec_.simulcastStream[0].targetBitrate = 100;
+  codec_.simulcastStream[0].active = true;
 
   codec_.simulcastStream[0].maxBitrate = 500;
   codec_.simulcastStream[1].minBitrate = 50;
   codec_.simulcastStream[1].targetBitrate = 500;
   codec_.simulcastStream[1].maxBitrate = 1000;
+  codec_.simulcastStream[1].active = true;
 
   codec_.simulcastStream[2].minBitrate = 2000;
   codec_.simulcastStream[2].targetBitrate = 3000;
   codec_.simulcastStream[2].maxBitrate = 4000;
+  codec_.simulcastStream[2].active = true;
   CreateAllocator();
 
   uint32_t preferred_bitrate_kbps;
@@ -305,7 +522,7 @@
 
 class ScreenshareRateAllocationTest : public SimulcastRateAllocatorTest {
  public:
-  void SetupConferenceScreenshare(bool use_simulcast) {
+  void SetupConferenceScreenshare(bool use_simulcast, bool active = true) {
     codec_.mode = VideoCodecMode::kScreensharing;
     codec_.minBitrate = kMinBitrateKbps;
     codec_.maxBitrate = kMaxBitrateKbps;
@@ -315,10 +532,12 @@
       codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
       codec_.simulcastStream[0].maxBitrate = kMaxBitrateKbps;
       codec_.simulcastStream[0].numberOfTemporalLayers = 2;
+      codec_.simulcastStream[0].active = active;
     } else {
       codec_.numberOfSimulcastStreams = 0;
       codec_.targetBitrate = kTargetBitrateKbps;
       codec_.VP8()->numberOfTemporalLayers = 2;
+      codec_.active = active;
     }
   }
 
@@ -373,4 +592,17 @@
             allocation.GetBitrate(0, 1) / 1000);
 }
 
+// This tests when the screenshare is inactive it should be allocated 0 bitrate
+// for all layers.
+TEST_P(ScreenshareRateAllocationTest, InactiveScreenshare) {
+  SetupConferenceScreenshare(GetParam(), false);
+  CreateAllocator();
+
+  // Enough bitrate for TL0 and TL1.
+  uint32_t target_bitrate_kbps = (kTargetBitrateKbps + kMaxBitrateKbps) / 2;
+  BitrateAllocation allocation =
+      allocator_->GetAllocation(target_bitrate_kbps * 1000, kFramerateFps);
+
+  EXPECT_EQ(0U, allocation.get_sum_kbps());
+}
 }  // namespace webrtc
diff --git a/modules/video_coding/video_codec_initializer.cc b/modules/video_coding/video_codec_initializer.cc
index 9b259f6..24c9e7c 100644
--- a/modules/video_coding/video_codec_initializer.cc
+++ b/modules/video_coding/video_codec_initializer.cc
@@ -192,6 +192,15 @@
   video_codec.numberOfSimulcastStreams =
       static_cast<unsigned char>(streams.size());
   video_codec.minBitrate = streams[0].min_bitrate_bps / 1000;
+  bool codec_active = false;
+  for (const VideoStream& stream : streams) {
+    if (stream.active) {
+      codec_active = true;
+      break;
+    }
+  }
+  // Set active for the entire video codec for the non simulcast case.
+  video_codec.active = codec_active;
   if (video_codec.minBitrate < kEncoderMinBitrateKbps)
     video_codec.minBitrate = kEncoderMinBitrateKbps;
   video_codec.timing_frame_thresholds = {kDefaultTimingFramesDelayMs,
@@ -231,6 +240,7 @@
     sim_stream->qpMax = streams[i].max_qp;
     sim_stream->numberOfTemporalLayers = static_cast<unsigned char>(
         streams[i].temporal_layer_thresholds_bps.size() + 1);
+    sim_stream->active = streams[i].active;
 
     video_codec.width =
         std::max(video_codec.width, static_cast<uint16_t>(streams[i].width));
diff --git a/modules/video_coding/video_codec_initializer_unittest.cc b/modules/video_coding/video_codec_initializer_unittest.cc
index 0862b72..e8925e1 100644
--- a/modules/video_coding/video_codec_initializer_unittest.cc
+++ b/modules/video_coding/video_codec_initializer_unittest.cc
@@ -118,6 +118,7 @@
     stream.target_bitrate_bps = kDefaultTargetBitrateBps;
     stream.max_bitrate_bps = kDefaultMaxBitrateBps;
     stream.max_qp = kDefaultMaxQp;
+    stream.active = true;
     return stream;
   }
 
@@ -128,6 +129,7 @@
     stream.max_bitrate_bps = 1000000;
     stream.max_framerate = kScreenshareDefaultFramerate;
     stream.temporal_layer_thresholds_bps.push_back(kScreenshareTl0BitrateBps);
+    stream.active = true;
     return stream;
   }
 
@@ -155,6 +157,20 @@
   EXPECT_EQ(kDefaultTargetBitrateBps, bitrate_allocation.get_sum_bps());
 }
 
+TEST_F(VideoCodecInitializerTest, SingleStreamVp8ScreenshareInactive) {
+  SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
+  VideoStream inactive_stream = DefaultStream();
+  inactive_stream.active = false;
+  streams_.push_back(inactive_stream);
+  EXPECT_TRUE(InitializeCodec());
+
+  BitrateAllocation bitrate_allocation = bitrate_allocator_out_->GetAllocation(
+      kDefaultTargetBitrateBps, kDefaultFrameRate);
+  EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
+  EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
+  EXPECT_EQ(0U, bitrate_allocation.get_sum_bps());
+}
+
 TEST_F(VideoCodecInitializerTest, TemporalLayeredVp8Screenshare) {
   SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 2, true);
   streams_.push_back(DefaultScreenshareStream());
@@ -169,7 +185,7 @@
   EXPECT_EQ(kScreenshareTl0BitrateBps, bitrate_allocation.GetBitrate(0, 0));
 }
 
-TEST_F(VideoCodecInitializerTest, SimlucastVp8Screenshare) {
+TEST_F(VideoCodecInitializerTest, SimulcastVp8Screenshare) {
   SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
   streams_.push_back(DefaultScreenshareStream());
   VideoStream video_stream = DefaultStream();
@@ -190,7 +206,31 @@
             bitrate_allocation.GetSpatialLayerSum(1));
 }
 
-TEST_F(VideoCodecInitializerTest, HighFpsSimlucastVp8Screenshare) {
+// Tests that when a video stream is inactive, then the bitrate allocation will
+// be 0 for that stream.
+TEST_F(VideoCodecInitializerTest, SimulcastVp8ScreenshareInactive) {
+  SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
+  streams_.push_back(DefaultScreenshareStream());
+  VideoStream inactive_video_stream = DefaultStream();
+  inactive_video_stream.active = false;
+  inactive_video_stream.max_framerate = kScreenshareDefaultFramerate;
+  streams_.push_back(inactive_video_stream);
+  EXPECT_TRUE(InitializeCodec());
+
+  EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
+  EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
+  const uint32_t target_bitrate =
+      streams_[0].target_bitrate_bps + streams_[1].target_bitrate_bps;
+  BitrateAllocation bitrate_allocation = bitrate_allocator_out_->GetAllocation(
+      target_bitrate, kScreenshareDefaultFramerate);
+  EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
+            bitrate_allocation.get_sum_bps());
+  EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
+            bitrate_allocation.GetSpatialLayerSum(0));
+  EXPECT_EQ(0U, bitrate_allocation.GetSpatialLayerSum(1));
+}
+
+TEST_F(VideoCodecInitializerTest, HighFpsSimulcastVp8Screenshare) {
   // Two simulcast streams, the lower one using legacy settings (two temporal
   // streams, 5fps), the higher one using 3 temporal streams and 30fps.
   SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 3, true);
diff --git a/test/encoder_settings.cc b/test/encoder_settings.cc
index 84d3916..205af7b 100644
--- a/test/encoder_settings.cc
+++ b/test/encoder_settings.cc
@@ -50,6 +50,7 @@
         std::min(bitrate_left_bps,
                  DefaultVideoStreamFactory::kMaxBitratePerStream[i]);
     stream_settings[i].max_qp = 56;
+    stream_settings[i].active = true;
     bitrate_left_bps -= stream_settings[i].target_bitrate_bps;
   }
 
diff --git a/test/video_codec_settings.h b/test/video_codec_settings.h
index 54cf717..5dabc70 100644
--- a/test/video_codec_settings.h
+++ b/test/video_codec_settings.h
@@ -43,6 +43,7 @@
       settings->timing_frame_thresholds = {
           kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent,
       };
+      settings->active = true;
       *(settings->VP8()) = VideoEncoder::GetDefaultVp8Settings();
       return;
     case kVideoCodecVP9:
@@ -61,6 +62,7 @@
       settings->timing_frame_thresholds = {
           kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent,
       };
+      settings->active = true;
       *(settings->VP9()) = VideoEncoder::GetDefaultVp9Settings();
       return;
     case kVideoCodecH264:
@@ -79,6 +81,7 @@
       settings->timing_frame_thresholds = {
           kTestTimingFramesDelayMs, kTestOutlierFrameSizePercent,
       };
+      settings->active = true;
       *(settings->H264()) = VideoEncoder::GetDefaultH264Settings();
       return;
     case kVideoCodecI420:
@@ -95,6 +98,7 @@
       settings->height = kTestHeight;
       settings->minBitrate = kTestMinBitrateKbps;
       settings->numberOfSimulcastStreams = 0;
+      settings->active = true;
       return;
     case kVideoCodecRED:
     case kVideoCodecULPFEC:
diff --git a/video/payload_router.cc b/video/payload_router.cc
index f221832..68d4ee8 100644
--- a/video/payload_router.cc
+++ b/video/payload_router.cc
@@ -258,8 +258,11 @@
       // rtp stream, moving over the temporal layer allocation.
       for (size_t si = 0; si < rtp_modules_.size(); ++si) {
         // Don't send empty TargetBitrate messages on streams not being relayed.
-        if (!bitrate.IsSpatialLayerUsed(si))
-          break;
+        if (!bitrate.IsSpatialLayerUsed(si)) {
+          // The next spatial layer could be used if the current one is
+          // inactive.
+          continue;
+        }
 
         BitrateAllocation layer_bitrate;
         for (int tl = 0; tl < kMaxTemporalStreams; ++tl) {
diff --git a/video/payload_router_unittest.cc b/video/payload_router_unittest.cc
index d670124..a512582 100644
--- a/video/payload_router_unittest.cc
+++ b/video/payload_router_unittest.cc
@@ -32,6 +32,7 @@
 const int8_t kPayloadType = 96;
 const uint32_t kSsrc1 = 12345;
 const uint32_t kSsrc2 = 23456;
+const uint32_t kSsrc3 = 34567;
 const int16_t kPictureId = 123;
 const int16_t kTl0PicIdx = 20;
 const uint8_t kTemporalIdx = 1;
@@ -186,23 +187,38 @@
   payload_router.OnBitrateAllocationUpdated(bitrate);
 }
 
+// If the middle of three streams is inactive the first and last streams should
+// be asked to send the TargetBitrate message.
 TEST(PayloadRouterTest, SimulcastTargetBitrateWithInactiveStream) {
-  // Set up two active rtp modules.
+  // Set up three active rtp modules.
   NiceMock<MockRtpRtcp> rtp_1;
   NiceMock<MockRtpRtcp> rtp_2;
-  std::vector<RtpRtcp*> modules = {&rtp_1, &rtp_2};
-  PayloadRouter payload_router(modules, {kSsrc1, kSsrc2}, kPayloadType, {});
+  NiceMock<MockRtpRtcp> rtp_3;
+  std::vector<RtpRtcp*> modules = {&rtp_1, &rtp_2, &rtp_3};
+  PayloadRouter payload_router(modules, {kSsrc1, kSsrc2, kSsrc3}, kPayloadType,
+                               {});
   payload_router.SetActive(true);
 
-  // Create bitrate allocation with bitrate only for the first stream.
+  // Create bitrate allocation with bitrate only for the first and third stream.
   BitrateAllocation bitrate;
   bitrate.SetBitrate(0, 0, 10000);
   bitrate.SetBitrate(0, 1, 20000);
+  bitrate.SetBitrate(2, 0, 40000);
+  bitrate.SetBitrate(2, 1, 80000);
 
-  // Expect only the first rtp module to be asked to send a TargetBitrate
+  BitrateAllocation layer0_bitrate;
+  layer0_bitrate.SetBitrate(0, 0, 10000);
+  layer0_bitrate.SetBitrate(0, 1, 20000);
+
+  BitrateAllocation layer2_bitrate;
+  layer2_bitrate.SetBitrate(0, 0, 40000);
+  layer2_bitrate.SetBitrate(0, 1, 80000);
+
+  // Expect the first and third rtp module to be asked to send a TargetBitrate
   // message. (No target bitrate with 0bps sent from the second one.)
-  EXPECT_CALL(rtp_1, SetVideoBitrateAllocation(bitrate)).Times(1);
+  EXPECT_CALL(rtp_1, SetVideoBitrateAllocation(layer0_bitrate)).Times(1);
   EXPECT_CALL(rtp_2, SetVideoBitrateAllocation(_)).Times(0);
+  EXPECT_CALL(rtp_3, SetVideoBitrateAllocation(layer2_bitrate)).Times(1);
 
   payload_router.OnBitrateAllocationUpdated(bitrate);
 }
diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc
index 3c39871..234f4d1 100644
--- a/video/video_quality_test.cc
+++ b/video/video_quality_test.cc
@@ -1200,6 +1200,7 @@
   stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps;
   stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps;
   stream.max_qp = kDefaultMaxQp;
+  stream.active = true;
   // TODO(sprang): Can we make this less of a hack?
   if (params.video[video_idx].num_temporal_layers == 2) {
     stream.temporal_layer_thresholds_bps.push_back(stream.target_bitrate_bps);
diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc
index 7ab2a72..a64efa7 100644
--- a/video/video_send_stream.cc
+++ b/video/video_send_stream.cc
@@ -967,7 +967,8 @@
   encoder_max_bitrate_bps_ = 0;
   double stream_bitrate_priority_sum = 0;
   for (const auto& stream : streams) {
-    encoder_max_bitrate_bps_ += stream.max_bitrate_bps;
+    // We don't want to allocate more bitrate than needed to inactive streams.
+    encoder_max_bitrate_bps_ += stream.active ? stream.max_bitrate_bps : 0;
     if (stream.bitrate_priority) {
       RTC_DCHECK_GT(*stream.bitrate_priority, 0);
       stream_bitrate_priority_sum += *stream.bitrate_priority;
@@ -975,6 +976,9 @@
   }
   RTC_DCHECK_GT(stream_bitrate_priority_sum, 0);
   encoder_bitrate_priority_ = stream_bitrate_priority_sum;
+  encoder_max_bitrate_bps_ =
+      std::max(static_cast<uint32_t>(encoder_min_bitrate_bps_),
+               encoder_max_bitrate_bps_);
   max_padding_bitrate_ = CalculateMaxPadBitrateBps(
       streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate);