diff --git a/api/video_codecs/BUILD.gn b/api/video_codecs/BUILD.gn index 023e8aec1d..253030b797 100644 --- a/api/video_codecs/BUILD.gn +++ b/api/video_codecs/BUILD.gn @@ -12,6 +12,10 @@ if (is_android) { import("//build/config/android/rules.gni") } +rtc_source_set("scalability_mode") { + sources = [ "scalability_mode.h" ] +} + rtc_library("video_codecs_api") { visibility = [ "*" ] sources = [ @@ -41,6 +45,7 @@ rtc_library("video_codecs_api") { ] deps = [ + ":scalability_mode", "..:fec_controller_api", "..:scoped_refptr", "../../api:array_view", @@ -153,7 +158,9 @@ rtc_source_set("video_encoder_factory_template_libaom_av1_adapter") { public = [ "video_encoder_factory_template_libaom_av1_adapter.h" ] deps = [ + ":scalability_mode", "../../modules/video_coding/codecs/av1:libaom_av1_encoder", + "../../modules/video_coding/svc:scalability_mode_util", "../../modules/video_coding/svc:scalability_structures", ] } diff --git a/api/video_codecs/scalability_mode.h b/api/video_codecs/scalability_mode.h new file mode 100644 index 0000000000..e5809ed11a --- /dev/null +++ b/api/video_codecs/scalability_mode.h @@ -0,0 +1,40 @@ +/* + * 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 API_VIDEO_CODECS_SCALABILITY_MODE_H_ +#define API_VIDEO_CODECS_SCALABILITY_MODE_H_ + +namespace webrtc { + +// Supported scalability modes. Most applications should use the +// PeerConnection-level apis where scalability mode is represented as a string. +// This list of currently recognized modes is intended for the api boundary +// between webrtc and injected encoders. Any application usage outside of +// injected encoders is strongly discouraged. +enum class ScalabilityMode { + kL1T1, + kL1T2, + kL1T3, + kL2T1, + kL2T1h, + kL2T1_KEY, + kL2T2, + kL2T2_KEY, + kL2T2_KEY_SHIFT, + kL2T3_KEY, + kL3T1, + kL3T3, + kL3T3_KEY, + kS2T1, + kS3T3, +}; + +} // namespace webrtc +#endif // API_VIDEO_CODECS_SCALABILITY_MODE_H_ diff --git a/api/video_codecs/video_codec.h b/api/video_codecs/video_codec.h index 2d805ca593..9210d2563d 100644 --- a/api/video_codecs/video_codec.h +++ b/api/video_codecs/video_codec.h @@ -19,6 +19,7 @@ #include "absl/strings/string_view.h" #include "api/video/video_bitrate_allocation.h" #include "api/video/video_codec_type.h" +#include "api/video_codecs/scalability_mode.h" #include "api/video_codecs/spatial_layer.h" #include "rtc_base/system/rtc_export.h" @@ -104,11 +105,13 @@ class RTC_EXPORT VideoCodec { // Scalability mode as described in // https://www.w3.org/TR/webrtc-svc/#scalabilitymodes* - // or value 'NONE' to indicate no scalability. - absl::string_view ScalabilityMode() const { return scalability_mode_; } - void SetScalabilityMode(absl::string_view scalability_mode) { - scalability_mode_ = std::string(scalability_mode); + absl::optional GetScalabilityMode() const { + return scalability_mode_; } + void SetScalabilityMode(ScalabilityMode scalability_mode) { + scalability_mode_ = scalability_mode; + } + void UnsetScalabilityMode() { scalability_mode_ = absl::nullopt; } VideoCodecComplexity GetVideoEncoderComplexity() const; void SetVideoEncoderComplexity(VideoCodecComplexity complexity_setting); @@ -172,7 +175,7 @@ class RTC_EXPORT VideoCodec { // TODO(hta): Consider replacing the union with a pointer type. // This will allow removing the VideoCodec* types from this file. VideoCodecUnion codec_specific_; - std::string scalability_mode_; + absl::optional scalability_mode_; // 'complexity_' indicates the CPU capability of the client. It's used to // determine encoder CPU complexity (e.g., cpu_used for VP8, VP9. and AV1). absl::optional complexity_; diff --git a/api/video_codecs/video_encoder_config.h b/api/video_codecs/video_encoder_config.h index cfda2ad7cf..ace71af51b 100644 --- a/api/video_codecs/video_encoder_config.h +++ b/api/video_codecs/video_encoder_config.h @@ -18,6 +18,7 @@ #include "absl/types/optional.h" #include "api/scoped_refptr.h" +#include "api/video_codecs/scalability_mode.h" #include "api/video_codecs/sdp_video_format.h" #include "api/video_codecs/video_codec.h" #include "rtc_base/ref_count.h" @@ -64,7 +65,7 @@ struct VideoStream { // between multiple streams. absl::optional bitrate_priority; - absl::optional scalability_mode; + absl::optional scalability_mode; // If this stream is enabled by the user, or not. bool active; diff --git a/api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h b/api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h index dcbdc82b86..e0363ddfac 100644 --- a/api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h +++ b/api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h @@ -16,6 +16,7 @@ #include "modules/video_coding/codecs/av1/libaom_av1_encoder.h" #include "modules/video_coding/svc/create_scalability_structure.h" +#include "modules/video_coding/svc/scalability_mode_util.h" namespace webrtc { struct LibaomAv1EncoderTemplateAdapter { @@ -28,10 +29,13 @@ struct LibaomAv1EncoderTemplateAdapter { return CreateLibaomAv1Encoder(); } - static bool IsScalabilityModeSupported(absl::string_view scalability_mode) { + static bool IsScalabilityModeSupported(absl::string_view mode_string) { // For libaom AV1, the scalability mode is supported if we can create the // scalability structure. - return ScalabilityStructureConfig(scalability_mode) != absl::nullopt; + absl::optional scalability_mode = + ScalabilityModeFromString(mode_string); + return scalability_mode != absl::nullopt && + ScalabilityStructureConfig(*scalability_mode) != absl::nullopt; } }; diff --git a/media/BUILD.gn b/media/BUILD.gn index 015bc46ddd..74fd7a890c 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -291,6 +291,7 @@ rtc_library("rtc_audio_video") { "../modules/video_coding", "../modules/video_coding:video_codec_interface", "../modules/video_coding:video_coding_utility", + "../modules/video_coding/svc:scalability_mode_util", "../rtc_base", "../rtc_base:audio_format_to_string", "../rtc_base:buffer", diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index 0e2cfa2983..f3ada60ce3 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -32,6 +32,7 @@ #include "media/engine/webrtc_media_engine.h" #include "media/engine/webrtc_voice_engine.h" #include "modules/rtp_rtcp/source/rtp_util.h" +#include "modules/video_coding/svc/scalability_mode_util.h" #include "rtc_base/copy_on_write_buffer.h" #include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/experiments/field_trial_units.h" @@ -2476,7 +2477,8 @@ WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig( encoder_config.simulcast_layers[i].active = rtp_parameters_.encodings[i].active; encoder_config.simulcast_layers[i].scalability_mode = - rtp_parameters_.encodings[i].scalability_mode; + webrtc::ScalabilityModeFromString( + rtp_parameters_.encodings[i].scalability_mode.value_or("")); if (rtp_parameters_.encodings[i].min_bitrate_bps) { encoder_config.simulcast_layers[i].min_bitrate_bps = *rtp_parameters_.encodings[i].min_bitrate_bps; diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn index 1d14022c08..88bd0799b2 100644 --- a/modules/video_coding/BUILD.gn +++ b/modules/video_coding/BUILD.gn @@ -804,6 +804,7 @@ rtc_library("webrtc_vp9") { "../../rtc_base/synchronization:mutex", "../../system_wrappers:field_trial", "../rtp_rtcp:rtp_rtcp_format", + "svc:scalability_mode_util", "svc:scalability_structures", "svc:scalable_video_controller", "svc:svc_rate_allocator", diff --git a/modules/video_coding/codecs/av1/BUILD.gn b/modules/video_coding/codecs/av1/BUILD.gn index 2e4d824821..520ed0aee0 100644 --- a/modules/video_coding/codecs/av1/BUILD.gn +++ b/modules/video_coding/codecs/av1/BUILD.gn @@ -99,6 +99,7 @@ rtc_library("libaom_av1_encoder_if_supported") { sources = [ "libaom_av1_encoder_supported.cc" ] deps = [ "../../../../api/video_codecs:video_codecs_api", + "../../svc:scalability_mode_util", "../../svc:scalability_structures", "../../svc:scalable_video_controller", ] @@ -139,6 +140,7 @@ if (rtc_include_tests) { "../../../../api/units:data_size", "../../../../api/units:time_delta", "../../../../api/video:video_frame", + "../../svc:scalability_mode_util", "../../svc:scalability_structures", "../../svc:scalable_video_controller", ] diff --git a/modules/video_coding/codecs/av1/av1_svc_config.cc b/modules/video_coding/codecs/av1/av1_svc_config.cc index abc7e69f84..f87237232b 100644 --- a/modules/video_coding/codecs/av1/av1_svc_config.cc +++ b/modules/video_coding/codecs/av1/av1_svc_config.cc @@ -24,16 +24,18 @@ namespace webrtc { bool SetAv1SvcConfig(VideoCodec& video_codec) { RTC_DCHECK_EQ(video_codec.codecType, kVideoCodecAV1); - absl::string_view scalability_mode = video_codec.ScalabilityMode(); - if (scalability_mode.empty()) { + absl::optional scalability_mode = + video_codec.GetScalabilityMode(); + if (!scalability_mode.has_value()) { RTC_LOG(LS_WARNING) << "Scalability mode is not set, using 'L1T1'."; - scalability_mode = "L1T1"; + scalability_mode = ScalabilityMode::kL1T1; } std::unique_ptr structure = - CreateScalabilityStructure(scalability_mode); + CreateScalabilityStructure(*scalability_mode); if (structure == nullptr) { - RTC_LOG(LS_WARNING) << "Failed to create structure " << scalability_mode; + RTC_LOG(LS_WARNING) << "Failed to create structure " + << static_cast(*scalability_mode); return false; } diff --git a/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc b/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc index dca17913bf..b4e264b5f7 100644 --- a/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc +++ b/modules/video_coding/codecs/av1/av1_svc_config_unittest.cc @@ -17,22 +17,10 @@ namespace webrtc { namespace { -TEST(Av1SvcConfigTest, RequireScalabilityMode) { +TEST(Av1SvcConfigTest, TreatsEmptyAsL1T1) { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; - video_codec.SetScalabilityMode("Unknown"); - EXPECT_FALSE(SetAv1SvcConfig(video_codec)); - - video_codec.SetScalabilityMode("L1T1"); - EXPECT_TRUE(SetAv1SvcConfig(video_codec)); -} - -TEST(Av1SvcConfigTest, TreatsEmptyAsNone) { - VideoCodec video_codec; - video_codec.codecType = kVideoCodecAV1; - - video_codec.SetScalabilityMode(""); EXPECT_TRUE(SetAv1SvcConfig(video_codec)); EXPECT_TRUE(video_codec.spatialLayers[0].active); @@ -43,7 +31,7 @@ TEST(Av1SvcConfigTest, TreatsEmptyAsNone) { TEST(Av1SvcConfigTest, SetsActiveSpatialLayersFromScalabilityMode) { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; - video_codec.SetScalabilityMode("L2T1"); + video_codec.SetScalabilityMode(ScalabilityMode::kL2T1); EXPECT_TRUE(SetAv1SvcConfig(video_codec)); @@ -55,7 +43,7 @@ TEST(Av1SvcConfigTest, SetsActiveSpatialLayersFromScalabilityMode) { TEST(Av1SvcConfigTest, ConfiguresDobuleResolutionRatioFromScalabilityMode) { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; - video_codec.SetScalabilityMode("L2T1"); + video_codec.SetScalabilityMode(ScalabilityMode::kL2T1); video_codec.width = 1200; video_codec.height = 800; @@ -71,7 +59,7 @@ TEST(Av1SvcConfigTest, ConfiguresSmallResolutionRatioFromScalabilityMode) { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; // h mode uses 1.5:1 ratio - video_codec.SetScalabilityMode("L2T1h"); + video_codec.SetScalabilityMode(ScalabilityMode::kL2T1h); video_codec.width = 1500; video_codec.height = 900; @@ -87,7 +75,7 @@ TEST(Av1SvcConfigTest, CopiesFramrate) { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; // h mode uses 1.5:1 ratio - video_codec.SetScalabilityMode("L2T1"); + video_codec.SetScalabilityMode(ScalabilityMode::kL2T1); video_codec.maxFramerate = 27; EXPECT_TRUE(SetAv1SvcConfig(video_codec)); @@ -99,7 +87,7 @@ TEST(Av1SvcConfigTest, CopiesFramrate) { TEST(Av1SvcConfigTest, SetsNumberOfTemporalLayers) { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; - video_codec.SetScalabilityMode("L1T3"); + video_codec.SetScalabilityMode(ScalabilityMode::kL1T3); EXPECT_TRUE(SetAv1SvcConfig(video_codec)); @@ -109,7 +97,7 @@ TEST(Av1SvcConfigTest, SetsNumberOfTemporalLayers) { TEST(Av1SvcConfigTest, CopiesMinMaxBitrateForSingleSpatialLayer) { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; - video_codec.SetScalabilityMode("L1T3"); + video_codec.SetScalabilityMode(ScalabilityMode::kL1T3); video_codec.minBitrate = 100; video_codec.maxBitrate = 500; @@ -126,7 +114,7 @@ TEST(Av1SvcConfigTest, CopiesMinMaxBitrateForSingleSpatialLayer) { TEST(Av1SvcConfigTest, SetsBitratesForMultipleSpatialLayers) { VideoCodec video_codec; video_codec.codecType = kVideoCodecAV1; - video_codec.SetScalabilityMode("L3T3"); + video_codec.SetScalabilityMode(ScalabilityMode::kL3T3); EXPECT_TRUE(SetAv1SvcConfig(video_codec)); diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder.cc b/modules/video_coding/codecs/av1/libaom_av1_encoder.cc index 3f28abca7b..6408d527e7 100644 --- a/modules/video_coding/codecs/av1/libaom_av1_encoder.cc +++ b/modules/video_coding/codecs/av1/libaom_av1_encoder.cc @@ -169,15 +169,16 @@ int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings, RTC_LOG(LS_WARNING) << "Simulcast is not implemented by LibaomAv1Encoder."; return result; } - absl::string_view scalability_mode = encoder_settings_.ScalabilityMode(); - if (scalability_mode.empty()) { + absl::optional scalability_mode = + encoder_settings_.GetScalabilityMode(); + if (!scalability_mode.has_value()) { RTC_LOG(LS_WARNING) << "Scalability mode is not set, using 'L1T1'."; - scalability_mode = "L1T1"; + scalability_mode = ScalabilityMode::kL1T1; } - svc_controller_ = CreateScalabilityStructure(scalability_mode); + svc_controller_ = CreateScalabilityStructure(*scalability_mode); if (svc_controller_ == nullptr) { RTC_LOG(LS_WARNING) << "Failed to set scalability mode " - << scalability_mode; + << static_cast(*scalability_mode); return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; } diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder_supported.cc b/modules/video_coding/codecs/av1/libaom_av1_encoder_supported.cc index 0bb31085e2..8a65da5073 100644 --- a/modules/video_coding/codecs/av1/libaom_av1_encoder_supported.cc +++ b/modules/video_coding/codecs/av1/libaom_av1_encoder_supported.cc @@ -10,6 +10,7 @@ #include "modules/video_coding/codecs/av1/libaom_av1_encoder_supported.h" #include "modules/video_coding/svc/create_scalability_structure.h" +#include "modules/video_coding/svc/scalability_mode_util.h" #if defined(RTC_USE_LIBAOM_AV1_ENCODER) #include "modules/video_coding/codecs/av1/libaom_av1_encoder.h" // nogncheck @@ -21,11 +22,14 @@ const bool kIsLibaomAv1EncoderSupported = true; std::unique_ptr CreateLibaomAv1EncoderIfSupported() { return CreateLibaomAv1Encoder(); } -bool LibaomAv1EncoderSupportsScalabilityMode( - absl::string_view scalability_mode) { +bool LibaomAv1EncoderSupportsScalabilityMode(absl::string_view mode_string) { + absl::optional scalability_mode = + ScalabilityModeFromString(mode_string); + // For libaom AV1, the scalability mode is supported if we can create the // scalability structure. - return ScalabilityStructureConfig(scalability_mode) != absl::nullopt; + return scalability_mode.has_value() && + ScalabilityStructureConfig(*scalability_mode) != absl::nullopt; } #else const bool kIsLibaomAv1EncoderSupported = false; diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc b/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc index 0c67e4dde4..5243edc1e4 100644 --- a/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc +++ b/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc @@ -64,7 +64,7 @@ TEST(LibaomAv1EncoderTest, NoBitrateOnTopLayerRefecltedInActiveDecodeTargets) { // Configure encoder with 2 temporal layers. std::unique_ptr encoder = CreateLibaomAv1Encoder(); VideoCodec codec_settings = DefaultCodecSettings(); - codec_settings.SetScalabilityMode("L1T2"); + codec_settings.SetScalabilityMode(ScalabilityMode::kL1T2); ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), WEBRTC_VIDEO_CODEC_OK); @@ -90,7 +90,7 @@ TEST(LibaomAv1EncoderTest, SpatialScalabilityInTemporalUnitReportedAsDeltaFrame) { std::unique_ptr encoder = CreateLibaomAv1Encoder(); VideoCodec codec_settings = DefaultCodecSettings(); - codec_settings.SetScalabilityMode("L2T1"); + codec_settings.SetScalabilityMode(ScalabilityMode::kL2T1); ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), WEBRTC_VIDEO_CODEC_OK); @@ -112,7 +112,7 @@ TEST(LibaomAv1EncoderTest, TEST(LibaomAv1EncoderTest, NoBitrateOnTopSpatialLayerProduceDeltaFrames) { std::unique_ptr encoder = CreateLibaomAv1Encoder(); VideoCodec codec_settings = DefaultCodecSettings(); - codec_settings.SetScalabilityMode("L2T1"); + codec_settings.SetScalabilityMode(ScalabilityMode::kL2T1); ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), WEBRTC_VIDEO_CODEC_OK); @@ -140,7 +140,7 @@ TEST(LibaomAv1EncoderTest, SetsEndOfPictureForLastFrameInTemporalUnit) { std::unique_ptr encoder = CreateLibaomAv1Encoder(); VideoCodec codec_settings = DefaultCodecSettings(); // Configure encoder with 3 spatial layers. - codec_settings.SetScalabilityMode("L3T1"); + codec_settings.SetScalabilityMode(ScalabilityMode::kL3T1); codec_settings.maxBitrate = allocation.get_sum_kbps(); ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), WEBRTC_VIDEO_CODEC_OK); @@ -167,7 +167,7 @@ TEST(LibaomAv1EncoderTest, CheckOddDimensionsWithSpatialLayers) { std::unique_ptr encoder = CreateLibaomAv1Encoder(); VideoCodec codec_settings = DefaultCodecSettings(); // Configure encoder with 3 spatial layers. - codec_settings.SetScalabilityMode("L3T1"); + codec_settings.SetScalabilityMode(ScalabilityMode::kL3T1); // Odd width and height values should not make encoder crash. codec_settings.width = 623; codec_settings.height = 405; @@ -186,7 +186,7 @@ TEST(LibaomAv1EncoderTest, CheckOddDimensionsWithSpatialLayers) { TEST(LibaomAv1EncoderTest, EncoderInfoProvidesFpsAllocation) { std::unique_ptr encoder = CreateLibaomAv1Encoder(); VideoCodec codec_settings = DefaultCodecSettings(); - codec_settings.SetScalabilityMode("L3T3"); + codec_settings.SetScalabilityMode(ScalabilityMode::kL3T3); codec_settings.maxFramerate = 60; ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), WEBRTC_VIDEO_CODEC_OK); @@ -208,7 +208,7 @@ TEST(LibaomAv1EncoderTest, PopulatesEncodedFrameSize) { codec_settings.maxBitrate = allocation.get_sum_kbps(); ASSERT_GT(codec_settings.width, 4); // Configure encoder with 3 spatial layers. - codec_settings.SetScalabilityMode("L3T1"); + codec_settings.SetScalabilityMode(ScalabilityMode::kL3T1); ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), WEBRTC_VIDEO_CODEC_OK); encoder->SetRates(VideoEncoder::RateControlParameters( diff --git a/modules/video_coding/codecs/av1/libaom_av1_unittest.cc b/modules/video_coding/codecs/av1/libaom_av1_unittest.cc index 269432a5d0..5d9c251bc7 100644 --- a/modules/video_coding/codecs/av1/libaom_av1_unittest.cc +++ b/modules/video_coding/codecs/av1/libaom_av1_unittest.cc @@ -28,6 +28,7 @@ #include "modules/video_coding/include/video_codec_interface.h" #include "modules/video_coding/include/video_error_codes.h" #include "modules/video_coding/svc/create_scalability_structure.h" +#include "modules/video_coding/svc/scalability_mode_util.h" #include "modules/video_coding/svc/scalable_video_controller.h" #include "modules/video_coding/svc/scalable_video_controller_no_layering.h" #include "test/gmock.h" @@ -55,7 +56,7 @@ constexpr int kFramerate = 30; VideoCodec DefaultCodecSettings() { VideoCodec codec_settings; - codec_settings.SetScalabilityMode("L1T1"); + codec_settings.SetScalabilityMode(ScalabilityMode::kL1T1); codec_settings.width = kWidth; codec_settings.height = kHeight; codec_settings.maxFramerate = kFramerate; @@ -175,6 +176,13 @@ struct LayerId { }; struct SvcTestParam { + ScalabilityMode GetScalabilityMode() const { + absl::optional scalability_mode = + ScalabilityModeFromString(name); + RTC_CHECK(scalability_mode.has_value()); + return *scalability_mode; + } + std::string name; int num_frames_to_generate; std::map configured_bitrates; @@ -185,7 +193,7 @@ class LibaomAv1SvcTest : public ::testing::TestWithParam {}; TEST_P(LibaomAv1SvcTest, EncodeAndDecodeAllDecodeTargets) { const SvcTestParam param = GetParam(); std::unique_ptr svc_controller = - CreateScalabilityStructure(param.name); + CreateScalabilityStructure(param.GetScalabilityMode()); ASSERT_TRUE(svc_controller); VideoBitrateAllocation allocation; if (param.configured_bitrates.empty()) { @@ -208,7 +216,7 @@ TEST_P(LibaomAv1SvcTest, EncodeAndDecodeAllDecodeTargets) { std::unique_ptr encoder = CreateLibaomAv1Encoder(); VideoCodec codec_settings = DefaultCodecSettings(); - codec_settings.SetScalabilityMode(GetParam().name); + codec_settings.SetScalabilityMode(GetParam().GetScalabilityMode()); ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), WEBRTC_VIDEO_CODEC_OK); encoder->SetRates(VideoEncoder::RateControlParameters( @@ -278,7 +286,7 @@ TEST_P(LibaomAv1SvcTest, SetRatesMatchMeasuredBitrate) { std::unique_ptr encoder = CreateLibaomAv1Encoder(); ASSERT_TRUE(encoder); VideoCodec codec_settings = DefaultCodecSettings(); - codec_settings.SetScalabilityMode(param.name); + codec_settings.SetScalabilityMode(param.GetScalabilityMode()); codec_settings.maxBitrate = allocation.get_sum_kbps(); codec_settings.maxFramerate = 30; ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), diff --git a/modules/video_coding/codecs/test/videocodec_test_av1.cc b/modules/video_coding/codecs/test/videocodec_test_av1.cc index 38b90abc60..7680957764 100644 --- a/modules/video_coding/codecs/test/videocodec_test_av1.cc +++ b/modules/video_coding/codecs/test/videocodec_test_av1.cc @@ -52,7 +52,7 @@ TEST_P(VideoCodecTestAv1, HighBitrate) { auto config = CreateConfig("foreman_cif"); config.SetCodecSettings(cricket::kAv1CodecName, 1, 1, 1, false, true, true, kCifWidth, kCifHeight); - config.codec_settings.SetScalabilityMode("L1T1"); + config.codec_settings.SetScalabilityMode(ScalabilityMode::kL1T1); config.num_frames = kNumFramesLong; auto fixture = CreateVideoCodecTestFixture(config); @@ -70,7 +70,7 @@ TEST_P(VideoCodecTestAv1, VeryLowBitrate) { auto config = CreateConfig("foreman_cif"); config.SetCodecSettings(cricket::kAv1CodecName, 1, 1, 1, false, true, true, kCifWidth, kCifHeight); - config.codec_settings.SetScalabilityMode("L1T1"); + config.codec_settings.SetScalabilityMode(ScalabilityMode::kL1T1); auto fixture = CreateVideoCodecTestFixture(config); std::vector rate_profiles = {{50, 30, 0}}; @@ -90,7 +90,7 @@ TEST_P(VideoCodecTestAv1, Hd) { auto config = CreateConfig("ConferenceMotion_1280_720_50"); config.SetCodecSettings(cricket::kAv1CodecName, 1, 1, 1, false, true, true, kHdWidth, kHdHeight); - config.codec_settings.SetScalabilityMode("L1T1"); + config.codec_settings.SetScalabilityMode(ScalabilityMode::kL1T1); config.num_frames = kNumFramesLong; auto fixture = CreateVideoCodecTestFixture(config); diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc index 2c9e4bc4f3..3f9f4e9235 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc @@ -27,6 +27,7 @@ #include "common_video/libyuv/include/webrtc_libyuv.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/video_coding/svc/create_scalability_structure.h" +#include "modules/video_coding/svc/scalability_mode_util.h" #include "modules/video_coding/svc/scalable_video_controller.h" #include "modules/video_coding/svc/scalable_video_controller_no_layering.h" #include "modules/video_coding/svc/svc_rate_allocator.h" @@ -142,7 +143,14 @@ std::unique_ptr CreateVp9ScalabilityStructure( } } - auto scalability_structure_controller = CreateScalabilityStructure(name); + absl::optional scalability_mode = + ScalabilityModeFromString(name); + if (!scalability_mode.has_value()) { + RTC_LOG(LS_WARNING) << "Invalid scalability mode " << name; + return nullptr; + } + auto scalability_structure_controller = + CreateScalabilityStructure(*scalability_mode); if (scalability_structure_controller == nullptr) { RTC_LOG(LS_WARNING) << "Unsupported scalability structure " << name; } else { diff --git a/modules/video_coding/svc/BUILD.gn b/modules/video_coding/svc/BUILD.gn index 2eb25025c1..f68001ad72 100644 --- a/modules/video_coding/svc/BUILD.gn +++ b/modules/video_coding/svc/BUILD.gn @@ -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") { diff --git a/modules/video_coding/svc/create_scalability_structure.cc b/modules/video_coding/svc/create_scalability_structure.cc index 80df766d3d..dfbfb14968 100644 --- a/modules/video_coding/svc/create_scalability_structure.cc +++ b/modules/video_coding/svc/create_scalability_structure.cc @@ -11,7 +11,7 @@ #include -#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 (*factory)(); ScalableVideoController::StreamLayersConfig config; @@ -114,28 +114,33 @@ constexpr ScalableVideoController::StreamLayersConfig kConfigS3T3 = { {4, 2, 1}}; constexpr NamedStructureFactory kFactories[] = { - {"L1T1", Create, kConfigL1T1}, - {"L1T2", Create, kConfigL1T2}, - {"L1T3", Create, kConfigL1T3}, - {"L2T1", Create, kConfigL2T1}, - {"L2T1h", CreateH, kConfigL2T1h}, - {"L2T1_KEY", Create, kConfigL2T1}, - {"L2T2", Create, kConfigL2T2}, - {"L2T2_KEY", Create, kConfigL2T2}, - {"L2T2_KEY_SHIFT", Create, kConfigL2T2}, - {"L2T3_KEY", Create, kConfigL2T3}, - {"L3T1", Create, kConfigL3T1}, - {"L3T3", Create, kConfigL3T3}, - {"L3T3_KEY", Create, kConfigL3T3}, - {"S2T1", Create, kConfigS2T1}, - {"S3T3", Create, kConfigS3T3}, + {ScalabilityMode::kL1T1, Create, + kConfigL1T1}, + {ScalabilityMode::kL1T2, Create, kConfigL1T2}, + {ScalabilityMode::kL1T3, Create, kConfigL1T3}, + {ScalabilityMode::kL2T1, Create, kConfigL2T1}, + {ScalabilityMode::kL2T1h, CreateH, kConfigL2T1h}, + {ScalabilityMode::kL2T1_KEY, Create, + kConfigL2T1}, + {ScalabilityMode::kL2T2, Create, kConfigL2T2}, + {ScalabilityMode::kL2T2_KEY, Create, + kConfigL2T2}, + {ScalabilityMode::kL2T2_KEY_SHIFT, Create, + kConfigL2T2}, + {ScalabilityMode::kL2T3_KEY, Create, + kConfigL2T3}, + {ScalabilityMode::kL3T1, Create, kConfigL3T1}, + {ScalabilityMode::kL3T3, Create, kConfigL3T3}, + {ScalabilityMode::kL3T3_KEY, Create, + kConfigL3T3}, + {ScalabilityMode::kS2T1, Create, kConfigS2T1}, + {ScalabilityMode::kS3T3, Create, kConfigS3T3}, }; } // namespace std::unique_ptr 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 CreateScalabilityStructure( } absl::optional -ScalabilityStructureConfig(absl::string_view name) { - RTC_DCHECK(!name.empty()); +ScalabilityStructureConfig(ScalabilityMode name) { for (const auto& entry : kFactories) { if (entry.name == name) { return entry.config; diff --git a/modules/video_coding/svc/create_scalability_structure.h b/modules/video_coding/svc/create_scalability_structure.h index fde034433e..3b67443693 100644 --- a/modules/video_coding/svc/create_scalability_structure.h +++ b/modules/video_coding/svc/create_scalability_structure.h @@ -13,8 +13,8 @@ #include #include -#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 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 -ScalabilityStructureConfig(absl::string_view name); +ScalabilityStructureConfig(ScalabilityMode name); } // namespace webrtc diff --git a/modules/video_coding/svc/scalability_mode_util.cc b/modules/video_coding/svc/scalability_mode_util.cc new file mode 100644 index 0000000000..6dc063d5b6 --- /dev/null +++ b/modules/video_coding/svc/scalability_mode_util.cc @@ -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 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 diff --git a/modules/video_coding/svc/scalability_mode_util.h b/modules/video_coding/svc/scalability_mode_util.h new file mode 100644 index 0000000000..363cb6e6e4 --- /dev/null +++ b/modules/video_coding/svc/scalability_mode_util.h @@ -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 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_ diff --git a/modules/video_coding/svc/scalability_mode_util_unittest.cc b/modules/video_coding/svc/scalability_mode_util_unittest.cc new file mode 100644 index 0000000000..7fb103631f --- /dev/null +++ b/modules/video_coding/svc/scalability_mode_util_unittest.cc @@ -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(kLastEnum); + numerical_enum++) { + ScalabilityMode scalability_mode = + static_cast(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 diff --git a/modules/video_coding/svc/scalability_structure_unittest.cc b/modules/video_coding/svc/scalability_structure_unittest.cc index 7b6e924ebf..ffc085da04 100644 --- a/modules/video_coding/svc/scalability_structure_unittest.cc +++ b/modules/video_coding/svc/scalability_structure_unittest.cc @@ -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 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 {}; TEST_P(ScalabilityStructureTest, StaticConfigMatchesConfigReturnedByController) { std::unique_ptr controller = - CreateScalabilityStructure(GetParam().name); + CreateScalabilityStructure(GetParam().GetScalabilityMode()); absl::optional 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 svc_controller = - CreateScalabilityStructure(GetParam().name); + CreateScalabilityStructure(GetParam().GetScalabilityMode()); FrameDependencyStructure structure = svc_controller->DependencyStructure(); std::vector frame_infos = ScalabilityStructureWrapper(*svc_controller) @@ -158,7 +169,7 @@ TEST_P(ScalabilityStructureTest, FrameInfoMatchesFrameDependencyStructure) { TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) { std::unique_ptr svc_controller = - CreateScalabilityStructure(GetParam().name); + CreateScalabilityStructure(GetParam().GetScalabilityMode()); FrameDependencyStructure structure = svc_controller->DependencyStructure(); std::vector frame_infos = ScalabilityStructureWrapper(*svc_controller) @@ -171,7 +182,7 @@ TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) { TEST_P(ScalabilityStructureTest, FrameDependsOnSameOrLowerLayer) { std::unique_ptr svc_controller = - CreateScalabilityStructure(GetParam().name); + CreateScalabilityStructure(GetParam().GetScalabilityMode()); std::vector 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 svc_controller = - CreateScalabilityStructure(GetParam().name); + CreateScalabilityStructure(GetParam().GetScalabilityMode()); std::vector 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 svc_controller = - CreateScalabilityStructure(GetParam().name); + CreateScalabilityStructure(GetParam().GetScalabilityMode()); FrameDependencyStructure structure = svc_controller->DependencyStructure(); std::vector frame_infos = ScalabilityStructureWrapper(*svc_controller) @@ -277,7 +288,7 @@ TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) { TEST_P(ScalabilityStructureTest, ProduceNoFrameForDisabledLayers) { std::unique_ptr svc_controller = - CreateScalabilityStructure(GetParam().name); + CreateScalabilityStructure(GetParam().GetScalabilityMode()); ScalableVideoController::StreamLayersConfig structure = svc_controller->StreamConfig(); diff --git a/modules/video_coding/svc/svc_rate_allocator.cc b/modules/video_coding/svc/svc_rate_allocator.cc index 2d27d47621..b6ae0d7430 100644 --- a/modules/video_coding/svc/svc_rate_allocator.cc +++ b/modules/video_coding/svc/svc_rate_allocator.cc @@ -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 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; diff --git a/modules/video_coding/svc/svc_rate_allocator_unittest.cc b/modules/video_coding/svc/svc_rate_allocator_unittest.cc index fd22acd85d..b3a365d722 100644 --- a/modules/video_coding/svc/svc_rate_allocator_unittest.cc +++ b/modules/video_coding/svc/svc_rate_allocator_unittest.cc @@ -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; diff --git a/modules/video_coding/video_codec_initializer.cc b/modules/video_coding/video_codec_initializer.cc index 5d06a2c133..80b9dc98f8 100644 --- a/modules/video_coding/video_codec_initializer.cc +++ b/modules/video_coding/video_codec_initializer.cc @@ -94,7 +94,8 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec( int max_framerate = 0; - absl::optional scalability_mode = streams[0].scalability_mode; + absl::optional scalability_mode = + streams[0].scalability_mode; for (size_t i = 0; i < streams.size(); ++i) { SpatialLayer* sim_stream = &video_codec.simulcastStream[i]; RTC_DCHECK_GT(streams[i].width, 0); diff --git a/modules/video_coding/video_codec_initializer_unittest.cc b/modules/video_coding/video_codec_initializer_unittest.cc index 902f991f29..85efa467d6 100644 --- a/modules/video_coding/video_codec_initializer_unittest.cc +++ b/modules/video_coding/video_codec_initializer_unittest.cc @@ -430,7 +430,7 @@ TEST_F(VideoCodecInitializerTest, Av1SingleSpatialLayerBitratesAreConsistent) { VideoEncoderConfig config; config.codec_type = VideoCodecType::kVideoCodecAV1; std::vector streams = {DefaultStream()}; - streams[0].scalability_mode = "L1T2"; + streams[0].scalability_mode = ScalabilityMode::kL1T2; VideoCodec codec; EXPECT_TRUE(VideoCodecInitializer::SetupCodec(config, streams, &codec)); @@ -445,7 +445,7 @@ TEST_F(VideoCodecInitializerTest, Av1TwoSpatialLayersBitratesAreConsistent) { VideoEncoderConfig config; config.codec_type = VideoCodecType::kVideoCodecAV1; std::vector streams = {DefaultStream()}; - streams[0].scalability_mode = "L2T2"; + streams[0].scalability_mode = ScalabilityMode::kL2T2; VideoCodec codec; EXPECT_TRUE(VideoCodecInitializer::SetupCodec(config, streams, &codec)); @@ -465,7 +465,7 @@ TEST_F(VideoCodecInitializerTest, Av1TwoSpatialLayersActiveByDefault) { VideoEncoderConfig config; config.codec_type = VideoCodecType::kVideoCodecAV1; std::vector streams = {DefaultStream()}; - streams[0].scalability_mode = "L2T2"; + streams[0].scalability_mode = ScalabilityMode::kL2T2; config.spatial_layers = {}; VideoCodec codec; @@ -479,7 +479,7 @@ TEST_F(VideoCodecInitializerTest, Av1TwoSpatialLayersOneDeactivated) { VideoEncoderConfig config; config.codec_type = VideoCodecType::kVideoCodecAV1; std::vector streams = {DefaultStream()}; - streams[0].scalability_mode = "L2T2"; + streams[0].scalability_mode = ScalabilityMode::kL2T2; config.spatial_layers.resize(2); config.spatial_layers[0].active = true; config.spatial_layers[1].active = false; diff --git a/video/BUILD.gn b/video/BUILD.gn index 90a8c99a6f..417e648a4d 100644 --- a/video/BUILD.gn +++ b/video/BUILD.gn @@ -919,6 +919,7 @@ if (rtc_include_tests) { "../modules/video_coding:webrtc_vp9", "../modules/video_coding:webrtc_vp9_helpers", "../modules/video_coding/codecs/av1:libaom_av1_encoder_if_supported", + "../modules/video_coding/svc:scalability_mode_util", "../rtc_base", "../rtc_base:byte_buffer", "../rtc_base:checks", diff --git a/video/frame_encode_metadata_writer.cc b/video/frame_encode_metadata_writer.cc index 9305779832..a7ae2e0589 100644 --- a/video/frame_encode_metadata_writer.cc +++ b/video/frame_encode_metadata_writer.cc @@ -67,9 +67,9 @@ void FrameEncodeMetadataWriter::OnEncoderInit(const VideoCodec& codec) { num_spatial_layers, static_cast(codec_settings_.VP9()->numberOfSpatialLayers)); } else if (codec_settings_.codecType == kVideoCodecAV1 && - codec_settings_.ScalabilityMode() != "") { + codec_settings_.GetScalabilityMode().has_value()) { std::unique_ptr structure = - CreateScalabilityStructure(codec_settings_.ScalabilityMode()); + CreateScalabilityStructure(*codec_settings_.GetScalabilityMode()); if (structure) { num_spatial_layers = structure->StreamConfig().num_spatial_layers; } else { diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc index 098cfce868..95838926e5 100644 --- a/video/video_send_stream_tests.cc +++ b/video/video_send_stream_tests.cc @@ -39,6 +39,7 @@ #include "modules/video_coding/codecs/interface/common_constants.h" #include "modules/video_coding/codecs/vp8/include/vp8.h" #include "modules/video_coding/codecs/vp9/include/vp9.h" +#include "modules/video_coding/svc/scalability_mode_util.h" #include "rtc_base/checks.h" #include "rtc_base/event.h" #include "rtc_base/experiments/alr_experiment.h" @@ -3383,7 +3384,7 @@ void VideoSendStreamTest::TestVp9NonFlexMode( vp9_settings_.interLayerPred = params_.inter_layer_pred; } else { encoder_config->simulcast_layers[0].scalability_mode = - params_.scalability_mode; + ScalabilityModeFromString(params_.scalability_mode); } } diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc index a77600fa38..052592ec9d 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc @@ -159,7 +159,8 @@ bool RequiresEncoderReset(const VideoCodec& prev_send_codec, } } - if (new_send_codec.ScalabilityMode() != prev_send_codec.ScalabilityMode()) { + if (new_send_codec.GetScalabilityMode() != + prev_send_codec.GetScalabilityMode()) { return true; } diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc index 334c773372..f7e028c628 100644 --- a/video/video_stream_encoder_unittest.cc +++ b/video/video_stream_encoder_unittest.cc @@ -8761,7 +8761,7 @@ TEST_P(VideoStreamEncoderWithRealEncoderTest, HandlesLayerToggling) { /*num_spatial_layers=*/3, /*num_temporal_layers=*/3, /*is_screenshare=*/false); - config.simulcast_layers[0].scalability_mode = "L3T3_KEY"; + config.simulcast_layers[0].scalability_mode = ScalabilityMode::kL3T3_KEY; } else { // Simulcast for VP8/H264. test::FillEncoderConfiguration(codec_type_, kNumSpatialLayers, &config); @@ -8973,7 +8973,7 @@ class ReconfigureEncoderTest : public VideoStreamEncoderTest { kHeight / expected.scale_resolution_down_by); EXPECT_EQ(actual.simulcastStream[0].numberOfTemporalLayers, expected.num_temporal_layers); - EXPECT_EQ(actual.ScalabilityMode(), expected.scalability_mode); + EXPECT_EQ(actual.GetScalabilityMode(), expected.scalability_mode); } VideoStream DefaultConfig() const { @@ -8984,7 +8984,7 @@ class ReconfigureEncoderTest : public VideoStreamEncoderTest { stream.scale_resolution_down_by = 1.0; stream.num_temporal_layers = 1; stream.bitrate_priority = 1.0; - stream.scalability_mode = ""; + stream.scalability_mode = absl::nullopt; return stream; } @@ -9044,7 +9044,7 @@ TEST_F(ReconfigureEncoderTest, ReconfiguredIfNumTemporalLayerChanges) { TEST_F(ReconfigureEncoderTest, ReconfiguredIfScalabilityModeChanges) { VideoStream config1 = DefaultConfig(); VideoStream config2 = config1; - config2.scalability_mode = "L1T2"; + config2.scalability_mode = ScalabilityMode::kL1T2; RunTest({config1, config2}, /*expected_num_init_encode=*/2); }