Make it possible to set spatial layer bitrates explicitly

Bug: webrtc:14852
Change-Id: Ie41d4223d0d5aef5a79f7e6067f0855f022ed428
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/335361
Auto-Submit: Sergey Silkin <ssilkin@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41698}
This commit is contained in:
Sergey Silkin 2024-02-06 15:44:02 +01:00 committed by WebRTC LUCI CQ
parent 974044efca
commit 6432970fe9
2 changed files with 237 additions and 50 deletions

View File

@ -1111,8 +1111,6 @@ class Encoder : public EncodedImageCallback {
int result = encoder_->InitEncode(&vc, ves);
RTC_CHECK(result == WEBRTC_VIDEO_CODEC_OK);
SetRates(es);
}
void SetRates(const EncodingSettings& es) {
@ -1261,6 +1259,29 @@ void ConfigureSimulcast(VideoCodec* vc) {
}
}
void SetDefaultCodecSpecificSettings(VideoCodec* vc, int num_temporal_layers) {
switch (vc->codecType) {
case kVideoCodecVP8:
*(vc->VP8()) = VideoEncoder::GetDefaultVp8Settings();
vc->VP8()->SetNumberOfTemporalLayers(num_temporal_layers);
break;
case kVideoCodecVP9: {
*(vc->VP9()) = VideoEncoder::GetDefaultVp9Settings();
vc->VP9()->SetNumberOfTemporalLayers(num_temporal_layers);
} break;
case kVideoCodecH264: {
*(vc->H264()) = VideoEncoder::GetDefaultH264Settings();
vc->H264()->SetNumberOfTemporalLayers(num_temporal_layers);
} break;
case kVideoCodecAV1:
case kVideoCodecH265:
break;
case kVideoCodecGeneric:
case kVideoCodecMultiplex:
RTC_CHECK_NOTREACHED();
}
}
std::tuple<std::vector<DataRate>, ScalabilityMode>
SplitBitrateAndUpdateScalabilityMode(std::string codec_type,
ScalabilityMode scalability_mode,
@ -1272,11 +1293,11 @@ SplitBitrateAndUpdateScalabilityMode(std::string codec_type,
int num_temporal_layers =
ScalabilityModeToNumTemporalLayers(scalability_mode);
if (bitrates_kbps.size() > 1 ||
(num_spatial_layers == 1 && num_temporal_layers == 1)) {
RTC_CHECK(bitrates_kbps.size() ==
static_cast<size_t>(num_spatial_layers * num_temporal_layers))
<< "bitrates must be provided for all layers";
int num_bitrates = static_cast<int>(bitrates_kbps.size());
RTC_CHECK(num_bitrates == 1 || num_bitrates == num_spatial_layers ||
num_bitrates == num_spatial_layers * num_temporal_layers);
if (num_bitrates == num_spatial_layers * num_temporal_layers) {
std::vector<DataRate> bitrates;
for (const auto& bitrate_kbps : bitrates_kbps) {
bitrates.push_back(DataRate::KilobitsPerSec(bitrate_kbps));
@ -1284,59 +1305,93 @@ SplitBitrateAndUpdateScalabilityMode(std::string codec_type,
return std::make_tuple(bitrates, scalability_mode);
}
int total_bitrate_kbps =
std::accumulate(bitrates_kbps.begin(), bitrates_kbps.end(), 0);
VideoCodec vc;
vc.codecType = PayloadStringToCodecType(codec_type);
vc.width = width;
vc.height = height;
vc.startBitrate = bitrates_kbps.front();
vc.maxBitrate = bitrates_kbps.front();
vc.startBitrate = total_bitrate_kbps;
vc.maxBitrate = total_bitrate_kbps;
vc.minBitrate = 0;
vc.maxFramerate = static_cast<uint32_t>(framerate_fps);
vc.numberOfSimulcastStreams = 0;
vc.mode = webrtc::VideoCodecMode::kRealtimeVideo;
vc.SetScalabilityMode(scalability_mode);
SetDefaultCodecSpecificSettings(&vc, num_temporal_layers);
switch (vc.codecType) {
case kVideoCodecVP8:
// TODO(webrtc:14852): Configure simulcast.
*(vc.VP8()) = VideoEncoder::GetDefaultVp8Settings();
vc.VP8()->SetNumberOfTemporalLayers(num_temporal_layers);
ConfigureSimulcast(&vc);
break;
case kVideoCodecVP9: {
*(vc.VP9()) = VideoEncoder::GetDefaultVp9Settings();
vc.VP9()->SetNumberOfTemporalLayers(num_temporal_layers);
const std::vector<SpatialLayer> spatialLayers = GetVp9SvcConfig(vc);
for (size_t i = 0; i < spatialLayers.size(); ++i) {
vc.spatialLayers[i] = spatialLayers[i];
vc.spatialLayers[i].active = true;
}
} break;
case kVideoCodecAV1: {
bool result =
SetAv1SvcConfig(vc, num_spatial_layers, num_temporal_layers);
RTC_CHECK(result) << "SetAv1SvcConfig failed";
} break;
case kVideoCodecH264: {
*(vc.H264()) = VideoEncoder::GetDefaultH264Settings();
vc.H264()->SetNumberOfTemporalLayers(num_temporal_layers);
ConfigureSimulcast(&vc);
} break;
case kVideoCodecH265:
break;
case kVideoCodecGeneric:
case kVideoCodecMultiplex:
RTC_CHECK_NOTREACHED();
}
if (num_bitrates == num_spatial_layers) {
switch (vc.codecType) {
case kVideoCodecVP8:
case kVideoCodecH264:
case kVideoCodecH265:
vc.numberOfSimulcastStreams = num_spatial_layers;
for (int sidx = 0; sidx < num_spatial_layers; ++sidx) {
SimulcastStream* ss = &vc.simulcastStream[sidx];
ss->width = width >> (num_spatial_layers - sidx - 1);
ss->height = height >> (num_spatial_layers - sidx - 1);
ss->maxFramerate = vc.maxFramerate;
ss->numberOfTemporalLayers = num_temporal_layers;
ss->maxBitrate = bitrates_kbps[sidx];
ss->targetBitrate = bitrates_kbps[sidx];
ss->minBitrate = 0;
ss->qpMax = 0;
ss->active = true;
}
break;
case kVideoCodecVP9:
case kVideoCodecAV1:
for (int sidx = num_spatial_layers - 1; sidx >= 0; --sidx) {
SpatialLayer* ss = &vc.spatialLayers[sidx];
ss->width = width >> (num_spatial_layers - sidx - 1);
ss->height = height >> (num_spatial_layers - sidx - 1);
ss->maxFramerate = vc.maxFramerate;
ss->numberOfTemporalLayers = num_temporal_layers;
ss->maxBitrate = bitrates_kbps[sidx];
ss->targetBitrate = bitrates_kbps[sidx];
ss->minBitrate = 0;
ss->qpMax = 0;
ss->active = true;
}
break;
case kVideoCodecGeneric:
case kVideoCodecMultiplex:
RTC_CHECK_NOTREACHED();
}
} else {
switch (vc.codecType) {
case kVideoCodecVP8:
case kVideoCodecH264:
case kVideoCodecH265:
ConfigureSimulcast(&vc);
break;
case kVideoCodecVP9: {
const std::vector<SpatialLayer> spatialLayers = GetVp9SvcConfig(vc);
for (size_t i = 0; i < spatialLayers.size(); ++i) {
vc.spatialLayers[i] = spatialLayers[i];
vc.spatialLayers[i].active = true;
}
} break;
case kVideoCodecAV1: {
bool result =
SetAv1SvcConfig(vc, num_spatial_layers, num_temporal_layers);
RTC_CHECK(result) << "SetAv1SvcConfig failed";
} break;
case kVideoCodecGeneric:
case kVideoCodecMultiplex:
RTC_CHECK_NOTREACHED();
}
if (*vc.GetScalabilityMode() != scalability_mode) {
RTC_LOG(LS_WARNING) << "Scalability mode changed from "
<< ScalabilityModeToString(scalability_mode) << " to "
<< ScalabilityModeToString(*vc.GetScalabilityMode());
num_spatial_layers =
ScalabilityModeToNumSpatialLayers(*vc.GetScalabilityMode());
num_temporal_layers =
ScalabilityModeToNumTemporalLayers(*vc.GetScalabilityMode());
if (*vc.GetScalabilityMode() != scalability_mode) {
RTC_LOG(LS_WARNING) << "Scalability mode changed from "
<< ScalabilityModeToString(scalability_mode) << " to "
<< ScalabilityModeToString(*vc.GetScalabilityMode());
num_spatial_layers =
ScalabilityModeToNumSpatialLayers(*vc.GetScalabilityMode());
num_temporal_layers =
ScalabilityModeToNumTemporalLayers(*vc.GetScalabilityMode());
}
}
std::unique_ptr<VideoBitrateAllocator> bitrate_allocator =
@ -1344,7 +1399,7 @@ SplitBitrateAndUpdateScalabilityMode(std::string codec_type,
vc);
VideoBitrateAllocation bitrate_allocation =
bitrate_allocator->Allocate(VideoBitrateAllocationParameters(
1000 * bitrates_kbps.front(), framerate_fps));
1000 * total_bitrate_kbps, framerate_fps));
std::vector<DataRate> bitrates;
for (int sidx = 0; sidx < num_spatial_layers; ++sidx) {

View File

@ -675,5 +675,137 @@ INSTANTIATE_TEST_SUITE_P(
std::make_tuple(PacingSettings{.mode = PacingMode::kConstantRate,
.constant_rate = Frequency::Hertz(20)},
/*expected_delta_ms=*/50)));
struct EncodingSettingsTestParameters {
std::string codec_type;
std::string scalability_mode;
std::vector<int> bitrate_kbps;
std::vector<int> expected_bitrate_kbps;
};
class VideoCodecTesterTestEncodingSettings
: public ::testing::TestWithParam<EncodingSettingsTestParameters> {};
TEST_P(VideoCodecTesterTestEncodingSettings, CreateEncodingSettings) {
EncodingSettingsTestParameters test_params = GetParam();
std::map<uint32_t, EncodingSettings> encoding_settings =
VideoCodecTester::CreateEncodingSettings(
test_params.codec_type, test_params.scalability_mode, /*width=*/1280,
/*height=*/720, test_params.bitrate_kbps, /*framerate_fps=*/30,
/*num_frames=*/1);
ASSERT_THAT(encoding_settings, SizeIs(1));
const std::map<LayerId, LayerSettings>& layers_settings =
encoding_settings.begin()->second.layers_settings;
std::vector<int> configured_bitrate_kbps;
std::transform(layers_settings.begin(), layers_settings.end(),
std::back_inserter(configured_bitrate_kbps),
[](const auto& layer_settings) {
return layer_settings.second.bitrate.kbps();
});
EXPECT_EQ(configured_bitrate_kbps, test_params.expected_bitrate_kbps);
}
INSTANTIATE_TEST_SUITE_P(
Vp8,
VideoCodecTesterTestEncodingSettings,
Values(EncodingSettingsTestParameters{.codec_type = "VP8",
.scalability_mode = "L1T1",
.bitrate_kbps = {1},
.expected_bitrate_kbps = {1}},
EncodingSettingsTestParameters{.codec_type = "VP8",
.scalability_mode = "L1T1",
.bitrate_kbps = {10000},
.expected_bitrate_kbps = {10000}},
EncodingSettingsTestParameters{
.codec_type = "VP8",
.scalability_mode = "L1T3",
.bitrate_kbps = {1000},
.expected_bitrate_kbps = {400, 200, 400}},
EncodingSettingsTestParameters{
.codec_type = "VP8",
.scalability_mode = "S3T3",
.bitrate_kbps = {100},
.expected_bitrate_kbps = {40, 20, 40, 0, 0, 0, 0, 0, 0}},
EncodingSettingsTestParameters{
.codec_type = "VP8",
.scalability_mode = "S3T3",
.bitrate_kbps = {10000},
.expected_bitrate_kbps = {60, 30, 60, 200, 100, 200, 1000, 500,
1000}},
EncodingSettingsTestParameters{
.codec_type = "VP8",
.scalability_mode = "S3T3",
.bitrate_kbps = {100, 200, 300, 400, 500, 600, 700, 800, 900},
.expected_bitrate_kbps = {100, 200, 300, 400, 500, 600, 700, 800,
900}}));
INSTANTIATE_TEST_SUITE_P(
Vp9,
VideoCodecTesterTestEncodingSettings,
Values(EncodingSettingsTestParameters{.codec_type = "VP9",
.scalability_mode = "L1T1",
.bitrate_kbps = {1},
.expected_bitrate_kbps = {1}},
EncodingSettingsTestParameters{.codec_type = "VP9",
.scalability_mode = "L1T1",
.bitrate_kbps = {10000},
.expected_bitrate_kbps = {10000}},
EncodingSettingsTestParameters{
.codec_type = "VP9",
.scalability_mode = "L1T3",
.bitrate_kbps = {1000},
.expected_bitrate_kbps = {540, 163, 297}},
EncodingSettingsTestParameters{
.codec_type = "VP9",
.scalability_mode = "L3T3",
.bitrate_kbps = {100},
.expected_bitrate_kbps = {54, 16, 30, 0, 0, 0, 0, 0, 0}},
EncodingSettingsTestParameters{
.codec_type = "VP9",
.scalability_mode = "L3T3",
.bitrate_kbps = {10000},
.expected_bitrate_kbps = {77, 23, 42, 226, 68, 124, 823, 249,
452}},
EncodingSettingsTestParameters{
.codec_type = "VP9",
.scalability_mode = "L3T3",
.bitrate_kbps = {100, 200, 300, 400, 500, 600, 700, 800, 900},
.expected_bitrate_kbps = {100, 200, 300, 400, 500, 600, 700, 800,
900}}));
INSTANTIATE_TEST_SUITE_P(
Av1,
VideoCodecTesterTestEncodingSettings,
Values(EncodingSettingsTestParameters{.codec_type = "AV1",
.scalability_mode = "L1T1",
.bitrate_kbps = {1},
.expected_bitrate_kbps = {1}},
EncodingSettingsTestParameters{.codec_type = "AV1",
.scalability_mode = "L1T1",
.bitrate_kbps = {10000},
.expected_bitrate_kbps = {10000}},
EncodingSettingsTestParameters{
.codec_type = "AV1",
.scalability_mode = "L1T3",
.bitrate_kbps = {1000},
.expected_bitrate_kbps = {540, 163, 297}},
EncodingSettingsTestParameters{
.codec_type = "AV1",
.scalability_mode = "L3T3",
.bitrate_kbps = {100},
.expected_bitrate_kbps = {54, 16, 30, 0, 0, 0, 0, 0, 0}},
EncodingSettingsTestParameters{
.codec_type = "AV1",
.scalability_mode = "L3T3",
.bitrate_kbps = {10000},
.expected_bitrate_kbps = {77, 23, 42, 226, 68, 124, 823, 249,
452}},
EncodingSettingsTestParameters{
.codec_type = "AV1",
.scalability_mode = "L3T3",
.bitrate_kbps = {100, 200, 300, 400, 500, 600, 700, 800, 900},
.expected_bitrate_kbps = {100, 200, 300, 400, 500, 600, 700, 800,
900}}));
} // namespace test
} // namespace webrtc