Add factory to create scalability structures by name

according to webrtc-svc spec draft

Bug: webrtc:11404
Change-Id: I318b8a1a5c5389f6e5d15c3dd7d93041459e37f9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/178603
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31731}
diff --git a/modules/video_coding/codecs/av1/BUILD.gn b/modules/video_coding/codecs/av1/BUILD.gn
index edaa30a..b6d5567 100644
--- a/modules/video_coding/codecs/av1/BUILD.gn
+++ b/modules/video_coding/codecs/av1/BUILD.gn
@@ -54,6 +54,8 @@
 
 rtc_source_set("scalability_structures") {
   sources = [
+    "create_scalability_structure.cc",
+    "create_scalability_structure.h",
     "scalability_structure_l1t2.cc",
     "scalability_structure_l1t2.h",
     "scalability_structure_l1t3.cc",
@@ -86,6 +88,7 @@
   ]
   absl_deps = [
     "//third_party/abseil-cpp/absl/base:core_headers",
+    "//third_party/abseil-cpp/absl/strings",
     "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
diff --git a/modules/video_coding/codecs/av1/create_scalability_structure.cc b/modules/video_coding/codecs/av1/create_scalability_structure.cc
new file mode 100644
index 0000000..1737554
--- /dev/null
+++ b/modules/video_coding/codecs/av1/create_scalability_structure.cc
@@ -0,0 +1,73 @@
+/*
+ *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/video_coding/codecs/av1/create_scalability_structure.h"
+
+#include <memory>
+
+#include "absl/strings/string_view.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_l1t2.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_l1t3.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_l2t1.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_l2t1_key.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_l2t1h.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_l2t2.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_l2t2_key.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_l3t1.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_l3t3.h"
+#include "modules/video_coding/codecs/av1/scalability_structure_s2t1.h"
+#include "modules/video_coding/codecs/av1/scalable_video_controller.h"
+#include "modules/video_coding/codecs/av1/scalable_video_controller_no_layering.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+struct NamedStructureFactory {
+  absl::string_view name;
+  // Use function pointer to make NamedStructureFactory trivally destructable.
+  std::unique_ptr<ScalableVideoController> (*factory)();
+};
+
+// Wrap std::make_unique function to have correct return type.
+template <typename T>
+std::unique_ptr<ScalableVideoController> Create() {
+  return std::make_unique<T>();
+}
+
+constexpr NamedStructureFactory kFactories[] = {
+    {"NONE", Create<ScalableVideoControllerNoLayering>},
+    {"L1T2", Create<ScalabilityStructureL1T2>},
+    {"L1T3", Create<ScalabilityStructureL1T3>},
+    {"L2T1", Create<ScalabilityStructureL2T1>},
+    {"L2T1h", Create<ScalabilityStructureL2T1h>},
+    {"L2T1_KEY", Create<ScalabilityStructureL2T1Key>},
+    {"L2T2", Create<ScalabilityStructureL2T2>},
+    {"L2T2_KEY", Create<ScalabilityStructureL2T2Key>},
+    {"L2T2_KEY_SHIFT", Create<ScalabilityStructureL2T2KeyShift>},
+    {"L3T1", Create<ScalabilityStructureL3T1>},
+    {"L3T3", Create<ScalabilityStructureL3T3>},
+    {"S2T1", Create<ScalabilityStructureS2T1>},
+};
+
+}  // namespace
+
+std::unique_ptr<ScalableVideoController> CreateScalabilityStructure(
+    absl::string_view name) {
+  RTC_DCHECK(!name.empty());
+  for (const auto& entry : kFactories) {
+    if (entry.name == name) {
+      return entry.factory();
+    }
+  }
+  return nullptr;
+}
+
+}  // namespace webrtc
diff --git a/modules/video_coding/codecs/av1/create_scalability_structure.h b/modules/video_coding/codecs/av1/create_scalability_structure.h
new file mode 100644
index 0000000..fe4a283
--- /dev/null
+++ b/modules/video_coding/codecs/av1/create_scalability_structure.h
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef MODULES_VIDEO_CODING_CODECS_AV1_CREATE_SCALABILITY_STRUCTURE_H_
+#define MODULES_VIDEO_CODING_CODECS_AV1_CREATE_SCALABILITY_STRUCTURE_H_
+
+#include <memory>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "modules/video_coding/codecs/av1/scalable_video_controller.h"
+
+namespace webrtc {
+
+// Creates a structure by name according to
+// https://w3c.github.io/webrtc-svc/#scalabilitymodes*
+// Returns nullptr for unknown name.
+std::unique_ptr<ScalableVideoController> CreateScalabilityStructure(
+    absl::string_view name);
+
+}  // namespace webrtc
+
+#endif  // MODULES_VIDEO_CODING_CODECS_AV1_CREATE_SCALABILITY_STRUCTURE_H_
diff --git a/modules/video_coding/codecs/av1/libaom_av1_unittest.cc b/modules/video_coding/codecs/av1/libaom_av1_unittest.cc
index afd54e1..970d43c 100644
--- a/modules/video_coding/codecs/av1/libaom_av1_unittest.cc
+++ b/modules/video_coding/codecs/av1/libaom_av1_unittest.cc
@@ -22,19 +22,9 @@
 #include "api/units/time_delta.h"
 #include "api/video_codecs/video_codec.h"
 #include "api/video_codecs/video_encoder.h"
+#include "modules/video_coding/codecs/av1/create_scalability_structure.h"
 #include "modules/video_coding/codecs/av1/libaom_av1_decoder.h"
 #include "modules/video_coding/codecs/av1/libaom_av1_encoder.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l1t2.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l1t3.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t1.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t1_key.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t1h.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t2.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t2_key.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l3t1.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l3t3.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_s2t1.h"
 #include "modules/video_coding/codecs/av1/scalable_video_controller.h"
 #include "modules/video_coding/codecs/av1/scalable_video_controller_no_layering.h"
 #include "modules/video_coding/codecs/test/encoded_video_frame_producer.h"
@@ -181,7 +171,7 @@
 };
 
 struct SvcTestParam {
-  std::function<std::unique_ptr<ScalableVideoController>()> svc_factory;
+  std::string name;
   int num_frames_to_generate;
   std::map<LayerId, DataRate> configured_bitrates;
 };
@@ -190,7 +180,7 @@
 
 TEST_P(LibaomAv1SvcTest, EncodeAndDecodeAllDecodeTargets) {
   std::unique_ptr<ScalableVideoController> svc_controller =
-      GetParam().svc_factory();
+      CreateScalabilityStructure(GetParam().name);
   size_t num_decode_targets =
       svc_controller->DependencyStructure().num_decode_targets;
 
@@ -262,7 +252,7 @@
   }
 
   std::unique_ptr<VideoEncoder> encoder =
-      CreateLibaomAv1Encoder(param.svc_factory());
+      CreateLibaomAv1Encoder(CreateScalabilityStructure(param.name));
   ASSERT_TRUE(encoder);
   VideoCodec codec_settings = DefaultCodecSettings();
   codec_settings.maxBitrate = allocation.get_sum_kbps();
@@ -304,44 +294,39 @@
 INSTANTIATE_TEST_SUITE_P(
     Svc,
     LibaomAv1SvcTest,
-    Values(SvcTestParam{std::make_unique<ScalableVideoControllerNoLayering>,
-                        /*num_frames_to_generate=*/4},
-           SvcTestParam{std::make_unique<ScalabilityStructureL1T2>,
+    Values(SvcTestParam{"NONE", /*num_frames_to_generate=*/4},
+           SvcTestParam{"L1T2",
                         /*num_frames_to_generate=*/4,
                         /*configured_bitrates=*/
                         {{{0, 0}, DataRate::KilobitsPerSec(60)},
                          {{0, 1}, DataRate::KilobitsPerSec(40)}}},
-           SvcTestParam{std::make_unique<ScalabilityStructureL1T3>,
-                        /*num_frames_to_generate=*/8},
-           SvcTestParam{std::make_unique<ScalabilityStructureL2T1>,
+           SvcTestParam{"L1T3", /*num_frames_to_generate=*/8},
+           SvcTestParam{"L2T1",
                         /*num_frames_to_generate=*/3,
                         /*configured_bitrates=*/
                         {{{0, 0}, DataRate::KilobitsPerSec(30)},
                          {{1, 0}, DataRate::KilobitsPerSec(70)}}},
-           SvcTestParam{std::make_unique<ScalabilityStructureL2T1h>,
+           SvcTestParam{"L2T1h",
                         /*num_frames_to_generate=*/3,
                         /*configured_bitrates=*/
                         {{{0, 0}, DataRate::KilobitsPerSec(30)},
                          {{1, 0}, DataRate::KilobitsPerSec(70)}}},
-           SvcTestParam{std::make_unique<ScalabilityStructureL2T1Key>,
-                        /*num_frames_to_generate=*/3},
-           SvcTestParam{std::make_unique<ScalabilityStructureL3T1>,
-                        /*num_frames_to_generate=*/3},
-           SvcTestParam{std::make_unique<ScalabilityStructureL3T3>,
-                        /*num_frames_to_generate=*/8},
-           SvcTestParam{std::make_unique<ScalabilityStructureS2T1>,
-                        /*num_frames_to_generate=*/3},
-           SvcTestParam{std::make_unique<ScalabilityStructureL2T2>,
-                        /*num_frames_to_generate=*/4},
-           SvcTestParam{std::make_unique<ScalabilityStructureL2T2Key>,
-                        /*num_frames_to_generate=*/4},
-           SvcTestParam{std::make_unique<ScalabilityStructureL2T2KeyShift>,
+           SvcTestParam{"L2T1_KEY", /*num_frames_to_generate=*/3},
+           SvcTestParam{"L3T1", /*num_frames_to_generate=*/3},
+           SvcTestParam{"L3T3", /*num_frames_to_generate=*/8},
+           SvcTestParam{"S2T1", /*num_frames_to_generate=*/3},
+           SvcTestParam{"L2T2", /*num_frames_to_generate=*/4},
+           SvcTestParam{"L2T2_KEY", /*num_frames_to_generate=*/4},
+           SvcTestParam{"L2T2_KEY_SHIFT",
                         /*num_frames_to_generate=*/4,
                         /*configured_bitrates=*/
                         {{{0, 0}, DataRate::KilobitsPerSec(70)},
                          {{0, 1}, DataRate::KilobitsPerSec(30)},
                          {{1, 0}, DataRate::KilobitsPerSec(140)},
-                         {{1, 1}, DataRate::KilobitsPerSec(80)}}}));
+                         {{1, 1}, DataRate::KilobitsPerSec(80)}}}),
+    [](const testing::TestParamInfo<SvcTestParam>& info) {
+      return info.param.name;
+    });
 
 }  // namespace
 }  // namespace webrtc
