Add helper to query scalability structure configuration

without creating svc controller for it.

Bug: chromium:1187565
Change-Id: I219f88203e73036bf48bce04527bb8e46ccf1c33
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/231128
Reviewed-by: Johannes Kron <kron@webrtc.org>
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#34968}
diff --git a/modules/video_coding/svc/create_scalability_structure.cc b/modules/video_coding/svc/create_scalability_structure.cc
index 39710d8..8e5c06f 100644
--- a/modules/video_coding/svc/create_scalability_structure.cc
+++ b/modules/video_coding/svc/create_scalability_structure.cc
@@ -27,6 +27,7 @@
   absl::string_view name;
   // Use function pointer to make NamedStructureFactory trivally destructable.
   std::unique_ptr<ScalableVideoController> (*factory)();
+  ScalableVideoController::StreamLayersConfig config;
 };
 
 // Wrap std::make_unique function to have correct return type.
@@ -44,22 +45,90 @@
   return std::make_unique<T>(factor);
 }
 
+constexpr ScalableVideoController::StreamLayersConfig kConfigNone = {
+    /*num_spatial_layers=*/1, /*num_temporal_layers=*/1,
+    /*uses_reference_scaling=*/false};
+
+constexpr ScalableVideoController::StreamLayersConfig kConfigL1T2 = {
+    /*num_spatial_layers=*/1, /*num_temporal_layers=*/2,
+    /*uses_reference_scaling=*/false};
+
+constexpr ScalableVideoController::StreamLayersConfig kConfigL1T3 = {
+    /*num_spatial_layers=*/1, /*num_temporal_layers=*/3,
+    /*uses_reference_scaling=*/false};
+
+constexpr ScalableVideoController::StreamLayersConfig kConfigL2T1 = {
+    /*num_spatial_layers=*/2,
+    /*num_temporal_layers=*/1,
+    /*uses_reference_scaling=*/true,
+    {1, 1},
+    {2, 1}};
+
+constexpr ScalableVideoController::StreamLayersConfig kConfigL2T1h = {
+    /*num_spatial_layers=*/2,
+    /*num_temporal_layers=*/1,
+    /*uses_reference_scaling=*/true,
+    {2, 1},
+    {3, 1}};
+
+constexpr ScalableVideoController::StreamLayersConfig kConfigL2T2 = {
+    /*num_spatial_layers=*/2,
+    /*num_temporal_layers=*/2,
+    /*uses_reference_scaling=*/true,
+    {1, 1},
+    {2, 1}};
+
+constexpr ScalableVideoController::StreamLayersConfig kConfigL2T3 = {
+    /*num_spatial_layers=*/2,
+    /*num_temporal_layers=*/3,
+    /*uses_reference_scaling=*/true,
+    {1, 1},
+    {2, 1}};
+
+constexpr ScalableVideoController::StreamLayersConfig kConfigL3T1 = {
+    /*num_spatial_layers=*/3,
+    /*num_temporal_layers=*/1,
+    /*uses_reference_scaling=*/true,
+    {1, 1, 1},
+    {4, 2, 1}};
+
+constexpr ScalableVideoController::StreamLayersConfig kConfigL3T3 = {
+    /*num_spatial_layers=*/3,
+    /*num_temporal_layers=*/3,
+    /*uses_reference_scaling=*/true,
+    {1, 1, 1},
+    {4, 2, 1}};
+
+constexpr ScalableVideoController::StreamLayersConfig kConfigS2T1 = {
+    /*num_spatial_layers=*/2,
+    /*num_temporal_layers=*/1,
+    /*uses_reference_scaling=*/false,
+    {1, 1},
+    {2, 1}};
+
+constexpr ScalableVideoController::StreamLayersConfig kConfigS3T3 = {
+    /*num_spatial_layers=*/3,
+    /*num_temporal_layers=*/3,
+    /*uses_reference_scaling=*/false,
+    {1, 1, 1},
+    {4, 2, 1}};
+
 constexpr NamedStructureFactory kFactories[] = {
-    {"NONE", Create<ScalableVideoControllerNoLayering>},
-    {"L1T2", Create<ScalabilityStructureL1T2>},
-    {"L1T3", Create<ScalabilityStructureL1T3>},
-    {"L2T1", Create<ScalabilityStructureL2T1>},
-    {"L2T1h", CreateH<ScalabilityStructureL2T1>},
-    {"L2T1_KEY", Create<ScalabilityStructureL2T1Key>},
-    {"L2T2", Create<ScalabilityStructureL2T2>},
-    {"L2T2_KEY", Create<ScalabilityStructureL2T2Key>},
-    {"L2T2_KEY_SHIFT", Create<ScalabilityStructureL2T2KeyShift>},
-    {"L2T3_KEY", Create<ScalabilityStructureL2T3Key>},
-    {"L3T1", Create<ScalabilityStructureL3T1>},
-    {"L3T3", Create<ScalabilityStructureL3T3>},
-    {"L3T3_KEY", Create<ScalabilityStructureL3T3Key>},
-    {"S2T1", Create<ScalabilityStructureS2T1>},
-    {"S3T3", Create<ScalabilityStructureS3T3>},
+    {"NONE", Create<ScalableVideoControllerNoLayering>, kConfigNone},
+    {"L1T2", Create<ScalabilityStructureL1T2>, kConfigL1T2},
+    {"L1T3", Create<ScalabilityStructureL1T3>, kConfigL1T3},
+    {"L2T1", Create<ScalabilityStructureL2T1>, kConfigL2T1},
+    {"L2T1h", CreateH<ScalabilityStructureL2T1>, kConfigL2T1h},
+    {"L2T1_KEY", Create<ScalabilityStructureL2T1Key>, kConfigL2T1},
+    {"L2T2", Create<ScalabilityStructureL2T2>, kConfigL2T2},
+    {"L2T2_KEY", Create<ScalabilityStructureL2T2Key>, kConfigL2T2},
+    {"L2T2_KEY_SHIFT", Create<ScalabilityStructureL2T2KeyShift>, kConfigL2T2},
+    {"L2T3_KEY", Create<ScalabilityStructureL2T3Key>, kConfigL2T3},
+    {"L3T1", Create<ScalabilityStructureL3T1>, kConfigL3T1},
+    {"L3T3", Create<ScalabilityStructureL3T3>, kConfigL3T3},
+    {"L3T3_KEY", Create<ScalabilityStructureL3T3Key>, kConfigL3T3},
+    {"S2T1", Create<ScalabilityStructureS2T1>, kConfigS2T1},
+    {"S3T3", Create<ScalabilityStructureS3T3>, kConfigS3T3},
 };
 
 }  // namespace
