Keep SVC max bitrate if number of spatial layers are reduced.

Bug: chromium:1423361
Change-Id: I02bcb11f2ac456db79ed835dd38d4d7621a49608
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/298446
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39614}
diff --git a/modules/video_coding/codecs/vp9/svc_config.cc b/modules/video_coding/codecs/vp9/svc_config.cc
index 3a32a43..43def0f 100644
--- a/modules/video_coding/codecs/vp9/svc_config.cc
+++ b/modules/video_coding/codecs/vp9/svc_config.cc
@@ -203,12 +203,7 @@
                    codec.GetScalabilityMode() ? info : absl::nullopt);
   RTC_DCHECK(!spatial_layers.empty());
 
-  // Use codec bitrate limits if spatial layering is not requested.
-  if (info->num_spatial_layers == 1) {
-    spatial_layers.back().minBitrate = codec.minBitrate;
-    spatial_layers.back().targetBitrate = codec.maxBitrate;
-    spatial_layers.back().maxBitrate = codec.maxBitrate;
-  }
+  spatial_layers[0].minBitrate = kMinVp9SvcBitrateKbps;
 
   return spatial_layers;
 }
diff --git a/modules/video_coding/video_codec_initializer.cc b/modules/video_coding/video_codec_initializer.cc
index b0b16d0..c468e99 100644
--- a/modules/video_coding/video_codec_initializer.cc
+++ b/modules/video_coding/video_codec_initializer.cc
@@ -237,6 +237,13 @@
         spatial_layers = GetVp9SvcConfig(video_codec);
         if (spatial_layers.empty())
           break;
+        // Use codec bitrate limits if spatial layering is not requested.
+        if (config.simulcast_layers.size() <= 1 &&
+            ScalabilityModeToNumSpatialLayers(*scalability_mode) == 1) {
+          spatial_layers.back().minBitrate = video_codec.minBitrate;
+          spatial_layers.back().targetBitrate = video_codec.maxBitrate;
+          spatial_layers.back().maxBitrate = video_codec.maxBitrate;
+        }
       } else {
         size_t first_active_layer = 0;
         for (size_t spatial_idx = 0;
diff --git a/modules/video_coding/video_codec_initializer_unittest.cc b/modules/video_coding/video_codec_initializer_unittest.cc
index e628680..b9d8465 100644
--- a/modules/video_coding/video_codec_initializer_unittest.cc
+++ b/modules/video_coding/video_codec_initializer_unittest.cc
@@ -332,6 +332,22 @@
 }
 
 TEST_F(VideoCodecInitializerTest,
+       Vp9SingleSpatialLayerMaxBitrateIsEqualToCodecMaxBitrateWithL1T1) {
+  SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 1, 1, false);
+  VideoStream stream = DefaultStream();
+  stream.num_temporal_layers = 1;
+  stream.scalability_mode = ScalabilityMode::kL1T1;
+  streams_.push_back(stream);
+
+  EXPECT_TRUE(InitializeCodec());
+  EXPECT_EQ(1u, codec_out_.VP9()->numberOfSpatialLayers);
+  EXPECT_EQ(codec_out_.spatialLayers[0].minBitrate,
+            kDefaultMinBitrateBps / 1000);
+  EXPECT_EQ(codec_out_.spatialLayers[0].maxBitrate,
+            kDefaultMaxBitrateBps / 1000);
+}
+
+TEST_F(VideoCodecInitializerTest,
        Vp9SingleSpatialLayerTargetBitrateIsEqualToCodecMaxBitrate) {
   SetUpFor(VideoCodecType::kVideoCodecVP9, absl::nullopt, 1, 1, true);
   VideoStream stream = DefaultStream();
@@ -360,6 +376,27 @@
             kDefaultMaxBitrateBps / 1000);
 }
 
+TEST_F(VideoCodecInitializerTest,
+       Vp9KeepBitrateLimitsIfNumberOfSpatialLayersIsReducedToOneWithL3T1) {
+  // Request 3 spatial layers for 320x180 input. Actual number of layers will be
+  // reduced to 1 due to low input resolution but SVC bitrate limits should be
+  // applied.
+  SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 3, 1, false);
+  VideoStream stream = DefaultStream();
+  stream.width = 320;
+  stream.height = 180;
+  stream.num_temporal_layers = 1;
+  stream.scalability_mode = ScalabilityMode::kL3T1;
+  streams_.push_back(stream);
+
+  EXPECT_TRUE(InitializeCodec());
+  EXPECT_EQ(1u, codec_out_.VP9()->numberOfSpatialLayers);
+  EXPECT_LT(codec_out_.spatialLayers[0].minBitrate,
+            kDefaultMinBitrateBps / 1000);
+  EXPECT_LT(codec_out_.spatialLayers[0].maxBitrate,
+            kDefaultMaxBitrateBps / 1000);
+}
+
 TEST_F(VideoCodecInitializerTest, Vp9DeactivateLayers) {
   SetUpFor(VideoCodecType::kVideoCodecVP9, absl::nullopt, 3, 1, false);
   VideoStream stream = DefaultStream();
@@ -537,4 +574,55 @@
   EXPECT_FALSE(codec.spatialLayers[1].active);
 }
 
