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:
@ -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",
|
||||||
|
@ -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() {
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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",
|
||||||
|
62
rtc_base/experiments/quality_scaler_settings.cc
Normal file
62
rtc_base/experiments/quality_scaler_settings.cc
Normal 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
|
39
rtc_base/experiments/quality_scaler_settings.h
Normal file
39
rtc_base/experiments/quality_scaler_settings.h
Normal 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_
|
76
rtc_base/experiments/quality_scaler_settings_unittest.cc
Normal file
76
rtc_base/experiments/quality_scaler_settings_unittest.cc
Normal 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
|
Reference in New Issue
Block a user