blob: eabf8b182d58b6dbfce8d619040b62810721563c [file] [log] [blame]
/*
* Copyright 2021 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 "rtc_base/experiments/encoder_info_settings.h"
#include <stdio.h>
#include "absl/strings/string_view.h"
#include "api/field_trials_view.h"
#include "rtc_base/experiments/field_trial_list.h"
#include "rtc_base/logging.h"
namespace webrtc {
namespace {
std::vector<VideoEncoder::ResolutionBitrateLimits> ToResolutionBitrateLimits(
const std::vector<EncoderInfoSettings::BitrateLimit>& limits) {
std::vector<VideoEncoder::ResolutionBitrateLimits> result;
for (const auto& limit : limits) {
result.push_back(VideoEncoder::ResolutionBitrateLimits(
limit.frame_size_pixels, limit.min_start_bitrate_bps,
limit.min_bitrate_bps, limit.max_bitrate_bps));
}
return result;
}
constexpr float kDefaultMinBitratebps = 30000;
} // namespace
// Default bitrate limits for simulcast with one active stream:
// {frame_size_pixels, min_start_bitrate_bps, min_bitrate_bps, max_bitrate_bps}.
std::vector<VideoEncoder::ResolutionBitrateLimits>
EncoderInfoSettings::GetDefaultSinglecastBitrateLimits(
VideoCodecType codec_type) {
if (codec_type == kVideoCodecAV1) {
// AV1 singlecast max bitrate limits are higher than AV1 SVC max limits.
// This is because in singlecast we normally have just one receiver, BWE is
// known end-to-end and the encode target bitrate guarantees delivery of
// video.
// The min bitrate limits are not used in singlecast (used in SVC/simulcast
// to de-/activate spatial layers) and are set to zero. Send resolution in
// singlecast is assumed to be regulated by QP-based quality scaler.
return {{320 * 180, 0, 0, 256000},
{480 * 270, 176000, 0, 384000},
{640 * 360, 256000, 0, 512000},
{960 * 540, 384000, 0, 1024000},
{1280 * 720, 576000, 0, 1536000}};
}
if (codec_type == kVideoCodecVP9) {
// VP9 singlecast bitrate limits are derived ~directly from VP9 SVC bitrate
// limits. The current max limits are unnecessarily too strict for
// singlecast, where BWE is known end-to-end, especially for low
// resolutions.
return {{320 * 180, 0, 30000, 150000},
{480 * 270, 120000, 30000, 300000},
{640 * 360, 190000, 30000, 420000},
{960 * 540, 350000, 30000, 1000000},
{1280 * 720, 480000, 30000, 1500000}};
}
// VP8 and other codecs.
return {{320 * 180, 0, 30000, 300000},
{480 * 270, 200000, 30000, 500000},
{640 * 360, 300000, 30000, 800000},
{960 * 540, 500000, 30000, 1500000},
{1280 * 720, 900000, 30000, 2500000}};
}
std::optional<VideoEncoder::ResolutionBitrateLimits>
EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsForResolution(
VideoCodecType codec_type,
int frame_size_pixels) {
VideoEncoder::EncoderInfo info;
info.resolution_bitrate_limits =
GetDefaultSinglecastBitrateLimits(codec_type);
return info.GetEncoderBitrateLimitsForResolution(frame_size_pixels);
}
// Return the suitable bitrate limits for specified resolution when qp is
// untrusted, they are experimental values.
// TODO(bugs.webrtc.org/12942): Maybe we need to add other codecs(VP8/VP9)
// experimental values.
std::vector<VideoEncoder::ResolutionBitrateLimits>
EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted() {
// Specific limits for H264/AVC
return {{0 * 0, 0, 0, 0},
{320 * 180, 0, 30000, 300000},
{480 * 270, 300000, 30000, 500000},
{640 * 360, 500000, 30000, 800000},
{960 * 540, 800000, 30000, 1500000},
{1280 * 720, 1500000, 30000, 2500000},
{1920 * 1080, 2500000, 30000, 4000000}};
}
// Through linear interpolation, return the bitrate limit corresponding to the
// specified |frame_size_pixels|.
std::optional<VideoEncoder::ResolutionBitrateLimits>
EncoderInfoSettings::GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted(
std::optional<int> frame_size_pixels,
const std::vector<VideoEncoder::ResolutionBitrateLimits>&
resolution_bitrate_limits) {
if (!frame_size_pixels.has_value() || frame_size_pixels.value() <= 0) {
return std::nullopt;
}
std::vector<VideoEncoder::ResolutionBitrateLimits> bitrate_limits =
resolution_bitrate_limits;
// Sort the list of bitrate limits by resolution.
sort(bitrate_limits.begin(), bitrate_limits.end(),
[](const VideoEncoder::ResolutionBitrateLimits& lhs,
const VideoEncoder::ResolutionBitrateLimits& rhs) {
return lhs.frame_size_pixels < rhs.frame_size_pixels;
});
if (bitrate_limits.empty()) {
return std::nullopt;
}
int interpolation_index = -1;
for (size_t i = 0; i < bitrate_limits.size(); ++i) {
if (bitrate_limits[i].frame_size_pixels >= frame_size_pixels.value()) {
interpolation_index = i;
break;
}
}
// -1 means that the maximum resolution is exceeded, we will select the
// largest data as the return result.
if (interpolation_index == -1) {
return *bitrate_limits.rbegin();
}
// If we have a matching resolution, return directly without interpolation.
if (bitrate_limits[interpolation_index].frame_size_pixels ==
frame_size_pixels.value()) {
return bitrate_limits[interpolation_index];
}
// 0 means our resolution is smaller than the smallest resolution in the list,
// we will select smallest data as the return result.
if (interpolation_index == 0) {
return *bitrate_limits.begin();
}
// No matching resolution, do a linear interpolate.
int lower_pixel_count =
bitrate_limits[interpolation_index - 1].frame_size_pixels;
int upper_pixel_count = bitrate_limits[interpolation_index].frame_size_pixels;
float alpha = (frame_size_pixels.value() - lower_pixel_count) * 1.0 /
(upper_pixel_count - lower_pixel_count);
int min_start_bitrate_bps = static_cast<int>(
bitrate_limits[interpolation_index].min_start_bitrate_bps * alpha +
bitrate_limits[interpolation_index - 1].min_start_bitrate_bps *
(1.0 - alpha));
int max_bitrate_bps = static_cast<int>(
bitrate_limits[interpolation_index].max_bitrate_bps * alpha +
bitrate_limits[interpolation_index - 1].max_bitrate_bps * (1.0 - alpha));
if (max_bitrate_bps >= min_start_bitrate_bps) {
return VideoEncoder::ResolutionBitrateLimits(
frame_size_pixels.value(), min_start_bitrate_bps, kDefaultMinBitratebps,
max_bitrate_bps);
} else {
RTC_LOG(LS_WARNING)
<< "BitRate interpolation calculating result is abnormal. "
<< " lower_pixel_count = " << lower_pixel_count
<< " upper_pixel_count = " << upper_pixel_count
<< " frame_size_pixels = " << frame_size_pixels.value()
<< " min_start_bitrate_bps = " << min_start_bitrate_bps
<< " min_bitrate_bps = " << kDefaultMinBitratebps
<< " max_bitrate_bps = " << max_bitrate_bps;
return std::nullopt;
}
}
EncoderInfoSettings::EncoderInfoSettings(const FieldTrialsView& field_trials,
absl::string_view name)
: requested_resolution_alignment_("requested_resolution_alignment"),
apply_alignment_to_all_simulcast_layers_(
"apply_alignment_to_all_simulcast_layers") {
FieldTrialStructList<BitrateLimit> bitrate_limits(
{FieldTrialStructMember(
"frame_size_pixels",
[](BitrateLimit* b) { return &b->frame_size_pixels; }),
FieldTrialStructMember(
"min_start_bitrate_bps",
[](BitrateLimit* b) { return &b->min_start_bitrate_bps; }),
FieldTrialStructMember(
"min_bitrate_bps",
[](BitrateLimit* b) { return &b->min_bitrate_bps; }),
FieldTrialStructMember(
"max_bitrate_bps",
[](BitrateLimit* b) { return &b->max_bitrate_bps; })},
{});
std::string experiment_string = field_trials.Lookup(name);
if (experiment_string.empty()) {
// Encoder name not found, use common string applying to all encoders.
experiment_string = field_trials.Lookup("WebRTC-GetEncoderInfoOverride");
}
ParseFieldTrial({&bitrate_limits, &requested_resolution_alignment_,
&apply_alignment_to_all_simulcast_layers_},
experiment_string);
resolution_bitrate_limits_ = ToResolutionBitrateLimits(bitrate_limits.Get());
}
std::optional<uint32_t> EncoderInfoSettings::requested_resolution_alignment()
const {
if (requested_resolution_alignment_ &&
requested_resolution_alignment_.Value() < 1) {
RTC_LOG(LS_WARNING) << "Unsupported alignment value, ignored.";
return std::nullopt;
}
return requested_resolution_alignment_.GetOptional();
}
EncoderInfoSettings::~EncoderInfoSettings() {}
SimulcastEncoderAdapterEncoderInfoSettings::
SimulcastEncoderAdapterEncoderInfoSettings(
const FieldTrialsView& field_trials)
: EncoderInfoSettings(
field_trials,
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride") {}
LibvpxVp8EncoderInfoSettings::LibvpxVp8EncoderInfoSettings(
const FieldTrialsView& field_trials)
: EncoderInfoSettings(field_trials, "WebRTC-VP8-GetEncoderInfoOverride") {}
LibvpxVp9EncoderInfoSettings::LibvpxVp9EncoderInfoSettings(
const FieldTrialsView& field_trials)
: EncoderInfoSettings(field_trials, "WebRTC-VP9-GetEncoderInfoOverride") {}
LibaomAv1EncoderInfoSettings::LibaomAv1EncoderInfoSettings(
const FieldTrialsView& field_trials)
: EncoderInfoSettings(field_trials, "WebRTC-Av1-GetEncoderInfoOverride") {}
} // namespace webrtc