@@ -75,4 +144,15 @@
   return nullptr;
 }
 
+absl::optional<ScalableVideoController::StreamLayersConfig>
+ScalabilityStructureConfig(absl::string_view name) {
+  RTC_DCHECK(!name.empty());
+  for (const auto& entry : kFactories) {
+    if (entry.name == name) {
+      return entry.config;
+    }
+  }
+  return absl::nullopt;
+}
+
 }  // namespace webrtc
diff --git a/modules/video_coding/svc/create_scalability_structure.h b/modules/video_coding/svc/create_scalability_structure.h
index 9a14221..fde0344 100644
--- a/modules/video_coding/svc/create_scalability_structure.h
+++ b/modules/video_coding/svc/create_scalability_structure.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
 #include "modules/video_coding/svc/scalable_video_controller.h"
 
 namespace webrtc {
@@ -24,6 +25,11 @@
 std::unique_ptr<ScalableVideoController> CreateScalabilityStructure(
     absl::string_view name);
 
+// Returns descrption of the scalability structure identified by 'name',
+// Return nullopt for unknown name.
+absl::optional<ScalableVideoController::StreamLayersConfig>
+ScalabilityStructureConfig(absl::string_view name);
+
 }  // namespace webrtc
 
 #endif  // MODULES_VIDEO_CODING_SVC_CREATE_SCALABILITY_STRUCTURE_H_
diff --git a/modules/video_coding/svc/scalability_structure_full_svc.cc b/modules/video_coding/svc/scalability_structure_full_svc.cc
index b89de99..9f66a5a 100644
--- a/modules/video_coding/svc/scalability_structure_full_svc.cc
+++ b/modules/video_coding/svc/scalability_structure_full_svc.cc
@@ -52,6 +52,7 @@
     result.scaling_factor_den[sid - 1] =
         resolution_factor_.den * result.scaling_factor_den[sid];
   }
+  result.uses_reference_scaling = num_spatial_layers_ > 1;
   return result;
 }
 
diff --git a/modules/video_coding/svc/scalability_structure_key_svc.cc b/modules/video_coding/svc/scalability_structure_key_svc.cc
index 1cee80e..6cd96a6 100644
--- a/modules/video_coding/svc/scalability_structure_key_svc.cc
+++ b/modules/video_coding/svc/scalability_structure_key_svc.cc
@@ -51,6 +51,7 @@
     result.scaling_factor_num[sid - 1] = 1;
     result.scaling_factor_den[sid - 1] = 2 * result.scaling_factor_den[sid];
   }
+  result.uses_reference_scaling = true;
   return result;
 }
 
diff --git a/modules/video_coding/svc/scalability_structure_l2t2_key_shift.cc b/modules/video_coding/svc/scalability_structure_l2t2_key_shift.cc
index c53ff8f..4d15942 100644
--- a/modules/video_coding/svc/scalability_structure_l2t2_key_shift.cc
+++ b/modules/video_coding/svc/scalability_structure_l2t2_key_shift.cc
@@ -51,6 +51,7 @@
   result.num_temporal_layers = 2;
   result.scaling_factor_num[0] = 1;
   result.scaling_factor_den[0] = 2;
