Configure default bitrate targets for VP9 simulcast


Bug: webrtc:15852
Change-Id: Icab74d4eafe4cfb95dace7ae0e3e5810f3052204
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/340441
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41908}
diff --git a/video/config/encoder_stream_factory.cc b/video/config/encoder_stream_factory.cc
index a4e41ad..2528a1b 100644
--- a/video/config/encoder_stream_factory.cc
+++ b/video/config/encoder_stream_factory.cc
@@ -320,7 +320,8 @@
                               encoder_config.number_of_streams, width, height,
                               encoder_config.bitrate_priority, max_qp_,
                               is_screenshare_ && conference_mode_,
-                              temporal_layers_supported, trials_);
+                              temporal_layers_supported, trials_,
+                              encoder_config.codec_type);
   // Allow an experiment to override the minimum bitrate for the lowest
   // spatial layer. The experiment's configuration has the lowest priority.
   if (experimental_min_bitrate) {
diff --git a/video/config/simulcast.cc b/video/config/simulcast.cc
index 7a78ef8..2c600c8 100644
--- a/video/config/simulcast.cc
+++ b/video/config/simulcast.cc
@@ -76,7 +76,7 @@
 // These tables describe from which resolution we can use how many
 // simulcast layers at what bitrates (maximum, target, and minimum).
 // Important!! Keep this table from high resolution to low resolution.
-constexpr const SimulcastFormat kSimulcastFormats[] = {
+constexpr const SimulcastFormat kSimulcastFormatsVP8[] = {
     {1920, 1080, 3, webrtc::DataRate::KilobitsPerSec(5000),
      webrtc::DataRate::KilobitsPerSec(4000),
      webrtc::DataRate::KilobitsPerSec(800)},
@@ -102,6 +102,38 @@
      webrtc::DataRate::KilobitsPerSec(0),
      webrtc::DataRate::KilobitsPerSec(30)}};
 
+// These tables describe from which resolution we can use how many
+// simulcast layers at what bitrates (maximum, target, and minimum).
+// Important!! Keep this table from high resolution to low resolution.
+constexpr const SimulcastFormat kSimulcastFormatsVP9[] = {
+    {1920, 1080, 3, webrtc::DataRate::KilobitsPerSec(3367),
+     webrtc::DataRate::KilobitsPerSec(3367),
+     webrtc::DataRate::KilobitsPerSec(769)},
+    {1280, 720, 3, webrtc::DataRate::KilobitsPerSec(1524),
+     webrtc::DataRate::KilobitsPerSec(1524),
+     webrtc::DataRate::KilobitsPerSec(481)},
+    {960, 540, 3, webrtc::DataRate::KilobitsPerSec(879),
+     webrtc::DataRate::KilobitsPerSec(879),
+     webrtc::DataRate::KilobitsPerSec(337)},
+    {640, 360, 2, webrtc::DataRate::KilobitsPerSec(420),
+     webrtc::DataRate::KilobitsPerSec(420),
+     webrtc::DataRate::KilobitsPerSec(193)},
+    {480, 270, 2, webrtc::DataRate::KilobitsPerSec(257),
+     webrtc::DataRate::KilobitsPerSec(257),
+     webrtc::DataRate::KilobitsPerSec(121)},
+    {320, 180, 1, webrtc::DataRate::KilobitsPerSec(142),
+     webrtc::DataRate::KilobitsPerSec(142),
+     webrtc::DataRate::KilobitsPerSec(49)},
+    {240, 135, 1, webrtc::DataRate::KilobitsPerSec(101),
+     webrtc::DataRate::KilobitsPerSec(101),
+     webrtc::DataRate::KilobitsPerSec(30)},
+    // As the resolution goes down, interpolate the target and max bitrates down
+    // towards zero. The min bitrate is still limited at 30 kbps and the target
+    // and the max will be capped from below accordingly.
+    {0, 0, 1, webrtc::DataRate::KilobitsPerSec(0),
+     webrtc::DataRate::KilobitsPerSec(0),
+     webrtc::DataRate::KilobitsPerSec(30)}};
+
 constexpr webrtc::DataRate Interpolate(const webrtc::DataRate& a,
                                        const webrtc::DataRate& b,
                                        float rate) {
@@ -115,10 +147,23 @@
 }
 
 std::vector<SimulcastFormat> GetSimulcastFormats(
-    bool enable_lowres_bitrate_interpolation) {
+    bool enable_lowres_bitrate_interpolation,
+    webrtc::VideoCodecType codec) {
   std::vector<SimulcastFormat> formats;
-  formats.insert(formats.begin(), std::begin(kSimulcastFormats),
-                 std::end(kSimulcastFormats));
+  switch (codec) {
+    case webrtc::kVideoCodecVP8:
+      formats.insert(formats.begin(), std::begin(kSimulcastFormatsVP8),
+                     std::end(kSimulcastFormatsVP8));
+      break;
+    case webrtc::kVideoCodecVP9:
+      formats.insert(formats.begin(), std::begin(kSimulcastFormatsVP9),
+                     std::end(kSimulcastFormatsVP9));
+      break;
+    default:
+      formats.insert(formats.begin(), std::begin(kSimulcastFormatsVP8),
+                     std::end(kSimulcastFormatsVP8));
+      break;
+  }
   if (!enable_lowres_bitrate_interpolation) {
     RTC_CHECK_GE(formats.size(), 2u);
     SimulcastFormat& format0x0 = formats[formats.size() - 1];
@@ -153,10 +198,12 @@
 
 int FindSimulcastFormatIndex(int width,
                              int height,
-                             bool enable_lowres_bitrate_interpolation) {
+                             bool enable_lowres_bitrate_interpolation,
+                             webrtc::VideoCodecType codec) {
   RTC_DCHECK_GE(width, 0);
   RTC_DCHECK_GE(height, 0);
-  const auto formats = GetSimulcastFormats(enable_lowres_bitrate_interpolation);
+  const auto formats =
+      GetSimulcastFormats(enable_lowres_bitrate_interpolation, codec);
   for (uint32_t i = 0; i < formats.size(); ++i) {
     if (width * height >= formats[i].width * formats[i].height) {
       return i;
@@ -186,10 +233,12 @@
     int width,
     int height,
     absl::optional<double> max_roundup_rate,
-    bool enable_lowres_bitrate_interpolation) {
-  const auto formats = GetSimulcastFormats(enable_lowres_bitrate_interpolation);
+    bool enable_lowres_bitrate_interpolation,
+    webrtc::VideoCodecType codec) {
+  const auto formats =
+      GetSimulcastFormats(enable_lowres_bitrate_interpolation, codec);
   const int index = FindSimulcastFormatIndex(
-      width, height, enable_lowres_bitrate_interpolation);
+      width, height, enable_lowres_bitrate_interpolation, codec);
   if (index == 0)
     return formats[index];
   const int total_pixels_up =
@@ -216,35 +265,39 @@
 SimulcastFormat InterpolateSimulcastFormat(
     int width,
     int height,
-    bool enable_lowres_bitrate_interpolation) {
+    bool enable_lowres_bitrate_interpolation,
+    webrtc::VideoCodecType codec) {
   return InterpolateSimulcastFormat(width, height, absl::nullopt,
-                                    enable_lowres_bitrate_interpolation);
+                                    enable_lowres_bitrate_interpolation, codec);
 }
 
 webrtc::DataRate FindSimulcastMaxBitrate(
     int width,
     int height,
-    bool enable_lowres_bitrate_interpolation) {
+    bool enable_lowres_bitrate_interpolation,
+    webrtc::VideoCodecType codec) {
   return InterpolateSimulcastFormat(width, height,
-                                    enable_lowres_bitrate_interpolation)
+                                    enable_lowres_bitrate_interpolation, codec)
       .max_bitrate;
 }
 
 webrtc::DataRate FindSimulcastTargetBitrate(
     int width,
     int height,
-    bool enable_lowres_bitrate_interpolation) {
+    bool enable_lowres_bitrate_interpolation,
+    webrtc::VideoCodecType codec) {
   return InterpolateSimulcastFormat(width, height,
-                                    enable_lowres_bitrate_interpolation)
+                                    enable_lowres_bitrate_interpolation, codec)
       .target_bitrate;
 }
 
 webrtc::DataRate FindSimulcastMinBitrate(
     int width,
     int height,
-    bool enable_lowres_bitrate_interpolation) {
+    bool enable_lowres_bitrate_interpolation,
+    webrtc::VideoCodecType codec) {
   return InterpolateSimulcastFormat(width, height,
-                                    enable_lowres_bitrate_interpolation)
+                                    enable_lowres_bitrate_interpolation, codec)
       .min_bitrate;
 }
 
@@ -280,7 +333,8 @@
                                 int height,
                                 size_t need_layers,
                                 size_t layer_count,
-                                const webrtc::FieldTrialsView& trials) {
+                                const webrtc::FieldTrialsView& trials,
+                                webrtc::VideoCodecType codec) {
   if (!absl::StartsWith(trials.Lookup(kUseLegacySimulcastLayerLimitFieldTrial),
                         "Disabled")) {
     // Max layers from one higher resolution in kSimulcastFormats will be used
@@ -296,7 +350,7 @@
     size_t adaptive_layer_count = std::max(
         need_layers,
         InterpolateSimulcastFormat(width, height, max_ratio.GetOptional(),
-                                   enable_lowres_bitrate_interpolation)
+                                   enable_lowres_bitrate_interpolation, codec)
             .max_layers);
     if (layer_count > adaptive_layer_count) {
       RTC_LOG(LS_WARNING) << "Reducing simulcast layer count from "
@@ -316,7 +370,8 @@
     int max_qp,
     bool is_screenshare_with_conference_mode,
     bool temporal_layers_supported,
-    const webrtc::FieldTrialsView& trials) {
+    const webrtc::FieldTrialsView& trials,
+    webrtc::VideoCodecType codec) {
   RTC_DCHECK_LE(min_layers, max_layers);
   RTC_DCHECK(max_layers > 1 || is_screenshare_with_conference_mode);
 
@@ -331,12 +386,12 @@
     // Some applications rely on the old behavior limiting the simulcast layer
     // count based on the resolution automatically, which they can get through
     // the WebRTC-LegacySimulcastLayerLimit field trial until they update.
-    max_layers =
-        LimitSimulcastLayerCount(width, height, min_layers, max_layers, trials);
+    max_layers = LimitSimulcastLayerCount(width, height, min_layers, max_layers,
+                                          trials, codec);
 
     return GetNormalSimulcastLayers(max_layers, width, height, bitrate_priority,
                                     max_qp, temporal_layers_supported,
-                                    base_heavy_tl3_rate_alloc, trials);
+                                    base_heavy_tl3_rate_alloc, trials, codec);
   }
 }
 
