Add ability to configure quality scaler settings through field trial.

optional<int> min_frames: The minimum number frames to observe to make a
                          scaling decision.
Default: kMinFramesNeededToScale in quality_scaler.cc

optional<double> initial_scale_factor: The sample period scale factor.
Default: kSamplePeriodScaleFactor in quality_scaler.cc

optional<double> scale_factor: Option to use a reduced sampling interval when
                               last check did not result in an adaptation (if
                               unset the initial_scale_factor is used).

Bug: none
Change-Id: I3bb955d1f8d7d7d49bc118361614b5aa59605231
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/135125
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27860}
This commit is contained in:
Åsa Persson
2019-05-06 14:17:35 +02:00
committed by Commit Bot
parent cfff652c82
commit 517678cc49
7 changed files with 222 additions and 5 deletions

View File

@ -257,6 +257,7 @@ rtc_source_set("video_coding_utility") {
"../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_approved",
"../../rtc_base:rtc_numerics", "../../rtc_base:rtc_numerics",
"../../rtc_base:rtc_task_queue", "../../rtc_base:rtc_task_queue",
"../../rtc_base/experiments:quality_scaler_settings",
"../../rtc_base/experiments:quality_scaling_experiment", "../../rtc_base/experiments:quality_scaling_experiment",
"../../rtc_base/experiments:rate_control_settings", "../../rtc_base/experiments:rate_control_settings",
"../../rtc_base/synchronization:sequence_checker", "../../rtc_base/synchronization:sequence_checker",

View File

@ -13,8 +13,8 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include "absl/types/optional.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/experiments/quality_scaler_settings.h"
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "rtc_base/numerics/exp_filter.h" #include "rtc_base/numerics/exp_filter.h"
#include "rtc_base/task_queue.h" #include "rtc_base/task_queue.h"
@ -33,7 +33,7 @@ namespace {
static const int kMeasureMs = 2000; static const int kMeasureMs = 2000;
static const float kSamplePeriodScaleFactor = 2.5; static const float kSamplePeriodScaleFactor = 2.5;
static const int kFramedropPercentThreshold = 60; static const int kFramedropPercentThreshold = 60;
static const int kMinFramesNeededToScale = 2 * 30; static const size_t kMinFramesNeededToScale = 2 * 30;
} // namespace } // namespace
@ -87,7 +87,16 @@ QualityScaler::QualityScaler(rtc::TaskQueue* task_queue,
framedrop_percent_media_opt_(5 * 30), framedrop_percent_media_opt_(5 * 30),
framedrop_percent_all_(5 * 30), framedrop_percent_all_(5 * 30),
experiment_enabled_(QualityScalingExperiment::Enabled()), experiment_enabled_(QualityScalingExperiment::Enabled()),
observed_enough_frames_(false) { observed_enough_frames_(false),
min_frames_needed_(
QualityScalerSettings::ParseFromFieldTrials().MinFrames().value_or(
kMinFramesNeededToScale)),
initial_scale_factor_(QualityScalerSettings::ParseFromFieldTrials()
.InitialScaleFactor()
.value_or(kSamplePeriodScaleFactor)),
scale_factor_(
QualityScalerSettings::ParseFromFieldTrials().ScaleFactor()),
last_adapted_(false) {
RTC_DCHECK_RUN_ON(&task_checker_); RTC_DCHECK_RUN_ON(&task_checker_);
if (experiment_enabled_) { if (experiment_enabled_) {
config_ = QualityScalingExperiment::GetConfig(); config_ = QualityScalingExperiment::GetConfig();
@ -118,7 +127,11 @@ int64_t QualityScaler::GetSamplingPeriodMs() const {
// Use half the interval while waiting for enough frames. // Use half the interval while waiting for enough frames.
return sampling_period_ms_ / 2; return sampling_period_ms_ / 2;
} }
return sampling_period_ms_ * kSamplePeriodScaleFactor; if (scale_factor_ && !last_adapted_) {
// Last check did not result in a AdaptDown/Up, possibly reduce interval.
return sampling_period_ms_ * scale_factor_.value();
}
return sampling_period_ms_ * initial_scale_factor_;
} }
void QualityScaler::ReportDroppedFrameByMediaOpt() { void QualityScaler::ReportDroppedFrameByMediaOpt() {
@ -147,13 +160,14 @@ void QualityScaler::CheckQp() {
RTC_DCHECK_RUN_ON(&task_checker_); RTC_DCHECK_RUN_ON(&task_checker_);
// Should be set through InitEncode -> Should be set by now. // Should be set through InitEncode -> Should be set by now.
RTC_DCHECK_GE(thresholds_.low, 0); RTC_DCHECK_GE(thresholds_.low, 0);
last_adapted_ = false;
// If we have not observed at least this many frames we can't make a good // If we have not observed at least this many frames we can't make a good
// scaling decision. // scaling decision.
const size_t frames = config_.use_all_drop_reasons const size_t frames = config_.use_all_drop_reasons
? framedrop_percent_all_.Size() ? framedrop_percent_all_.Size()
: framedrop_percent_media_opt_.Size(); : framedrop_percent_media_opt_.Size();
if (frames < kMinFramesNeededToScale) { if (frames < min_frames_needed_) {
observed_enough_frames_ = false; observed_enough_frames_ = false;
return; return;
} }
@ -196,6 +210,7 @@ void QualityScaler::ReportQpLow() {
RTC_DCHECK_RUN_ON(&task_checker_); RTC_DCHECK_RUN_ON(&task_checker_);
ClearSamples(); ClearSamples();
observer_->AdaptUp(AdaptationObserverInterface::AdaptReason::kQuality); observer_->AdaptUp(AdaptationObserverInterface::AdaptReason::kQuality);
last_adapted_ = true;
} }
void QualityScaler::ReportQpHigh() { void QualityScaler::ReportQpHigh() {
@ -206,6 +221,7 @@ void QualityScaler::ReportQpHigh() {
if (fast_rampup_) { if (fast_rampup_) {
fast_rampup_ = false; fast_rampup_ = false;
} }
last_adapted_ = true;
} }
void QualityScaler::ClearSamples() { void QualityScaler::ClearSamples() {

View File

@ -15,6 +15,7 @@
#include <stdint.h> #include <stdint.h>
#include <memory> #include <memory>
#include "absl/types/optional.h"
#include "api/video_codecs/video_encoder.h" #include "api/video_codecs/video_encoder.h"
#include "rtc_base/experiments/quality_scaling_experiment.h" #include "rtc_base/experiments/quality_scaling_experiment.h"
#include "rtc_base/numerics/moving_average.h" #include "rtc_base/numerics/moving_average.h"
@ -93,6 +94,11 @@ class QualityScaler {
std::unique_ptr<QpSmoother> qp_smoother_high_ RTC_GUARDED_BY(&task_checker_); std::unique_ptr<QpSmoother> qp_smoother_high_ RTC_GUARDED_BY(&task_checker_);
std::unique_ptr<QpSmoother> qp_smoother_low_ RTC_GUARDED_BY(&task_checker_); std::unique_ptr<QpSmoother> qp_smoother_low_ RTC_GUARDED_BY(&task_checker_);
bool observed_enough_frames_ RTC_GUARDED_BY(&task_checker_); bool observed_enough_frames_ RTC_GUARDED_BY(&task_checker_);
const size_t min_frames_needed_;
const double initial_scale_factor_;
const absl::optional<double> scale_factor_;
bool last_adapted_ RTC_GUARDED_BY(&task_checker_);
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -59,6 +59,21 @@ rtc_static_library("field_trial_parser") {
] ]
} }
rtc_static_library("quality_scaler_settings") {
sources = [
"quality_scaler_settings.cc",
"quality_scaler_settings.h",
]
deps = [
":field_trial_parser",
"../:rtc_base_approved",
"../../api/transport:field_trial_based_config",
"../../api/transport:webrtc_key_value_config",
"../../system_wrappers:field_trial",
"//third_party/abseil-cpp/absl/types:optional",
]
}
rtc_static_library("quality_scaling_experiment") { rtc_static_library("quality_scaling_experiment") {
sources = [ sources = [
"quality_scaling_experiment.cc", "quality_scaling_experiment.cc",
@ -160,6 +175,7 @@ if (rtc_include_tests) {
"field_trial_units_unittest.cc", "field_trial_units_unittest.cc",
"keyframe_interval_settings_unittest.cc", "keyframe_interval_settings_unittest.cc",
"normalize_simulcast_size_experiment_unittest.cc", "normalize_simulcast_size_experiment_unittest.cc",
"quality_scaler_settings_unittest.cc",
"quality_scaling_experiment_unittest.cc", "quality_scaling_experiment_unittest.cc",
"rate_control_settings_unittest.cc", "rate_control_settings_unittest.cc",
"rtt_mult_experiment_unittest.cc", "rtt_mult_experiment_unittest.cc",
@ -169,6 +185,7 @@ if (rtc_include_tests) {
":field_trial_parser", ":field_trial_parser",
":keyframe_interval_settings_experiment", ":keyframe_interval_settings_experiment",
":normalize_simulcast_size_experiment", ":normalize_simulcast_size_experiment",
":quality_scaler_settings",
":quality_scaling_experiment", ":quality_scaling_experiment",
":rate_control_settings", ":rate_control_settings",
":rtt_mult_experiment", ":rtt_mult_experiment",

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2019 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/quality_scaler_settings.h"
#include "api/transport/field_trial_based_config.h"
#include "rtc_base/logging.h"
namespace webrtc {
namespace {
const int kMinFrames = 10;
const double kMinScaleFactor = 0.01;
} // namespace
QualityScalerSettings::QualityScalerSettings(
const WebRtcKeyValueConfig* const key_value_config)
: min_frames_("min_frames"),
initial_scale_factor_("initial_scale_factor"),
scale_factor_("scale_factor") {
ParseFieldTrial(
{&min_frames_, &initial_scale_factor_, &scale_factor_},
key_value_config->Lookup("WebRTC-Video-QualityScalerSettings"));
}
QualityScalerSettings QualityScalerSettings::ParseFromFieldTrials() {
FieldTrialBasedConfig field_trial_config;
return QualityScalerSettings(&field_trial_config);
}
absl::optional<int> QualityScalerSettings::MinFrames() const {
if (min_frames_ && min_frames_.Value() < kMinFrames) {
RTC_LOG(LS_WARNING) << "Unsupported min_frames value, ignored.";
return absl::nullopt;
}
return min_frames_.GetOptional();
}
absl::optional<double> QualityScalerSettings::InitialScaleFactor() const {
if (initial_scale_factor_ &&
initial_scale_factor_.Value() < kMinScaleFactor) {
RTC_LOG(LS_WARNING) << "Unsupported initial_scale_factor value, ignored.";
return absl::nullopt;
}
return initial_scale_factor_.GetOptional();
}
absl::optional<double> QualityScalerSettings::ScaleFactor() const {
if (scale_factor_ && scale_factor_.Value() < kMinScaleFactor) {
RTC_LOG(LS_WARNING) << "Unsupported scale_factor value, ignored.";
return absl::nullopt;
}
return scale_factor_.GetOptional();
}
} // namespace webrtc

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2019 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.
*/
#ifndef RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_
#define RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_
#include "absl/types/optional.h"
#include "api/transport/webrtc_key_value_config.h"
#include "rtc_base/experiments/field_trial_parser.h"
namespace webrtc {
class QualityScalerSettings final {
public:
static QualityScalerSettings ParseFromFieldTrials();
absl::optional<int> MinFrames() const;
absl::optional<double> InitialScaleFactor() const;
absl::optional<double> ScaleFactor() const;
private:
explicit QualityScalerSettings(
const WebRtcKeyValueConfig* const key_value_config);
FieldTrialOptional<int> min_frames_;
FieldTrialOptional<double> initial_scale_factor_;
FieldTrialOptional<double> scale_factor_;
};
} // namespace webrtc
#endif // RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_

View File

@ -0,0 +1,76 @@
/*
* Copyright 2019 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/quality_scaler_settings.h"
#include "test/field_trial.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
TEST(QualityScalerSettingsTest, ValuesNotSetByDefault) {
EXPECT_FALSE(QualityScalerSettings::ParseFromFieldTrials().MinFrames());
EXPECT_FALSE(
QualityScalerSettings::ParseFromFieldTrials().InitialScaleFactor());
EXPECT_FALSE(QualityScalerSettings::ParseFromFieldTrials().ScaleFactor());
}
TEST(QualityScalerSettingsTest, ParseMinFrames) {
test::ScopedFieldTrials field_trials(
"WebRTC-Video-QualityScalerSettings/min_frames:100/");
EXPECT_EQ(100, QualityScalerSettings::ParseFromFieldTrials().MinFrames());
}
TEST(QualityScalerSettingsTest, ParseInitialScaleFactor) {
test::ScopedFieldTrials field_trials(
"WebRTC-Video-QualityScalerSettings/initial_scale_factor:1.5/");
EXPECT_EQ(1.5,
QualityScalerSettings::ParseFromFieldTrials().InitialScaleFactor());
}
TEST(QualityScalerSettingsTest, ParseScaleFactor) {
test::ScopedFieldTrials field_trials(
"WebRTC-Video-QualityScalerSettings/scale_factor:1.1/");
EXPECT_EQ(1.1, QualityScalerSettings::ParseFromFieldTrials().ScaleFactor());
}
TEST(QualityScalerSettingsTest, ParseAll) {
test::ScopedFieldTrials field_trials(
"WebRTC-Video-QualityScalerSettings/"
"min_frames:100,initial_scale_factor:1.5,scale_factor:0.9/");
const auto settings = QualityScalerSettings::ParseFromFieldTrials();
EXPECT_EQ(100, settings.MinFrames());
EXPECT_EQ(1.5, settings.InitialScaleFactor());
EXPECT_EQ(0.9, settings.ScaleFactor());
}
TEST(QualityScalerSettingsTest, DoesNotParseIncorrectValue) {
test::ScopedFieldTrials field_trials(
"WebRTC-Video-QualityScalerSettings/"
"min_frames:a,initial_scale_factor:b,scale_factor:c/");
const auto settings = QualityScalerSettings::ParseFromFieldTrials();
EXPECT_FALSE(settings.MinFrames());
EXPECT_FALSE(settings.InitialScaleFactor());
EXPECT_FALSE(settings.ScaleFactor());
}
TEST(QualityScalerSettingsTest, DoesNotReturnTooSmallValue) {
test::ScopedFieldTrials field_trials(
"WebRTC-Video-QualityScalerSettings/"
"min_frames:0,initial_scale_factor:0.0,scale_factor:0.0/");
const auto settings = QualityScalerSettings::ParseFromFieldTrials();
EXPECT_FALSE(settings.MinFrames());
EXPECT_FALSE(settings.InitialScaleFactor());
EXPECT_FALSE(settings.ScaleFactor());
}
} // namespace
} // namespace webrtc