+TEST_F(VideoCodecInitializerTest, Vp9SingleSpatialLayerBitratesAreConsistent) {
+  VideoEncoderConfig config;
+  config.simulcast_layers.resize(3);
+  config.simulcast_layers[0].active = true;
+  config.simulcast_layers[1].active = false;
+  config.simulcast_layers[2].active = false;
+
+  config.codec_type = VideoCodecType::kVideoCodecVP9;
+  std::vector<VideoStream> streams = {DefaultStream()};
+  streams[0].scalability_mode = ScalabilityMode::kL1T2;
+
+  VideoCodec codec;
+  EXPECT_TRUE(VideoCodecInitializer::SetupCodec(config, streams, &codec));
+
+  EXPECT_EQ(1u, codec.VP9()->numberOfSpatialLayers);
+  EXPECT_GE(codec.spatialLayers[0].targetBitrate,
+            codec.spatialLayers[0].minBitrate);
+  EXPECT_LE(codec.spatialLayers[0].targetBitrate,
+            codec.spatialLayers[0].maxBitrate);
+  EXPECT_LT(codec.spatialLayers[0].minBitrate, kDefaultMinBitrateBps / 1000);
+}
+
+TEST_F(VideoCodecInitializerTest, Vp9TwoSpatialLayersBitratesAreConsistent) {
+  VideoEncoderConfig config;
+  config.simulcast_layers.resize(3);
+  config.simulcast_layers[0].active = true;
+  config.simulcast_layers[1].active = false;
+  config.simulcast_layers[2].active = false;
+
+  config.codec_type = VideoCodecType::kVideoCodecVP9;
+  std::vector<VideoStream> streams = {DefaultStream()};
+  streams[0].scalability_mode = ScalabilityMode::kL2T2;
+
+  VideoCodec codec;
+  EXPECT_TRUE(VideoCodecInitializer::SetupCodec(config, streams, &codec));
+
+  EXPECT_EQ(2u, codec.VP9()->numberOfSpatialLayers);
+  EXPECT_GE(codec.spatialLayers[0].targetBitrate,
+            codec.spatialLayers[0].minBitrate);
+  EXPECT_LE(codec.spatialLayers[0].targetBitrate,
+            codec.spatialLayers[0].maxBitrate);
+  EXPECT_LT(codec.spatialLayers[0].minBitrate, kDefaultMinBitrateBps / 1000);
+
+  EXPECT_GE(codec.spatialLayers[1].targetBitrate,
+            codec.spatialLayers[1].minBitrate);
+  EXPECT_LE(codec.spatialLayers[1].targetBitrate,
+            codec.spatialLayers[1].maxBitrate);
+  EXPECT_GT(codec.spatialLayers[1].minBitrate,
+            codec.spatialLayers[0].maxBitrate);
+}
+
 }  // namespace webrtc
diff --git a/video/end_to_end_tests/resolution_bitrate_limits_tests.cc b/video/end_to_end_tests/resolution_bitrate_limits_tests.cc
index d550339..86167ac 100644
--- a/video/end_to_end_tests/resolution_bitrate_limits_tests.cc
+++ b/video/end_to_end_tests/resolution_bitrate_limits_tests.cc
@@ -229,6 +229,33 @@
 }
 
 TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest,
+       OneStreamDefaultMaxBitrateAppliedForOneSpatialLayer) {
+  InitEncodeTest test("VP9",
+                      {{.active = true,
+                        .bitrate = {DataRate::KilobitsPerSec(30),
+                                    DataRate::KilobitsPerSec(3000)},
+                        .scalability_mode = ScalabilityMode::kL1T1}},
+                      // Expectations:
+                      {{.pixels = 1280 * 720,
+                        .eq_bitrate = {DataRate::KilobitsPerSec(30),
+                                       DataRate::KilobitsPerSec(3000)}}});
+  RunBaseTest(&test);
+}
+
+TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest,
+       OneStreamSvcMaxBitrateAppliedForTwoSpatialLayers) {
+  InitEncodeTest test(
+      "VP9",
+      {{.active = true,
+        .bitrate = {DataRate::KilobitsPerSec(30),
+                    DataRate::KilobitsPerSec(3000)},
+        .scalability_mode = ScalabilityMode::kL2T1}},
+      // Expectations:
+      {{.pixels = 1280 * 720,
+        .ne_bitrate = {absl::nullopt, DataRate::KilobitsPerSec(3000)}}});
+  RunBaseTest(&test);
+}
+TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest,
        OneStreamLimitsAppliedForOneSpatialLayer) {
   webrtc::test::ScopedFieldTrials field_trials(
       "WebRTC-GetEncoderInfoOverride/"