@@ -348,7 +403,8 @@
     int max_qp,
     bool temporal_layers_supported,
     bool base_heavy_tl3_rate_alloc,
-    const webrtc::FieldTrialsView& trials) {
+    const webrtc::FieldTrialsView& trials,
+    webrtc::VideoCodecType codec) {
   std::vector<webrtc::VideoStream> layers(layer_count);
   const bool enable_lowres_bitrate_interpolation =
       EnableLowresBitrateInterpolation(trials);
@@ -368,11 +424,11 @@
         temporal_layers_supported ? num_temporal_layers : 1;
     layers[s].max_bitrate_bps =
         FindSimulcastMaxBitrate(width, height,
-                                enable_lowres_bitrate_interpolation)
+                                enable_lowres_bitrate_interpolation, codec)
             .bps();
     layers[s].target_bitrate_bps =
         FindSimulcastTargetBitrate(width, height,
-                                   enable_lowres_bitrate_interpolation)
+                                   enable_lowres_bitrate_interpolation, codec)
             .bps();
     if (s == 0) {
       // If alternative temporal rate allocation is selected, adjust the
@@ -401,7 +457,7 @@
     }
     layers[s].min_bitrate_bps =
         FindSimulcastMinBitrate(width, height,
-                                enable_lowres_bitrate_interpolation)
+                                enable_lowres_bitrate_interpolation, codec)
             .bps();
 
     // Ensure consistency.
