Add support for VP9 configuration through scalability mode.
Bug: webrtc:13960 Change-Id: Ia930647b15f624a4d10d8d335519b69ffdae6636 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/260983 Commit-Queue: Åsa Persson <asapersson@webrtc.org> Reviewed-by: Niels Moller <nisse@webrtc.org> Reviewed-by: Sergey Silkin <ssilkin@webrtc.org> Cr-Commit-Position: refs/heads/main@{#36919}
This commit is contained in:
committed by
WebRTC LUCI CQ
parent
15a73be295
commit
cde992ddad
@ -745,9 +745,13 @@ rtc_library("webrtc_vp9_helpers") {
|
||||
"../../api/video:video_codec_constants",
|
||||
"../../api/video_codecs:video_codecs_api",
|
||||
"../../common_video",
|
||||
"../../media:rtc_media_base",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:logging",
|
||||
"../../rtc_base/experiments:stable_target_rate_experiment",
|
||||
"svc:scalability_mode_util",
|
||||
"svc:scalability_structures",
|
||||
"svc:scalable_video_controller",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/container:inlined_vector" ]
|
||||
}
|
||||
|
||||
@ -499,7 +499,7 @@ void LibvpxVp9Encoder::SetActiveSpatialLayers() {
|
||||
|
||||
void LibvpxVp9Encoder::SetRates(const RateControlParameters& parameters) {
|
||||
if (!inited_) {
|
||||
RTC_LOG(LS_WARNING) << "SetRates() calll while uninitialzied.";
|
||||
RTC_LOG(LS_WARNING) << "SetRates() called while uninitialized.";
|
||||
return;
|
||||
}
|
||||
if (encoder_->err) {
|
||||
@ -570,14 +570,32 @@ int LibvpxVp9Encoder::InitEncode(const VideoCodec* inst,
|
||||
force_key_frame_ = true;
|
||||
pics_since_key_ = 0;
|
||||
|
||||
num_spatial_layers_ = inst->VP9().numberOfSpatialLayers;
|
||||
RTC_DCHECK_GT(num_spatial_layers_, 0);
|
||||
num_temporal_layers_ = inst->VP9().numberOfTemporalLayers;
|
||||
if (num_temporal_layers_ == 0) {
|
||||
num_temporal_layers_ = 1;
|
||||
absl::optional<ScalabilityMode> scalability_mode = inst->GetScalabilityMode();
|
||||
if (scalability_mode.has_value()) {
|
||||
// Use settings from `ScalabilityMode` identifier.
|
||||
RTC_LOG(LS_INFO) << "Create scalability structure "
|
||||
<< ScalabilityModeToString(*scalability_mode);
|
||||
svc_controller_ = CreateScalabilityStructure(*scalability_mode);
|
||||
if (!svc_controller_) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to create scalability structure.";
|
||||
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
|
||||
}
|
||||
ScalableVideoController::StreamLayersConfig info =
|
||||
svc_controller_->StreamConfig();
|
||||
num_spatial_layers_ = info.num_spatial_layers;
|
||||
num_temporal_layers_ = info.num_temporal_layers;
|
||||
inter_layer_pred_ = ScalabilityModeToInterLayerPredMode(*scalability_mode);
|
||||
} else {
|
||||
num_spatial_layers_ = inst->VP9().numberOfSpatialLayers;
|
||||
RTC_DCHECK_GT(num_spatial_layers_, 0);
|
||||
num_temporal_layers_ = inst->VP9().numberOfTemporalLayers;
|
||||
if (num_temporal_layers_ == 0) {
|
||||
num_temporal_layers_ = 1;
|
||||
}
|
||||
inter_layer_pred_ = inst->VP9().interLayerPred;
|
||||
svc_controller_ = CreateVp9ScalabilityStructure(*inst);
|
||||
}
|
||||
|
||||
svc_controller_ = CreateVp9ScalabilityStructure(*inst);
|
||||
framerate_controller_ = std::vector<FramerateControllerDeprecated>(
|
||||
num_spatial_layers_, FramerateControllerDeprecated(codec_.maxFramerate));
|
||||
|
||||
@ -661,8 +679,6 @@ int LibvpxVp9Encoder::InitEncode(const VideoCodec* inst,
|
||||
|
||||
is_flexible_mode_ = inst->VP9().flexibleMode;
|
||||
|
||||
inter_layer_pred_ = inst->VP9().interLayerPred;
|
||||
|
||||
if (num_spatial_layers_ > 1 &&
|
||||
codec_.mode == VideoCodecMode::kScreensharing && !is_flexible_mode_) {
|
||||
RTC_LOG(LS_ERROR) << "Flexible mode is required for screenshare with "
|
||||
|
||||
@ -12,9 +12,13 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "media/base/video_common.h"
|
||||
#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
|
||||
#include "modules/video_coding/svc/create_scalability_structure.h"
|
||||
#include "modules/video_coding/svc/scalability_mode_util.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
@ -29,6 +33,19 @@ const size_t kMinScreenSharingLayerBitrateKbps[] = {30, 200, 500};
|
||||
const size_t kTargetScreenSharingLayerBitrateKbps[] = {150, 350, 950};
|
||||
const size_t kMaxScreenSharingLayerBitrateKbps[] = {250, 500, 950};
|
||||
|
||||
// Gets limited number of layers for given resolution.
|
||||
size_t GetLimitedNumSpatialLayers(size_t width, size_t height) {
|
||||
const bool is_landscape = width >= height;
|
||||
const size_t min_width = is_landscape ? kMinVp9SpatialLayerLongSideLength
|
||||
: kMinVp9SpatialLayerShortSideLength;
|
||||
const size_t min_height = is_landscape ? kMinVp9SpatialLayerShortSideLength
|
||||
: kMinVp9SpatialLayerLongSideLength;
|
||||
const size_t num_layers_fit_horz = static_cast<size_t>(
|
||||
std::floor(1 + std::max(0.0f, std::log2(1.0f * width / min_width))));
|
||||
const size_t num_layers_fit_vert = static_cast<size_t>(
|
||||
std::floor(1 + std::max(0.0f, std::log2(1.0f * height / min_height))));
|
||||
return std::min(num_layers_fit_horz, num_layers_fit_vert);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::vector<SpatialLayer> ConfigureSvcScreenSharing(size_t input_width,
|
||||
@ -59,27 +76,19 @@ std::vector<SpatialLayer> ConfigureSvcScreenSharing(size_t input_width,
|
||||
return spatial_layers;
|
||||
}
|
||||
|
||||
std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
|
||||
size_t input_height,
|
||||
float max_framerate_fps,
|
||||
size_t first_active_layer,
|
||||
size_t num_spatial_layers,
|
||||
size_t num_temporal_layers) {
|
||||
std::vector<SpatialLayer> ConfigureSvcNormalVideo(
|
||||
size_t input_width,
|
||||
size_t input_height,
|
||||
float max_framerate_fps,
|
||||
size_t first_active_layer,
|
||||
size_t num_spatial_layers,
|
||||
size_t num_temporal_layers,
|
||||
absl::optional<ScalableVideoController::StreamLayersConfig> config) {
|
||||
RTC_DCHECK_LT(first_active_layer, num_spatial_layers);
|
||||
std::vector<SpatialLayer> spatial_layers;
|
||||
|
||||
// Limit number of layers for given resolution.
|
||||
const bool is_landscape = input_width >= input_height;
|
||||
const size_t min_width = is_landscape ? kMinVp9SpatialLayerLongSideLength
|
||||
: kMinVp9SpatialLayerShortSideLength;
|
||||
const size_t min_height = is_landscape ? kMinVp9SpatialLayerShortSideLength
|
||||
: kMinVp9SpatialLayerLongSideLength;
|
||||
const size_t num_layers_fit_horz = static_cast<size_t>(std::floor(
|
||||
1 + std::max(0.0f, std::log2(1.0f * input_width / min_width))));
|
||||
const size_t num_layers_fit_vert = static_cast<size_t>(std::floor(
|
||||
1 + std::max(0.0f, std::log2(1.0f * input_height / min_height))));
|
||||
const size_t limited_num_spatial_layers =
|
||||
std::min(num_layers_fit_horz, num_layers_fit_vert);
|
||||
size_t limited_num_spatial_layers =
|
||||
GetLimitedNumSpatialLayers(input_width, input_height);
|
||||
if (limited_num_spatial_layers < num_spatial_layers) {
|
||||
RTC_LOG(LS_WARNING) << "Reducing number of spatial layers from "
|
||||
<< num_spatial_layers << " to "
|
||||
@ -87,14 +96,23 @@ std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
|
||||
<< " due to low input resolution.";
|
||||
num_spatial_layers = limited_num_spatial_layers;
|
||||
}
|
||||
|
||||
// First active layer must be configured.
|
||||
num_spatial_layers = std::max(num_spatial_layers, first_active_layer + 1);
|
||||
|
||||
// Ensure top layer is even enough.
|
||||
int required_divisiblity = 1 << (num_spatial_layers - first_active_layer - 1);
|
||||
if (config) {
|
||||
required_divisiblity = 1;
|
||||
for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) {
|
||||
required_divisiblity = cricket::LeastCommonMultiple(
|
||||
required_divisiblity, config->scaling_factor_den[sl_idx]);
|
||||
}
|
||||
}
|
||||
input_width = input_width - input_width % required_divisiblity;
|
||||
input_height = input_height - input_height % required_divisiblity;
|
||||
|
||||
std::vector<SpatialLayer> spatial_layers;
|
||||
for (size_t sl_idx = first_active_layer; sl_idx < num_spatial_layers;
|
||||
++sl_idx) {
|
||||
SpatialLayer spatial_layer = {0};
|
||||
@ -104,6 +122,13 @@ std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
|
||||
spatial_layer.numberOfTemporalLayers = num_temporal_layers;
|
||||
spatial_layer.active = true;
|
||||
|
||||
if (config) {
|
||||
spatial_layer.width = input_width * config->scaling_factor_num[sl_idx] /
|
||||
config->scaling_factor_den[sl_idx];
|
||||
spatial_layer.height = input_height * config->scaling_factor_num[sl_idx] /
|
||||
config->scaling_factor_den[sl_idx];
|
||||
}
|
||||
|
||||
// minBitrate and maxBitrate formulas were derived from
|
||||
// subjective-quality data to determing bit rates below which video
|
||||
// quality is unacceptable and above which additional bits do not provide
|
||||
@ -124,7 +149,7 @@ std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
|
||||
spatial_layers.push_back(spatial_layer);
|
||||
}
|
||||
|
||||
// A workaround for sitiation when single HD layer is left with minBitrate
|
||||
// A workaround for situation when single HD layer is left with minBitrate
|
||||
// about 500kbps. This would mean that there will always be at least 500kbps
|
||||
// allocated to video regardless of how low is the actual BWE.
|
||||
// Also, boost maxBitrate for the first layer to account for lost ability to
|
||||
@ -140,13 +165,58 @@ std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
|
||||
return spatial_layers;
|
||||
}
|
||||
|
||||
std::vector<SpatialLayer> GetSvcConfig(size_t input_width,
|
||||
size_t input_height,
|
||||
float max_framerate_fps,
|
||||
size_t first_active_layer,
|
||||
size_t num_spatial_layers,
|
||||
size_t num_temporal_layers,
|
||||
bool is_screen_sharing) {
|
||||
// Uses scalability mode to configure spatial layers.
|
||||
std::vector<SpatialLayer> GetVp9SvcConfig(VideoCodec& codec) {
|
||||
RTC_DCHECK_EQ(codec.codecType, kVideoCodecVP9);
|
||||
|
||||
absl::optional<ScalabilityMode> scalability_mode = codec.GetScalabilityMode();
|
||||
RTC_DCHECK(scalability_mode.has_value());
|
||||
|
||||
absl::optional<ScalableVideoController::StreamLayersConfig> info =
|
||||
ScalabilityStructureConfig(*scalability_mode);
|
||||
if (!info.has_value()) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to create structure "
|
||||
<< ScalabilityModeToString(*scalability_mode);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (static_cast<int>(GetLimitedNumSpatialLayers(codec.width, codec.height)) <
|
||||
info->num_spatial_layers) {
|
||||
// Layers will be reduced, do not use scalability mode for now.
|
||||
// TODO(bugs.webrtc.org/11607): Use a lower scalability mode once all lower
|
||||
// modes are supported.
|
||||
codec.UnsetScalabilityMode();
|
||||
codec.VP9()->interLayerPred =
|
||||
ScalabilityModeToInterLayerPredMode(*scalability_mode);
|
||||
}
|
||||
|
||||
// TODO(bugs.webrtc.org/11607): Add support for screensharing.
|
||||
std::vector<SpatialLayer> spatial_layers =
|
||||
GetSvcConfig(codec.width, codec.height, codec.maxFramerate,
|
||||
/*first_active_layer=*/0, info->num_spatial_layers,
|
||||
info->num_temporal_layers, /*is_screen_sharing=*/false,
|
||||
codec.GetScalabilityMode() ? info : absl::nullopt);
|
||||
RTC_DCHECK(!spatial_layers.empty());
|
||||
|
||||
// Use codec bitrate limits if spatial layering is not requested.
|
||||
if (info->num_spatial_layers == 1) {
|
||||
spatial_layers.back().minBitrate = codec.minBitrate;
|
||||
spatial_layers.back().targetBitrate = codec.maxBitrate;
|
||||
spatial_layers.back().maxBitrate = codec.maxBitrate;
|
||||
}
|
||||
|
||||
return spatial_layers;
|
||||
}
|
||||
|
||||
std::vector<SpatialLayer> GetSvcConfig(
|
||||
size_t input_width,
|
||||
size_t input_height,
|
||||
float max_framerate_fps,
|
||||
size_t first_active_layer,
|
||||
size_t num_spatial_layers,
|
||||
size_t num_temporal_layers,
|
||||
bool is_screen_sharing,
|
||||
absl::optional<ScalableVideoController::StreamLayersConfig> config) {
|
||||
RTC_DCHECK_GT(input_width, 0);
|
||||
RTC_DCHECK_GT(input_height, 0);
|
||||
RTC_DCHECK_GT(num_spatial_layers, 0);
|
||||
@ -158,7 +228,7 @@ std::vector<SpatialLayer> GetSvcConfig(size_t input_width,
|
||||
} else {
|
||||
return ConfigureSvcNormalVideo(input_width, input_height, max_framerate_fps,
|
||||
first_active_layer, num_spatial_layers,
|
||||
num_temporal_layers);
|
||||
num_temporal_layers, config);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,16 +15,24 @@
|
||||
#include <vector>
|
||||
|
||||
#include "api/video_codecs/spatial_layer.h"
|
||||
#include "api/video_codecs/video_codec.h"
|
||||
#include "modules/video_coding/svc/scalable_video_controller.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
std::vector<SpatialLayer> GetSvcConfig(size_t input_width,
|
||||
size_t input_height,
|
||||
float max_framerate_fps,
|
||||
size_t first_active_layer,
|
||||
size_t num_spatial_layers,
|
||||
size_t num_temporal_layers,
|
||||
bool is_screen_sharing);
|
||||
// Uses scalability mode to configure spatial layers.
|
||||
std::vector<SpatialLayer> GetVp9SvcConfig(VideoCodec& video_codec);
|
||||
|
||||
std::vector<SpatialLayer> GetSvcConfig(
|
||||
size_t input_width,
|
||||
size_t input_height,
|
||||
float max_framerate_fps,
|
||||
size_t first_active_layer,
|
||||
size_t num_spatial_layers,
|
||||
size_t num_temporal_layers,
|
||||
bool is_screen_sharing,
|
||||
absl::optional<ScalableVideoController::StreamLayersConfig> config =
|
||||
absl::nullopt);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@ -14,8 +14,12 @@
|
||||
#include <vector>
|
||||
|
||||
#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Field;
|
||||
|
||||
namespace webrtc {
|
||||
TEST(SvcConfig, NumSpatialLayers) {
|
||||
const size_t max_num_spatial_layers = 6;
|
||||
@ -43,6 +47,92 @@ TEST(SvcConfig, NumSpatialLayersPortrait) {
|
||||
EXPECT_EQ(spatial_layers.size(), num_spatial_layers);
|
||||
}
|
||||
|
||||
TEST(SvcConfig, NumSpatialLayersWithScalabilityMode) {
|
||||
VideoCodec codec;
|
||||
codec.codecType = kVideoCodecVP9;
|
||||
codec.width = 960;
|
||||
codec.height = 540;
|
||||
codec.SetScalabilityMode(ScalabilityMode::kL3T3_KEY);
|
||||
|
||||
std::vector<SpatialLayer> spatial_layers = GetVp9SvcConfig(codec);
|
||||
EXPECT_THAT(spatial_layers, ElementsAre(Field(&SpatialLayer::height, 135),
|
||||
Field(&SpatialLayer::height, 270),
|
||||
Field(&SpatialLayer::height, 540)));
|
||||
EXPECT_THAT(spatial_layers,
|
||||
ElementsAre(Field(&SpatialLayer::numberOfTemporalLayers, 3),
|
||||
Field(&SpatialLayer::numberOfTemporalLayers, 3),
|
||||
Field(&SpatialLayer::numberOfTemporalLayers, 3)));
|
||||
EXPECT_EQ(codec.GetScalabilityMode(), ScalabilityMode::kL3T3_KEY);
|
||||
}
|
||||
|
||||
TEST(SvcConfig, NumSpatialLayersLimitedWithScalabilityMode) {
|
||||
VideoCodec codec;
|
||||
codec.codecType = kVideoCodecVP9;
|
||||
codec.width = 480;
|
||||
codec.height = 270;
|
||||
codec.SetScalabilityMode(ScalabilityMode::kL3T3_KEY);
|
||||
|
||||
// Scalability mode reset, configuration should be in accordance to L2T3_KEY.
|
||||
std::vector<SpatialLayer> spatial_layers = GetVp9SvcConfig(codec);
|
||||
EXPECT_THAT(spatial_layers, ElementsAre(Field(&SpatialLayer::height, 135),
|
||||
Field(&SpatialLayer::height, 270)));
|
||||
EXPECT_THAT(spatial_layers,
|
||||
ElementsAre(Field(&SpatialLayer::numberOfTemporalLayers, 3),
|
||||
Field(&SpatialLayer::numberOfTemporalLayers, 3)));
|
||||
EXPECT_EQ(codec.VP9()->interLayerPred, InterLayerPredMode::kOnKeyPic);
|
||||
EXPECT_EQ(codec.GetScalabilityMode(), absl::nullopt);
|
||||
}
|
||||
|
||||
TEST(SvcConfig, NumSpatialLayersLimitedWithScalabilityModePortrait) {
|
||||
VideoCodec codec;
|
||||
codec.codecType = kVideoCodecVP9;
|
||||
codec.width = 270;
|
||||
codec.height = 480;
|
||||
codec.SetScalabilityMode(ScalabilityMode::kL3T1);
|
||||
|
||||
// Scalability mode reset, configuration should be in accordance to L2T1.
|
||||
std::vector<SpatialLayer> spatial_layers = GetVp9SvcConfig(codec);
|
||||
EXPECT_THAT(spatial_layers, ElementsAre(Field(&SpatialLayer::width, 135),
|
||||
Field(&SpatialLayer::width, 270)));
|
||||
EXPECT_THAT(spatial_layers,
|
||||
ElementsAre(Field(&SpatialLayer::numberOfTemporalLayers, 1),
|
||||
Field(&SpatialLayer::numberOfTemporalLayers, 1)));
|
||||
EXPECT_EQ(codec.VP9()->interLayerPred, InterLayerPredMode::kOn);
|
||||
EXPECT_EQ(codec.GetScalabilityMode(), absl::nullopt);
|
||||
}
|
||||
|
||||
TEST(SvcConfig, NumSpatialLayersWithScalabilityModeResolutionRatio1_5) {
|
||||
VideoCodec codec;
|
||||
codec.codecType = kVideoCodecVP9;
|
||||
codec.width = 270;
|
||||
codec.height = 480;
|
||||
codec.SetScalabilityMode(ScalabilityMode::kL2T1h); // 1.5:1
|
||||
|
||||
std::vector<SpatialLayer> spatial_layers = GetVp9SvcConfig(codec);
|
||||
EXPECT_THAT(spatial_layers, ElementsAre(Field(&SpatialLayer::width, 180),
|
||||
Field(&SpatialLayer::width, 270)));
|
||||
EXPECT_THAT(spatial_layers,
|
||||
ElementsAre(Field(&SpatialLayer::numberOfTemporalLayers, 1),
|
||||
Field(&SpatialLayer::numberOfTemporalLayers, 1)));
|
||||
EXPECT_EQ(codec.GetScalabilityMode(), ScalabilityMode::kL2T1h);
|
||||
}
|
||||
|
||||
TEST(SvcConfig, NumSpatialLayersLimitedWithScalabilityModeResolutionRatio1_5) {
|
||||
VideoCodec codec;
|
||||
codec.codecType = kVideoCodecVP9;
|
||||
codec.width = 320;
|
||||
codec.height = 180;
|
||||
codec.SetScalabilityMode(ScalabilityMode::kL2T1h); // 1.5:1
|
||||
|
||||
// Scalability mode reset, configuration should be in accordance to L1T1.
|
||||
std::vector<SpatialLayer> spatial_layers = GetVp9SvcConfig(codec);
|
||||
EXPECT_THAT(spatial_layers, ElementsAre(Field(&SpatialLayer::width, 320)));
|
||||
EXPECT_THAT(spatial_layers,
|
||||
ElementsAre(Field(&SpatialLayer::numberOfTemporalLayers, 1)));
|
||||
EXPECT_EQ(codec.VP9()->interLayerPred, InterLayerPredMode::kOn);
|
||||
EXPECT_EQ(codec.GetScalabilityMode(), absl::nullopt);
|
||||
}
|
||||
|
||||
TEST(SvcConfig, AlwaysSendsAtLeastOneLayer) {
|
||||
const size_t max_num_spatial_layers = 6;
|
||||
const size_t first_active_layer = 5;
|
||||
@ -91,6 +181,44 @@ TEST(SvcConfig, EnforcesMinimalRequiredParity) {
|
||||
EXPECT_EQ(spatial_layers.back().width, kOddSize);
|
||||
}
|
||||
|
||||
TEST(SvcConfig, EnforcesMinimalRequiredParityWithScalabilityMode) {
|
||||
VideoCodec codec;
|
||||
codec.codecType = kVideoCodecVP9;
|
||||
codec.width = 1023;
|
||||
codec.height = 1023;
|
||||
codec.SetScalabilityMode(ScalabilityMode::kL3T1);
|
||||
|
||||
std::vector<SpatialLayer> spatial_layers = GetVp9SvcConfig(codec);
|
||||
EXPECT_THAT(spatial_layers, // Divisiblity by 4 required.
|
||||
ElementsAre(Field(&SpatialLayer::width, 255),
|
||||
Field(&SpatialLayer::width, 510),
|
||||
Field(&SpatialLayer::width, 1020)));
|
||||
|
||||
codec.SetScalabilityMode(ScalabilityMode::kL2T1);
|
||||
spatial_layers = GetVp9SvcConfig(codec);
|
||||
EXPECT_THAT(spatial_layers, // Divisiblity by 2 required.
|
||||
ElementsAre(Field(&SpatialLayer::width, 511),
|
||||
Field(&SpatialLayer::width, 1022)));
|
||||
|
||||
codec.SetScalabilityMode(ScalabilityMode::kL1T1);
|
||||
spatial_layers = GetVp9SvcConfig(codec);
|
||||
EXPECT_THAT(spatial_layers, // Divisiblity by 1 required.
|
||||
ElementsAre(Field(&SpatialLayer::width, 1023)));
|
||||
}
|
||||
|
||||
TEST(SvcConfig, EnforcesMinimalRequiredParityWithScalabilityModeResRatio1_5) {
|
||||
VideoCodec codec;
|
||||
codec.codecType = kVideoCodecVP9;
|
||||
codec.width = 1280;
|
||||
codec.height = 1280;
|
||||
codec.SetScalabilityMode(ScalabilityMode::kL2T1h); // 1.5:1
|
||||
|
||||
std::vector<SpatialLayer> spatial_layers = GetVp9SvcConfig(codec);
|
||||
EXPECT_THAT(spatial_layers, // Divisiblity by 3 required.
|
||||
ElementsAre(Field(&SpatialLayer::width, 852),
|
||||
Field(&SpatialLayer::width, 1278)));
|
||||
}
|
||||
|
||||
TEST(SvcConfig, SkipsInactiveLayers) {
|
||||
const size_t num_spatial_layers = 4;
|
||||
const size_t first_active_layer = 2;
|
||||
@ -121,6 +249,25 @@ TEST(SvcConfig, BitrateThresholds) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SvcConfig, BitrateThresholdsWithScalabilityMode) {
|
||||
VideoCodec codec;
|
||||
codec.codecType = kVideoCodecVP9;
|
||||
codec.width = 960;
|
||||
codec.height = 540;
|
||||
codec.SetScalabilityMode(ScalabilityMode::kS3T3);
|
||||
|
||||
std::vector<SpatialLayer> spatial_layers = GetVp9SvcConfig(codec);
|
||||
EXPECT_THAT(spatial_layers, ElementsAre(Field(&SpatialLayer::height, 135),
|
||||
Field(&SpatialLayer::height, 270),
|
||||
Field(&SpatialLayer::height, 540)));
|
||||
|
||||
for (const SpatialLayer& layer : spatial_layers) {
|
||||
EXPECT_LE(layer.minBitrate, layer.maxBitrate);
|
||||
EXPECT_LE(layer.minBitrate, layer.targetBitrate);
|
||||
EXPECT_LE(layer.targetBitrate, layer.maxBitrate);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SvcConfig, ScreenSharing) {
|
||||
std::vector<SpatialLayer> spatial_layers =
|
||||
GetSvcConfig(1920, 1080, 30, 1, 3, 3, true);
|
||||
|
||||
@ -15,6 +15,7 @@ rtc_source_set("scalability_mode_util") {
|
||||
]
|
||||
deps = [
|
||||
"../../../api/video_codecs:scalability_mode",
|
||||
"../../../api/video_codecs:video_codecs_api",
|
||||
"../../../rtc_base:checks",
|
||||
]
|
||||
absl_deps = [
|
||||
|
||||
@ -139,6 +139,52 @@ absl::string_view ScalabilityModeToString(ScalabilityMode scalability_mode) {
|
||||
RTC_CHECK_NOTREACHED();
|
||||
}
|
||||
|
||||
InterLayerPredMode ScalabilityModeToInterLayerPredMode(
|
||||
ScalabilityMode scalability_mode) {
|
||||
switch (scalability_mode) {
|
||||
case ScalabilityMode::kL1T1:
|
||||
case ScalabilityMode::kL1T2:
|
||||
case ScalabilityMode::kL1T2h:
|
||||
case ScalabilityMode::kL1T3:
|
||||
case ScalabilityMode::kL1T3h:
|
||||
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::kS3T3:
|
||||
return InterLayerPredMode::kOff;
|
||||
}
|
||||
RTC_CHECK_NOTREACHED();
|
||||
}
|
||||
|
||||
int ScalabilityModeToNumSpatialLayers(ScalabilityMode scalability_mode) {
|
||||
switch (scalability_mode) {
|
||||
case ScalabilityMode::kL1T1:
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#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"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -22,6 +23,9 @@ absl::optional<ScalabilityMode> ScalabilityModeFromString(
|
||||
|
||||
absl::string_view ScalabilityModeToString(ScalabilityMode scalability_mode);
|
||||
|
||||
InterLayerPredMode ScalabilityModeToInterLayerPredMode(
|
||||
ScalabilityMode scalability_mode);
|
||||
|
||||
int ScalabilityModeToNumSpatialLayers(ScalabilityMode scalability_mode);
|
||||
|
||||
int ScalabilityModeToNumTemporalLayers(ScalabilityMode scalability_mode);
|
||||
|
||||
@ -231,6 +231,11 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec(
|
||||
if (!config.spatial_layers.empty()) {
|
||||
// Layering is set explicitly.
|
||||
spatial_layers = config.spatial_layers;
|
||||
} else if (scalability_mode.has_value()) {
|
||||
// Layering is set via scalability mode.
|
||||
spatial_layers = GetVp9SvcConfig(video_codec);
|
||||
if (spatial_layers.empty())
|
||||
break;
|
||||
} else {
|
||||
size_t first_active_layer = 0;
|
||||
for (size_t spatial_idx = 0;
|
||||
|
||||
Reference in New Issue
Block a user