Fix vp9 svc singlecast mode and enable quality scaler for vp9

1) Fix several typos and small mistakes which could lead to crashes
2) Adjust bitrates if leading layers are disabled
3) Wire up webrtc quality scaler

Bug: webrtc:11319
Change-Id: I16e52bdb1c315d64906288e4f2be55fe698d5ceb
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/177525
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31546}
This commit is contained in:
Ilya Nikolaevskiy
2020-06-18 19:16:53 +02:00
committed by Commit Bot
parent 79ca92d952
commit 7a82467d0d
7 changed files with 74 additions and 8 deletions

View File

@ -121,6 +121,19 @@ 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
// 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
// predict from previous layers.
if (first_active_layer > 0) {
spatial_layers[0].minBitrate = kMinVp9SvcBitrateKbps;
// TODO(ilnik): tune this value or come up with a different formula to
// ensure that all singlecast configurations look good and not too much
// bitrate is added.
spatial_layers[0].maxBitrate *= 1.1;
}
return spatial_layers;
}

View File

@ -140,7 +140,8 @@ DataRate FindLayerTogglingThreshold(const VideoCodec& codec,
}
}
upper_bound += DataRate::KilobitsPerSec(
codec.spatialLayers[num_active_layers - 1].minBitrate);
codec.spatialLayers[first_active_layer + num_active_layers - 1]
.minBitrate);
// Do a binary search until upper and lower bound is the highest bitrate for
// |num_active_layers| - 1 layers and lowest bitrate for |num_active_layers|

View File