diff --git a/video/config/simulcast.h b/video/config/simulcast.h
index 32af168..4bd9993 100644
--- a/video/config/simulcast.h
+++ b/video/config/simulcast.h
@@ -43,7 +43,8 @@
     int max_qp,
     bool is_screenshare_with_conference_mode,
     bool temporal_layers_supported,
-    const webrtc::FieldTrialsView& trials);
+    const webrtc::FieldTrialsView& trials,
+    webrtc::VideoCodecType codec);
 
 // Gets the simulcast config layers for a non-screensharing case.
 std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
@@ -54,7 +55,8 @@
     int max_qp,
     bool temporal_layers_supported,
     bool base_heavy_tl3_rate_alloc,
-    const webrtc::FieldTrialsView& trials);
+    const webrtc::FieldTrialsView& trials,
+    webrtc::VideoCodecType codec);
 
 // Gets simulcast config layers for screenshare settings.
 std::vector<webrtc::VideoStream> GetScreenshareLayers(
diff --git a/video/config/simulcast_unittest.cc b/video/config/simulcast_unittest.cc
index 152a0f9..8dbc003 100644
--- a/video/config/simulcast_unittest.cc
+++ b/video/config/simulcast_unittest.cc
@@ -86,7 +86,7 @@
   const size_t kMaxLayers = 3;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 1280, 720, kBitratePriority, kQpMax,
-      !kScreenshare, true, trials);
+      !kScreenshare, true, trials, webrtc::kVideoCodecVP8);
 
   EXPECT_EQ(kMaxLayers, streams.size());
   EXPECT_EQ(320u, streams[0].width);
