Add support for more scalability modes (1.5:1 resolution ratio).

Added modes:
- L2T2h
- L2T3h
- L3T1h
- L3T2h
- L3T3h

Bug: webrtc:13960
Change-Id: I046a9a1f90629f6d4a5a82d4434e7cc0fa983263
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/273345
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37951}
diff --git a/modules/video_coding/svc/create_scalability_structure.cc b/modules/video_coding/svc/create_scalability_structure.cc
index ad5353b..dd3225c 100644
--- a/modules/video_coding/svc/create_scalability_structure.cc
+++ b/modules/video_coding/svc/create_scalability_structure.cc
@@ -78,6 +78,13 @@
     {1, 1},
     {2, 1}};
 
+constexpr ScalableVideoController::StreamLayersConfig kConfigL2T2h = {
+    /*num_spatial_layers=*/2,
+    /*num_temporal_layers=*/2,
+    /*uses_reference_scaling=*/true,
+    {2, 1},
+    {3, 1}};
+
 constexpr ScalableVideoController::StreamLayersConfig kConfigL2T3 = {
     /*num_spatial_layers=*/2,
     /*num_temporal_layers=*/3,
@@ -85,6 +92,13 @@
     {1, 1},
     {2, 1}};
 
+constexpr ScalableVideoController::StreamLayersConfig kConfigL2T3h = {
+    /*num_spatial_layers=*/2,
+    /*num_temporal_layers=*/3,
+    /*uses_reference_scaling=*/true,
+    {2, 1},
+    {3, 1}};
+
 constexpr ScalableVideoController::StreamLayersConfig kConfigL3T1 = {
     /*num_spatial_layers=*/3,
     /*num_temporal_layers=*/1,
@@ -92,6 +106,13 @@
     {1, 1, 1},
     {4, 2, 1}};
 
+constexpr ScalableVideoController::StreamLayersConfig kConfigL3T1h = {
+    /*num_spatial_layers=*/3,
+    /*num_temporal_layers=*/1,
+    /*uses_reference_scaling=*/true,
+    {4, 2, 1},
+    {9, 3, 1}};
+
 constexpr ScalableVideoController::StreamLayersConfig kConfigL3T2 = {
     /*num_spatial_layers=*/3,
     /*num_temporal_layers=*/2,
@@ -99,6 +120,13 @@
     {1, 1, 1},
     {4, 2, 1}};
 
+constexpr ScalableVideoController::StreamLayersConfig kConfigL3T2h = {
+    /*num_spatial_layers=*/3,
+    /*num_temporal_layers=*/2,
+    /*uses_reference_scaling=*/true,
+    {4, 2, 1},
+    {9, 3, 1}};
+
 constexpr ScalableVideoController::StreamLayersConfig kConfigL3T3 = {
     /*num_spatial_layers=*/3,
     /*num_temporal_layers=*/3,
@@ -106,6 +134,13 @@
     {1, 1, 1},
     {4, 2, 1}};
 