@ -52,6 +52,15 @@ const int kMaxAllowedPidDiff = 30;
constexpr double kLowRateFactor = 1.0;
constexpr double kHighRateFactor = 2.0;
// TODO(ilink): Tune these thresholds further.
// Selected using ConverenceMotion_1280_720_50.yuv clip.
// No toggling observed on any link capacity from 100-2000kbps.
// HD was reached consistently when link capacity was 1500kbps.
// Set resolutions are a bit more conservative than svc_config.cc sets, e.g.
// for 300kbps resolution converged to 270p instead of 360p.
constexpr int kLowVp9QpThreshold = 149;
constexpr int kHighVp9QpThreshold = 205;
// These settings correspond to the settings in vpx_codec_enc_cfg.
struct Vp9RateSettings {
uint32_t rc_undershoot_pct;
@ -248,6 +257,8 @@ VP9EncoderImpl::VP9EncoderImpl(const cricket::VideoCodec& codec)
"WebRTC-VP9VariableFramerateScreenshare")),
variable_framerate_controller_(
variable_framerate_experiment_.framerate_limit),
quality_scaler_experiment_(
ParseQualityScalerConfig("WebRTC-VP9QualityScaler")),
num_steady_state_frames_(0),
config_changed_(true) {
codec_ = {};
@ -398,7 +409,6 @@ bool VP9EncoderImpl::SetSvcRates(
expect_no_more_active_layers = seen_active_layer;
}
}
RTC_DCHECK_GT(num_active_spatial_layers_, 0);
if (higher_layers_enabled && !force_key_frame_) {
// Prohibit drop of all layers for the next frame, so newly enabled
@ -566,7 +576,13 @@ int VP9EncoderImpl::InitEncode(const VideoCodec* inst,
// put some key-frames at will even in VPX_KF_DISABLED kf_mode.
config_->kf_max_dist = inst->VP9().keyFrameInterval;
config_->kf_min_dist = config_->kf_max_dist;
if (quality_scaler_experiment_.enabled) {
// In that experiment webrtc wide quality scaler is used instead of libvpx
// internal scaler.
config_->rc_resize_allowed = 0;
} else {
config_->rc_resize_allowed = inst->VP9().automaticResizeOn ? 1 : 0;
}
// Determine number of threads based on the image size and #cores.
config_->g_threads =
NumberOfThreads(config_->g_w, config_->g_h, settings.number_of_cores);
@ -1555,7 +1571,12 @@ VideoEncoder::EncoderInfo VP9EncoderImpl::GetEncoderInfo() const {
EncoderInfo info;
info.supports_native_handle = false;
info.implementation_name = "libvpx";
if (quality_scaler_experiment_.enabled) {
info.scaling_settings = VideoEncoder::ScalingSettings(
quality_scaler_experiment_.low_qp, quality_scaler_experiment_.high_qp);
} else {
info.scaling_settings = VideoEncoder::ScalingSettings::kOff;
}
info.has_trusted_rate_controller = trusted_rate_controller_;
info.is_hardware_accelerated = false;
info.has_internal_source = false;
@ -1628,6 +1649,24 @@ VP9EncoderImpl::ParseVariableFramerateConfig(std::string group_name) {
return config;
}
// static
VP9EncoderImpl::QualityScalerExperiment
VP9EncoderImpl::ParseQualityScalerConfig(std::string group_name) {
FieldTrialFlag disabled = FieldTrialFlag("Disabled");
FieldTrialParameter<int> low_qp("low_qp", kLowVp9QpThreshold);
FieldTrialParameter<int> high_qp("hihg_qp", kHighVp9QpThreshold);
ParseFieldTrial({&disabled, &low_qp, &high_qp},
field_trial::FindFullName(group_name));
QualityScalerExperiment config;
config.enabled = !disabled.Get();
RTC_LOG(LS_INFO) << "Webrtc quality scaler for vp9 is "
<< (config.enabled ? "enabled." : "disabled");
config.low_qp = low_qp.Get();
config.high_qp = high_qp.Get();
return config;
}
VP9DecoderImpl::VP9DecoderImpl()
: decode_complete_callback_(nullptr),
inited_(false),

View File

@ -175,6 +175,15 @@ class VP9EncoderImpl : public VP9Encoder {
static VariableFramerateExperiment ParseVariableFramerateConfig(
std::string group_name);
FramerateController variable_framerate_controller_;
const struct QualityScalerExperiment {
int low_qp;
int high_qp;
bool enabled;
} quality_scaler_experiment_;
static QualityScalerExperiment ParseQualityScalerConfig(
std::string group_name);
int num_steady_state_frames_;
// Only set config when this flag is set.
bool config_changed_;

View File

@ -75,7 +75,9 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec(
static_cast<unsigned char>(streams.size());
video_codec.minBitrate = streams[0].min_bitrate_bps / 1000;
bool codec_active = false;
for (const VideoStream& stream : streams) {
// Active configuration might not be fully copied to |streams| for SVC yet.
// Therefore the |config| is checked here.
for (const VideoStream& stream : config.simulcast_layers) {
if (stream.active) {
codec_active = true;
break;
@ -205,7 +207,7 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec(
spatial_layers.back().maxBitrate = video_codec.maxBitrate;
}
for (size_t spatial_idx = 0;
for (size_t spatial_idx = first_active_layer;
spatial_idx < config.simulcast_layers.size() &&
spatial_idx < spatial_layers.size();
++spatial_idx) {

View File

@ -233,7 +233,8 @@ TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrateWithScalingOff) {
TEST_F(QualityScalingTest, NoAdaptDownForHighQp_Vp9) {
// VP9 QP thresholds, low:1, high:1 -> high QP.
test::ScopedFieldTrials field_trials(kPrefix + "0,0,1,1,0,0" + kEnd);
test::ScopedFieldTrials field_trials(kPrefix + "0,0,1,1,0,0" + kEnd +
"WebRTC-VP9QualityScaler/Disabled/");
// QualityScaler always disabled.
const bool kAutomaticResize = true;

View File

@ -1730,7 +1730,8 @@ bool VideoStreamEncoder::DropDueToSize(uint32_t pixel_count) const {
bool simulcast_or_svc =
(send_codec_.codecType == VideoCodecType::kVideoCodecVP9 &&
send_codec_.VP9().numberOfSpatialLayers > 1) ||
send_codec_.numberOfSimulcastStreams > 1;
send_codec_.numberOfSimulcastStreams > 1 ||
encoder_config_.simulcast_layers.size() > 1;
if (simulcast_or_svc || !stream_resource_manager_.DropInitialFrames() ||
!encoder_target_bitrate_bps_.has_value()) {