@@ -122,7 +122,7 @@
   const size_t kMaxLayers = 3;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 1280, 720, kBitratePriority, kQpMax,
-      !kScreenshare, true, trials);
+      !kScreenshare, true, trials, webrtc::kVideoCodecVP8);
 
   EXPECT_EQ(kExpected[0].min_bitrate_bps, streams[0].min_bitrate_bps);
   EXPECT_EQ(static_cast<int>(0.4 * kExpected[0].target_bitrate_bps / 0.6),
@@ -142,7 +142,7 @@
   FieldTrialBasedConfig trials;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 1280, 720, kBitratePriority, kQpMax,
-      !kScreenshare, true, trials);
+      !kScreenshare, true, trials, webrtc::kVideoCodecVP8);
 
   EXPECT_EQ(kMaxLayers, streams.size());
   EXPECT_EQ(640u, streams[0].width);
@@ -159,7 +159,7 @@
   const size_t kMaxLayers = 3;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 800, 600, kBitratePriority, kQpMax, !kScreenshare,
-      true, trials);
+      true, trials, webrtc::kVideoCodecVP8);
 
   EXPECT_EQ(2u, streams.size());
   EXPECT_EQ(400u, streams[0].width);
@@ -176,7 +176,7 @@
   const size_t kMaxLayers = 3;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 100, 100, kBitratePriority, kQpMax, kScreenshare,
-      true, trials);
+      true, trials, webrtc::kVideoCodecVP8);
 
   // Simulcast streams number is never decreased for screenshare,
   // even for very low resolution.
@@ -191,7 +191,7 @@
   const size_t kMaxLayers = 3;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 800, 600, kBitratePriority, kQpMax, !kScreenshare,
-      true, trials);
+      true, trials, webrtc::kVideoCodecVP8);
 
   EXPECT_EQ(kMaxLayers, streams.size());
   EXPECT_EQ(200u, streams[0].width);
@@ -208,7 +208,7 @@
   const size_t kMaxLayers = 2;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 640 + 1, 360 + 1, kBitratePriority, kQpMax,
-      !kScreenshare, true, trials);
+      !kScreenshare, true, trials, webrtc::kVideoCodecVP8);
 
   // Must be divisible by |2 ^ (num_layers - 1)|.
   EXPECT_EQ(kMaxLayers, streams.size());
@@ -227,7 +227,7 @@
   const size_t kMaxLayers = 2;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 709, 501, kBitratePriority, kQpMax, !kScreenshare,
-      true, trials);
+      true, trials, webrtc::kVideoCodecVP8);
 
   // Must be divisible by |2 ^ 2|.
   EXPECT_EQ(kMaxLayers, streams.size());
@@ -246,7 +246,7 @@
   const size_t kMaxLayers = 2;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 709, 501, kBitratePriority, kQpMax, !kScreenshare,
-      true, trials);
+      true, trials, webrtc::kVideoCodecVP8);
 
   // Must be divisible by |2 ^ 3|.
   EXPECT_EQ(kMaxLayers, streams.size());
@@ -265,17 +265,17 @@
   const int kMaxLayers = 3;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 320, 180, kBitratePriority, kQpMax, !kScreenshare,