+constexpr ScalableVideoController::StreamLayersConfig kConfigL3T3h = {
+    /*num_spatial_layers=*/3,
+    /*num_temporal_layers=*/3,
+    /*uses_reference_scaling=*/true,
+    {4, 2, 1},
+    {9, 3, 1}};
+
 constexpr ScalableVideoController::StreamLayersConfig kConfigS2T1 = {
     /*num_spatial_layers=*/2,
     /*num_temporal_layers=*/1,
@@ -158,20 +193,25 @@
     {ScalabilityMode::kL2T1_KEY, Create<ScalabilityStructureL2T1Key>,
      kConfigL2T1},
     {ScalabilityMode::kL2T2, Create<ScalabilityStructureL2T2>, kConfigL2T2},
+    {ScalabilityMode::kL2T2h, CreateH<ScalabilityStructureL2T2>, kConfigL2T2h},
     {ScalabilityMode::kL2T2_KEY, Create<ScalabilityStructureL2T2Key>,
      kConfigL2T2},
     {ScalabilityMode::kL2T2_KEY_SHIFT, Create<ScalabilityStructureL2T2KeyShift>,
      kConfigL2T2},
     {ScalabilityMode::kL2T3, Create<ScalabilityStructureL2T3>, kConfigL2T3},
+    {ScalabilityMode::kL2T3h, CreateH<ScalabilityStructureL2T3>, kConfigL2T3h},
     {ScalabilityMode::kL2T3_KEY, Create<ScalabilityStructureL2T3Key>,
      kConfigL2T3},
     {ScalabilityMode::kL3T1, Create<ScalabilityStructureL3T1>, kConfigL3T1},
+    {ScalabilityMode::kL3T1h, CreateH<ScalabilityStructureL3T1>, kConfigL3T1h},
     {ScalabilityMode::kL3T1_KEY, Create<ScalabilityStructureL3T1Key>,
      kConfigL3T1},
     {ScalabilityMode::kL3T2, Create<ScalabilityStructureL3T2>, kConfigL3T2},
+    {ScalabilityMode::kL3T2h, CreateH<ScalabilityStructureL3T2>, kConfigL3T2h},
     {ScalabilityMode::kL3T2_KEY, Create<ScalabilityStructureL3T2Key>,
      kConfigL3T2},
     {ScalabilityMode::kL3T3, Create<ScalabilityStructureL3T3>, kConfigL3T3},
+    {ScalabilityMode::kL3T3h, CreateH<ScalabilityStructureL3T3>, kConfigL3T3h},
     {ScalabilityMode::kL3T3_KEY, Create<ScalabilityStructureL3T3Key>,
      kConfigL3T3},
     {ScalabilityMode::kS2T1, Create<ScalabilityStructureS2T1>, kConfigS2T1},
diff --git a/pc/peer_connection_factory_unittest.cc b/pc/peer_connection_factory_unittest.cc
index 12078c2..fdbc415 100644
--- a/pc/peer_connection_factory_unittest.cc
+++ b/pc/peer_connection_factory_unittest.cc
@@ -206,15 +206,20 @@
                 webrtc::ScalabilityMode::kL2T1h,
                 webrtc::ScalabilityMode::kL2T1_KEY,
                 webrtc::ScalabilityMode::kL2T2,
+                webrtc::ScalabilityMode::kL2T2h,
                 webrtc::ScalabilityMode::kL2T2_KEY,
                 webrtc::ScalabilityMode::kL2T2_KEY_SHIFT,
                 webrtc::ScalabilityMode::kL2T3,
+                webrtc::ScalabilityMode::kL2T3h,
                 webrtc::ScalabilityMode::kL2T3_KEY,
                 webrtc::ScalabilityMode::kL3T1,
+                webrtc::ScalabilityMode::kL3T1h,
                 webrtc::ScalabilityMode::kL3T1_KEY,
                 webrtc::ScalabilityMode::kL3T2,
+                webrtc::ScalabilityMode::kL3T2h,
                 webrtc::ScalabilityMode::kL3T2_KEY,
                 webrtc::ScalabilityMode::kL3T3,
+                webrtc::ScalabilityMode::kL3T3h,
                 webrtc::ScalabilityMode::kL3T3_KEY,
                 webrtc::ScalabilityMode::kS2T1,
                 webrtc::ScalabilityMode::kS2T2,
diff --git a/pc/test/svc_e2e_tests.cc b/pc/test/svc_e2e_tests.cc
index 607c85d..d33d286 100644
--- a/pc/test/svc_e2e_tests.cc
+++ b/pc/test/svc_e2e_tests.cc
@@ -328,22 +328,22 @@
             SvcTestParameters{kVp9CodecName, "L2T1h", 2, 1},
             SvcTestParameters{kVp9CodecName, "L2T1_KEY", 2, 1},
             SvcTestParameters{kVp9CodecName, "L2T2", 2, 2},
-            // SvcTestParameters{kVp9CodecName, "L2T2h", 2, 2},
+            SvcTestParameters{kVp9CodecName, "L2T2h", 2, 2},
             SvcTestParameters{kVp9CodecName, "L2T2_KEY", 2, 2},
             SvcTestParameters{kVp9CodecName, "L2T2_KEY_SHIFT", 2, 2},
             SvcTestParameters{kVp9CodecName, "L2T3", 2, 3},
-            // SvcTestParameters{kVp9CodecName, "L2T3h", 2, 3},
+            SvcTestParameters{kVp9CodecName, "L2T3h", 2, 3},
             SvcTestParameters{kVp9CodecName, "L2T3_KEY", 2, 3},
             // SvcTestParameters{kVp9CodecName, "L2T3_KEY_SHIFT", 2, 3},
             SvcTestParameters{kVp9CodecName, "L3T1", 3, 1},
-            // SvcTestParameters{kVp9CodecName, "L3T1h", 3, 1},
+            SvcTestParameters{kVp9CodecName, "L3T1h", 3, 1},
             SvcTestParameters{kVp9CodecName, "L3T1_KEY", 3, 1},
             SvcTestParameters{kVp9CodecName, "L3T2", 3, 2},
-            // SvcTestParameters{kVp9CodecName, "L3T2h", 3, 2},
+            SvcTestParameters{kVp9CodecName, "L3T2h", 3, 2},
             SvcTestParameters{kVp9CodecName, "L3T2_KEY", 3, 2},
             // SvcTestParameters{kVp9CodecName, "L3T2_KEY_SHIFT", 3, 2},
             SvcTestParameters{kVp9CodecName, "L3T3", 3, 3},
-            // SvcTestParameters{kVp9CodecName, "L3T3h", 3, 3},
+            SvcTestParameters{kVp9CodecName, "L3T3h", 3, 3},
             SvcTestParameters{kVp9CodecName, "L3T3_KEY", 3, 3},
             // SvcTestParameters{kVp9CodecName, "L3T3_KEY_SHIFT", 3, 3},
             // SvcTestParameters{kVp9CodecName, "S2T1", 2, 1},
@@ -376,22 +376,22 @@
                 SvcTestParameters{kAv1CodecName, "L2T1h", 2, 1},
                 SvcTestParameters{kAv1CodecName, "L2T1_KEY", 2, 1},
                 SvcTestParameters{kAv1CodecName, "L2T2", 2, 2},
-                // SvcTestParameters{kAv1CodecName, "L2T2h", 2, 2},
+                SvcTestParameters{kAv1CodecName, "L2T2h", 2, 2},
                 SvcTestParameters{kAv1CodecName, "L2T2_KEY", 2, 2},
                 SvcTestParameters{kAv1CodecName, "L2T2_KEY_SHIFT", 2, 2},
                 SvcTestParameters{kAv1CodecName, "L2T3", 2, 3},
-                // SvcTestParameters{kAv1CodecName, "L2T3h", 2, 3},
+                SvcTestParameters{kAv1CodecName, "L2T3h", 2, 3},
                 SvcTestParameters{kAv1CodecName, "L2T3_KEY", 2, 3},
                 // SvcTestParameters{kAv1CodecName, "L2T3_KEY_SHIFT", 2, 3},
                 SvcTestParameters{kAv1CodecName, "L3T1", 3, 1},
-                // SvcTestParameters{kAv1CodecName, "L3T1h", 3, 1},
+                SvcTestParameters{kAv1CodecName, "L3T1h", 3, 1},
                 SvcTestParameters{kAv1CodecName, "L3T1_KEY", 3, 1},
                 SvcTestParameters{kAv1CodecName, "L3T2", 3, 2},
-                // SvcTestParameters{kAv1CodecName, "L3T2h", 3, 2},
+                SvcTestParameters{kAv1CodecName, "L3T2h", 3, 2},
                 SvcTestParameters{kAv1CodecName, "L3T2_KEY", 3, 2},
                 // SvcTestParameters{kAv1CodecName, "L3T2_KEY_SHIFT", 3, 2},
                 SvcTestParameters{kAv1CodecName, "L3T3", 3, 3},
-                // SvcTestParameters{kAv1CodecName, "L3T3h", 3, 3},
+                SvcTestParameters{kAv1CodecName, "L3T3h", 3, 3},
                 SvcTestParameters{kAv1CodecName, "L3T3_KEY", 3, 3},
                 // SvcTestParameters{kAv1CodecName, "L3T3_KEY_SHIFT", 3, 3},
                 // SvcTestParameters{kAv1CodecName, "S2T1", 2, 1},
diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc
index 92ac208..c948012 100644
--- a/video/video_send_stream_tests.cc
+++ b/video/video_send_stream_tests.cc
@@ -3387,7 +3387,12 @@
     ::testing::Combine(
         ::testing::ValuesIn<Vp9TestParams>(
             {{"L2T1h", 2, 1, InterLayerPredMode::kOn},
-             {"L2T2_KEY_SHIFT", 2, 2, InterLayerPredMode::kOnKeyPic}}),
+             {"L2T2h", 2, 2, InterLayerPredMode::kOn},
+             {"L2T3h", 2, 3, InterLayerPredMode::kOn},
+             {"L2T2_KEY_SHIFT", 2, 2, InterLayerPredMode::kOnKeyPic},
+             {"L3T1h", 3, 1, InterLayerPredMode::kOn},
+             {"L3T2h", 3, 2, InterLayerPredMode::kOn},
+             {"L3T3h", 3, 3, InterLayerPredMode::kOn}}),
         ::testing::Values(true)),  // use_scalability_mode_identifier
     ParamInfoToStr);
 
