New enum ScalabilityMode.

Used instead of string representation in lower-levels of encoder configuration, to avoid string comparisons (with risk of misspelling) in lots of places.

Bug: webrtc:11607
Change-Id: I4d51c2265aac297c29976d2aa601d8ffb33b7326
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/259870
Commit-Queue: Niels Moller <nisse@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36706}
This commit is contained in:
Niels Möller
2022-04-29 11:03:13 +02:00
committed by WebRTC LUCI CQ
parent cbf07f70e2
commit 79d566b0cf
33 changed files with 397 additions and 112 deletions

View File

@ -8,6 +8,21 @@
import("../../../webrtc.gni")
rtc_source_set("scalability_mode_util") {
sources = [
"scalability_mode_util.cc",
"scalability_mode_util.h",
]
deps = [
"../../../api/video_codecs:scalability_mode",
"../../../rtc_base:checks",
]
absl_deps = [
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
]
}
rtc_source_set("scalable_video_controller") {
sources = [
"scalable_video_controller.h",
@ -43,6 +58,7 @@ rtc_source_set("scalability_structures") {
":scalable_video_controller",
"../../../api/transport/rtp:dependency_descriptor",
"../../../api/video:video_bitrate_allocation",
"../../../api/video_codecs:scalability_mode",
"../../../common_video/generic_frame_descriptor",
"../../../rtc_base:checks",
"../../../rtc_base:logging",
@ -75,6 +91,7 @@ if (rtc_include_tests) {
rtc_source_set("scalability_structure_tests") {
testonly = true
sources = [
"scalability_mode_util_unittest.cc",
"scalability_structure_full_svc_unittest.cc",
"scalability_structure_key_svc_unittest.cc",
"scalability_structure_l2t2_key_shift_unittest.cc",
@ -83,6 +100,7 @@ if (rtc_include_tests) {
"scalability_structure_unittest.cc",
]
deps = [
":scalability_mode_util",
":scalability_structures",
":scalable_video_controller",
"..:chain_diff_calculator",
@ -91,10 +109,14 @@ if (rtc_include_tests) {
"../../../api/transport/rtp:dependency_descriptor",
"../../../api/video:video_bitrate_allocation",
"../../../api/video:video_frame_type",
"../../../api/video_codecs:scalability_mode",
"../../../common_video/generic_frame_descriptor",
"../../../test:test_support",
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
absl_deps = [
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
]
}
rtc_source_set("svc_rate_allocator_tests") {

View File

@ -11,7 +11,7 @@
#include <memory>
#include "absl/strings/string_view.h"
#include "api/video_codecs/scalability_mode.h"
#include "modules/video_coding/svc/scalability_structure_full_svc.h"
#include "modules/video_coding/svc/scalability_structure_key_svc.h"
#include "modules/video_coding/svc/scalability_structure_l2t2_key_shift.h"
@ -24,7 +24,7 @@ namespace webrtc {
namespace {
struct NamedStructureFactory {
absl::string_view name;
ScalabilityMode name;
// Use function pointer to make NamedStructureFactory trivally destructable.
std::unique_ptr<ScalableVideoController> (*factory)();
ScalableVideoController::StreamLayersConfig config;
@ -114,28 +114,33 @@ constexpr ScalableVideoController::StreamLayersConfig kConfigS3T3 = {
{4, 2, 1}};
constexpr NamedStructureFactory kFactories[] = {
{"L1T1", Create<ScalableVideoControllerNoLayering>, kConfigL1T1},
{"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},
{ScalabilityMode::kL1T1, Create<ScalableVideoControllerNoLayering>,
kConfigL1T1},
{ScalabilityMode::kL1T2, Create<ScalabilityStructureL1T2>, kConfigL1T2},
{ScalabilityMode::kL1T3, Create<ScalabilityStructureL1T3>, kConfigL1T3},
{ScalabilityMode::kL2T1, Create<ScalabilityStructureL2T1>, kConfigL2T1},
{ScalabilityMode::kL2T1h, CreateH<ScalabilityStructureL2T1>, kConfigL2T1h},
{ScalabilityMode::kL2T1_KEY, Create<ScalabilityStructureL2T1Key>,
kConfigL2T1},
{ScalabilityMode::kL2T2, Create<ScalabilityStructureL2T2>, kConfigL2T2},
{ScalabilityMode::kL2T2_KEY, Create<ScalabilityStructureL2T2Key>,
kConfigL2T2},
{ScalabilityMode::kL2T2_KEY_SHIFT, Create<ScalabilityStructureL2T2KeyShift>,
kConfigL2T2},
{ScalabilityMode::kL2T3_KEY, Create<ScalabilityStructureL2T3Key>,
kConfigL2T3},
{ScalabilityMode::kL3T1, Create<ScalabilityStructureL3T1>, kConfigL3T1},
{ScalabilityMode::kL3T3, Create<ScalabilityStructureL3T3>, kConfigL3T3},
{ScalabilityMode::kL3T3_KEY, Create<ScalabilityStructureL3T3Key>,
kConfigL3T3},
{ScalabilityMode::kS2T1, Create<ScalabilityStructureS2T1>, kConfigS2T1},
{ScalabilityMode::kS3T3, Create<ScalabilityStructureS3T3>, kConfigS3T3},
};
} // namespace
std::unique_ptr<ScalableVideoController> CreateScalabilityStructure(
absl::string_view name) {
RTC_DCHECK(!name.empty());
ScalabilityMode name) {
for (const auto& entry : kFactories) {
if (entry.name == name) {
return entry.factory();
@ -145,8 +150,7 @@ std::unique_ptr<ScalableVideoController> CreateScalabilityStructure(
}
absl::optional<ScalableVideoController::StreamLayersConfig>
ScalabilityStructureConfig(absl::string_view name) {
RTC_DCHECK(!name.empty());
ScalabilityStructureConfig(ScalabilityMode name) {
for (const auto& entry : kFactories) {
if (entry.name == name) {
return entry.config;

View File

@ -13,8 +13,8 @@
#include <memory>
#include <vector>
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "api/video_codecs/scalability_mode.h"
#include "modules/video_coding/svc/scalable_video_controller.h"
namespace webrtc {
@ -23,12 +23,12 @@ namespace webrtc {
// https://w3c.github.io/webrtc-svc/#scalabilitymodes*
// Returns nullptr for unknown name.
std::unique_ptr<ScalableVideoController> CreateScalabilityStructure(
absl::string_view name);
ScalabilityMode name);
// Returns descrption of the scalability structure identified by 'name',
// Returns description of the scalability structure identified by 'name',
// Return nullopt for unknown name.
absl::optional<ScalableVideoController::StreamLayersConfig>
ScalabilityStructureConfig(absl::string_view name);
ScalabilityStructureConfig(ScalabilityMode name);
} // namespace webrtc

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2022 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/svc/scalability_mode_util.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "api/video_codecs/scalability_mode.h"
#include "rtc_base/checks.h"
namespace webrtc {
absl::optional<ScalabilityMode> ScalabilityModeFromString(
absl::string_view mode_string) {
if (mode_string == "L1T1")
return ScalabilityMode::kL1T1;
if (mode_string == "L1T2")
return ScalabilityMode::kL1T2;
if (mode_string == "L1T3")
return ScalabilityMode::kL1T3;
if (mode_string == "L2T1")
return ScalabilityMode::kL2T1;
if (mode_string == "L2T1h")
return ScalabilityMode::kL2T1h;
if (mode_string == "L2T1_KEY")
return ScalabilityMode::kL2T1_KEY;
if (mode_string == "L2T2")
return ScalabilityMode::kL2T2;
if (mode_string == "L2T2_KEY")
return ScalabilityMode::kL2T2_KEY;
if (mode_string == "L2T2_KEY_SHIFT")
return ScalabilityMode::kL2T2_KEY_SHIFT;
if (mode_string == "L2T3_KEY")
return ScalabilityMode::kL2T3_KEY;
if (mode_string == "L3T1")
return ScalabilityMode::kL3T1;
if (mode_string == "L3T3")
return ScalabilityMode::kL3T3;
if (mode_string == "L3T3_KEY")
return ScalabilityMode::kL3T3_KEY;
if (mode_string == "S2T1")
return ScalabilityMode::kS2T1;
if (mode_string == "S3T3")
return ScalabilityMode::kS3T3;
return absl::nullopt;
}
absl::string_view ScalabilityModeToString(ScalabilityMode scalability_mode) {
switch (scalability_mode) {
case ScalabilityMode::kL1T1:
return "L1T1";
case ScalabilityMode::kL1T2:
return "L1T2";
case ScalabilityMode::kL1T3:
return "L1T3";
case ScalabilityMode::kL2T1:
return "L2T1";
case ScalabilityMode::kL2T1h:
return "L2T1h";
case ScalabilityMode::kL2T1_KEY:
return "L2T1_KEY";
case ScalabilityMode::kL2T2:
return "L2T2";
case ScalabilityMode::kL2T2_KEY:
return "L2T2_KEY";
case ScalabilityMode::kL2T2_KEY_SHIFT:
return "L2T2_KEY_SHIFT";
case ScalabilityMode::kL2T3_KEY:
return "L2T3_KEY";
case ScalabilityMode::kL3T1:
return "L3T1";
case ScalabilityMode::kL3T3:
return "L3T3";
case ScalabilityMode::kL3T3_KEY:
return "L3T3_KEY";
case ScalabilityMode::kS2T1:
return "S2T1";
case ScalabilityMode::kS3T3:
return "S3T3";
}
RTC_CHECK_NOTREACHED();
}
} // namespace webrtc

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2022 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_SVC_SCALABILITY_MODE_UTIL_H_
#define MODULES_VIDEO_CODING_SVC_SCALABILITY_MODE_UTIL_H_
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "api/video_codecs/scalability_mode.h"
namespace webrtc {
absl::optional<ScalabilityMode> ScalabilityModeFromString(
absl::string_view scalability_mode_string);
absl::string_view ScalabilityModeToString(ScalabilityMode scalability_mode);
} // namespace webrtc
#endif // MODULES_VIDEO_CODING_SVC_SCALABILITY_MODE_UTIL_H_

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2022 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/svc/scalability_mode_util.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "api/video_codecs/scalability_mode.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
TEST(ScalabilityModeUtil, ConvertsL1T2) {
EXPECT_EQ(ScalabilityModeFromString("L1T2"), ScalabilityMode::kL1T2);
EXPECT_EQ(ScalabilityModeToString(ScalabilityMode::kL1T2), "L1T2");
}
TEST(ScalabilityModeUtil, RejectsUnknownString) {
EXPECT_EQ(ScalabilityModeFromString(""), absl::nullopt);
EXPECT_EQ(ScalabilityModeFromString("not-a-mode"), absl::nullopt);
}
// Check roundtrip conversion of all enum values.
TEST(ScalabilityModeUtil, ConvertsAllToAndFromString) {
const ScalabilityMode kLastEnum = ScalabilityMode::kS3T3;
for (int numerical_enum = 0; numerical_enum <= static_cast<int>(kLastEnum);
numerical_enum++) {
ScalabilityMode scalability_mode =
static_cast<ScalabilityMode>(numerical_enum);
absl::string_view scalability_mode_string =
ScalabilityModeToString(scalability_mode);
EXPECT_FALSE(scalability_mode_string.empty());
EXPECT_EQ(ScalabilityModeFromString(scalability_mode_string),
scalability_mode);
}
}
} // namespace
} // namespace webrtc

View File

@ -19,6 +19,7 @@
#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_mode_util.h"
#include "modules/video_coding/svc/scalability_structure_test_helpers.h"
#include "modules/video_coding/svc/scalable_video_controller.h"
#include "test/gmock.h"
@ -47,6 +48,13 @@ struct SvcTestParam {
return os << param.name;
}
ScalabilityMode GetScalabilityMode() const {
absl::optional<ScalabilityMode> scalability_mode =
ScalabilityModeFromString(name);
RTC_CHECK(scalability_mode.has_value());
return *scalability_mode;
}
std::string name;
int num_temporal_units;
};
@ -56,9 +64,9 @@ class ScalabilityStructureTest : public TestWithParam<SvcTestParam> {};
TEST_P(ScalabilityStructureTest,
StaticConfigMatchesConfigReturnedByController) {
std::unique_ptr<ScalableVideoController> controller =
CreateScalabilityStructure(GetParam().name);
CreateScalabilityStructure(GetParam().GetScalabilityMode());
absl::optional<ScalableVideoController::StreamLayersConfig> static_config =
ScalabilityStructureConfig(GetParam().name);
ScalabilityStructureConfig(GetParam().GetScalabilityMode());
ASSERT_THAT(controller, NotNull());
ASSERT_NE(static_config, absl::nullopt);
ScalableVideoController::StreamLayersConfig config =
@ -78,7 +86,8 @@ TEST_P(ScalabilityStructureTest,
TEST_P(ScalabilityStructureTest,
NumberOfDecodeTargetsAndChainsAreInRangeAndConsistent) {
FrameDependencyStructure structure =
CreateScalabilityStructure(GetParam().name)->DependencyStructure();
CreateScalabilityStructure(GetParam().GetScalabilityMode())
->DependencyStructure();
EXPECT_GT(structure.num_decode_targets, 0);
EXPECT_LE(structure.num_decode_targets,
DependencyDescriptor::kMaxDecodeTargets);
@ -97,7 +106,8 @@ TEST_P(ScalabilityStructureTest,
TEST_P(ScalabilityStructureTest, TemplatesAreSortedByLayerId) {
FrameDependencyStructure structure =
CreateScalabilityStructure(GetParam().name)->DependencyStructure();
CreateScalabilityStructure(GetParam().GetScalabilityMode())
->DependencyStructure();
ASSERT_THAT(structure.templates, Not(IsEmpty()));
const auto& first_templates = structure.templates.front();
EXPECT_EQ(first_templates.spatial_id, 0);
@ -128,7 +138,8 @@ TEST_P(ScalabilityStructureTest, TemplatesAreSortedByLayerId) {
TEST_P(ScalabilityStructureTest, TemplatesMatchNumberOfDecodeTargetsAndChains) {
FrameDependencyStructure structure =
CreateScalabilityStructure(GetParam().name)->DependencyStructure();
CreateScalabilityStructure(GetParam().GetScalabilityMode())
->DependencyStructure();
EXPECT_THAT(
structure.templates,
Each(AllOf(Field(&FrameDependencyTemplate::decode_target_indications,
@ -139,7 +150,7 @@ TEST_P(ScalabilityStructureTest, TemplatesMatchNumberOfDecodeTargetsAndChains) {
TEST_P(ScalabilityStructureTest, FrameInfoMatchesFrameDependencyStructure) {
std::unique_ptr<ScalableVideoController> svc_controller =
CreateScalabilityStructure(GetParam().name);
CreateScalabilityStructure(GetParam().GetScalabilityMode());
FrameDependencyStructure structure = svc_controller->DependencyStructure();
std::vector<GenericFrameInfo> frame_infos =
ScalabilityStructureWrapper(*svc_controller)
@ -158,7 +169,7 @@ TEST_P(ScalabilityStructureTest, FrameInfoMatchesFrameDependencyStructure) {
TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) {
std::unique_ptr<ScalableVideoController> svc_controller =
CreateScalabilityStructure(GetParam().name);
CreateScalabilityStructure(GetParam().GetScalabilityMode());
FrameDependencyStructure structure = svc_controller->DependencyStructure();
std::vector<GenericFrameInfo> frame_infos =
ScalabilityStructureWrapper(*svc_controller)
@ -171,7 +182,7 @@ TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) {
TEST_P(ScalabilityStructureTest, FrameDependsOnSameOrLowerLayer) {
std::unique_ptr<ScalableVideoController> svc_controller =
CreateScalabilityStructure(GetParam().name);
CreateScalabilityStructure(GetParam().GetScalabilityMode());
std::vector<GenericFrameInfo> frame_infos =
ScalabilityStructureWrapper(*svc_controller)
.GenerateFrames(GetParam().num_temporal_units);
@ -192,7 +203,7 @@ TEST_P(ScalabilityStructureTest, FrameDependsOnSameOrLowerLayer) {
TEST_P(ScalabilityStructureTest, NoFrameDependsOnDiscardableOrNotPresent) {
std::unique_ptr<ScalableVideoController> svc_controller =
CreateScalabilityStructure(GetParam().name);
CreateScalabilityStructure(GetParam().GetScalabilityMode());
std::vector<GenericFrameInfo> frame_infos =
ScalabilityStructureWrapper(*svc_controller)
.GenerateFrames(GetParam().num_temporal_units);
@ -224,7 +235,7 @@ TEST_P(ScalabilityStructureTest, NoFrameDependsOnDiscardableOrNotPresent) {
TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) {
std::unique_ptr<ScalableVideoController> svc_controller =
CreateScalabilityStructure(GetParam().name);
CreateScalabilityStructure(GetParam().GetScalabilityMode());
FrameDependencyStructure structure = svc_controller->DependencyStructure();
std::vector<GenericFrameInfo> frame_infos =
ScalabilityStructureWrapper(*svc_controller)
@ -277,7 +288,7 @@ TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) {
TEST_P(ScalabilityStructureTest, ProduceNoFrameForDisabledLayers) {
std::unique_ptr<ScalableVideoController> svc_controller =
CreateScalabilityStructure(GetParam().name);
CreateScalabilityStructure(GetParam().GetScalabilityMode());
ScalableVideoController::StreamLayersConfig structure =
svc_controller->StreamConfig();

View File

@ -174,8 +174,10 @@ DataRate FindLayerTogglingThreshold(const VideoCodec& codec,
SvcRateAllocator::NumLayers SvcRateAllocator::GetNumLayers(
const VideoCodec& codec) {
NumLayers layers;
if (!codec.ScalabilityMode().empty()) {
if (auto structure = CreateScalabilityStructure(codec.ScalabilityMode())) {
if (absl::optional<ScalabilityMode> scalability_mode =
codec.GetScalabilityMode();
scalability_mode.has_value()) {
if (auto structure = CreateScalabilityStructure(*scalability_mode)) {
ScalableVideoController::StreamLayersConfig config =
structure->StreamConfig();
layers.spatial = config.num_spatial_layers;

View File

@ -275,7 +275,7 @@ TEST(SvcRateAllocatorTest, SupportsAv1) {
codec.width = 640;
codec.height = 360;
codec.codecType = kVideoCodecAV1;
codec.SetScalabilityMode("L3T3");
codec.SetScalabilityMode(ScalabilityMode::kL3T3);
codec.spatialLayers[0].active = true;
codec.spatialLayers[0].minBitrate = 30;
codec.spatialLayers[0].targetBitrate = 51;
@ -304,7 +304,7 @@ TEST(SvcRateAllocatorTest, SupportsAv1WithSkippedLayer) {
codec.width = 640;
codec.height = 360;
codec.codecType = kVideoCodecAV1;
codec.SetScalabilityMode("L3T3");
codec.SetScalabilityMode(ScalabilityMode::kL3T3);
codec.spatialLayers[0].active = false;
codec.spatialLayers[0].minBitrate = 30;
codec.spatialLayers[0].targetBitrate = 51;
@ -333,7 +333,7 @@ TEST(SvcRateAllocatorTest, UsesScalabilityModeToGetNumberOfLayers) {
codec.width = 640;
codec.height = 360;
codec.codecType = kVideoCodecAV1;
codec.SetScalabilityMode("L2T2");
codec.SetScalabilityMode(ScalabilityMode::kL2T2);
codec.spatialLayers[0].active = true;
codec.spatialLayers[0].minBitrate = 30;
codec.spatialLayers[0].targetBitrate = 51;