-      true, trials);
+      true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(1u, streams.size());
 
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 640, 360,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(2u, streams.size());
 
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1920, 1080,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(3u, streams.size());
 }
 
@@ -288,17 +288,17 @@
   const int kMaxLayers = 3;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 320, 180, kBitratePriority, kQpMax, !kScreenshare,
-      true, trials);
+      true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(3u, streams.size());
 
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 640, 360,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(3u, streams.size());
 
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1920, 1080,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(3u, streams.size());
 }
 
@@ -308,7 +308,7 @@
   const size_t kMaxLayers = 3;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 1400, 800, kBitratePriority, kQpMax, kScreenshare,
-      true, trials);
+      true, trials, webrtc::kVideoCodecVP8);
 
   EXPECT_GT(streams.size(), 1u);
   for (size_t i = 0; i < streams.size(); ++i) {
@@ -330,7 +330,7 @@
   const size_t kMaxLayers = 1;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 1400, 800, kBitratePriority, kQpMax, kScreenshare,
-      true, trials);
+      true, trials, webrtc::kVideoCodecVP8);
 
   EXPECT_EQ(kMaxLayers, streams.size());
 }
@@ -341,7 +341,7 @@
   const size_t kMaxLayers = 3;
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, 900, 800, kBitratePriority, kQpMax, !kScreenshare,
-      true, trials);
+      true, trials, webrtc::kVideoCodecVP8);
 
   EXPECT_EQ(kMaxLayers, streams.size());
   EXPECT_EQ(900u, streams[2].width);
@@ -362,7 +362,7 @@
 
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       kMinLayers, kMaxLayers, kWidth, kHeight, kBitratePriority, kQpMax,
-      !kScreenshare, true, trials);
+      !kScreenshare, true, trials, webrtc::kVideoCodecVP8);
 
   EXPECT_EQ(kMaxLayers, streams.size());
   EXPECT_EQ(kWidth, streams[2].width);
@@ -387,21 +387,21 @@
   std::vector<VideoStream> streams;
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 540,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(3u, streams.size());
   // <960x540: 2 layers
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 539,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(2u, streams.size());
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 270,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(2u, streams.size());
   // <480x270: 1 layer
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 269,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(1u, streams.size());
 }
 
@@ -414,29 +414,29 @@
   std::vector<VideoStream> streams;
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 540,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(3u, streams.size());
   // Lowest cropped height where max layers from higher resolution is used.
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 512,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(3u, streams.size());
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 508,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(2u, streams.size());
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 270,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(2u, streams.size());
   // Lowest cropped height where max layers from higher resolution is used.
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 256,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(2u, streams.size());
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 254,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(1u, streams.size());
 }
 
@@ -450,16 +450,16 @@
   std::vector<VideoStream> streams;
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 270,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(2u, streams.size());
   // Lowest cropped height where max layers from higher resolution is used.
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 252,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(2u, streams.size());
   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 250,
                                         kBitratePriority, kQpMax, !kScreenshare,
-                                        true, trials);
+                                        true, trials, webrtc::kVideoCodecVP8);
   EXPECT_EQ(1u, streams.size());
 }
 
@@ -473,7 +473,8 @@
 
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       /* min_layers = */ 1, kMaxLayers, /* width = */ 960, /* height = */ 540,
-      kBitratePriority, kQpMax, !kScreenshare, true, trials);
+      kBitratePriority, kQpMax, !kScreenshare, true, trials,
+      webrtc::kVideoCodecVP8);
 
   ASSERT_EQ(streams.size(), kMaxLayers);
   EXPECT_EQ(240u, streams[0].width);
@@ -492,7 +493,8 @@
 
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       /* min_layers = */ 1, /* max_layers = */ 3, /* width = */ 1,
-      /* height = */ 1, kBitratePriority, kQpMax, !kScreenshare, true, trials);
+      /* height = */ 1, kBitratePriority, kQpMax, !kScreenshare, true, trials,
+      webrtc::kVideoCodecVP8);
 
   ASSERT_TRUE(!streams.empty());
   EXPECT_EQ(1u, streams[0].width);
@@ -512,7 +514,8 @@
 
   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
       /* min_layers = */ 1, kMaxLayers, /* width = */ 960, /* height = */ 540,