diff --git a/modules/video_coding/codecs/av1/scalability_structure_unittest.cc b/modules/video_coding/codecs/av1/scalability_structure_unittest.cc
index d2a0516..77b34c3 100644
--- a/modules/video_coding/codecs/av1/scalability_structure_unittest.cc
+++ b/modules/video_coding/codecs/av1/scalability_structure_unittest.cc
@@ -11,7 +11,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <functional>
 #include <memory>
 #include <ostream>
 #include <string>
@@ -20,16 +19,7 @@
 #include "api/transport/rtp/dependency_descriptor.h"
 #include "api/video/video_frame_type.h"
 #include "modules/video_coding/chain_diff_calculator.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l1t2.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l1t3.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t1.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t1_key.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t2.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t2_key.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l3t1.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_l3t3.h"
-#include "modules/video_coding/codecs/av1/scalability_structure_s2t1.h"
+#include "modules/video_coding/codecs/av1/create_scalability_structure.h"
 #include "modules/video_coding/codecs/av1/scalable_video_controller.h"
 #include "modules/video_coding/frame_dependencies_calculator.h"
 #include "test/gmock.h"
@@ -57,7 +47,6 @@
   }
 
   std::string name;
-  std::function<std::unique_ptr<ScalableVideoController>()> svc_factory;
   int num_temporal_units;
 };
 
