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:
parent
6bbbc08747
commit
e0287f2797
@ -107,6 +107,15 @@ ACTIVE_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([
|
||||
FieldTrial('WebRTC-PermuteTlsClientHello',
|
||||
42225803,
|
||||
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',
|
||||
42225927,
|
||||
date(2024, 4, 1)),
|
||||
|
||||
@ -13,8 +13,76 @@
|
||||
#include <numeric>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/experiments/struct_parameters_parser.h"
|
||||
|
||||
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)
|
||||
: params_(params) {
|
||||
@ -121,4 +189,14 @@ bool QualityConvergenceMonitor::AtTargetQuality() const {
|
||||
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
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/video/video_codec_type.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -47,6 +48,11 @@ class QualityConvergenceMonitor {
|
||||
|
||||
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.
|
||||
// `is_refresh_frame` must only be `true` if the corresponding
|
||||
// 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.
|
||||
bool AtTargetQuality() const;
|
||||
|
||||
// Used in tests to verify that default values and field trials are set
|
||||
// correctly.
|
||||
Parameters GetParametersForTesting() const { return params_; }
|
||||
|
||||
private:
|
||||
const Parameters params_;
|
||||
bool at_target_quality_ = false;
|
||||
|
||||
@ -13,18 +13,21 @@
|
||||
#include <vector>
|
||||
|
||||
#include "test/gtest.h"
|
||||
#include "test/scoped_key_value_config.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr int kStaticQpThreshold = 13;
|
||||
constexpr QualityConvergenceMonitor::Parameters kParametersOnlyStaticThreshold =
|
||||
{.static_qp_threshold = 13, .dynamic_detection_enabled = false};
|
||||
{.static_qp_threshold = kStaticQpThreshold,
|
||||
.dynamic_detection_enabled = false};
|
||||
constexpr QualityConvergenceMonitor::Parameters
|
||||
kParametersWithDynamicDetection = {.static_qp_threshold = 13,
|
||||
.dynamic_detection_enabled = true,
|
||||
.recent_window_length = 3,
|
||||
.past_window_length = 9,
|
||||
.dynamic_qp_threshold = 24};
|
||||
kParametersWithDynamicDetection = {
|
||||
.static_qp_threshold = kStaticQpThreshold,
|
||||
.dynamic_detection_enabled = true,
|
||||
.recent_window_length = 3,
|
||||
.past_window_length = 9,
|
||||
.dynamic_qp_threshold = 24};
|
||||
|
||||
// Test the basics of the algorithm.
|
||||
|
||||
@ -192,5 +195,108 @@ TEST(QualityConvergenceMonitorAlgorithm,
|
||||
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 webrtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user