-      kBitratePriority, kQpMax, !kScreenshare, true, trials);
+      kBitratePriority, kQpMax, !kScreenshare, true, trials,
+      webrtc::kVideoCodecVP8);
 
   ASSERT_EQ(streams.size(), kMaxLayers);
   EXPECT_EQ(240u, streams[0].width);
@@ -522,4 +525,69 @@
   EXPECT_EQ(streams[0].min_bitrate_bps, 30000);
 }
 
+TEST(SimulcastTest, BitratesBasedOnCodec) {
+  const size_t kMaxLayers = 3;
+  FieldTrialBasedConfig trials;
+
+  std::vector<VideoStream> streams_vp8 = cricket::GetSimulcastConfig(
+      /* min_layers = */ 1, /* max_layers = */ 3, /* width = */ 1280,
+      /* height = */ 720, kBitratePriority, kQpMax, !kScreenshare, true, trials,
+      webrtc::kVideoCodecVP8);
+
+  std::vector<VideoStream> streams_vp9 = cricket::GetSimulcastConfig(
+      /* min_layers = */ 1, /* max_layers = */ 3, /* width = */ 1280,
+      /* height = */ 720, kBitratePriority, kQpMax, !kScreenshare, true, trials,
+      webrtc::kVideoCodecVP9);
+
+  ASSERT_EQ(streams_vp8.size(), kMaxLayers);
+  ASSERT_EQ(streams_vp9.size(), kMaxLayers);
+
+  EXPECT_EQ(streams_vp9[0].width, streams_vp8[0].width);
+  EXPECT_EQ(streams_vp9[0].height, streams_vp8[0].height);
+
+  EXPECT_NE(streams_vp9[0].max_bitrate_bps, streams_vp8[0].max_bitrate_bps);
+  EXPECT_NE(streams_vp9[0].target_bitrate_bps,
+            streams_vp8[0].target_bitrate_bps);
+  EXPECT_NE(streams_vp9[0].min_bitrate_bps, streams_vp8[0].min_bitrate_bps);
+
+  EXPECT_NE(streams_vp9[1].max_bitrate_bps, streams_vp8[1].max_bitrate_bps);
+  EXPECT_NE(streams_vp9[1].target_bitrate_bps,
+            streams_vp8[1].target_bitrate_bps);
+  EXPECT_NE(streams_vp9[1].min_bitrate_bps, streams_vp8[1].min_bitrate_bps);
+
+  EXPECT_NE(streams_vp9[2].max_bitrate_bps, streams_vp8[2].max_bitrate_bps);
+  EXPECT_NE(streams_vp9[2].target_bitrate_bps,
+            streams_vp8[2].target_bitrate_bps);
+  EXPECT_NE(streams_vp9[2].min_bitrate_bps, streams_vp8[2].min_bitrate_bps);
+}
+
+TEST(SimulcastTest, BitratesForVP9) {
+  const size_t kMaxLayers = 3;
+  FieldTrialBasedConfig trials;
+
+  std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
+      /* min_layers = */ 1, kMaxLayers, /* width = */ 1280, /* height = */ 720,
+      kBitratePriority, kQpMax, !kScreenshare, true, trials,
+      webrtc::kVideoCodecVP9);
+
+  ASSERT_EQ(streams.size(), kMaxLayers);
+  EXPECT_EQ(1280u, streams[2].width);
+  EXPECT_EQ(720u, streams[2].height);
+  EXPECT_EQ(streams[2].max_bitrate_bps, 1524000);
+  EXPECT_EQ(streams[2].target_bitrate_bps, 1524000);
+  EXPECT_EQ(streams[2].min_bitrate_bps, 481000);
+
+  streams = cricket::GetSimulcastConfig(
+      /* min_layers = */ 1, kMaxLayers, /* width = */ 1276, /* height = */ 716,
+      kBitratePriority, kQpMax, !kScreenshare, true, trials,
+      webrtc::kVideoCodecVP9);
+
+  ASSERT_EQ(streams.size(), kMaxLayers);
+  EXPECT_EQ(1276u, streams[2].width);
+  EXPECT_EQ(716u, streams[2].height);
+  EXPECT_NEAR(streams[2].max_bitrate_bps, 1524000, 20000);
+  EXPECT_NEAR(streams[2].target_bitrate_bps, 1524000, 20000);
+  EXPECT_NEAR(streams[2].min_bitrate_bps, 481000, 20000);
+}
+
 }  // namespace webrtc