@@ -3446,6 +3451,22 @@
       }
     }
 
+    int GetRequiredDivisibility() const {
+      absl::optional<ScalabilityMode> scalability_mode =
+          ScalabilityModeFromString(params_.scalability_mode);
+      EXPECT_TRUE(scalability_mode);
+      absl::optional<ScalableVideoController::StreamLayersConfig> config =
+          ScalabilityStructureConfig(*scalability_mode);
+      EXPECT_TRUE(config);
+
+      int required_divisibility = 1;
+      for (size_t sl_idx = 0; sl_idx < params_.num_spatial_layers; ++sl_idx) {
+        required_divisibility = cricket::LeastCommonMultiple(
+            required_divisibility, config->scaling_factor_den[sl_idx]);
+      }
+      return required_divisibility;
+    }
+
     void ModifyVideoCaptureStartResolution(int* width,
                                            int* height,
                                            int* frame_rate) override {
@@ -3453,6 +3474,10 @@
       expected_height_ = kHeight << (params_.num_spatial_layers - 1);
       *width = expected_width_;
       *height = expected_height_;
+      // Top layer may be adjusted to ensure evenly divided layers.
+      int divisibility = GetRequiredDivisibility();
+      expected_width_ -= (expected_width_ % divisibility);
+      expected_height_ -= (expected_height_ % divisibility);
     }
 
     void InspectHeader(const RTPVideoHeaderVP9& vp9) override {