+  result.uses_reference_scaling = true;
   return result;
 }
 
diff --git a/modules/video_coding/svc/scalability_structure_simulcast.cc b/modules/video_coding/svc/scalability_structure_simulcast.cc
index c236066..0db91cc 100644
--- a/modules/video_coding/svc/scalability_structure_simulcast.cc
+++ b/modules/video_coding/svc/scalability_structure_simulcast.cc
@@ -65,6 +65,7 @@
     result.scaling_factor_num[sid - 1] = 1;
     result.scaling_factor_den[sid - 1] = 2 * result.scaling_factor_den[sid];
   }
+  result.uses_reference_scaling = false;
   return result;
 }
 
diff --git a/modules/video_coding/svc/scalability_structure_unittest.cc b/modules/video_coding/svc/scalability_structure_unittest.cc
index 8bd933b..9368f57 100644
--- a/modules/video_coding/svc/scalability_structure_unittest.cc
+++ b/modules/video_coding/svc/scalability_structure_unittest.cc
@@ -16,6 +16,7 @@
 #include <string>
 
 #include "absl/types/optional.h"
+#include "api/array_view.h"
 #include "api/transport/rtp/dependency_descriptor.h"
 #include "modules/video_coding/svc/create_scalability_structure.h"
 #include "modules/video_coding/svc/scalability_structure_test_helpers.h"
@@ -29,12 +30,14 @@
 using ::testing::AllOf;
 using ::testing::Contains;
 using ::testing::Each;
+using ::testing::ElementsAreArray;
 using ::testing::Field;
 using ::testing::Ge;
 using ::testing::IsEmpty;
 using ::testing::Le;
 using ::testing::Lt;
 using ::testing::Not;
+using ::testing::NotNull;
 using ::testing::SizeIs;
 using ::testing::TestWithParam;
 using ::testing::Values;
@@ -51,6 +54,28 @@
 class ScalabilityStructureTest : public TestWithParam<SvcTestParam> {};
 
 TEST_P(ScalabilityStructureTest,
+       StaticConfigMatchesConfigReturnedByController) {
+  std::unique_ptr<ScalableVideoController> controller =
+      CreateScalabilityStructure(GetParam().name);
+  absl::optional<ScalableVideoController::StreamLayersConfig> static_config =
+      ScalabilityStructureConfig(GetParam().name);
+  ASSERT_THAT(controller, NotNull());
+  ASSERT_NE(static_config, absl::nullopt);
+  ScalableVideoController::StreamLayersConfig config =
+      controller->StreamConfig();
+  EXPECT_EQ(config.num_spatial_layers, static_config->num_spatial_layers);
+  EXPECT_EQ(config.num_temporal_layers, static_config->num_temporal_layers);
+  EXPECT_THAT(
+      rtc::MakeArrayView(config.scaling_factor_num, config.num_spatial_layers),
+      ElementsAreArray(static_config->scaling_factor_num,
+                       static_config->num_spatial_layers));
+  EXPECT_THAT(
+      rtc::MakeArrayView(config.scaling_factor_den, config.num_spatial_layers),
+      ElementsAreArray(static_config->scaling_factor_den,
+                       static_config->num_spatial_layers));
+}
+
+TEST_P(ScalabilityStructureTest,
        NumberOfDecodeTargetsAndChainsAreInRangeAndConsistent) {
   FrameDependencyStructure structure =
       CreateScalabilityStructure(GetParam().name)->DependencyStructure();
diff --git a/modules/video_coding/svc/scalable_video_controller.h b/modules/video_coding/svc/scalable_video_controller.h
index d2d8486..c736265 100644
--- a/modules/video_coding/svc/scalable_video_controller.h
+++ b/modules/video_coding/svc/scalable_video_controller.h
@@ -27,6 +27,8 @@
   struct StreamLayersConfig {
     int num_spatial_layers = 1;
     int num_temporal_layers = 1;
+    // Indicates if frames can reference frames of a different resolution.
+    bool uses_reference_scaling = true;
     // Spatial layers scaling. Frames with spatial_id = i expected to be encoded
     // with original_resolution * scaling_factor_num[i] / scaling_factor_den[i].
     int scaling_factor_num[DependencyDescriptor::kMaxSpatialIds] = {1, 1, 1, 1};
diff --git a/modules/video_coding/svc/scalable_video_controller_no_layering.cc b/modules/video_coding/svc/scalable_video_controller_no_layering.cc
index 3934e57..a9d530d 100644
--- a/modules/video_coding/svc/scalable_video_controller_no_layering.cc
+++ b/modules/video_coding/svc/scalable_video_controller_no_layering.cc
@@ -25,6 +25,7 @@
   StreamLayersConfig result;
   result.num_spatial_layers = 1;
   result.num_temporal_layers = 1;
+  result.uses_reference_scaling = false;
   return result;
 }