Add default values and field trials to QualityConvergenceMonitor

Add default values and a static Create() function that determines
the parameters to use based on the specified codec and potential
field trial overrides.

Bug: chromium:328598314
Change-Id: I7a9331a1fd0ed4bd258788760592ea84e535e43b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/355903
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Markus Handell <handellm@google.com>
Commit-Queue: Johannes Kron <kron@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42567}
This commit is contained in:
Johannes Kron 2024-07-02 00:27:10 +02:00 committed by WebRTC LUCI CQ
parent 6bbbc08747
commit e0287f2797
4 changed files with 210 additions and 7 deletions

View File

@ -107,6 +107,15 @@ ACTIVE_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([
FieldTrial('WebRTC-PermuteTlsClientHello', FieldTrial('WebRTC-PermuteTlsClientHello',
42225803, 42225803,
date(2024, 7, 1)), date(2024, 7, 1)),
FieldTrial('WebRTC-QCM-Dynamic-AV1',
349860657,
date(2025, 7, 1)),
FieldTrial('WebRTC-QCM-Dynamic-VP8',
349860657,
date(2025, 7, 1)),
FieldTrial('WebRTC-QCM-Dynamic-VP9',
349860657,
date(2025, 7, 1)),
FieldTrial('WebRTC-ReceiveBufferSize', FieldTrial('WebRTC-ReceiveBufferSize',
42225927, 42225927,
date(2024, 4, 1)), date(2024, 4, 1)),

View File

@ -13,8 +13,76 @@
#include <numeric> #include <numeric>
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/experiments/struct_parameters_parser.h"
namespace webrtc { namespace webrtc {
namespace {
constexpr size_t kDefaultRecentWindowLength = 6;
constexpr size_t kDefaultPastWindowLength = 6;
constexpr float kDefaultAlpha = 0.06;
struct DynamicDetectionConfig {
bool enabled = false;
// alpha is a percentage of the codec-specific max QP value that is used to
// determine the dynamic QP threshold:
// dynamic_qp_threshold = static_qp_threshold + alpha * max_QP
double alpha = kDefaultAlpha;
int recent_length = kDefaultRecentWindowLength;
int past_length = kDefaultPastWindowLength;
std::unique_ptr<StructParametersParser> Parser();
};
std::unique_ptr<StructParametersParser> DynamicDetectionConfig::Parser() {
// The empty comments ensures that each pair is on a separate line.
return StructParametersParser::Create("enabled", &enabled, //
"alpha", &alpha, //
"recent_length", &recent_length, //
"past_length", &past_length);
}
QualityConvergenceMonitor::Parameters GetParameters(
int static_qp_threshold,
VideoCodecType codec,
const FieldTrialsView& trials) {
QualityConvergenceMonitor::Parameters params;
params.static_qp_threshold = static_qp_threshold;
DynamicDetectionConfig dynamic_config;
// Apply codec specific settings.
int max_qp = 0;
switch (codec) {
case kVideoCodecVP8:
dynamic_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Dynamic-VP8"));
max_qp = 127;
break;
case kVideoCodecVP9:
// Change to enabled by default for VP9.
dynamic_config.enabled = true;
dynamic_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Dynamic-VP9"));
max_qp = 255;
break;
case kVideoCodecAV1:
// Change to enabled by default for AV1.
dynamic_config.enabled = true;
dynamic_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Dynamic-AV1"));
max_qp = 255;
break;
case kVideoCodecGeneric:
case kVideoCodecH264:
case kVideoCodecH265:
break;
}
if (dynamic_config.enabled) {
params.dynamic_detection_enabled = dynamic_config.enabled;
params.dynamic_qp_threshold =
params.static_qp_threshold + max_qp * dynamic_config.alpha;
params.recent_window_length = dynamic_config.recent_length;
params.past_window_length = dynamic_config.past_length;
}
return params;
}
} // namespace
QualityConvergenceMonitor::QualityConvergenceMonitor(const Parameters& params) QualityConvergenceMonitor::QualityConvergenceMonitor(const Parameters& params)
: params_(params) { : params_(params) {
@ -121,4 +189,14 @@ bool QualityConvergenceMonitor::AtTargetQuality() const {
return at_target_quality_; return at_target_quality_;
} }
// Static
std::unique_ptr<QualityConvergenceMonitor> QualityConvergenceMonitor::Create(
int static_qp_threshold,
VideoCodecType codec,
const FieldTrialsView& trials) {
Parameters params = GetParameters(static_qp_threshold, codec, trials);
return std::unique_ptr<QualityConvergenceMonitor>(
new QualityConvergenceMonitor(params));
}
} // namespace webrtc } // namespace webrtc

View File

@ -14,6 +14,7 @@
#include <deque> #include <deque>
#include <memory> #include <memory>
#include "api/field_trials_view.h"
#include "api/video/video_codec_type.h" #include "api/video/video_codec_type.h"
namespace webrtc { namespace webrtc {
@ -47,6 +48,11 @@ class QualityConvergenceMonitor {
explicit QualityConvergenceMonitor(const Parameters& params); explicit QualityConvergenceMonitor(const Parameters& params);
static std::unique_ptr<QualityConvergenceMonitor> Create(
int static_qp_threshold,
VideoCodecType codec,
const FieldTrialsView& trials);
// Add the supplied `qp` value to the detection window. // Add the supplied `qp` value to the detection window.
// `is_refresh_frame` must only be `true` if the corresponding // `is_refresh_frame` must only be `true` if the corresponding
// video frame is a refresh frame that is used to improve the visual quality. // video frame is a refresh frame that is used to improve the visual quality.
@ -56,6 +62,10 @@ class QualityConvergenceMonitor {
// have converged and reached the target quality. // have converged and reached the target quality.
bool AtTargetQuality() const; bool AtTargetQuality() const;
// Used in tests to verify that default values and field trials are set
// correctly.
Parameters GetParametersForTesting() const { return params_; }
private: private:
const Parameters params_; const Parameters params_;
bool at_target_quality_ = false; bool at_target_quality_ = false;

View File

@ -13,14 +13,17 @@
#include <vector> #include <vector>
#include "test/gtest.h" #include "test/gtest.h"
#include "test/scoped_key_value_config.h"
namespace webrtc { namespace webrtc {
namespace { namespace {
constexpr int kStaticQpThreshold = 13;
constexpr QualityConvergenceMonitor::Parameters kParametersOnlyStaticThreshold = constexpr QualityConvergenceMonitor::Parameters kParametersOnlyStaticThreshold =
{.static_qp_threshold = 13, .dynamic_detection_enabled = false}; {.static_qp_threshold = kStaticQpThreshold,
.dynamic_detection_enabled = false};
constexpr QualityConvergenceMonitor::Parameters constexpr QualityConvergenceMonitor::Parameters
kParametersWithDynamicDetection = {.static_qp_threshold = 13, kParametersWithDynamicDetection = {
.static_qp_threshold = kStaticQpThreshold,
.dynamic_detection_enabled = true, .dynamic_detection_enabled = true,
.recent_window_length = 3, .recent_window_length = 3,
.past_window_length = 9, .past_window_length = 9,
@ -192,5 +195,108 @@ TEST(QualityConvergenceMonitorAlgorithm,
EXPECT_TRUE(monitor->AtTargetQuality()); EXPECT_TRUE(monitor->AtTargetQuality());
} }
// Test default values and that they can be overridden with field trials.
TEST(QualityConvergenceMonitorSetup, DefaultParameters) {
test::ScopedKeyValueConfig field_trials;
auto monitor = QualityConvergenceMonitor::Create(
kStaticQpThreshold, kVideoCodecVP8, field_trials);
ASSERT_TRUE(monitor);
QualityConvergenceMonitor::Parameters vp8_parameters =
monitor->GetParametersForTesting();
EXPECT_EQ(vp8_parameters.static_qp_threshold, kStaticQpThreshold);
EXPECT_FALSE(vp8_parameters.dynamic_detection_enabled);
monitor = QualityConvergenceMonitor::Create(kStaticQpThreshold,
kVideoCodecVP9, field_trials);
ASSERT_TRUE(monitor);
QualityConvergenceMonitor::Parameters vp9_parameters =
monitor->GetParametersForTesting();
EXPECT_EQ(vp9_parameters.static_qp_threshold, kStaticQpThreshold);
EXPECT_TRUE(vp9_parameters.dynamic_detection_enabled);
EXPECT_EQ(vp9_parameters.dynamic_qp_threshold, 28); // 13 + 15.
EXPECT_EQ(vp9_parameters.recent_window_length, 6u);
EXPECT_EQ(vp9_parameters.past_window_length, 6u);
monitor = QualityConvergenceMonitor::Create(kStaticQpThreshold,
kVideoCodecAV1, field_trials);
ASSERT_TRUE(monitor);
QualityConvergenceMonitor::Parameters av1_parameters =
monitor->GetParametersForTesting();
EXPECT_EQ(av1_parameters.static_qp_threshold, kStaticQpThreshold);
EXPECT_TRUE(av1_parameters.dynamic_detection_enabled);
EXPECT_EQ(av1_parameters.dynamic_qp_threshold, 28); // 13 + 15.
EXPECT_EQ(av1_parameters.recent_window_length, 6u);
EXPECT_EQ(av1_parameters.past_window_length, 6u);
}
TEST(QualityConvergenceMonitorSetup, OverrideVp8Parameters) {
test::ScopedKeyValueConfig field_trials(
"WebRTC-QCM-Dynamic-VP8/"
"enabled:1,alpha:0.08,recent_length:6,past_length:4/");
auto monitor = QualityConvergenceMonitor::Create(
kStaticQpThreshold, kVideoCodecVP8, field_trials);
ASSERT_TRUE(monitor);
QualityConvergenceMonitor::Parameters p = monitor->GetParametersForTesting();
EXPECT_EQ(p.static_qp_threshold, kStaticQpThreshold);
EXPECT_TRUE(p.dynamic_detection_enabled);
EXPECT_EQ(p.dynamic_qp_threshold, 23); // 13 + 10.
EXPECT_EQ(p.recent_window_length, 6u);
EXPECT_EQ(p.past_window_length, 4u);
}
TEST(QualityConvergenceMonitorSetup, OverrideVp9Parameters) {
test::ScopedKeyValueConfig field_trials(
"WebRTC-QCM-Dynamic-VP9/"
"enabled:1,alpha:0.08,recent_length:6,past_length:4/");
auto monitor = QualityConvergenceMonitor::Create(
kStaticQpThreshold, kVideoCodecVP9, field_trials);
ASSERT_TRUE(monitor);
QualityConvergenceMonitor::Parameters p = monitor->GetParametersForTesting();
EXPECT_EQ(p.static_qp_threshold, kStaticQpThreshold);
EXPECT_TRUE(p.dynamic_detection_enabled);
EXPECT_EQ(p.dynamic_qp_threshold, 33); // 13 + 20.
EXPECT_EQ(p.recent_window_length, 6u);
EXPECT_EQ(p.past_window_length, 4u);
}
TEST(QualityConvergenceMonitorSetup, OverrideAv1Parameters) {
test::ScopedKeyValueConfig field_trials(
"WebRTC-QCM-Dynamic-AV1/"
"enabled:1,alpha:0.10,recent_length:8,past_length:8/");
auto monitor = QualityConvergenceMonitor::Create(
kStaticQpThreshold, kVideoCodecAV1, field_trials);
ASSERT_TRUE(monitor);
QualityConvergenceMonitor::Parameters p = monitor->GetParametersForTesting();
EXPECT_EQ(p.static_qp_threshold, kStaticQpThreshold);
EXPECT_TRUE(p.dynamic_detection_enabled);
EXPECT_EQ(p.dynamic_qp_threshold, 38); // 13 + 25.
EXPECT_EQ(p.recent_window_length, 8u);
EXPECT_EQ(p.past_window_length, 8u);
}
TEST(QualityConvergenceMonitorSetup, DisableVp9Dynamic) {
test::ScopedKeyValueConfig field_trials("WebRTC-QCM-Dynamic-VP9/enabled:0/");
auto monitor = QualityConvergenceMonitor::Create(
kStaticQpThreshold, kVideoCodecVP9, field_trials);
ASSERT_TRUE(monitor);
QualityConvergenceMonitor::Parameters p = monitor->GetParametersForTesting();
EXPECT_FALSE(p.dynamic_detection_enabled);
}
TEST(QualityConvergenceMonitorSetup, DisableAv1Dynamic) {
test::ScopedKeyValueConfig field_trials("WebRTC-QCM-Dynamic-AV1/enabled:0/");
auto monitor = QualityConvergenceMonitor::Create(
kStaticQpThreshold, kVideoCodecAV1, field_trials);
ASSERT_TRUE(monitor);
QualityConvergenceMonitor::Parameters p = monitor->GetParametersForTesting();
EXPECT_FALSE(p.dynamic_detection_enabled);
}
} // namespace } // namespace
} // namespace webrtc } // namespace webrtc