/* * 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 #include #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "api/video_codecs/scalability_mode.h" #include "api/video_codecs/video_codec.h" #include "rtc_base/checks.h" namespace webrtc { namespace { struct ScalabilityModeParameters { int num_spatial_layers; int num_temporal_layers; InterLayerPredMode inter_layer_pred; absl::optional ratio; bool shift; constexpr bool operator==(const ScalabilityModeParameters& other) const { // For all L1Tx modes, ignore inter_layer_pred, ratio and shift. if (this->num_spatial_layers == 1) { return this->num_spatial_layers == other.num_spatial_layers && this->num_temporal_layers == other.num_temporal_layers; } return this->num_spatial_layers == other.num_spatial_layers && this->num_temporal_layers == other.num_temporal_layers && this->inter_layer_pred == other.inter_layer_pred && this->ratio == other.ratio && this->shift == other.shift; } }; struct ScalabilityModeConfiguration { explicit ScalabilityModeConfiguration(ScalabilityMode scalability_mode) : scalability_mode(scalability_mode), params{ .num_spatial_layers = (ScalabilityModeToNumSpatialLayers(scalability_mode)), .num_temporal_layers = (ScalabilityModeToNumTemporalLayers(scalability_mode)), .inter_layer_pred = (ScalabilityModeToInterLayerPredMode(scalability_mode)), .ratio = (ScalabilityModeToResolutionRatio(scalability_mode)), .shift = (ScalabilityModeIsShiftMode(scalability_mode)), } {} const ScalabilityMode scalability_mode; const ScalabilityModeParameters params; }; constexpr size_t kNumScalabilityModes = static_cast(ScalabilityMode::kS3T3h) + 1; } // namespace absl::optional MakeScalabilityMode( int num_spatial_layers, int num_temporal_layers, InterLayerPredMode inter_layer_pred, absl::optional ratio, bool shift) { ScalabilityModeParameters params{num_spatial_layers, num_temporal_layers, inter_layer_pred, std::move(ratio), shift}; static const ScalabilityModeConfiguration kScalabilityModeConfigs[] = { ScalabilityModeConfiguration{ScalabilityMode::kL1T1}, ScalabilityModeConfiguration{ScalabilityMode::kL1T2}, ScalabilityModeConfiguration{ScalabilityMode::kL1T3}, ScalabilityModeConfiguration{ScalabilityMode::kL2T1}, ScalabilityModeConfiguration{ScalabilityMode::kL2T1h}, ScalabilityModeConfiguration{ScalabilityMode::kL2T1_KEY}, ScalabilityModeConfiguration{ScalabilityMode::kL2T2}, ScalabilityModeConfiguration{ScalabilityMode::kL2T2h}, ScalabilityModeConfiguration{ScalabilityMode::kL2T2_KEY}, ScalabilityModeConfiguration{ScalabilityMode::kL2T2_KEY_SHIFT}, ScalabilityModeConfiguration{ScalabilityMode::kL2T3}, ScalabilityModeConfiguration{ScalabilityMode::kL2T3h}, ScalabilityModeConfiguration{ScalabilityMode::kL2T3_KEY}, ScalabilityModeConfiguration{ScalabilityMode::kL3T1}, ScalabilityModeConfiguration{ScalabilityMode::kL3T1h}, ScalabilityModeConfiguration{ScalabilityMode::kL3T1_KEY}, ScalabilityModeConfiguration{ScalabilityMode::kL3T2}, ScalabilityModeConfiguration{ScalabilityMode::kL3T2h}, ScalabilityModeConfiguration{ScalabilityMode::kL3T2_KEY}, ScalabilityModeConfiguration{ScalabilityMode::kL3T3}, ScalabilityModeConfiguration{ScalabilityMode::kL3T3h}, ScalabilityModeConfiguration{ScalabilityMode::kL3T3_KEY}, ScalabilityModeConfiguration{ScalabilityMode::kS2T1}, ScalabilityModeConfiguration{ScalabilityMode::kS2T1h}, ScalabilityModeConfiguration{ScalabilityMode::kS2T2}, ScalabilityModeConfiguration{ScalabilityMode::kS2T2h}, ScalabilityModeConfiguration{ScalabilityMode::kS2T3}, ScalabilityModeConfiguration{ScalabilityMode::kS2T3h}, ScalabilityModeConfiguration{ScalabilityMode::kS3T1}, ScalabilityModeConfiguration{ScalabilityMode::kS3T1h}, ScalabilityModeConfiguration{ScalabilityMode::kS3T2}, ScalabilityModeConfiguration{ScalabilityMode::kS3T2h}, ScalabilityModeConfiguration{ScalabilityMode::kS3T3}, ScalabilityModeConfiguration{ScalabilityMode::kS3T3h}, }; static_assert(std::size(kScalabilityModeConfigs) == kNumScalabilityModes); for (const auto& candidate_mode : kScalabilityModeConfigs) { if (candidate_mode.params == params) { return candidate_mode.scalability_mode; } } return absl::nullopt; } 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 == "L2T2h") return ScalabilityMode::kL2T2h; if (mode_string == "L2T2_KEY") return ScalabilityMode::kL2T2_KEY; if (mode_string == "L2T2_KEY_SHIFT") return ScalabilityMode::kL2T2_KEY_SHIFT; if (mode_string == "L2T3") return ScalabilityMode::kL2T3; if (mode_string == "L2T3h") return ScalabilityMode::kL2T3h; if (mode_string == "L2T3_KEY") return ScalabilityMode::kL2T3_KEY; if (mode_string == "L3T1") return ScalabilityMode::kL3T1; if (mode_string == "L3T1h") return ScalabilityMode::kL3T1h; if (mode_string == "L3T1_KEY") return ScalabilityMode::kL3T1_KEY; if (mode_string == "L3T2") return ScalabilityMode::kL3T2; if (mode_string == "L3T2h") return ScalabilityMode::kL3T2h; if (mode_string == "L3T2_KEY") return ScalabilityMode::kL3T2_KEY; if (mode_string == "L3T3") return ScalabilityMode::kL3T3; if (mode_string == "L3T3h") return ScalabilityMode::kL3T3h; if (mode_string == "L3T3_KEY") return ScalabilityMode::kL3T3_KEY; if (mode_string == "S2T1") return ScalabilityMode::kS2T1; if (mode_string == "S2T1h") return ScalabilityMode::kS2T1h; if (mode_string == "S2T2") return ScalabilityMode::kS2T2; if (mode_string == "S2T2h") return ScalabilityMode::kS2T2h; if (mode_string == "S2T3") return ScalabilityMode::kS2T3; if (mode_string == "S2T3h") return ScalabilityMode::kS2T3h; if (mode_string == "S3T1") return ScalabilityMode::kS3T1; if (mode_string == "S3T1h") return ScalabilityMode::kS3T1h; if (mode_string == "S3T2") return ScalabilityMode::kS3T2; if (mode_string == "S3T2h") return ScalabilityMode::kS3T2h; if (mode_string == "S3T3") return ScalabilityMode::kS3T3; if (mode_string == "S3T3h") return ScalabilityMode::kS3T3h; return absl::nullopt; } InterLayerPredMode ScalabilityModeToInterLayerPredMode( ScalabilityMode scalability_mode) { switch (scalability_mode) { case ScalabilityMode::kL1T1: case ScalabilityMode::kL1T2: case ScalabilityMode::kL1T3: case ScalabilityMode::kL2T1: case ScalabilityMode::kL2T1h: return InterLayerPredMode::kOn; case ScalabilityMode::kL2T1_KEY: return InterLayerPredMode::kOnKeyPic; case ScalabilityMode::kL2T2: case ScalabilityMode::kL2T2h: return InterLayerPredMode::kOn; case ScalabilityMode::kL2T2_KEY: case ScalabilityMode::kL2T2_KEY_SHIFT: return InterLayerPredMode::kOnKeyPic; case ScalabilityMode::kL2T3: case ScalabilityMode::kL2T3h: return InterLayerPredMode::kOn; case ScalabilityMode::kL2T3_KEY: return InterLayerPredMode::kOnKeyPic; case ScalabilityMode::kL3T1: case ScalabilityMode::kL3T1h: return InterLayerPredMode::kOn; case ScalabilityMode::kL3T1_KEY: return InterLayerPredMode::kOnKeyPic; case ScalabilityMode::kL3T2: case ScalabilityMode::kL3T2h: return InterLayerPredMode::kOn; case ScalabilityMode::kL3T2_KEY: return InterLayerPredMode::kOnKeyPic; case ScalabilityMode::kL3T3: case ScalabilityMode::kL3T3h: return InterLayerPredMode::kOn; case ScalabilityMode::kL3T3_KEY: return InterLayerPredMode::kOnKeyPic; case ScalabilityMode::kS2T1: case ScalabilityMode::kS2T1h: case ScalabilityMode::kS2T2: case ScalabilityMode::kS2T2h: case ScalabilityMode::kS2T3: case ScalabilityMode::kS2T3h: case ScalabilityMode::kS3T1: case ScalabilityMode::kS3T1h: case ScalabilityMode::kS3T2: case ScalabilityMode::kS3T2h: case ScalabilityMode::kS3T3: case ScalabilityMode::kS3T3h: return InterLayerPredMode::kOff; } RTC_CHECK_NOTREACHED(); } int ScalabilityModeToNumSpatialLayers(ScalabilityMode scalability_mode) { switch (scalability_mode) { case ScalabilityMode::kL1T1: case ScalabilityMode::kL1T2: case ScalabilityMode::kL1T3: return 1; case ScalabilityMode::kL2T1: case ScalabilityMode::kL2T1h: case ScalabilityMode::kL2T1_KEY: case ScalabilityMode::kL2T2: case ScalabilityMode::kL2T2h: case ScalabilityMode::kL2T2_KEY: case ScalabilityMode::kL2T2_KEY_SHIFT: case ScalabilityMode::kL2T3: case ScalabilityMode::kL2T3h: case ScalabilityMode::kL2T3_KEY: return 2; case ScalabilityMode::kL3T1: case ScalabilityMode::kL3T1h: case ScalabilityMode::kL3T1_KEY: case ScalabilityMode::kL3T2: case ScalabilityMode::kL3T2h: case ScalabilityMode::kL3T2_KEY: case ScalabilityMode::kL3T3: case ScalabilityMode::kL3T3h: case ScalabilityMode::kL3T3_KEY: return 3; case ScalabilityMode::kS2T1: case ScalabilityMode::kS2T1h: case ScalabilityMode::kS2T2: case ScalabilityMode::kS2T2h: case ScalabilityMode::kS2T3: case ScalabilityMode::kS2T3h: return 2; case ScalabilityMode::kS3T1: case ScalabilityMode::kS3T1h: case ScalabilityMode::kS3T2: case ScalabilityMode::kS3T2h: case ScalabilityMode::kS3T3: case ScalabilityMode::kS3T3h: return 3; } RTC_CHECK_NOTREACHED(); } int ScalabilityModeToNumTemporalLayers(ScalabilityMode scalability_mode) { switch (scalability_mode) { case ScalabilityMode::kL1T1: return 1; case ScalabilityMode::kL1T2: return 2; case ScalabilityMode::kL1T3: return 3; case ScalabilityMode::kL2T1: case ScalabilityMode::kL2T1h: case ScalabilityMode::kL2T1_KEY: return 1; case ScalabilityMode::kL2T2: case ScalabilityMode::kL2T2h: case ScalabilityMode::kL2T2_KEY: case ScalabilityMode::kL2T2_KEY_SHIFT: return 2; case ScalabilityMode::kL2T3: case ScalabilityMode::kL2T3h: case ScalabilityMode::kL2T3_KEY: return 3; case ScalabilityMode::kL3T1: case ScalabilityMode::kL3T1h: case ScalabilityMode::kL3T1_KEY: return 1; case ScalabilityMode::kL3T2: case ScalabilityMode::kL3T2h: case ScalabilityMode::kL3T2_KEY: return 2; case ScalabilityMode::kL3T3: case ScalabilityMode::kL3T3h: case ScalabilityMode::kL3T3_KEY: return 3; case ScalabilityMode::kS2T1: case ScalabilityMode::kS2T1h: case ScalabilityMode::kS3T1: case ScalabilityMode::kS3T1h: return 1; case ScalabilityMode::kS2T2: case ScalabilityMode::kS2T2h: case ScalabilityMode::kS3T2: case ScalabilityMode::kS3T2h: return 2; case ScalabilityMode::kS2T3: case ScalabilityMode::kS2T3h: case ScalabilityMode::kS3T3: case ScalabilityMode::kS3T3h: return 3; } RTC_CHECK_NOTREACHED(); } absl::optional ScalabilityModeToResolutionRatio( ScalabilityMode scalability_mode) { switch (scalability_mode) { case ScalabilityMode::kL1T1: case ScalabilityMode::kL1T2: case ScalabilityMode::kL1T3: return absl::nullopt; case ScalabilityMode::kL2T1: case ScalabilityMode::kL2T1_KEY: case ScalabilityMode::kL2T2: case ScalabilityMode::kL2T2_KEY: case ScalabilityMode::kL2T2_KEY_SHIFT: case ScalabilityMode::kL2T3: case ScalabilityMode::kL2T3_KEY: case ScalabilityMode::kL3T1: case ScalabilityMode::kL3T1_KEY: case ScalabilityMode::kL3T2: case ScalabilityMode::kL3T2_KEY: case ScalabilityMode::kL3T3: case ScalabilityMode::kL3T3_KEY: case ScalabilityMode::kS2T1: case ScalabilityMode::kS2T2: case ScalabilityMode::kS2T3: case ScalabilityMode::kS3T1: case ScalabilityMode::kS3T2: case ScalabilityMode::kS3T3: return ScalabilityModeResolutionRatio::kTwoToOne; case ScalabilityMode::kL2T1h: case ScalabilityMode::kL2T2h: case ScalabilityMode::kL2T3h: case ScalabilityMode::kL3T1h: case ScalabilityMode::kL3T2h: case ScalabilityMode::kL3T3h: case ScalabilityMode::kS2T1h: case ScalabilityMode::kS2T2h: case ScalabilityMode::kS2T3h: case ScalabilityMode::kS3T1h: case ScalabilityMode::kS3T2h: case ScalabilityMode::kS3T3h: return ScalabilityModeResolutionRatio::kThreeToTwo; } RTC_CHECK_NOTREACHED(); } ScalabilityMode LimitNumSpatialLayers(ScalabilityMode scalability_mode, int max_spatial_layers) { int num_spatial_layers = ScalabilityModeToNumSpatialLayers(scalability_mode); if (max_spatial_layers >= num_spatial_layers) { return scalability_mode; } switch (scalability_mode) { case ScalabilityMode::kL1T1: return ScalabilityMode::kL1T1; case ScalabilityMode::kL1T2: return ScalabilityMode::kL1T2; case ScalabilityMode::kL1T3: return ScalabilityMode::kL1T3; case ScalabilityMode::kL2T1: return ScalabilityMode::kL1T1; case ScalabilityMode::kL2T1h: return ScalabilityMode::kL1T1; case ScalabilityMode::kL2T1_KEY: return ScalabilityMode::kL1T1; case ScalabilityMode::kL2T2: return ScalabilityMode::kL1T2; case ScalabilityMode::kL2T2h: return ScalabilityMode::kL1T2; case ScalabilityMode::kL2T2_KEY: return ScalabilityMode::kL1T2; case ScalabilityMode::kL2T2_KEY_SHIFT: return ScalabilityMode::kL1T2; case ScalabilityMode::kL2T3: return ScalabilityMode::kL1T3; case ScalabilityMode::kL2T3h: return ScalabilityMode::kL1T3; case ScalabilityMode::kL2T3_KEY: return ScalabilityMode::kL1T3; case ScalabilityMode::kL3T1: return max_spatial_layers == 2 ? ScalabilityMode::kL2T1 : ScalabilityMode::kL1T1; case ScalabilityMode::kL3T1h: return max_spatial_layers == 2 ? ScalabilityMode::kL2T1h : ScalabilityMode::kL1T1; case ScalabilityMode::kL3T1_KEY: return max_spatial_layers == 2 ? ScalabilityMode::kL2T1_KEY : ScalabilityMode::kL1T1; case ScalabilityMode::kL3T2: return max_spatial_layers == 2 ? ScalabilityMode::kL2T2 : ScalabilityMode::kL1T2; case ScalabilityMode::kL3T2h: return max_spatial_layers == 2 ? ScalabilityMode::kL2T2h : ScalabilityMode::kL1T2; case ScalabilityMode::kL3T2_KEY: return max_spatial_layers == 2 ? ScalabilityMode::kL2T2_KEY : ScalabilityMode::kL1T2; case ScalabilityMode::kL3T3: return max_spatial_layers == 2 ? ScalabilityMode::kL2T3 : ScalabilityMode::kL1T3; case ScalabilityMode::kL3T3h: return max_spatial_layers == 2 ? ScalabilityMode::kL2T3h : ScalabilityMode::kL1T3; case ScalabilityMode::kL3T3_KEY: return max_spatial_layers == 2 ? ScalabilityMode::kL2T3_KEY : ScalabilityMode::kL1T3; case ScalabilityMode::kS2T1: return ScalabilityMode::kL1T1; case ScalabilityMode::kS2T1h: return ScalabilityMode::kL1T1; case ScalabilityMode::kS2T2: return ScalabilityMode::kL1T2; case ScalabilityMode::kS2T2h: return ScalabilityMode::kL1T2; case ScalabilityMode::kS2T3: return ScalabilityMode::kL1T3; case ScalabilityMode::kS2T3h: return ScalabilityMode::kL1T3; case ScalabilityMode::kS3T1: return max_spatial_layers == 2 ? ScalabilityMode::kS2T1 : ScalabilityMode::kL1T1; case ScalabilityMode::kS3T1h: return max_spatial_layers == 2 ? ScalabilityMode::kS2T1h : ScalabilityMode::kL1T1; case ScalabilityMode::kS3T2: return max_spatial_layers == 2 ? ScalabilityMode::kS2T2 : ScalabilityMode::kL1T2; case ScalabilityMode::kS3T2h: return max_spatial_layers == 2 ? ScalabilityMode::kS2T2h : ScalabilityMode::kL1T2; case ScalabilityMode::kS3T3: return max_spatial_layers == 2 ? ScalabilityMode::kS2T3 : ScalabilityMode::kL1T3; case ScalabilityMode::kS3T3h: return max_spatial_layers == 2 ? ScalabilityMode::kS2T3h : ScalabilityMode::kL1T3; } RTC_CHECK_NOTREACHED(); } bool ScalabilityModeIsShiftMode(ScalabilityMode scalability_mode) { return scalability_mode == ScalabilityMode::kL2T2_KEY_SHIFT; } } // namespace webrtc