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',
|
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)),
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user