@@ -69,7 +58,7 @@
     FrameDependenciesCalculator frame_deps_calculator;
     ChainDiffCalculator chain_diff_calculator;
     std::unique_ptr<ScalableVideoController> structure_controller =
-        GetParam().svc_factory();
+        CreateScalabilityStructure(GetParam().name);
     FrameDependencyStructure structure =
         structure_controller->DependencyStructure();
     for (int i = 0; i < GetParam().num_temporal_units; ++i) {
@@ -104,7 +93,7 @@
 TEST_P(ScalabilityStructureTest,
        NumberOfDecodeTargetsAndChainsAreInRangeAndConsistent) {
   FrameDependencyStructure structure =
-      GetParam().svc_factory()->DependencyStructure();
+      CreateScalabilityStructure(GetParam().name)->DependencyStructure();
   EXPECT_GT(structure.num_decode_targets, 0);
   EXPECT_LE(structure.num_decode_targets,
             DependencyDescriptor::kMaxDecodeTargets);
@@ -123,7 +112,7 @@
 
 TEST_P(ScalabilityStructureTest, TemplatesAreSortedByLayerId) {
   FrameDependencyStructure structure =
-      GetParam().svc_factory()->DependencyStructure();
+      CreateScalabilityStructure(GetParam().name)->DependencyStructure();
   ASSERT_THAT(structure.templates, Not(IsEmpty()));
   const auto& first_templates = structure.templates.front();
   EXPECT_EQ(first_templates.spatial_id, 0);
@@ -154,7 +143,7 @@
 
 TEST_P(ScalabilityStructureTest, TemplatesMatchNumberOfDecodeTargetsAndChains) {
   FrameDependencyStructure structure =
-      GetParam().svc_factory()->DependencyStructure();
+      CreateScalabilityStructure(GetParam().name)->DependencyStructure();
   EXPECT_THAT(
       structure.templates,
       Each(AllOf(Field(&FrameDependencyTemplate::decode_target_indications,
@@ -165,7 +154,7 @@
 
 TEST_P(ScalabilityStructureTest, FrameInfoMatchesFrameDependencyStructure) {
   FrameDependencyStructure structure =
-      GetParam().svc_factory()->DependencyStructure();
+      CreateScalabilityStructure(GetParam().name)->DependencyStructure();
   std::vector<GenericFrameInfo> frame_infos = GenerateAllFrames();
   for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
     const auto& frame = frame_infos[frame_id];
@@ -181,7 +170,7 @@
 
 TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) {
   FrameDependencyStructure structure =
-      GetParam().svc_factory()->DependencyStructure();
+      CreateScalabilityStructure(GetParam().name)->DependencyStructure();
   std::vector<GenericFrameInfo> frame_infos = GenerateAllFrames();
   for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
     EXPECT_THAT(structure.templates, Contains(frame_infos[frame_id]))
@@ -210,7 +199,7 @@
   std::vector<GenericFrameInfo> frame_infos = GenerateAllFrames();
   int64_t num_frames = frame_infos.size();
   FrameDependencyStructure structure =
-      GetParam().svc_factory()->DependencyStructure();
+      CreateScalabilityStructure(GetParam().name)->DependencyStructure();
 
   for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
     for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
@@ -237,7 +226,7 @@
 
 TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) {
   FrameDependencyStructure structure =
-      GetParam().svc_factory()->DependencyStructure();
+      CreateScalabilityStructure(GetParam().name)->DependencyStructure();
   std::vector<GenericFrameInfo> frame_infos = GenerateAllFrames();
   int64_t num_frames = frame_infos.size();
   std::vector<std::set<int64_t>> full_deps(num_frames);
@@ -288,29 +277,16 @@
 INSTANTIATE_TEST_SUITE_P(
     Svc,
     ScalabilityStructureTest,
-    Values(SvcTestParam{"L1T2", std::make_unique<ScalabilityStructureL1T2>,
-                        /*num_temporal_units=*/4},
-           SvcTestParam{"L1T3", std::make_unique<ScalabilityStructureL1T3>,
-                        /*num_temporal_units=*/8},
-           SvcTestParam{"L2T1", std::make_unique<ScalabilityStructureL2T1>,
-                        /*num_temporal_units=*/3},
-           SvcTestParam{"L2T1Key",
-                        std::make_unique<ScalabilityStructureL2T1Key>,
-                        /*num_temporal_units=*/3},
-           SvcTestParam{"L3T1", std::make_unique<ScalabilityStructureL3T1>,
-                        /*num_temporal_units=*/3},
-           SvcTestParam{"L3T3", std::make_unique<ScalabilityStructureL3T3>,
-                        /*num_temporal_units=*/8},
-           SvcTestParam{"S2T1", std::make_unique<ScalabilityStructureS2T1>,
-                        /*num_temporal_units=*/3},
-           SvcTestParam{"L2T2", std::make_unique<ScalabilityStructureL2T2>,
-                        /*num_temporal_units=*/4},
-           SvcTestParam{"L2T2Key",
-                        std::make_unique<ScalabilityStructureL2T2Key>,
-                        /*num_temporal_units=*/4},
-           SvcTestParam{"L2T2KeyShift",
-                        std::make_unique<ScalabilityStructureL2T2KeyShift>,
-                        /*num_temporal_units=*/4}),
+    Values(SvcTestParam{"L1T2", /*num_temporal_units=*/4},
+           SvcTestParam{"L1T3", /*num_temporal_units=*/8},
+           SvcTestParam{"L2T1", /*num_temporal_units=*/3},
+           SvcTestParam{"L2T1_KEY", /*num_temporal_units=*/3},
+           SvcTestParam{"L3T1", /*num_temporal_units=*/3},
+           SvcTestParam{"L3T3", /*num_temporal_units=*/8},
+           SvcTestParam{"S2T1", /*num_temporal_units=*/3},
+           SvcTestParam{"L2T2", /*num_temporal_units=*/4},
+           SvcTestParam{"L2T2_KEY", /*num_temporal_units=*/4},
+           SvcTestParam{"L2T2_KEY_SHIFT", /*num_temporal_units=*/4}),
     [](const testing::TestParamInfo<SvcTestParam>& info) {
       return info.param.name;
     });