Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
13
TMessagesProj/jni/voip/webrtc/rtc_base/experiments/OWNERS
Normal file
13
TMessagesProj/jni/voip/webrtc/rtc_base/experiments/OWNERS
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
asapersson@webrtc.org
|
||||
sprang@webrtc.org
|
||||
srte@webrtc.org
|
||||
|
||||
per-file audio_allocation_settings*=srte@webrtc.org
|
||||
per-file congestion_controller_experiment*=srte@webrtc.org
|
||||
per-file cpu_speed_experiment*=asapersson@webrtc.org
|
||||
per-file field_trial*=srte@webrtc.org
|
||||
per-file keyframe_interval_settings*=brandtr@webrtc.org
|
||||
per-file normalize_simulcast_size_experiment*=asapersson@webrtc.org
|
||||
per-file quality_scaling_experiment*=asapersson@webrtc.org
|
||||
per-file rtt_mult_experiment*=mhoro@webrtc.org
|
||||
per-file rate_control_settings*=srte@webrtc.org
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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/alr_experiment.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr absl::string_view kDefaultProbingScreenshareBweSettings =
|
||||
"1.0,2875,80,40,-60,3";
|
||||
|
||||
} // namespace
|
||||
|
||||
bool AlrExperimentSettings::MaxOneFieldTrialEnabled(
|
||||
const FieldTrialsView& key_value_config) {
|
||||
return key_value_config.Lookup(kStrictPacingAndProbingExperimentName)
|
||||
.empty() ||
|
||||
key_value_config.Lookup(kScreenshareProbingBweExperimentName).empty();
|
||||
}
|
||||
|
||||
absl::optional<AlrExperimentSettings>
|
||||
AlrExperimentSettings::CreateFromFieldTrial(
|
||||
const FieldTrialsView& key_value_config,
|
||||
absl::string_view experiment_name) {
|
||||
absl::optional<AlrExperimentSettings> ret;
|
||||
std::string group_name = key_value_config.Lookup(experiment_name);
|
||||
|
||||
const std::string kIgnoredSuffix = "_Dogfood";
|
||||
std::string::size_type suffix_pos = group_name.rfind(kIgnoredSuffix);
|
||||
if (suffix_pos != std::string::npos &&
|
||||
suffix_pos == group_name.length() - kIgnoredSuffix.length()) {
|
||||
group_name.resize(group_name.length() - kIgnoredSuffix.length());
|
||||
}
|
||||
|
||||
if (group_name.empty()) {
|
||||
if (experiment_name == kScreenshareProbingBweExperimentName) {
|
||||
// This experiment is now default-on with fixed settings.
|
||||
// TODO(sprang): Remove this kill-switch and clean up experiment code.
|
||||
group_name = kDefaultProbingScreenshareBweSettings;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
AlrExperimentSettings settings;
|
||||
if (sscanf(group_name.c_str(), "%f,%" PRId64 ",%d,%d,%d,%d",
|
||||
&settings.pacing_factor, &settings.max_paced_queue_time,
|
||||
&settings.alr_bandwidth_usage_percent,
|
||||
&settings.alr_start_budget_level_percent,
|
||||
&settings.alr_stop_budget_level_percent,
|
||||
&settings.group_id) == 6) {
|
||||
ret.emplace(settings);
|
||||
RTC_LOG(LS_INFO) << "Using ALR experiment settings: "
|
||||
"pacing factor: "
|
||||
<< settings.pacing_factor << ", max pacer queue length: "
|
||||
<< settings.max_paced_queue_time
|
||||
<< ", ALR bandwidth usage percent: "
|
||||
<< settings.alr_bandwidth_usage_percent
|
||||
<< ", ALR start budget level percent: "
|
||||
<< settings.alr_start_budget_level_percent
|
||||
<< ", ALR end budget level percent: "
|
||||
<< settings.alr_stop_budget_level_percent
|
||||
<< ", ALR experiment group ID: " << settings.group_id;
|
||||
} else {
|
||||
RTC_LOG(LS_INFO) << "Failed to parse ALR experiment: " << experiment_name;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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_ALR_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_ALR_EXPERIMENT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
|
||||
namespace webrtc {
|
||||
struct AlrExperimentSettings {
|
||||
public:
|
||||
float pacing_factor;
|
||||
int64_t max_paced_queue_time;
|
||||
int alr_bandwidth_usage_percent;
|
||||
int alr_start_budget_level_percent;
|
||||
int alr_stop_budget_level_percent;
|
||||
// Will be sent to the receive side for stats slicing.
|
||||
// Can be 0..6, because it's sent as a 3 bits value and there's also
|
||||
// reserved value to indicate absence of experiment.
|
||||
int group_id;
|
||||
|
||||
static constexpr absl::string_view kScreenshareProbingBweExperimentName =
|
||||
"WebRTC-ProbingScreenshareBwe";
|
||||
static constexpr absl::string_view kStrictPacingAndProbingExperimentName =
|
||||
"WebRTC-StrictPacingAndProbing";
|
||||
|
||||
static absl::optional<AlrExperimentSettings> CreateFromFieldTrial(
|
||||
const FieldTrialsView& key_value_config,
|
||||
absl::string_view experiment_name);
|
||||
static bool MaxOneFieldTrialEnabled(const FieldTrialsView& key_value_config);
|
||||
|
||||
private:
|
||||
AlrExperimentSettings() = default;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_ALR_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,487 @@
|
|||
/*
|
||||
* 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/balanced_degradation_settings.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "rtc_base/experiments/field_trial_list.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr char kFieldTrial[] = "WebRTC-Video-BalancedDegradationSettings";
|
||||
constexpr int kMinFps = 1;
|
||||
constexpr int kMaxFps = 100; // 100 means unlimited fps.
|
||||
|
||||
std::vector<BalancedDegradationSettings::Config> DefaultConfigs() {
|
||||
return {{320 * 240,
|
||||
7,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0}},
|
||||
{480 * 360,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0}},
|
||||
{640 * 480,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0}}};
|
||||
}
|
||||
|
||||
bool IsValidConfig(
|
||||
const BalancedDegradationSettings::CodecTypeSpecific& config) {
|
||||
if (config.GetQpLow().has_value() != config.GetQpHigh().has_value()) {
|
||||
RTC_LOG(LS_WARNING) << "Neither or both thresholds should be set.";
|
||||
return false;
|
||||
}
|
||||
if (config.GetQpLow().has_value() && config.GetQpHigh().has_value() &&
|
||||
config.GetQpLow().value() >= config.GetQpHigh().value()) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid threshold value, low >= high threshold.";
|
||||
return false;
|
||||
}
|
||||
if (config.GetFps().has_value() && (config.GetFps().value() < kMinFps ||
|
||||
config.GetFps().value() > kMaxFps)) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported fps setting, value ignored.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValid(const BalancedDegradationSettings::CodecTypeSpecific& config1,
|
||||
const BalancedDegradationSettings::CodecTypeSpecific& config2) {
|
||||
bool both_or_none_set = ((config1.qp_low > 0) == (config2.qp_low > 0) &&
|
||||
(config1.qp_high > 0) == (config2.qp_high > 0) &&
|
||||
(config1.fps > 0) == (config2.fps > 0));
|
||||
if (!both_or_none_set) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid value, all/none should be set.";
|
||||
return false;
|
||||
}
|
||||
if (config1.fps > 0 && config1.fps < config2.fps) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid fps/pixel value provided.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValid(const std::vector<BalancedDegradationSettings::Config>& configs) {
|
||||
if (configs.size() <= 1) {
|
||||
if (configs.size() == 1)
|
||||
RTC_LOG(LS_WARNING) << "Unsupported size, value ignored.";
|
||||
return false;
|
||||
}
|
||||
for (const auto& config : configs) {
|
||||
if (config.fps < kMinFps || config.fps > kMaxFps) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported fps setting, value ignored.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int last_kbps = configs[0].kbps;
|
||||
for (size_t i = 1; i < configs.size(); ++i) {
|
||||
if (configs[i].kbps > 0) {
|
||||
if (configs[i].kbps < last_kbps) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid bitrate value provided.";
|
||||
return false;
|
||||
}
|
||||
last_kbps = configs[i].kbps;
|
||||
}
|
||||
}
|
||||
for (size_t i = 1; i < configs.size(); ++i) {
|
||||
if (configs[i].pixels < configs[i - 1].pixels ||
|
||||
configs[i].fps < configs[i - 1].fps) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid fps/pixel value provided.";
|
||||
return false;
|
||||
}
|
||||
if (!IsValid(configs[i].vp8, configs[i - 1].vp8) ||
|
||||
!IsValid(configs[i].vp9, configs[i - 1].vp9) ||
|
||||
!IsValid(configs[i].h264, configs[i - 1].h264) ||
|
||||
!IsValid(configs[i].av1, configs[i - 1].av1) ||
|
||||
!IsValid(configs[i].generic, configs[i - 1].generic)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& config : configs) {
|
||||
if (!IsValidConfig(config.vp8) || !IsValidConfig(config.vp9) ||
|
||||
!IsValidConfig(config.h264) || !IsValidConfig(config.av1) ||
|
||||
!IsValidConfig(config.generic)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<BalancedDegradationSettings::Config> GetValidOrDefault(
|
||||
const std::vector<BalancedDegradationSettings::Config>& configs) {
|
||||
if (IsValid(configs)) {
|
||||
return configs;
|
||||
}
|
||||
return DefaultConfigs();
|
||||
}
|
||||
|
||||
absl::optional<VideoEncoder::QpThresholds> GetThresholds(
|
||||
VideoCodecType type,
|
||||
const BalancedDegradationSettings::Config& config) {
|
||||
absl::optional<int> low;
|
||||
absl::optional<int> high;
|
||||
|
||||
switch (type) {
|
||||
case kVideoCodecVP8:
|
||||
low = config.vp8.GetQpLow();
|
||||
high = config.vp8.GetQpHigh();
|
||||
break;
|
||||
case kVideoCodecVP9:
|
||||
low = config.vp9.GetQpLow();
|
||||
high = config.vp9.GetQpHigh();
|
||||
break;
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now.
|
||||
case kVideoCodecH264:
|
||||
low = config.h264.GetQpLow();
|
||||
high = config.h264.GetQpHigh();
|
||||
break;
|
||||
case kVideoCodecAV1:
|
||||
low = config.av1.GetQpLow();
|
||||
high = config.av1.GetQpHigh();
|
||||
break;
|
||||
case kVideoCodecGeneric:
|
||||
low = config.generic.GetQpLow();
|
||||
high = config.generic.GetQpHigh();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (low && high) {
|
||||
RTC_LOG(LS_INFO) << "QP thresholds: low: " << *low << ", high: " << *high;
|
||||
return absl::optional<VideoEncoder::QpThresholds>(
|
||||
VideoEncoder::QpThresholds(*low, *high));
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
int GetFps(VideoCodecType type,
|
||||
const absl::optional<BalancedDegradationSettings::Config>& config) {
|
||||
if (!config.has_value()) {
|
||||
return std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
absl::optional<int> fps;
|
||||
switch (type) {
|
||||
case kVideoCodecVP8:
|
||||
fps = config->vp8.GetFps();
|
||||
break;
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
|
||||
case kVideoCodecVP9:
|
||||
fps = config->vp9.GetFps();
|
||||
break;
|
||||
case kVideoCodecH264:
|
||||
fps = config->h264.GetFps();
|
||||
break;
|
||||
case kVideoCodecAV1:
|
||||
fps = config->av1.GetFps();
|
||||
break;
|
||||
case kVideoCodecGeneric:
|
||||
fps = config->generic.GetFps();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const int framerate = fps.value_or(config->fps);
|
||||
|
||||
return (framerate == kMaxFps) ? std::numeric_limits<int>::max() : framerate;
|
||||
}
|
||||
|
||||
absl::optional<int> GetKbps(
|
||||
VideoCodecType type,
|
||||
const absl::optional<BalancedDegradationSettings::Config>& config) {
|
||||
if (!config.has_value())
|
||||
return absl::nullopt;
|
||||
|
||||
absl::optional<int> kbps;
|
||||
switch (type) {
|
||||
case kVideoCodecVP8:
|
||||
kbps = config->vp8.GetKbps();
|
||||
break;
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
|
||||
case kVideoCodecVP9:
|
||||
kbps = config->vp9.GetKbps();
|
||||
break;
|
||||
case kVideoCodecH264:
|
||||
kbps = config->h264.GetKbps();
|
||||
break;
|
||||
case kVideoCodecAV1:
|
||||
kbps = config->av1.GetKbps();
|
||||
break;
|
||||
case kVideoCodecGeneric:
|
||||
kbps = config->generic.GetKbps();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (kbps.has_value())
|
||||
return kbps;
|
||||
|
||||
return config->kbps > 0 ? absl::optional<int>(config->kbps) : absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int> GetKbpsRes(
|
||||
VideoCodecType type,
|
||||
const absl::optional<BalancedDegradationSettings::Config>& config) {
|
||||
if (!config.has_value())
|
||||
return absl::nullopt;
|
||||
|
||||
absl::optional<int> kbps_res;
|
||||
switch (type) {
|
||||
case kVideoCodecVP8:
|
||||
kbps_res = config->vp8.GetKbpsRes();
|
||||
break;
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
|
||||
case kVideoCodecVP9:
|
||||
kbps_res = config->vp9.GetKbpsRes();
|
||||
break;
|
||||
case kVideoCodecH264:
|
||||
kbps_res = config->h264.GetKbpsRes();
|
||||
break;
|
||||
case kVideoCodecAV1:
|
||||
kbps_res = config->av1.GetKbpsRes();
|
||||
break;
|
||||
case kVideoCodecGeneric:
|
||||
kbps_res = config->generic.GetKbpsRes();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (kbps_res.has_value())
|
||||
return kbps_res;
|
||||
|
||||
return config->kbps_res > 0 ? absl::optional<int>(config->kbps_res)
|
||||
: absl::nullopt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetQpLow()
|
||||
const {
|
||||
return (qp_low > 0) ? absl::optional<int>(qp_low) : absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetQpHigh()
|
||||
const {
|
||||
return (qp_high > 0) ? absl::optional<int>(qp_high) : absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetFps()
|
||||
const {
|
||||
return (fps > 0) ? absl::optional<int>(fps) : absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetKbps()
|
||||
const {
|
||||
return (kbps > 0) ? absl::optional<int>(kbps) : absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetKbpsRes()
|
||||
const {
|
||||
return (kbps_res > 0) ? absl::optional<int>(kbps_res) : absl::nullopt;
|
||||
}
|
||||
|
||||
BalancedDegradationSettings::Config::Config() = default;
|
||||
|
||||
BalancedDegradationSettings::Config::Config(int pixels,
|
||||
int fps,
|
||||
int kbps,
|
||||
int kbps_res,
|
||||
int fps_diff,
|
||||
CodecTypeSpecific vp8,
|
||||
CodecTypeSpecific vp9,
|
||||
CodecTypeSpecific h264,
|
||||
CodecTypeSpecific av1,
|
||||
CodecTypeSpecific generic)
|
||||
: pixels(pixels),
|
||||
fps(fps),
|
||||
kbps(kbps),
|
||||
kbps_res(kbps_res),
|
||||
fps_diff(fps_diff),
|
||||
vp8(vp8),
|
||||
vp9(vp9),
|
||||
h264(h264),
|
||||
av1(av1),
|
||||
generic(generic) {}
|
||||
|
||||
BalancedDegradationSettings::BalancedDegradationSettings(
|
||||
const FieldTrialsView& field_trials) {
|
||||
FieldTrialStructList<Config> configs(
|
||||
{FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }),
|
||||
FieldTrialStructMember("fps", [](Config* c) { return &c->fps; }),
|
||||
FieldTrialStructMember("kbps", [](Config* c) { return &c->kbps; }),
|
||||
FieldTrialStructMember("kbps_res",
|
||||
[](Config* c) { return &c->kbps_res; }),
|
||||
FieldTrialStructMember("fps_diff",
|
||||
[](Config* c) { return &c->fps_diff; }),
|
||||
FieldTrialStructMember("vp8_qp_low",
|
||||
[](Config* c) { return &c->vp8.qp_low; }),
|
||||
FieldTrialStructMember("vp8_qp_high",
|
||||
[](Config* c) { return &c->vp8.qp_high; }),
|
||||
FieldTrialStructMember("vp8_fps", [](Config* c) { return &c->vp8.fps; }),
|
||||
FieldTrialStructMember("vp8_kbps",
|
||||
[](Config* c) { return &c->vp8.kbps; }),
|
||||
FieldTrialStructMember("vp8_kbps_res",
|
||||
[](Config* c) { return &c->vp8.kbps_res; }),
|
||||
FieldTrialStructMember("vp9_qp_low",
|
||||
[](Config* c) { return &c->vp9.qp_low; }),
|
||||
FieldTrialStructMember("vp9_qp_high",
|
||||
[](Config* c) { return &c->vp9.qp_high; }),
|
||||
FieldTrialStructMember("vp9_fps", [](Config* c) { return &c->vp9.fps; }),
|
||||
FieldTrialStructMember("vp9_kbps",
|
||||
[](Config* c) { return &c->vp9.kbps; }),
|
||||
FieldTrialStructMember("vp9_kbps_res",
|
||||
[](Config* c) { return &c->vp9.kbps_res; }),
|
||||
FieldTrialStructMember("h264_qp_low",
|
||||
[](Config* c) { return &c->h264.qp_low; }),
|
||||
FieldTrialStructMember("h264_qp_high",
|
||||
[](Config* c) { return &c->h264.qp_high; }),
|
||||
FieldTrialStructMember("h264_fps",
|
||||
[](Config* c) { return &c->h264.fps; }),
|
||||
FieldTrialStructMember("h264_kbps",
|
||||
[](Config* c) { return &c->h264.kbps; }),
|
||||
FieldTrialStructMember("h264_kbps_res",
|
||||
[](Config* c) { return &c->h264.kbps_res; }),
|
||||
FieldTrialStructMember("av1_qp_low",
|
||||
[](Config* c) { return &c->av1.qp_low; }),
|
||||
FieldTrialStructMember("av1_qp_high",
|
||||
[](Config* c) { return &c->av1.qp_high; }),
|
||||
FieldTrialStructMember("av1_fps", [](Config* c) { return &c->av1.fps; }),
|
||||
FieldTrialStructMember("av1_kbps",
|
||||
[](Config* c) { return &c->av1.kbps; }),
|
||||
FieldTrialStructMember("av1_kbps_res",
|
||||
[](Config* c) { return &c->av1.kbps_res; }),
|
||||
FieldTrialStructMember("generic_qp_low",
|
||||
[](Config* c) { return &c->generic.qp_low; }),
|
||||
FieldTrialStructMember("generic_qp_high",
|
||||
[](Config* c) { return &c->generic.qp_high; }),
|
||||
FieldTrialStructMember("generic_fps",
|
||||
[](Config* c) { return &c->generic.fps; }),
|
||||
FieldTrialStructMember("generic_kbps",
|
||||
[](Config* c) { return &c->generic.kbps; }),
|
||||
FieldTrialStructMember("generic_kbps_res",
|
||||
[](Config* c) { return &c->generic.kbps_res; })},
|
||||
{});
|
||||
|
||||
ParseFieldTrial({&configs}, field_trials.Lookup(kFieldTrial));
|
||||
|
||||
configs_ = GetValidOrDefault(configs.Get());
|
||||
RTC_DCHECK_GT(configs_.size(), 1);
|
||||
}
|
||||
|
||||
BalancedDegradationSettings::~BalancedDegradationSettings() {}
|
||||
|
||||
std::vector<BalancedDegradationSettings::Config>
|
||||
BalancedDegradationSettings::GetConfigs() const {
|
||||
return configs_;
|
||||
}
|
||||
|
||||
int BalancedDegradationSettings::MinFps(VideoCodecType type, int pixels) const {
|
||||
return GetFps(type, GetMinFpsConfig(pixels));
|
||||
}
|
||||
|
||||
absl::optional<BalancedDegradationSettings::Config>
|
||||
BalancedDegradationSettings::GetMinFpsConfig(int pixels) const {
|
||||
for (const auto& config : configs_) {
|
||||
if (pixels <= config.pixels)
|
||||
return config;
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
int BalancedDegradationSettings::MaxFps(VideoCodecType type, int pixels) const {
|
||||
return GetFps(type, GetMaxFpsConfig(pixels));
|
||||
}
|
||||
|
||||
absl::optional<BalancedDegradationSettings::Config>
|
||||
BalancedDegradationSettings::GetMaxFpsConfig(int pixels) const {
|
||||
for (size_t i = 0; i < configs_.size() - 1; ++i) {
|
||||
if (pixels <= configs_[i].pixels)
|
||||
return configs_[i + 1];
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
bool BalancedDegradationSettings::CanAdaptUp(VideoCodecType type,
|
||||
int pixels,
|
||||
uint32_t bitrate_bps) const {
|
||||
absl::optional<int> min_kbps = GetKbps(type, GetMaxFpsConfig(pixels));
|
||||
if (!min_kbps.has_value() || bitrate_bps == 0) {
|
||||
return true; // No limit configured or bitrate provided.
|
||||
}
|
||||
return bitrate_bps >= static_cast<uint32_t>(min_kbps.value() * 1000);
|
||||
}
|
||||
|
||||
bool BalancedDegradationSettings::CanAdaptUpResolution(
|
||||
VideoCodecType type,
|
||||
int pixels,
|
||||
uint32_t bitrate_bps) const {
|
||||
absl::optional<int> min_kbps = GetKbpsRes(type, GetMaxFpsConfig(pixels));
|
||||
if (!min_kbps.has_value() || bitrate_bps == 0) {
|
||||
return true; // No limit configured or bitrate provided.
|
||||
}
|
||||
return bitrate_bps >= static_cast<uint32_t>(min_kbps.value() * 1000);
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::MinFpsDiff(int pixels) const {
|
||||
for (const auto& config : configs_) {
|
||||
if (pixels <= config.pixels) {
|
||||
return (config.fps_diff > kNoFpsDiff)
|
||||
? absl::optional<int>(config.fps_diff)
|
||||
: absl::nullopt;
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<VideoEncoder::QpThresholds>
|
||||
BalancedDegradationSettings::GetQpThresholds(VideoCodecType type,
|
||||
int pixels) const {
|
||||
return GetThresholds(type, GetConfig(pixels));
|
||||
}
|
||||
|
||||
BalancedDegradationSettings::Config BalancedDegradationSettings::GetConfig(
|
||||
int pixels) const {
|
||||
for (const auto& config : configs_) {
|
||||
if (pixels <= config.pixels)
|
||||
return config;
|
||||
}
|
||||
return configs_.back(); // Use last above highest pixels.
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_EXPERIMENTS_BALANCED_DEGRADATION_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_BALANCED_DEGRADATION_SETTINGS_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class BalancedDegradationSettings {
|
||||
public:
|
||||
static constexpr int kNoFpsDiff = -100;
|
||||
|
||||
BalancedDegradationSettings(const FieldTrialsView& field_trials);
|
||||
~BalancedDegradationSettings();
|
||||
|
||||
struct CodecTypeSpecific {
|
||||
CodecTypeSpecific() {}
|
||||
CodecTypeSpecific(int qp_low, int qp_high, int fps, int kbps, int kbps_res)
|
||||
: qp_low(qp_low),
|
||||
qp_high(qp_high),
|
||||
fps(fps),
|
||||
kbps(kbps),
|
||||
kbps_res(kbps_res) {}
|
||||
|
||||
bool operator==(const CodecTypeSpecific& o) const {
|
||||
return qp_low == o.qp_low && qp_high == o.qp_high && fps == o.fps &&
|
||||
kbps == o.kbps && kbps_res == o.kbps_res;
|
||||
}
|
||||
|
||||
absl::optional<int> GetQpLow() const;
|
||||
absl::optional<int> GetQpHigh() const;
|
||||
absl::optional<int> GetFps() const;
|
||||
absl::optional<int> GetKbps() const;
|
||||
absl::optional<int> GetKbpsRes() const;
|
||||
|
||||
// Optional settings.
|
||||
int qp_low = 0;
|
||||
int qp_high = 0;
|
||||
int fps = 0; // If unset, defaults to `fps` in Config.
|
||||
int kbps = 0; // If unset, defaults to `kbps` in Config.
|
||||
int kbps_res = 0; // If unset, defaults to `kbps_res` in Config.
|
||||
};
|
||||
|
||||
struct Config {
|
||||
Config();
|
||||
Config(int pixels,
|
||||
int fps,
|
||||
int kbps,
|
||||
int kbps_res,
|
||||
int fps_diff,
|
||||
CodecTypeSpecific vp8,
|
||||
CodecTypeSpecific vp9,
|
||||
CodecTypeSpecific h264,
|
||||
CodecTypeSpecific av1,
|
||||
CodecTypeSpecific generic);
|
||||
|
||||
bool operator==(const Config& o) const {
|
||||
return pixels == o.pixels && fps == o.fps && kbps == o.kbps &&
|
||||
kbps_res == o.kbps_res && fps_diff == o.fps_diff && vp8 == o.vp8 &&
|
||||
vp9 == o.vp9 && h264 == o.h264 && av1 == o.av1 &&
|
||||
generic == o.generic;
|
||||
}
|
||||
|
||||
// Example:
|
||||
// WebRTC-Video-BalancedDegradationSettings/pixels:100|200|300,fps:5|15|25/
|
||||
// pixels <= 100 -> min framerate: 5 fps
|
||||
// pixels <= 200 -> min framerate: 15 fps
|
||||
// pixels <= 300 -> min framerate: 25 fps
|
||||
//
|
||||
// WebRTC-Video-BalancedDegradationSettings/pixels:100|200|300,
|
||||
// fps:5|15|25, // Min framerate.
|
||||
// kbps:0|60|70, // Min bitrate needed to adapt up.
|
||||
// kbps_res:0|65|75/ // Min bitrate needed to adapt up in resolution.
|
||||
//
|
||||
// pixels: fps: kbps: kbps_res:
|
||||
// 300 30 - -
|
||||
// 300 25 70 kbps 75 kbps
|
||||
// 200 25 70 kbps -
|
||||
// 200 15 60 kbps 65 kbps
|
||||
// 100 15 60 kbps -
|
||||
// 100 5
|
||||
// optional optional
|
||||
|
||||
int pixels = 0; // Video frame size.
|
||||
// If the frame size is less than or equal to `pixels`:
|
||||
int fps = 0; // Min framerate to be used.
|
||||
int kbps = 0; // Min bitrate needed to adapt up (resolution/fps).
|
||||
int kbps_res = 0; // Min bitrate needed to adapt up in resolution.
|
||||
int fps_diff = kNoFpsDiff; // Min fps reduction needed (input fps - `fps`)
|
||||
// w/o triggering a new subsequent downgrade
|
||||
// check.
|
||||
CodecTypeSpecific vp8;
|
||||
CodecTypeSpecific vp9;
|
||||
CodecTypeSpecific h264;
|
||||
CodecTypeSpecific av1;
|
||||
CodecTypeSpecific generic;
|
||||
};
|
||||
|
||||
// Returns configurations from field trial on success (default on failure).
|
||||
std::vector<Config> GetConfigs() const;
|
||||
|
||||
// Gets the min/max framerate from `configs_` based on `pixels`.
|
||||
int MinFps(VideoCodecType type, int pixels) const;
|
||||
int MaxFps(VideoCodecType type, int pixels) const;
|
||||
|
||||
// Checks if quality can be increased based on `pixels` and `bitrate_bps`.
|
||||
bool CanAdaptUp(VideoCodecType type, int pixels, uint32_t bitrate_bps) const;
|
||||
bool CanAdaptUpResolution(VideoCodecType type,
|
||||
int pixels,
|
||||
uint32_t bitrate_bps) const;
|
||||
|
||||
// Gets the min framerate diff from `configs_` based on `pixels`.
|
||||
absl::optional<int> MinFpsDiff(int pixels) const;
|
||||
|
||||
// Gets QpThresholds for the codec `type` based on `pixels`.
|
||||
absl::optional<VideoEncoder::QpThresholds> GetQpThresholds(
|
||||
VideoCodecType type,
|
||||
int pixels) const;
|
||||
|
||||
private:
|
||||
absl::optional<Config> GetMinFpsConfig(int pixels) const;
|
||||
absl::optional<Config> GetMaxFpsConfig(int pixels) const;
|
||||
Config GetConfig(int pixels) const;
|
||||
|
||||
std::vector<Config> configs_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_BALANCED_DEGRADATION_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2021 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/bandwidth_quality_scaler_settings.h"
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
BandwidthQualityScalerSettings::BandwidthQualityScalerSettings(
|
||||
const FieldTrialsView* const key_value_config)
|
||||
: bitrate_state_update_interval_s_("bitrate_state_update_interval_s_") {
|
||||
ParseFieldTrial(
|
||||
{&bitrate_state_update_interval_s_},
|
||||
key_value_config->Lookup("WebRTC-Video-BandwidthQualityScalerSettings"));
|
||||
}
|
||||
|
||||
BandwidthQualityScalerSettings
|
||||
BandwidthQualityScalerSettings::ParseFromFieldTrials() {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return BandwidthQualityScalerSettings(&field_trial_config);
|
||||
}
|
||||
|
||||
absl::optional<uint32_t>
|
||||
BandwidthQualityScalerSettings::BitrateStateUpdateInterval() const {
|
||||
if (bitrate_state_update_interval_s_ &&
|
||||
bitrate_state_update_interval_s_.Value() <= 0) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Unsupported bitrate_state_update_interval_s_ value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return bitrate_state_update_interval_s_.GetOptional();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2021 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_BANDWIDTH_QUALITY_SCALER_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_BANDWIDTH_QUALITY_SCALER_SETTINGS_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class BandwidthQualityScalerSettings final {
|
||||
public:
|
||||
static BandwidthQualityScalerSettings ParseFromFieldTrials();
|
||||
|
||||
absl::optional<uint32_t> BitrateStateUpdateInterval() const;
|
||||
|
||||
private:
|
||||
explicit BandwidthQualityScalerSettings(
|
||||
const FieldTrialsView* const key_value_config);
|
||||
|
||||
FieldTrialOptional<uint32_t> bitrate_state_update_interval_s_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_BANDWIDTH_QUALITY_SCALER_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2018 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/cpu_speed_experiment.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rtc_base/experiments/field_trial_list.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr char kFieldTrial[] = "WebRTC-VP8-CpuSpeed-Arm";
|
||||
constexpr int kMinSetting = -16;
|
||||
constexpr int kMaxSetting = -1;
|
||||
|
||||
std::vector<CpuSpeedExperiment::Config> GetValidOrEmpty(
|
||||
const std::vector<CpuSpeedExperiment::Config>& configs) {
|
||||
if (configs.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (const auto& config : configs) {
|
||||
if (config.cpu_speed < kMinSetting || config.cpu_speed > kMaxSetting) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported cpu speed setting, value ignored.";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < configs.size(); ++i) {
|
||||
if (configs[i].pixels < configs[i - 1].pixels ||
|
||||
configs[i].cpu_speed > configs[i - 1].cpu_speed) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid parameter value provided.";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
bool HasLeCores(const std::vector<CpuSpeedExperiment::Config>& configs) {
|
||||
for (const auto& config : configs) {
|
||||
if (config.cpu_speed_le_cores == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CpuSpeedExperiment::CpuSpeedExperiment() : cores_("cores") {
|
||||
FieldTrialStructList<Config> configs(
|
||||
{FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }),
|
||||
FieldTrialStructMember("cpu_speed",
|
||||
[](Config* c) { return &c->cpu_speed; }),
|
||||
FieldTrialStructMember(
|
||||
"cpu_speed_le_cores",
|
||||
[](Config* c) { return &c->cpu_speed_le_cores; })},
|
||||
{});
|
||||
ParseFieldTrial({&configs, &cores_}, field_trial::FindFullName(kFieldTrial));
|
||||
|
||||
configs_ = GetValidOrEmpty(configs.Get());
|
||||
}
|
||||
|
||||
CpuSpeedExperiment::~CpuSpeedExperiment() {}
|
||||
|
||||
absl::optional<int> CpuSpeedExperiment::GetValue(int pixels,
|
||||
int num_cores) const {
|
||||
if (configs_.empty())
|
||||
return absl::nullopt;
|
||||
|
||||
bool use_le = HasLeCores(configs_) && cores_ && num_cores <= cores_.Value();
|
||||
|
||||
for (const auto& config : configs_) {
|
||||
if (pixels <= config.pixels)
|
||||
return use_le ? absl::optional<int>(config.cpu_speed_le_cores)
|
||||
: absl::optional<int>(config.cpu_speed);
|
||||
}
|
||||
return absl::optional<int>(kMinSetting);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2018 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_CPU_SPEED_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class CpuSpeedExperiment {
|
||||
public:
|
||||
CpuSpeedExperiment();
|
||||
~CpuSpeedExperiment();
|
||||
|
||||
// Example:
|
||||
// WebRTC-VP8-CpuSpeed-Arm/pixels:100|200|300,cpu_speed:-1|-2|-3/
|
||||
// pixels <= 100 -> cpu speed: -1
|
||||
// pixels <= 200 -> cpu speed: -2
|
||||
// pixels <= 300 -> cpu speed: -3
|
||||
|
||||
// WebRTC-VP8-CpuSpeed-Arm/pixels:100|200|300,cpu_speed:-1|-2|-3/,
|
||||
// cpu_speed_le_cores:-4|-5|-6,cores:3/
|
||||
// If `num_cores` > 3
|
||||
// pixels <= 100 -> cpu speed: -1
|
||||
// pixels <= 200 -> cpu speed: -2
|
||||
// pixels <= 300 -> cpu speed: -3
|
||||
// else
|
||||
// pixels <= 100 -> cpu speed: -4
|
||||
// pixels <= 200 -> cpu speed: -5
|
||||
// pixels <= 300 -> cpu speed: -6
|
||||
|
||||
struct Config {
|
||||
int pixels = 0; // The video frame size.
|
||||
int cpu_speed = 0; // The `cpu_speed` to be used if the frame size is less
|
||||
// than or equal to `pixels`.
|
||||
// Optional.
|
||||
int cpu_speed_le_cores = 0; // Same as `cpu_speed` above but only used if
|
||||
// `num_cores` <= `cores_`.
|
||||
};
|
||||
|
||||
// Gets the cpu speed based on `pixels` and `num_cores`.
|
||||
absl::optional<int> GetValue(int pixels, int num_cores) const;
|
||||
|
||||
private:
|
||||
std::vector<Config> configs_;
|
||||
|
||||
// Threshold for when to use `cpu_speed_le_cores`.
|
||||
FieldTrialOptional<int> cores_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* Copyright 2021 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/encoder_info_settings.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/experiments/field_trial_list.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits> ToResolutionBitrateLimits(
|
||||
const std::vector<EncoderInfoSettings::BitrateLimit>& limits) {
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits> result;
|
||||
for (const auto& limit : limits) {
|
||||
result.push_back(VideoEncoder::ResolutionBitrateLimits(
|
||||
limit.frame_size_pixels, limit.min_start_bitrate_bps,
|
||||
limit.min_bitrate_bps, limit.max_bitrate_bps));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
constexpr float kDefaultMinBitratebps = 30000;
|
||||
} // namespace
|
||||
|
||||
// Default bitrate limits for simulcast with one active stream:
|
||||
// {frame_size_pixels, min_start_bitrate_bps, min_bitrate_bps, max_bitrate_bps}.
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits>
|
||||
EncoderInfoSettings::GetDefaultSinglecastBitrateLimits(
|
||||
VideoCodecType codec_type) {
|
||||
if (codec_type == kVideoCodecAV1) {
|
||||
// AV1 singlecast max bitrate limits are higher than AV1 SVC max limits.
|
||||
// This is because in singlecast we normally have just one receiver, BWE is
|
||||
// known end-to-end and the encode target bitrate guarantees delivery of
|
||||
// video.
|
||||
// The min bitrate limits are not used in singlecast (used in SVC/simulcast
|
||||
// to de-/activate spatial layers) and are set to zero. Send resolution in
|
||||
// singlecast is assumed to be regulated by QP-based quality scaler.
|
||||
return {{320 * 180, 0, 0, 256000},
|
||||
{480 * 270, 176000, 0, 384000},
|
||||
{640 * 360, 256000, 0, 512000},
|
||||
{960 * 540, 384000, 0, 1024000},
|
||||
{1280 * 720, 576000, 0, 1536000}};
|
||||
}
|
||||
|
||||
if (codec_type == kVideoCodecVP9) {
|
||||
// VP9 singlecast bitrate limits are derived ~directly from VP9 SVC bitrate
|
||||
// limits. The current max limits are unnecessarily too strict for
|
||||
// singlecast, where BWE is known end-to-end, especially for low
|
||||
// resolutions.
|
||||
return {{320 * 180, 0, 30000, 150000},
|
||||
{480 * 270, 120000, 30000, 300000},
|
||||
{640 * 360, 190000, 30000, 420000},
|
||||
{960 * 540, 350000, 30000, 1000000},
|
||||
{1280 * 720, 480000, 30000, 1500000}};
|
||||
}
|
||||
|
||||
// VP8 and other codecs.
|
||||
return {{320 * 180, 0, 30000, 300000},
|
||||
{480 * 270, 200000, 30000, 500000},
|
||||
{640 * 360, 300000, 30000, 800000},
|
||||
{960 * 540, 500000, 30000, 1500000},
|
||||
{1280 * 720, 900000, 30000, 2500000}};
|
||||
}
|
||||
|
||||
absl::optional<VideoEncoder::ResolutionBitrateLimits>
|
||||
EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsForResolution(
|
||||
VideoCodecType codec_type,
|
||||
int frame_size_pixels) {
|
||||
VideoEncoder::EncoderInfo info;
|
||||
info.resolution_bitrate_limits =
|
||||
GetDefaultSinglecastBitrateLimits(codec_type);
|
||||
return info.GetEncoderBitrateLimitsForResolution(frame_size_pixels);
|
||||
}
|
||||
|
||||
// Return the suitable bitrate limits for specified resolution when qp is
|
||||
// untrusted, they are experimental values.
|
||||
// TODO(bugs.webrtc.org/12942): Maybe we need to add other codecs(VP8/VP9)
|
||||
// experimental values.
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits>
|
||||
EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted() {
|
||||
// Specific limits for H264/AVC
|
||||
return {{0 * 0, 0, 0, 0},
|
||||
{320 * 180, 0, 30000, 300000},
|
||||
{480 * 270, 300000, 30000, 500000},
|
||||
{640 * 360, 500000, 30000, 800000},
|
||||
{960 * 540, 800000, 30000, 1500000},
|
||||
{1280 * 720, 1500000, 30000, 2500000},
|
||||
{1920 * 1080, 2500000, 30000, 4000000}};
|
||||
}
|
||||
|
||||
// Through linear interpolation, return the bitrate limit corresponding to the
|
||||
// specified |frame_size_pixels|.
|
||||
absl::optional<VideoEncoder::ResolutionBitrateLimits>
|
||||
EncoderInfoSettings::GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted(
|
||||
absl::optional<int> frame_size_pixels,
|
||||
const std::vector<VideoEncoder::ResolutionBitrateLimits>&
|
||||
resolution_bitrate_limits) {
|
||||
if (!frame_size_pixels.has_value() || frame_size_pixels.value() <= 0) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits> bitrate_limits =
|
||||
resolution_bitrate_limits;
|
||||
|
||||
// Sort the list of bitrate limits by resolution.
|
||||
sort(bitrate_limits.begin(), bitrate_limits.end(),
|
||||
[](const VideoEncoder::ResolutionBitrateLimits& lhs,
|
||||
const VideoEncoder::ResolutionBitrateLimits& rhs) {
|
||||
return lhs.frame_size_pixels < rhs.frame_size_pixels;
|
||||
});
|
||||
|
||||
if (bitrate_limits.empty()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
int interpolation_index = -1;
|
||||
for (size_t i = 0; i < bitrate_limits.size(); ++i) {
|
||||
if (bitrate_limits[i].frame_size_pixels >= frame_size_pixels.value()) {
|
||||
interpolation_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -1 means that the maximum resolution is exceeded, we will select the
|
||||
// largest data as the return result.
|
||||
if (interpolation_index == -1) {
|
||||
return *bitrate_limits.rbegin();
|
||||
}
|
||||
|
||||
// If we have a matching resolution, return directly without interpolation.
|
||||
if (bitrate_limits[interpolation_index].frame_size_pixels ==
|
||||
frame_size_pixels.value()) {
|
||||
return bitrate_limits[interpolation_index];
|
||||
}
|
||||
|
||||
// No matching resolution, do a linear interpolate.
|
||||
int lower_pixel_count =
|
||||
bitrate_limits[interpolation_index - 1].frame_size_pixels;
|
||||
int upper_pixel_count = bitrate_limits[interpolation_index].frame_size_pixels;
|
||||
float alpha = (frame_size_pixels.value() - lower_pixel_count) * 1.0 /
|
||||
(upper_pixel_count - lower_pixel_count);
|
||||
int min_start_bitrate_bps = static_cast<int>(
|
||||
bitrate_limits[interpolation_index].min_start_bitrate_bps * alpha +
|
||||
bitrate_limits[interpolation_index - 1].min_start_bitrate_bps *
|
||||
(1.0 - alpha));
|
||||
int max_bitrate_bps = static_cast<int>(
|
||||
bitrate_limits[interpolation_index].max_bitrate_bps * alpha +
|
||||
bitrate_limits[interpolation_index - 1].max_bitrate_bps * (1.0 - alpha));
|
||||
|
||||
if (max_bitrate_bps >= min_start_bitrate_bps) {
|
||||
return VideoEncoder::ResolutionBitrateLimits(
|
||||
frame_size_pixels.value(), min_start_bitrate_bps, kDefaultMinBitratebps,
|
||||
max_bitrate_bps);
|
||||
} else {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "BitRate interpolation calculating result is abnormal. "
|
||||
<< " lower_pixel_count = " << lower_pixel_count
|
||||
<< " upper_pixel_count = " << upper_pixel_count
|
||||
<< " frame_size_pixels = " << frame_size_pixels.value()
|
||||
<< " min_start_bitrate_bps = " << min_start_bitrate_bps
|
||||
<< " min_bitrate_bps = " << kDefaultMinBitratebps
|
||||
<< " max_bitrate_bps = " << max_bitrate_bps;
|
||||
return absl::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
EncoderInfoSettings::EncoderInfoSettings(absl::string_view name)
|
||||
: requested_resolution_alignment_("requested_resolution_alignment"),
|
||||
apply_alignment_to_all_simulcast_layers_(
|
||||
"apply_alignment_to_all_simulcast_layers") {
|
||||
FieldTrialStructList<BitrateLimit> bitrate_limits(
|
||||
{FieldTrialStructMember(
|
||||
"frame_size_pixels",
|
||||
[](BitrateLimit* b) { return &b->frame_size_pixels; }),
|
||||
FieldTrialStructMember(
|
||||
"min_start_bitrate_bps",
|
||||
[](BitrateLimit* b) { return &b->min_start_bitrate_bps; }),
|
||||
FieldTrialStructMember(
|
||||
"min_bitrate_bps",
|
||||
[](BitrateLimit* b) { return &b->min_bitrate_bps; }),
|
||||
FieldTrialStructMember(
|
||||
"max_bitrate_bps",
|
||||
[](BitrateLimit* b) { return &b->max_bitrate_bps; })},
|
||||
{});
|
||||
|
||||
std::string name_str(name);
|
||||
if (field_trial::FindFullName(name_str).empty()) {
|
||||
// Encoder name not found, use common string applying to all encoders.
|
||||
name_str = "WebRTC-GetEncoderInfoOverride";
|
||||
}
|
||||
|
||||
ParseFieldTrial({&bitrate_limits, &requested_resolution_alignment_,
|
||||
&apply_alignment_to_all_simulcast_layers_},
|
||||
field_trial::FindFullName(name_str));
|
||||
|
||||
resolution_bitrate_limits_ = ToResolutionBitrateLimits(bitrate_limits.Get());
|
||||
}
|
||||
|
||||
absl::optional<uint32_t> EncoderInfoSettings::requested_resolution_alignment()
|
||||
const {
|
||||
if (requested_resolution_alignment_ &&
|
||||
requested_resolution_alignment_.Value() < 1) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported alignment value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return requested_resolution_alignment_.GetOptional();
|
||||
}
|
||||
|
||||
EncoderInfoSettings::~EncoderInfoSettings() {}
|
||||
|
||||
SimulcastEncoderAdapterEncoderInfoSettings::
|
||||
SimulcastEncoderAdapterEncoderInfoSettings()
|
||||
: EncoderInfoSettings(
|
||||
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride") {}
|
||||
|
||||
LibvpxVp8EncoderInfoSettings::LibvpxVp8EncoderInfoSettings()
|
||||
: EncoderInfoSettings("WebRTC-VP8-GetEncoderInfoOverride") {}
|
||||
|
||||
LibvpxVp9EncoderInfoSettings::LibvpxVp9EncoderInfoSettings()
|
||||
: EncoderInfoSettings("WebRTC-VP9-GetEncoderInfoOverride") {}
|
||||
|
||||
LibaomAv1EncoderInfoSettings::LibaomAv1EncoderInfoSettings()
|
||||
: EncoderInfoSettings("WebRTC-Av1-GetEncoderInfoOverride") {}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2021 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_ENCODER_INFO_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class EncoderInfoSettings {
|
||||
public:
|
||||
virtual ~EncoderInfoSettings();
|
||||
|
||||
// Bitrate limits per resolution.
|
||||
struct BitrateLimit {
|
||||
int frame_size_pixels = 0; // The video frame size.
|
||||
int min_start_bitrate_bps = 0; // The minimum bitrate to start encoding.
|
||||
int min_bitrate_bps = 0; // The minimum bitrate.
|
||||
int max_bitrate_bps = 0; // The maximum bitrate.
|
||||
};
|
||||
|
||||
absl::optional<uint32_t> requested_resolution_alignment() const;
|
||||
bool apply_alignment_to_all_simulcast_layers() const {
|
||||
return apply_alignment_to_all_simulcast_layers_.Get();
|
||||
}
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits> resolution_bitrate_limits()
|
||||
const {
|
||||
return resolution_bitrate_limits_;
|
||||
}
|
||||
|
||||
static std::vector<VideoEncoder::ResolutionBitrateLimits>
|
||||
GetDefaultSinglecastBitrateLimits(VideoCodecType codec_type);
|
||||
|
||||
static absl::optional<VideoEncoder::ResolutionBitrateLimits>
|
||||
GetDefaultSinglecastBitrateLimitsForResolution(VideoCodecType codec_type,
|
||||
int frame_size_pixels);
|
||||
|
||||
static std::vector<VideoEncoder::ResolutionBitrateLimits>
|
||||
GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted();
|
||||
|
||||
static absl::optional<VideoEncoder::ResolutionBitrateLimits>
|
||||
GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted(
|
||||
absl::optional<int> frame_size_pixels,
|
||||
const std::vector<VideoEncoder::ResolutionBitrateLimits>&
|
||||
resolution_bitrate_limits);
|
||||
|
||||
protected:
|
||||
explicit EncoderInfoSettings(absl::string_view name);
|
||||
|
||||
private:
|
||||
FieldTrialOptional<uint32_t> requested_resolution_alignment_;
|
||||
FieldTrialFlag apply_alignment_to_all_simulcast_layers_;
|
||||
std::vector<VideoEncoder::ResolutionBitrateLimits> resolution_bitrate_limits_;
|
||||
};
|
||||
|
||||
// EncoderInfo settings for SimulcastEncoderAdapter.
|
||||
class SimulcastEncoderAdapterEncoderInfoSettings : public EncoderInfoSettings {
|
||||
public:
|
||||
SimulcastEncoderAdapterEncoderInfoSettings();
|
||||
~SimulcastEncoderAdapterEncoderInfoSettings() override {}
|
||||
};
|
||||
|
||||
// EncoderInfo settings for LibvpxVp8Encoder.
|
||||
class LibvpxVp8EncoderInfoSettings : public EncoderInfoSettings {
|
||||
public:
|
||||
LibvpxVp8EncoderInfoSettings();
|
||||
~LibvpxVp8EncoderInfoSettings() override {}
|
||||
};
|
||||
|
||||
// EncoderInfo settings for LibvpxVp9Encoder.
|
||||
class LibvpxVp9EncoderInfoSettings : public EncoderInfoSettings {
|
||||
public:
|
||||
LibvpxVp9EncoderInfoSettings();
|
||||
~LibvpxVp9EncoderInfoSettings() override {}
|
||||
};
|
||||
|
||||
// EncoderInfo settings for LibaomAv1Encoder.
|
||||
class LibaomAv1EncoderInfoSettings : public EncoderInfoSettings {
|
||||
public:
|
||||
LibaomAv1EncoderInfoSettings();
|
||||
~LibaomAv1EncoderInfoSettings() override {}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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/field_trial_list.h"
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
FieldTrialListBase::FieldTrialListBase(absl::string_view key)
|
||||
: FieldTrialParameterInterface(key),
|
||||
failed_(false),
|
||||
parse_got_called_(false) {}
|
||||
|
||||
bool FieldTrialListBase::Failed() const {
|
||||
return failed_;
|
||||
}
|
||||
bool FieldTrialListBase::Used() const {
|
||||
return parse_got_called_;
|
||||
}
|
||||
|
||||
int FieldTrialListWrapper::Length() {
|
||||
return GetList()->Size();
|
||||
}
|
||||
bool FieldTrialListWrapper::Failed() {
|
||||
return GetList()->Failed();
|
||||
}
|
||||
bool FieldTrialListWrapper::Used() {
|
||||
return GetList()->Used();
|
||||
}
|
||||
|
||||
bool FieldTrialStructListBase::Parse(absl::optional<std::string> str_value) {
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return true;
|
||||
}
|
||||
|
||||
int FieldTrialStructListBase::ValidateAndGetLength() {
|
||||
int length = -1;
|
||||
for (std::unique_ptr<FieldTrialListWrapper>& list : sub_lists_) {
|
||||
if (list->Failed())
|
||||
return -1;
|
||||
else if (!list->Used())
|
||||
continue;
|
||||
else if (length == -1)
|
||||
length = list->Length();
|
||||
else if (length != list->Length())
|
||||
return -1;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Copyright 2018 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_FIELD_TRIAL_LIST_H_
|
||||
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/string_encode.h"
|
||||
|
||||
// List support for field trial strings. FieldTrialList and FieldTrialStructList
|
||||
// are used similarly to the other FieldTrialParameters, but take a variable
|
||||
// number of parameters. A FieldTrialList<T> parses a |-delimeted string into a
|
||||
// list of T, using ParseTypedParameter to parse the individual tokens.
|
||||
// Example string: "my_list:1|2|3,empty_list,other_list:aardvark".
|
||||
|
||||
// A FieldTrialStructList combines multiple lists into a list-of-structs. It
|
||||
// ensures that all its sublists parse correctly and have the same length, then
|
||||
// uses user-supplied accessor functions to write those elements into structs of
|
||||
// a user-supplied type.
|
||||
|
||||
// See the unit test for usage and behavior.
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FieldTrialListBase : public FieldTrialParameterInterface {
|
||||
protected:
|
||||
friend class FieldTrialListWrapper;
|
||||
explicit FieldTrialListBase(absl::string_view key);
|
||||
|
||||
bool Failed() const;
|
||||
bool Used() const;
|
||||
|
||||
virtual int Size() = 0;
|
||||
|
||||
bool failed_;
|
||||
bool parse_got_called_;
|
||||
};
|
||||
|
||||
// This class represents a vector of type T. The elements are separated by a |
|
||||
// and parsed using ParseTypedParameter.
|
||||
template <typename T>
|
||||
class FieldTrialList : public FieldTrialListBase {
|
||||
public:
|
||||
explicit FieldTrialList(absl::string_view key) : FieldTrialList(key, {}) {}
|
||||
FieldTrialList(absl::string_view key, std::initializer_list<T> default_values)
|
||||
: FieldTrialListBase(key), values_(default_values) {}
|
||||
|
||||
std::vector<T> Get() const { return values_; }
|
||||
operator std::vector<T>() const { return Get(); }
|
||||
typename std::vector<T>::const_reference operator[](size_t index) const {
|
||||
return values_[index];
|
||||
}
|
||||
const std::vector<T>* operator->() const { return &values_; }
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override {
|
||||
parse_got_called_ = true;
|
||||
|
||||
if (!str_value) {
|
||||
values_.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<T> new_values_;
|
||||
|
||||
for (const absl::string_view token : rtc::split(str_value.value(), '|')) {
|
||||
absl::optional<T> value = ParseTypedParameter<T>(token);
|
||||
if (value) {
|
||||
new_values_.push_back(*value);
|
||||
} else {
|
||||
failed_ = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
values_.swap(new_values_);
|
||||
return true;
|
||||
}
|
||||
|
||||
int Size() override { return values_.size(); }
|
||||
|
||||
private:
|
||||
std::vector<T> values_;
|
||||
};
|
||||
|
||||
class FieldTrialListWrapper {
|
||||
public:
|
||||
virtual ~FieldTrialListWrapper() = default;
|
||||
|
||||
// Takes the element at the given index in the wrapped list and writes it to
|
||||
// the given struct.
|
||||
virtual void WriteElement(void* struct_to_write, int index) = 0;
|
||||
|
||||
virtual FieldTrialListBase* GetList() = 0;
|
||||
|
||||
int Length();
|
||||
|
||||
// Returns true iff the wrapped list has failed to parse at least one token.
|
||||
bool Failed();
|
||||
|
||||
bool Used();
|
||||
|
||||
protected:
|
||||
FieldTrialListWrapper() = default;
|
||||
};
|
||||
|
||||
namespace field_trial_list_impl {
|
||||
// The LambdaTypeTraits struct provides type information about lambdas in the
|
||||
// template expressions below.
|
||||
template <typename T>
|
||||
struct LambdaTypeTraits : public LambdaTypeTraits<decltype(&T::operator())> {};
|
||||
|
||||
template <typename ClassType, typename RetType, typename SourceType>
|
||||
struct LambdaTypeTraits<RetType* (ClassType::*)(SourceType*) const> {
|
||||
using ret = RetType;
|
||||
using src = SourceType;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TypedFieldTrialListWrapper : FieldTrialListWrapper {
|
||||
public:
|
||||
TypedFieldTrialListWrapper(absl::string_view key,
|
||||
std::function<void(void*, T)> sink)
|
||||
: list_(key), sink_(sink) {}
|
||||
|
||||
void WriteElement(void* struct_to_write, int index) override {
|
||||
sink_(struct_to_write, list_[index]);
|
||||
}
|
||||
|
||||
FieldTrialListBase* GetList() override { return &list_; }
|
||||
|
||||
private:
|
||||
FieldTrialList<T> list_;
|
||||
std::function<void(void*, T)> sink_;
|
||||
};
|
||||
|
||||
} // namespace field_trial_list_impl
|
||||
|
||||
template <typename F,
|
||||
typename Traits = typename field_trial_list_impl::LambdaTypeTraits<F>>
|
||||
FieldTrialListWrapper* FieldTrialStructMember(absl::string_view key,
|
||||
F accessor) {
|
||||
return new field_trial_list_impl::TypedFieldTrialListWrapper<
|
||||
typename Traits::ret>(key, [accessor](void* s, typename Traits::ret t) {
|
||||
*accessor(static_cast<typename Traits::src*>(s)) = t;
|
||||
});
|
||||
}
|
||||
|
||||
// This base class is here to reduce the amount of code we have to generate for
|
||||
// each type of FieldTrialStructList.
|
||||
class FieldTrialStructListBase : public FieldTrialParameterInterface {
|
||||
protected:
|
||||
FieldTrialStructListBase(
|
||||
std::initializer_list<FieldTrialListWrapper*> sub_lists)
|
||||
: FieldTrialParameterInterface(""), sub_lists_() {
|
||||
// Take ownership of the list wrappers generated by FieldTrialStructMember
|
||||
// on the call site.
|
||||
for (FieldTrialListWrapper* const* it = sub_lists.begin();
|
||||
it != sub_lists.end(); it++) {
|
||||
sub_parameters_.push_back((*it)->GetList());
|
||||
sub_lists_.push_back(std::unique_ptr<FieldTrialListWrapper>(*it));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all of our sublists that were in the field trial string had the
|
||||
// same number of elements. If they do, we return that length. If they had
|
||||
// different lengths, any sublist had parse failures or no sublists had
|
||||
// user-supplied values, we return -1.
|
||||
int ValidateAndGetLength();
|
||||
|
||||
bool Parse(absl::optional<std::string> str_value) override;
|
||||
|
||||
std::vector<std::unique_ptr<FieldTrialListWrapper>> sub_lists_;
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
class FieldTrialStructList : public FieldTrialStructListBase {
|
||||
public:
|
||||
FieldTrialStructList(std::initializer_list<FieldTrialListWrapper*> l,
|
||||
std::initializer_list<S> default_list)
|
||||
: FieldTrialStructListBase(l), values_(default_list) {}
|
||||
|
||||
std::vector<S> Get() const { return values_; }
|
||||
operator std::vector<S>() const { return Get(); }
|
||||
const S& operator[](size_t index) const { return values_[index]; }
|
||||
const std::vector<S>* operator->() const { return &values_; }
|
||||
|
||||
protected:
|
||||
void ParseDone() override {
|
||||
int length = ValidateAndGetLength();
|
||||
|
||||
if (length == -1)
|
||||
return;
|
||||
|
||||
std::vector<S> new_values(length, S());
|
||||
|
||||
for (std::unique_ptr<FieldTrialListWrapper>& li : sub_lists_) {
|
||||
if (li->Used()) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
li->WriteElement(&new_values[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
values_.swap(new_values);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<S> values_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* 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/field_trial_parser.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
FieldTrialParameterInterface::FieldTrialParameterInterface(
|
||||
absl::string_view key)
|
||||
: key_(key) {}
|
||||
FieldTrialParameterInterface::~FieldTrialParameterInterface() {
|
||||
RTC_DCHECK(used_) << "Field trial parameter with key: '" << key_
|
||||
<< "' never used.";
|
||||
}
|
||||
|
||||
void ParseFieldTrial(
|
||||
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||||
absl::string_view trial_string) {
|
||||
std::map<absl::string_view, FieldTrialParameterInterface*> field_map;
|
||||
FieldTrialParameterInterface* keyless_field = nullptr;
|
||||
for (FieldTrialParameterInterface* field : fields) {
|
||||
field->MarkAsUsed();
|
||||
if (!field->sub_parameters_.empty()) {
|
||||
for (FieldTrialParameterInterface* sub_field : field->sub_parameters_) {
|
||||
RTC_DCHECK(!sub_field->key_.empty());
|
||||
sub_field->MarkAsUsed();
|
||||
field_map[sub_field->key_] = sub_field;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field->key_.empty()) {
|
||||
RTC_DCHECK(!keyless_field);
|
||||
keyless_field = field;
|
||||
} else {
|
||||
field_map[field->key_] = field;
|
||||
}
|
||||
}
|
||||
bool logged_unknown_key = false;
|
||||
|
||||
absl::string_view tail = trial_string;
|
||||
while (!tail.empty()) {
|
||||
size_t key_end = tail.find_first_of(",:");
|
||||
absl::string_view key = tail.substr(0, key_end);
|
||||
absl::optional<std::string> opt_value;
|
||||
if (key_end == absl::string_view::npos) {
|
||||
tail = "";
|
||||
} else if (tail[key_end] == ':') {
|
||||
tail = tail.substr(key_end + 1);
|
||||
size_t value_end = tail.find(',');
|
||||
opt_value.emplace(tail.substr(0, value_end));
|
||||
if (value_end == absl::string_view::npos) {
|
||||
tail = "";
|
||||
} else {
|
||||
tail = tail.substr(value_end + 1);
|
||||
}
|
||||
} else {
|
||||
RTC_DCHECK_EQ(tail[key_end], ',');
|
||||
tail = tail.substr(key_end + 1);
|
||||
}
|
||||
|
||||
auto field = field_map.find(key);
|
||||
if (field != field_map.end()) {
|
||||
if (!field->second->Parse(std::move(opt_value))) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
|
||||
<< "' in trial: \"" << trial_string << "\"";
|
||||
}
|
||||
} else if (!opt_value && keyless_field && !key.empty()) {
|
||||
if (!keyless_field->Parse(std::string(key))) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to read empty key field with value '"
|
||||
<< key << "' in trial: \"" << trial_string << "\"";
|
||||
}
|
||||
} else if (key.empty() || key[0] != '_') {
|
||||
// "_" is be used to prefix keys that are part of the string for
|
||||
// debugging purposes but not neccessarily used.
|
||||
// e.g. WebRTC-Experiment/param: value, _DebuggingString
|
||||
if (!logged_unknown_key) {
|
||||
RTC_LOG(LS_INFO) << "No field with key: '" << key
|
||||
<< "' (found in trial: \"" << trial_string << "\")";
|
||||
std::string valid_keys;
|
||||
for (const auto& f : field_map) {
|
||||
valid_keys.append(f.first.data(), f.first.size());
|
||||
valid_keys += ", ";
|
||||
}
|
||||
RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys;
|
||||
logged_unknown_key = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (FieldTrialParameterInterface* field : fields) {
|
||||
field->ParseDone();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str) {
|
||||
if (str == "true" || str == "1") {
|
||||
return true;
|
||||
} else if (str == "false" || str == "0") {
|
||||
return false;
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<double> ParseTypedParameter<double>(absl::string_view str) {
|
||||
double value;
|
||||
char unit[2]{0, 0};
|
||||
if (sscanf(std::string(str).c_str(), "%lf%1s", &value, unit) >= 1) {
|
||||
if (unit[0] == '%')
|
||||
return value / 100;
|
||||
return value;
|
||||
} else {
|
||||
return absl::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<int> ParseTypedParameter<int>(absl::string_view str) {
|
||||
int64_t value;
|
||||
if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) {
|
||||
if (rtc::IsValueInRangeForNumericType<int, int64_t>(value)) {
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str) {
|
||||
int64_t value;
|
||||
if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) {
|
||||
if (rtc::IsValueInRangeForNumericType<unsigned, int64_t>(value)) {
|
||||
return static_cast<unsigned>(value);
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<std::string> ParseTypedParameter<std::string>(
|
||||
absl::string_view str) {
|
||||
return std::string(str);
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
|
||||
absl::string_view str) {
|
||||
return ParseOptionalParameter<bool>(str);
|
||||
}
|
||||
template <>
|
||||
absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
|
||||
absl::string_view str) {
|
||||
return ParseOptionalParameter<int>(str);
|
||||
}
|
||||
template <>
|
||||
absl::optional<absl::optional<unsigned>>
|
||||
ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str) {
|
||||
return ParseOptionalParameter<unsigned>(str);
|
||||
}
|
||||
template <>
|
||||
absl::optional<absl::optional<double>>
|
||||
ParseTypedParameter<absl::optional<double>>(absl::string_view str) {
|
||||
return ParseOptionalParameter<double>(str);
|
||||
}
|
||||
|
||||
FieldTrialFlag::FieldTrialFlag(absl::string_view key)
|
||||
: FieldTrialFlag(key, false) {}
|
||||
|
||||
FieldTrialFlag::FieldTrialFlag(absl::string_view key, bool default_value)
|
||||
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||||
|
||||
bool FieldTrialFlag::Get() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
webrtc::FieldTrialFlag::operator bool() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
bool FieldTrialFlag::Parse(absl::optional<std::string> str_value) {
|
||||
// Only set the flag if there is no argument provided.
|
||||
if (str_value) {
|
||||
absl::optional<bool> opt_value = ParseTypedParameter<bool>(*str_value);
|
||||
if (!opt_value)
|
||||
return false;
|
||||
value_ = *opt_value;
|
||||
} else {
|
||||
value_ = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFieldTrialEnum::AbstractFieldTrialEnum(
|
||||
absl::string_view key,
|
||||
int default_value,
|
||||
std::map<std::string, int> mapping)
|
||||
: FieldTrialParameterInterface(key),
|
||||
value_(default_value),
|
||||
enum_mapping_(mapping) {
|
||||
for (auto& key_val : enum_mapping_)
|
||||
valid_values_.insert(key_val.second);
|
||||
}
|
||||
AbstractFieldTrialEnum::AbstractFieldTrialEnum(const AbstractFieldTrialEnum&) =
|
||||
default;
|
||||
AbstractFieldTrialEnum::~AbstractFieldTrialEnum() = default;
|
||||
|
||||
bool AbstractFieldTrialEnum::Parse(absl::optional<std::string> str_value) {
|
||||
if (str_value) {
|
||||
auto it = enum_mapping_.find(*str_value);
|
||||
if (it != enum_mapping_.end()) {
|
||||
value_ = it->second;
|
||||
return true;
|
||||
}
|
||||
absl::optional<int> value = ParseTypedParameter<int>(*str_value);
|
||||
if (value.has_value() &&
|
||||
(valid_values_.find(*value) != valid_values_.end())) {
|
||||
value_ = *value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template class FieldTrialParameter<bool>;
|
||||
template class FieldTrialParameter<double>;
|
||||
template class FieldTrialParameter<int>;
|
||||
template class FieldTrialParameter<unsigned>;
|
||||
template class FieldTrialParameter<std::string>;
|
||||
|
||||
template class FieldTrialConstrained<double>;
|
||||
template class FieldTrialConstrained<int>;
|
||||
template class FieldTrialConstrained<unsigned>;
|
||||
|
||||
template class FieldTrialOptional<double>;
|
||||
template class FieldTrialOptional<int>;
|
||||
template class FieldTrialOptional<unsigned>;
|
||||
template class FieldTrialOptional<bool>;
|
||||
template class FieldTrialOptional<std::string>;
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright 2018 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_FIELD_TRIAL_PARSER_H_
|
||||
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
// Field trial parser functionality. Provides funcitonality to parse field trial
|
||||
// argument strings in key:value format. Each parameter is described using
|
||||
// key:value, parameters are separated with a ,. Values can't include the comma
|
||||
// character, since there's no quote facility. For most types, white space is
|
||||
// ignored. Parameters are declared with a given type for which an
|
||||
// implementation of ParseTypedParameter should be provided. The
|
||||
// ParseTypedParameter implementation is given whatever is between the : and the
|
||||
// ,. If the key is provided without : a FieldTrialOptional will use nullopt.
|
||||
|
||||
// Example string: "my_optional,my_int:3,my_string:hello"
|
||||
|
||||
// For further description of usage and behavior, see the examples in the unit
|
||||
// tests.
|
||||
|
||||
namespace webrtc {
|
||||
class FieldTrialParameterInterface {
|
||||
public:
|
||||
virtual ~FieldTrialParameterInterface();
|
||||
std::string key() const { return key_; }
|
||||
|
||||
protected:
|
||||
// Protected to allow implementations to provide assignment and copy.
|
||||
FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default;
|
||||
FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) =
|
||||
default;
|
||||
explicit FieldTrialParameterInterface(absl::string_view key);
|
||||
friend void ParseFieldTrial(
|
||||
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||||
absl::string_view trial_string);
|
||||
void MarkAsUsed() { used_ = true; }
|
||||
virtual bool Parse(absl::optional<std::string> str_value) = 0;
|
||||
|
||||
virtual void ParseDone() {}
|
||||
|
||||
std::vector<FieldTrialParameterInterface*> sub_parameters_;
|
||||
|
||||
private:
|
||||
std::string key_;
|
||||
bool used_ = false;
|
||||
};
|
||||
|
||||
// ParseFieldTrial function parses the given string and fills the given fields
|
||||
// with extracted values if available.
|
||||
void ParseFieldTrial(
|
||||
std::initializer_list<FieldTrialParameterInterface*> fields,
|
||||
absl::string_view trial_string);
|
||||
|
||||
// Specialize this in code file for custom types. Should return absl::nullopt if
|
||||
// the given string cannot be properly parsed.
|
||||
template <typename T>
|
||||
absl::optional<T> ParseTypedParameter(absl::string_view);
|
||||
|
||||
// This class uses the ParseTypedParameter function to implement a parameter
|
||||
// implementation with an enforced default value.
|
||||
template <typename T>
|
||||
class FieldTrialParameter : public FieldTrialParameterInterface {
|
||||
public:
|
||||
FieldTrialParameter(absl::string_view key, T default_value)
|
||||
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||||
T Get() const { return value_; }
|
||||
operator T() const { return Get(); }
|
||||
const T* operator->() const { return &value_; }
|
||||
|
||||
void SetForTest(T value) { value_ = value; }
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override {
|
||||
if (str_value) {
|
||||
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
|
||||
if (value.has_value()) {
|
||||
value_ = value.value();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
};
|
||||
|
||||
// This class uses the ParseTypedParameter function to implement a parameter
|
||||
// implementation with an enforced default value and a range constraint. Values
|
||||
// outside the configured range will be ignored.
|
||||
template <typename T>
|
||||
class FieldTrialConstrained : public FieldTrialParameterInterface {
|
||||
public:
|
||||
FieldTrialConstrained(absl::string_view key,
|
||||
T default_value,
|
||||
absl::optional<T> lower_limit,
|
||||
absl::optional<T> upper_limit)
|
||||
: FieldTrialParameterInterface(key),
|
||||
value_(default_value),
|
||||
lower_limit_(lower_limit),
|
||||
upper_limit_(upper_limit) {}
|
||||
T Get() const { return value_; }
|
||||
operator T() const { return Get(); }
|
||||
const T* operator->() const { return &value_; }
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override {
|
||||
if (str_value) {
|
||||
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
|
||||
if (value && (!lower_limit_ || *value >= *lower_limit_) &&
|
||||
(!upper_limit_ || *value <= *upper_limit_)) {
|
||||
value_ = *value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
absl::optional<T> lower_limit_;
|
||||
absl::optional<T> upper_limit_;
|
||||
};
|
||||
|
||||
class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
|
||||
public:
|
||||
AbstractFieldTrialEnum(absl::string_view key,
|
||||
int default_value,
|
||||
std::map<std::string, int> mapping);
|
||||
~AbstractFieldTrialEnum() override;
|
||||
AbstractFieldTrialEnum(const AbstractFieldTrialEnum&);
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override;
|
||||
|
||||
protected:
|
||||
int value_;
|
||||
std::map<std::string, int> enum_mapping_;
|
||||
std::set<int> valid_values_;
|
||||
};
|
||||
|
||||
// The FieldTrialEnum class can be used to quickly define a parser for a
|
||||
// specific enum. It handles values provided as integers and as strings if a
|
||||
// mapping is provided.
|
||||
template <typename T>
|
||||
class FieldTrialEnum : public AbstractFieldTrialEnum {
|
||||
public:
|
||||
FieldTrialEnum(absl::string_view key,
|
||||
T default_value,
|
||||
std::map<std::string, T> mapping)
|
||||
: AbstractFieldTrialEnum(key,
|
||||
static_cast<int>(default_value),
|
||||
ToIntMap(mapping)) {}
|
||||
T Get() const { return static_cast<T>(value_); }
|
||||
operator T() const { return Get(); }
|
||||
|
||||
private:
|
||||
static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) {
|
||||
std::map<std::string, int> res;
|
||||
for (const auto& it : mapping)
|
||||
res[it.first] = static_cast<int>(it.second);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
// This class uses the ParseTypedParameter function to implement an optional
|
||||
// parameter implementation that can default to absl::nullopt.
|
||||
template <typename T>
|
||||
class FieldTrialOptional : public FieldTrialParameterInterface {
|
||||
public:
|
||||
explicit FieldTrialOptional(absl::string_view key)
|
||||
: FieldTrialParameterInterface(key) {}
|
||||
FieldTrialOptional(absl::string_view key, absl::optional<T> default_value)
|
||||
: FieldTrialParameterInterface(key), value_(default_value) {}
|
||||
absl::optional<T> GetOptional() const { return value_; }
|
||||
const T& Value() const { return value_.value(); }
|
||||
const T& operator*() const { return value_.value(); }
|
||||
const T* operator->() const { return &value_.value(); }
|
||||
explicit operator bool() const { return value_.has_value(); }
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override {
|
||||
if (str_value) {
|
||||
absl::optional<T> value = ParseTypedParameter<T>(*str_value);
|
||||
if (!value.has_value())
|
||||
return false;
|
||||
value_ = value.value();
|
||||
} else {
|
||||
value_ = absl::nullopt;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
absl::optional<T> value_;
|
||||
};
|
||||
|
||||
// Equivalent to a FieldTrialParameter<bool> in the case that both key and value
|
||||
// are present. If key is missing, evaluates to false. If key is present, but no
|
||||
// explicit value is provided, the flag evaluates to true.
|
||||
class FieldTrialFlag : public FieldTrialParameterInterface {
|
||||
public:
|
||||
explicit FieldTrialFlag(absl::string_view key);
|
||||
FieldTrialFlag(absl::string_view key, bool default_value);
|
||||
bool Get() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
protected:
|
||||
bool Parse(absl::optional<std::string> str_value) override;
|
||||
|
||||
private:
|
||||
bool value_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
absl::optional<absl::optional<T>> ParseOptionalParameter(
|
||||
absl::string_view str) {
|
||||
if (str.empty())
|
||||
return absl::optional<T>();
|
||||
auto parsed = ParseTypedParameter<T>(str);
|
||||
if (parsed.has_value())
|
||||
return parsed;
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<double> ParseTypedParameter<double>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<int> ParseTypedParameter<int>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<std::string> ParseTypedParameter<std::string>(
|
||||
absl::string_view str);
|
||||
|
||||
template <>
|
||||
absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
|
||||
absl::string_view str);
|
||||
template <>
|
||||
absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
|
||||
absl::string_view str);
|
||||
template <>
|
||||
absl::optional<absl::optional<unsigned>>
|
||||
ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<absl::optional<double>>
|
||||
ParseTypedParameter<absl::optional<double>>(absl::string_view str);
|
||||
|
||||
// Accepts true, false, else parsed with sscanf %i, true if != 0.
|
||||
extern template class FieldTrialParameter<bool>;
|
||||
// Interpreted using sscanf %lf.
|
||||
extern template class FieldTrialParameter<double>;
|
||||
// Interpreted using sscanf %i.
|
||||
extern template class FieldTrialParameter<int>;
|
||||
// Interpreted using sscanf %u.
|
||||
extern template class FieldTrialParameter<unsigned>;
|
||||
// Using the given value as is.
|
||||
extern template class FieldTrialParameter<std::string>;
|
||||
|
||||
extern template class FieldTrialConstrained<double>;
|
||||
extern template class FieldTrialConstrained<int>;
|
||||
extern template class FieldTrialConstrained<unsigned>;
|
||||
|
||||
extern template class FieldTrialOptional<double>;
|
||||
extern template class FieldTrialOptional<int>;
|
||||
extern template class FieldTrialOptional<unsigned>;
|
||||
extern template class FieldTrialOptional<bool>;
|
||||
extern template class FieldTrialOptional<std::string>;
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright 2018 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/field_trial_units.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
// Large enough to fit "seconds", the longest supported unit name.
|
||||
#define RTC_TRIAL_UNIT_LENGTH_STR "7"
|
||||
#define RTC_TRIAL_UNIT_SIZE 8
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
struct ValueWithUnit {
|
||||
double value;
|
||||
std::string unit;
|
||||
};
|
||||
|
||||
absl::optional<ValueWithUnit> ParseValueWithUnit(absl::string_view str) {
|
||||
if (str == "inf") {
|
||||
return ValueWithUnit{std::numeric_limits<double>::infinity(), ""};
|
||||
} else if (str == "-inf") {
|
||||
return ValueWithUnit{-std::numeric_limits<double>::infinity(), ""};
|
||||
} else {
|
||||
double double_val;
|
||||
char unit_char[RTC_TRIAL_UNIT_SIZE];
|
||||
unit_char[0] = 0;
|
||||
if (sscanf(std::string(str).c_str(), "%lf%" RTC_TRIAL_UNIT_LENGTH_STR "s",
|
||||
&double_val, unit_char) >= 1) {
|
||||
return ValueWithUnit{double_val, unit_char};
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
absl::optional<DataRate> ParseTypedParameter<DataRate>(absl::string_view str) {
|
||||
absl::optional<ValueWithUnit> result = ParseValueWithUnit(str);
|
||||
if (result) {
|
||||
if (result->unit.empty() || result->unit == "kbps") {
|
||||
return DataRate::KilobitsPerSec(result->value);
|
||||
} else if (result->unit == "bps") {
|
||||
return DataRate::BitsPerSec(result->value);
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<DataSize> ParseTypedParameter<DataSize>(absl::string_view str) {
|
||||
absl::optional<ValueWithUnit> result = ParseValueWithUnit(str);
|
||||
if (result) {
|
||||
if (result->unit.empty() || result->unit == "bytes")
|
||||
return DataSize::Bytes(result->value);
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<TimeDelta> ParseTypedParameter<TimeDelta>(
|
||||
absl::string_view str) {
|
||||
absl::optional<ValueWithUnit> result = ParseValueWithUnit(str);
|
||||
if (result) {
|
||||
if (result->unit == "s" || result->unit == "seconds") {
|
||||
return TimeDelta::Seconds(result->value);
|
||||
} else if (result->unit == "us") {
|
||||
return TimeDelta::Micros(result->value);
|
||||
} else if (result->unit.empty() || result->unit == "ms") {
|
||||
return TimeDelta::Millis(result->value);
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <>
|
||||
absl::optional<absl::optional<DataRate>>
|
||||
ParseTypedParameter<absl::optional<DataRate>>(absl::string_view str) {
|
||||
return ParseOptionalParameter<DataRate>(str);
|
||||
}
|
||||
template <>
|
||||
absl::optional<absl::optional<DataSize>>
|
||||
ParseTypedParameter<absl::optional<DataSize>>(absl::string_view str) {
|
||||
return ParseOptionalParameter<DataSize>(str);
|
||||
}
|
||||
template <>
|
||||
absl::optional<absl::optional<TimeDelta>>
|
||||
ParseTypedParameter<absl::optional<TimeDelta>>(absl::string_view str) {
|
||||
return ParseOptionalParameter<TimeDelta>(str);
|
||||
}
|
||||
|
||||
template class FieldTrialParameter<DataRate>;
|
||||
template class FieldTrialParameter<DataSize>;
|
||||
template class FieldTrialParameter<TimeDelta>;
|
||||
|
||||
template class FieldTrialConstrained<DataRate>;
|
||||
template class FieldTrialConstrained<DataSize>;
|
||||
template class FieldTrialConstrained<TimeDelta>;
|
||||
|
||||
template class FieldTrialOptional<DataRate>;
|
||||
template class FieldTrialOptional<DataSize>;
|
||||
template class FieldTrialOptional<TimeDelta>;
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2018 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_FIELD_TRIAL_UNITS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template <>
|
||||
absl::optional<DataRate> ParseTypedParameter<DataRate>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<DataSize> ParseTypedParameter<DataSize>(absl::string_view str);
|
||||
template <>
|
||||
absl::optional<TimeDelta> ParseTypedParameter<TimeDelta>(absl::string_view str);
|
||||
|
||||
extern template class FieldTrialParameter<DataRate>;
|
||||
extern template class FieldTrialParameter<DataSize>;
|
||||
extern template class FieldTrialParameter<TimeDelta>;
|
||||
|
||||
extern template class FieldTrialConstrained<DataRate>;
|
||||
extern template class FieldTrialConstrained<DataSize>;
|
||||
extern template class FieldTrialConstrained<TimeDelta>;
|
||||
|
||||
extern template class FieldTrialOptional<DataRate>;
|
||||
extern template class FieldTrialOptional<DataSize>;
|
||||
extern template class FieldTrialOptional<TimeDelta>;
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
||||
#include "rtc_base/experiments/keyframe_interval_settings.h"
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr char kFieldTrialName[] = "WebRTC-KeyframeInterval";
|
||||
|
||||
} // namespace
|
||||
|
||||
KeyframeIntervalSettings::KeyframeIntervalSettings(
|
||||
const FieldTrialsView* const key_value_config)
|
||||
: min_keyframe_send_interval_ms_("min_keyframe_send_interval_ms") {
|
||||
ParseFieldTrial({&min_keyframe_send_interval_ms_},
|
||||
key_value_config->Lookup(kFieldTrialName));
|
||||
}
|
||||
|
||||
KeyframeIntervalSettings KeyframeIntervalSettings::ParseFromFieldTrials() {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return KeyframeIntervalSettings(&field_trial_config);
|
||||
}
|
||||
|
||||
absl::optional<int> KeyframeIntervalSettings::MinKeyframeSendIntervalMs()
|
||||
const {
|
||||
return min_keyframe_send_interval_ms_.GetOptional();
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
|
@ -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_KEYFRAME_INTERVAL_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// TODO(bugs.webrtc.org/10427): Remove and replace with proper configuration
|
||||
// parameter, or move to using FIR if intent is to avoid triggering multiple
|
||||
// times to PLIs corresponding to the same request when RTT is large.
|
||||
class KeyframeIntervalSettings final {
|
||||
public:
|
||||
static KeyframeIntervalSettings ParseFromFieldTrials();
|
||||
|
||||
// Sender side.
|
||||
// The encoded keyframe send rate is <= 1/MinKeyframeSendIntervalMs().
|
||||
absl::optional<int> MinKeyframeSendIntervalMs() const;
|
||||
|
||||
private:
|
||||
explicit KeyframeIntervalSettings(const FieldTrialsView* key_value_config);
|
||||
|
||||
FieldTrialOptional<int> min_keyframe_send_interval_ms_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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/min_video_bitrate_experiment.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
const int kDefaultMinVideoBitrateBps = 30000;
|
||||
|
||||
namespace {
|
||||
const char kForcedFallbackFieldTrial[] =
|
||||
"WebRTC-VP8-Forced-Fallback-Encoder-v2";
|
||||
const char kMinVideoBitrateExperiment[] = "WebRTC-Video-MinVideoBitrate";
|
||||
|
||||
absl::optional<int> GetFallbackMinBpsFromFieldTrial(VideoCodecType type) {
|
||||
if (type != kVideoCodecVP8) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial)) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
const std::string group =
|
||||
webrtc::field_trial::FindFullName(kForcedFallbackFieldTrial);
|
||||
if (group.empty()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
int min_pixels; // Ignored.
|
||||
int max_pixels; // Ignored.
|
||||
int min_bps;
|
||||
if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels,
|
||||
&min_bps) != 3) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
if (min_bps <= 0) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
return min_bps;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
absl::optional<DataRate> GetExperimentalMinVideoBitrate(VideoCodecType type) {
|
||||
const absl::optional<int> fallback_min_bitrate_bps =
|
||||
GetFallbackMinBpsFromFieldTrial(type);
|
||||
if (fallback_min_bitrate_bps) {
|
||||
return DataRate::BitsPerSec(*fallback_min_bitrate_bps);
|
||||
}
|
||||
|
||||
if (webrtc::field_trial::IsEnabled(kMinVideoBitrateExperiment)) {
|
||||
webrtc::FieldTrialFlag enabled("Enabled");
|
||||
|
||||
// Backwards-compatibility with an old experiment - a generic minimum which,
|
||||
// if set, applies to all codecs.
|
||||
webrtc::FieldTrialOptional<webrtc::DataRate> min_video_bitrate("br");
|
||||
|
||||
// New experiment - per-codec minimum bitrate.
|
||||
webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_vp8("vp8_br");
|
||||
webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_vp9("vp9_br");
|
||||
webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_av1("av1_br");
|
||||
webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_h264("h264_br");
|
||||
|
||||
webrtc::ParseFieldTrial(
|
||||
{&enabled, &min_video_bitrate, &min_bitrate_vp8, &min_bitrate_vp9,
|
||||
&min_bitrate_av1, &min_bitrate_h264},
|
||||
webrtc::field_trial::FindFullName(kMinVideoBitrateExperiment));
|
||||
|
||||
if (min_video_bitrate) {
|
||||
if (min_bitrate_vp8 || min_bitrate_vp9 || min_bitrate_av1 ||
|
||||
min_bitrate_h264) {
|
||||
// "br" is mutually-exclusive with the other configuration possibilites.
|
||||
RTC_LOG(LS_WARNING) << "Self-contradictory experiment config.";
|
||||
}
|
||||
return *min_video_bitrate;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case kVideoCodecVP8:
|
||||
return min_bitrate_vp8.GetOptional();
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
|
||||
case kVideoCodecVP9:
|
||||
return min_bitrate_vp9.GetOptional();
|
||||
case kVideoCodecAV1:
|
||||
return min_bitrate_av1.GetOptional();
|
||||
case kVideoCodecH264:
|
||||
return min_bitrate_h264.GetOptional();
|
||||
case kVideoCodecGeneric:
|
||||
case kVideoCodecMultiplex:
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
}
|
||||
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/video/video_codec_type.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
extern const int kDefaultMinVideoBitrateBps;
|
||||
|
||||
// Return the experiment-driven minimum video bitrate.
|
||||
// If no experiment is effective, returns nullopt.
|
||||
absl::optional<DataRate> GetExperimentalMinVideoBitrate(VideoCodecType type);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2018 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/normalize_simulcast_size_experiment.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr char kFieldTrial[] = "WebRTC-NormalizeSimulcastResolution";
|
||||
constexpr int kMinSetting = 0;
|
||||
constexpr int kMaxSetting = 5;
|
||||
} // namespace
|
||||
|
||||
absl::optional<int> NormalizeSimulcastSizeExperiment::GetBase2Exponent() {
|
||||
if (!webrtc::field_trial::IsEnabled(kFieldTrial))
|
||||
return absl::nullopt;
|
||||
|
||||
const std::string group = webrtc::field_trial::FindFullName(kFieldTrial);
|
||||
if (group.empty())
|
||||
return absl::nullopt;
|
||||
|
||||
int exponent;
|
||||
if (sscanf(group.c_str(), "Enabled-%d", &exponent) != 1) {
|
||||
RTC_LOG(LS_WARNING) << "No parameter provided.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
if (exponent < kMinSetting || exponent > kMaxSetting) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported exp value provided, value ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
return absl::optional<int>(exponent);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2018 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_NORMALIZE_SIMULCAST_SIZE_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_NORMALIZE_SIMULCAST_SIZE_EXPERIMENT_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace webrtc {
|
||||
class NormalizeSimulcastSizeExperiment {
|
||||
public:
|
||||
// Returns the base two exponent from field trial.
|
||||
static absl::optional<int> GetBase2Exponent();
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_NORMALIZE_SIMULCAST_SIZE_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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_rampup_experiment.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
QualityRampupExperiment::QualityRampupExperiment(
|
||||
const FieldTrialsView* const key_value_config)
|
||||
: min_pixels_("min_pixels"),
|
||||
min_duration_ms_("min_duration_ms"),
|
||||
max_bitrate_factor_("max_bitrate_factor") {
|
||||
ParseFieldTrial(
|
||||
{&min_pixels_, &min_duration_ms_, &max_bitrate_factor_},
|
||||
key_value_config->Lookup("WebRTC-Video-QualityRampupSettings"));
|
||||
}
|
||||
|
||||
QualityRampupExperiment QualityRampupExperiment::ParseSettings() {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return QualityRampupExperiment(&field_trial_config);
|
||||
}
|
||||
|
||||
absl::optional<int> QualityRampupExperiment::MinPixels() const {
|
||||
return min_pixels_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<int> QualityRampupExperiment::MinDurationMs() const {
|
||||
return min_duration_ms_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<double> QualityRampupExperiment::MaxBitrateFactor() const {
|
||||
return max_bitrate_factor_.GetOptional();
|
||||
}
|
||||
|
||||
void QualityRampupExperiment::SetMaxBitrate(int pixels,
|
||||
uint32_t max_bitrate_kbps) {
|
||||
if (!min_pixels_ || pixels < min_pixels_.Value() || max_bitrate_kbps == 0) {
|
||||
return;
|
||||
}
|
||||
max_bitrate_kbps_ = std::max(max_bitrate_kbps_.value_or(0), max_bitrate_kbps);
|
||||
}
|
||||
|
||||
bool QualityRampupExperiment::BwHigh(int64_t now_ms,
|
||||
uint32_t available_bw_kbps) {
|
||||
if (!min_pixels_ || !min_duration_ms_ || !max_bitrate_kbps_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (available_bw_kbps <
|
||||
max_bitrate_kbps_.value() * MaxBitrateFactor().value_or(1)) {
|
||||
start_ms_.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!start_ms_)
|
||||
start_ms_ = now_ms;
|
||||
|
||||
return (now_ms - *start_ms_) >= min_duration_ms_.Value();
|
||||
}
|
||||
|
||||
void QualityRampupExperiment::Reset() {
|
||||
start_ms_.reset();
|
||||
max_bitrate_kbps_.reset();
|
||||
}
|
||||
|
||||
bool QualityRampupExperiment::Enabled() const {
|
||||
return min_pixels_ && min_duration_ms_;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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_RAMPUP_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_QUALITY_RAMPUP_EXPERIMENT_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class QualityRampupExperiment final {
|
||||
public:
|
||||
static QualityRampupExperiment ParseSettings();
|
||||
|
||||
absl::optional<int> MinPixels() const;
|
||||
absl::optional<int> MinDurationMs() const;
|
||||
absl::optional<double> MaxBitrateFactor() const;
|
||||
|
||||
// Sets the max bitrate and the frame size.
|
||||
// The call has no effect if the frame size is less than `min_pixels_`.
|
||||
void SetMaxBitrate(int pixels, uint32_t max_bitrate_kbps);
|
||||
|
||||
// Returns true if the available bandwidth is a certain percentage
|
||||
// (max_bitrate_factor_) above `max_bitrate_kbps_` for `min_duration_ms_`.
|
||||
bool BwHigh(int64_t now_ms, uint32_t available_bw_kbps);
|
||||
|
||||
void Reset();
|
||||
bool Enabled() const;
|
||||
|
||||
private:
|
||||
explicit QualityRampupExperiment(
|
||||
const FieldTrialsView* const key_value_config);
|
||||
|
||||
FieldTrialOptional<int> min_pixels_;
|
||||
FieldTrialOptional<int> min_duration_ms_;
|
||||
FieldTrialOptional<double> max_bitrate_factor_;
|
||||
|
||||
absl::optional<int64_t> start_ms_;
|
||||
absl::optional<uint32_t> max_bitrate_kbps_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_QUALITY_RAMPUP_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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/field_trials_view.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
const int kMinFrames = 10;
|
||||
const double kMinScaleFactor = 0.01;
|
||||
} // namespace
|
||||
|
||||
QualityScalerSettings::QualityScalerSettings(
|
||||
const FieldTrialsView& field_trials)
|
||||
: sampling_period_ms_("sampling_period_ms"),
|
||||
average_qp_window_("average_qp_window"),
|
||||
min_frames_("min_frames"),
|
||||
initial_scale_factor_("initial_scale_factor"),
|
||||
scale_factor_("scale_factor"),
|
||||
initial_bitrate_interval_ms_("initial_bitrate_interval_ms"),
|
||||
initial_bitrate_factor_("initial_bitrate_factor") {
|
||||
ParseFieldTrial({&sampling_period_ms_, &average_qp_window_, &min_frames_,
|
||||
&initial_scale_factor_, &scale_factor_,
|
||||
&initial_bitrate_interval_ms_, &initial_bitrate_factor_},
|
||||
field_trials.Lookup("WebRTC-Video-QualityScalerSettings"));
|
||||
}
|
||||
|
||||
absl::optional<int> QualityScalerSettings::SamplingPeriodMs() const {
|
||||
if (sampling_period_ms_ && sampling_period_ms_.Value() <= 0) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported sampling_period_ms value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return sampling_period_ms_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<int> QualityScalerSettings::AverageQpWindow() const {
|
||||
if (average_qp_window_ && average_qp_window_.Value() <= 0) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported average_qp_window value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return average_qp_window_.GetOptional();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
absl::optional<int> QualityScalerSettings::InitialBitrateIntervalMs() const {
|
||||
if (initial_bitrate_interval_ms_ &&
|
||||
initial_bitrate_interval_ms_.Value() < 0) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported bitrate_interval value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return initial_bitrate_interval_ms_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<double> QualityScalerSettings::InitialBitrateFactor() const {
|
||||
if (initial_bitrate_factor_ &&
|
||||
initial_bitrate_factor_.Value() < kMinScaleFactor) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported initial_bitrate_factor value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return initial_bitrate_factor_.GetOptional();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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/field_trials_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class QualityScalerSettings final {
|
||||
public:
|
||||
explicit QualityScalerSettings(const FieldTrialsView& field_trials);
|
||||
|
||||
absl::optional<int> SamplingPeriodMs() const;
|
||||
absl::optional<int> AverageQpWindow() const;
|
||||
absl::optional<int> MinFrames() const;
|
||||
absl::optional<double> InitialScaleFactor() const;
|
||||
absl::optional<double> ScaleFactor() const;
|
||||
absl::optional<int> InitialBitrateIntervalMs() const;
|
||||
absl::optional<double> InitialBitrateFactor() const;
|
||||
|
||||
private:
|
||||
FieldTrialOptional<int> sampling_period_ms_;
|
||||
FieldTrialOptional<int> average_qp_window_;
|
||||
FieldTrialOptional<int> min_frames_;
|
||||
FieldTrialOptional<double> initial_scale_factor_;
|
||||
FieldTrialOptional<double> scale_factor_;
|
||||
FieldTrialOptional<int> initial_bitrate_interval_ms_;
|
||||
FieldTrialOptional<double> initial_bitrate_factor_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2018 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_scaling_experiment.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr char kFieldTrial[] = "WebRTC-Video-QualityScaling";
|
||||
constexpr int kMinQp = 1;
|
||||
constexpr int kMaxVp8Qp = 127;
|
||||
constexpr int kMaxVp9Qp = 255;
|
||||
constexpr int kMaxH264Qp = 51;
|
||||
constexpr int kMaxGenericQp = 255;
|
||||
|
||||
#if !defined(WEBRTC_IOS)
|
||||
constexpr char kDefaultQualityScalingSetttings[] =
|
||||
"Enabled-29,95,149,205,24,37,26,36,0.9995,0.9999,1";
|
||||
#endif
|
||||
|
||||
absl::optional<VideoEncoder::QpThresholds> GetThresholds(int low,
|
||||
int high,
|
||||
int max) {
|
||||
if (low < kMinQp || high > max || high < low)
|
||||
return absl::nullopt;
|
||||
|
||||
RTC_LOG(LS_INFO) << "QP thresholds: low: " << low << ", high: " << high;
|
||||
return absl::optional<VideoEncoder::QpThresholds>(
|
||||
VideoEncoder::QpThresholds(low, high));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool QualityScalingExperiment::Enabled(const FieldTrialsView& field_trials) {
|
||||
#if defined(WEBRTC_IOS)
|
||||
return absl::StartsWith(field_trials.Lookup(kFieldTrial), "Enabled");
|
||||
#else
|
||||
return !absl::StartsWith(field_trials.Lookup(kFieldTrial), "Disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
absl::optional<QualityScalingExperiment::Settings>
|
||||
QualityScalingExperiment::ParseSettings(const FieldTrialsView& field_trials) {
|
||||
std::string group = field_trials.Lookup(kFieldTrial);
|
||||
// TODO(http://crbug.com/webrtc/12401): Completely remove the experiment code
|
||||
// after few releases.
|
||||
#if !defined(WEBRTC_IOS)
|
||||
if (group.empty())
|
||||
group = kDefaultQualityScalingSetttings;
|
||||
#endif
|
||||
Settings s;
|
||||
if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d,%d,%d,%d,%d,%f,%f,%d",
|
||||
&s.vp8_low, &s.vp8_high, &s.vp9_low, &s.vp9_high, &s.h264_low,
|
||||
&s.h264_high, &s.generic_low, &s.generic_high, &s.alpha_high,
|
||||
&s.alpha_low, &s.drop) != 11) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid number of parameters provided.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
absl::optional<VideoEncoder::QpThresholds>
|
||||
QualityScalingExperiment::GetQpThresholds(VideoCodecType codec_type,
|
||||
const FieldTrialsView& field_trials) {
|
||||
const auto settings = ParseSettings(field_trials);
|
||||
if (!settings)
|
||||
return absl::nullopt;
|
||||
|
||||
switch (codec_type) {
|
||||
case kVideoCodecVP8:
|
||||
return GetThresholds(settings->vp8_low, settings->vp8_high, kMaxVp8Qp);
|
||||
case kVideoCodecVP9:
|
||||
return GetThresholds(settings->vp9_low, settings->vp9_high, kMaxVp9Qp);
|
||||
case kVideoCodecH265:
|
||||
// TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now.
|
||||
case kVideoCodecH264:
|
||||
return GetThresholds(settings->h264_low, settings->h264_high, kMaxH264Qp);
|
||||
case kVideoCodecGeneric:
|
||||
return GetThresholds(settings->generic_low, settings->generic_high,
|
||||
kMaxGenericQp);
|
||||
default:
|
||||
return absl::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
QualityScalingExperiment::Config QualityScalingExperiment::GetConfig(
|
||||
const FieldTrialsView& field_trials) {
|
||||
const auto settings = ParseSettings(field_trials);
|
||||
if (!settings)
|
||||
return Config();
|
||||
|
||||
Config config;
|
||||
config.use_all_drop_reasons = settings->drop > 0;
|
||||
|
||||
if (settings->alpha_high < 0 || settings->alpha_low < settings->alpha_high) {
|
||||
RTC_LOG(LS_WARNING) << "Invalid alpha value provided, using default.";
|
||||
return config;
|
||||
}
|
||||
config.alpha_high = settings->alpha_high;
|
||||
config.alpha_low = settings->alpha_low;
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2018 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_SCALING_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
|
||||
namespace webrtc {
|
||||
class QualityScalingExperiment {
|
||||
public:
|
||||
struct Settings {
|
||||
int vp8_low; // VP8: low QP threshold.
|
||||
int vp8_high; // VP8: high QP threshold.
|
||||
int vp9_low; // VP9: low QP threshold.
|
||||
int vp9_high; // VP9: high QP threshold.
|
||||
int h264_low; // H264: low QP threshold.
|
||||
int h264_high; // H264: high QP threshold.
|
||||
int generic_low; // Generic: low QP threshold.
|
||||
int generic_high; // Generic: high QP threshold.
|
||||
float alpha_high; // `alpha_` for ExpFilter used when checking high QP.
|
||||
float alpha_low; // `alpha_` for ExpFilter used when checking low QP.
|
||||
int drop; // >0 sets `use_all_drop_reasons` to true.
|
||||
};
|
||||
|
||||
// Used by QualityScaler.
|
||||
struct Config {
|
||||
float alpha_high = 0.9995f;
|
||||
float alpha_low = 0.9999f;
|
||||
// If set, all type of dropped frames are used.
|
||||
// Otherwise only dropped frames by MediaOptimization are used.
|
||||
bool use_all_drop_reasons = false;
|
||||
};
|
||||
|
||||
// Returns true if the experiment is enabled.
|
||||
static bool Enabled(const FieldTrialsView& field_trials);
|
||||
|
||||
// Returns settings from field trial.
|
||||
static absl::optional<Settings> ParseSettings(
|
||||
const FieldTrialsView& field_trials);
|
||||
|
||||
// Returns QpThresholds for the `codec_type`.
|
||||
static absl::optional<VideoEncoder::QpThresholds> GetQpThresholds(
|
||||
VideoCodecType codec_type,
|
||||
const FieldTrialsView& field_trials);
|
||||
|
||||
// Returns parsed values. If the parsing fails, default values are returned.
|
||||
static Config GetConfig(const FieldTrialsView& field_trials);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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/rate_control_settings.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kDefaultAcceptedQueueMs = 350;
|
||||
|
||||
const int kDefaultMinPushbackTargetBitrateBps = 30000;
|
||||
|
||||
const char kCongestionWindowDefaultFieldTrialString[] =
|
||||
"QueueSize:350,MinBitrate:30000,DropFrame:true";
|
||||
|
||||
const char kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName[] =
|
||||
"WebRTC-UseBaseHeavyVP8TL3RateAllocation";
|
||||
|
||||
bool IsEnabled(const FieldTrialsView* const key_value_config,
|
||||
absl::string_view key) {
|
||||
return absl::StartsWith(key_value_config->Lookup(key), "Enabled");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
constexpr char CongestionWindowConfig::kKey[];
|
||||
|
||||
std::unique_ptr<StructParametersParser> CongestionWindowConfig::Parser() {
|
||||
return StructParametersParser::Create("QueueSize", &queue_size_ms, //
|
||||
"MinBitrate", &min_bitrate_bps,
|
||||
"InitWin", &initial_data_window,
|
||||
"DropFrame", &drop_frame_only);
|
||||
}
|
||||
|
||||
// static
|
||||
CongestionWindowConfig CongestionWindowConfig::Parse(absl::string_view config) {
|
||||
CongestionWindowConfig res;
|
||||
res.Parser()->Parse(config);
|
||||
return res;
|
||||
}
|
||||
|
||||
constexpr char VideoRateControlConfig::kKey[];
|
||||
|
||||
std::unique_ptr<StructParametersParser> VideoRateControlConfig::Parser() {
|
||||
// The empty comments ensures that each pair is on a separate line.
|
||||
return StructParametersParser::Create(
|
||||
"pacing_factor", &pacing_factor, //
|
||||
"alr_probing", &alr_probing, //
|
||||
"vp8_qp_max", &vp8_qp_max, //
|
||||
"vp8_min_pixels", &vp8_min_pixels, //
|
||||
"trust_vp8", &trust_vp8, //
|
||||
"trust_vp9", &trust_vp9, //
|
||||
"bitrate_adjuster", &bitrate_adjuster, //
|
||||
"adjuster_use_headroom", &adjuster_use_headroom, //
|
||||
"vp8_s0_boost", &vp8_s0_boost, //
|
||||
"vp8_base_heavy_tl3_alloc", &vp8_base_heavy_tl3_alloc);
|
||||
}
|
||||
|
||||
RateControlSettings::RateControlSettings(
|
||||
const FieldTrialsView* const key_value_config) {
|
||||
std::string congestion_window_config =
|
||||
key_value_config->Lookup(CongestionWindowConfig::kKey).empty()
|
||||
? kCongestionWindowDefaultFieldTrialString
|
||||
: key_value_config->Lookup(CongestionWindowConfig::kKey);
|
||||
congestion_window_config_ =
|
||||
CongestionWindowConfig::Parse(congestion_window_config);
|
||||
video_config_.vp8_base_heavy_tl3_alloc = IsEnabled(
|
||||
key_value_config, kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName);
|
||||
video_config_.Parser()->Parse(
|
||||
key_value_config->Lookup(VideoRateControlConfig::kKey));
|
||||
}
|
||||
|
||||
RateControlSettings::~RateControlSettings() = default;
|
||||
RateControlSettings::RateControlSettings(RateControlSettings&&) = default;
|
||||
|
||||
RateControlSettings RateControlSettings::ParseFromFieldTrials() {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return RateControlSettings(&field_trial_config);
|
||||
}
|
||||
|
||||
RateControlSettings RateControlSettings::ParseFromKeyValueConfig(
|
||||
const FieldTrialsView* const key_value_config) {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return RateControlSettings(key_value_config ? key_value_config
|
||||
: &field_trial_config);
|
||||
}
|
||||
|
||||
bool RateControlSettings::UseCongestionWindow() const {
|
||||
return static_cast<bool>(congestion_window_config_.queue_size_ms);
|
||||
}
|
||||
|
||||
int64_t RateControlSettings::GetCongestionWindowAdditionalTimeMs() const {
|
||||
return congestion_window_config_.queue_size_ms.value_or(
|
||||
kDefaultAcceptedQueueMs);
|
||||
}
|
||||
|
||||
bool RateControlSettings::UseCongestionWindowPushback() const {
|
||||
return congestion_window_config_.queue_size_ms &&
|
||||
congestion_window_config_.min_bitrate_bps;
|
||||
}
|
||||
|
||||
bool RateControlSettings::UseCongestionWindowDropFrameOnly() const {
|
||||
return congestion_window_config_.drop_frame_only;
|
||||
}
|
||||
|
||||
uint32_t RateControlSettings::CongestionWindowMinPushbackTargetBitrateBps()
|
||||
const {
|
||||
return congestion_window_config_.min_bitrate_bps.value_or(
|
||||
kDefaultMinPushbackTargetBitrateBps);
|
||||
}
|
||||
|
||||
absl::optional<DataSize>
|
||||
RateControlSettings::CongestionWindowInitialDataWindow() const {
|
||||
return congestion_window_config_.initial_data_window;
|
||||
}
|
||||
|
||||
absl::optional<double> RateControlSettings::GetPacingFactor() const {
|
||||
return video_config_.pacing_factor;
|
||||
}
|
||||
|
||||
bool RateControlSettings::UseAlrProbing() const {
|
||||
return video_config_.alr_probing;
|
||||
}
|
||||
|
||||
absl::optional<int> RateControlSettings::LibvpxVp8QpMax() const {
|
||||
if (video_config_.vp8_qp_max &&
|
||||
(*video_config_.vp8_qp_max < 0 || *video_config_.vp8_qp_max > 63)) {
|
||||
RTC_LOG(LS_WARNING) << "Unsupported vp8_qp_max_ value, ignored.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
return video_config_.vp8_qp_max;
|
||||
}
|
||||
|
||||
absl::optional<int> RateControlSettings::LibvpxVp8MinPixels() const {
|
||||
if (video_config_.vp8_min_pixels && *video_config_.vp8_min_pixels < 1) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
return video_config_.vp8_min_pixels;
|
||||
}
|
||||
|
||||
bool RateControlSettings::LibvpxVp8TrustedRateController() const {
|
||||
return video_config_.trust_vp8;
|
||||
}
|
||||
|
||||
bool RateControlSettings::Vp8BoostBaseLayerQuality() const {
|
||||
return video_config_.vp8_s0_boost;
|
||||
}
|
||||
|
||||
bool RateControlSettings::LibvpxVp9TrustedRateController() const {
|
||||
return video_config_.trust_vp9;
|
||||
}
|
||||
|
||||
bool RateControlSettings::Vp8BaseHeavyTl3RateAllocation() const {
|
||||
return video_config_.vp8_base_heavy_tl3_alloc;
|
||||
}
|
||||
|
||||
bool RateControlSettings::UseEncoderBitrateAdjuster() const {
|
||||
return video_config_.bitrate_adjuster;
|
||||
}
|
||||
|
||||
bool RateControlSettings::BitrateAdjusterCanUseNetworkHeadroom() const {
|
||||
return video_config_.adjuster_use_headroom;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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_RATE_CONTROL_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/video_codecs/video_codec.h"
|
||||
#include "rtc_base/experiments/struct_parameters_parser.h"
|
||||
#include "video/config/video_encoder_config.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
struct CongestionWindowConfig {
|
||||
static constexpr char kKey[] = "WebRTC-CongestionWindow";
|
||||
absl::optional<int> queue_size_ms;
|
||||
absl::optional<int> min_bitrate_bps;
|
||||
absl::optional<DataSize> initial_data_window;
|
||||
bool drop_frame_only = false;
|
||||
std::unique_ptr<StructParametersParser> Parser();
|
||||
static CongestionWindowConfig Parse(absl::string_view config);
|
||||
};
|
||||
|
||||
struct VideoRateControlConfig {
|
||||
static constexpr char kKey[] = "WebRTC-VideoRateControl";
|
||||
absl::optional<double> pacing_factor;
|
||||
bool alr_probing = false;
|
||||
absl::optional<int> vp8_qp_max;
|
||||
absl::optional<int> vp8_min_pixels;
|
||||
bool trust_vp8 = true;
|
||||
bool trust_vp9 = true;
|
||||
bool bitrate_adjuster = true;
|
||||
bool adjuster_use_headroom = true;
|
||||
bool vp8_s0_boost = false;
|
||||
bool vp8_base_heavy_tl3_alloc = false;
|
||||
|
||||
std::unique_ptr<StructParametersParser> Parser();
|
||||
};
|
||||
|
||||
class RateControlSettings final {
|
||||
public:
|
||||
~RateControlSettings();
|
||||
RateControlSettings(RateControlSettings&&);
|
||||
|
||||
static RateControlSettings ParseFromFieldTrials();
|
||||
static RateControlSettings ParseFromKeyValueConfig(
|
||||
const FieldTrialsView* const key_value_config);
|
||||
|
||||
// When CongestionWindowPushback is enabled, the pacer is oblivious to
|
||||
// the congestion window. The relation between outstanding data and
|
||||
// the congestion window affects encoder allocations directly.
|
||||
bool UseCongestionWindow() const;
|
||||
int64_t GetCongestionWindowAdditionalTimeMs() const;
|
||||
bool UseCongestionWindowPushback() const;
|
||||
bool UseCongestionWindowDropFrameOnly() const;
|
||||
uint32_t CongestionWindowMinPushbackTargetBitrateBps() const;
|
||||
absl::optional<DataSize> CongestionWindowInitialDataWindow() const;
|
||||
|
||||
absl::optional<double> GetPacingFactor() const;
|
||||
bool UseAlrProbing() const;
|
||||
|
||||
absl::optional<int> LibvpxVp8QpMax() const;
|
||||
absl::optional<int> LibvpxVp8MinPixels() const;
|
||||
bool LibvpxVp8TrustedRateController() const;
|
||||
bool Vp8BoostBaseLayerQuality() const;
|
||||
bool Vp8DynamicRateSettings() const;
|
||||
bool LibvpxVp9TrustedRateController() const;
|
||||
bool Vp9DynamicRateSettings() const;
|
||||
|
||||
bool Vp8BaseHeavyTl3RateAllocation() const;
|
||||
|
||||
bool UseEncoderBitrateAdjuster() const;
|
||||
bool BitrateAdjusterCanUseNetworkHeadroom() const;
|
||||
|
||||
private:
|
||||
explicit RateControlSettings(const FieldTrialsView* const key_value_config);
|
||||
|
||||
CongestionWindowConfig congestion_window_config_;
|
||||
VideoRateControlConfig video_config_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2018 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/rtt_mult_experiment.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
const char kRttMultExperiment[] = "WebRTC-RttMult";
|
||||
} // namespace
|
||||
|
||||
bool RttMultExperiment::RttMultEnabled() {
|
||||
return !field_trial::IsDisabled(kRttMultExperiment);
|
||||
}
|
||||
|
||||
absl::optional<RttMultExperiment::Settings>
|
||||
RttMultExperiment::GetRttMultValue() {
|
||||
if (!RttMultExperiment::RttMultEnabled()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
return RttMultExperiment::Settings{.rtt_mult_setting = 0.9,
|
||||
.rtt_mult_add_cap_ms = 200.0};
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2018 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_RTT_MULT_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_RTT_MULT_EXPERIMENT_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class RttMultExperiment {
|
||||
public:
|
||||
struct Settings {
|
||||
float rtt_mult_setting; // Jitter buffer size is increased by this factor
|
||||
// times the estimated RTT.
|
||||
float rtt_mult_add_cap_ms; // Jitter buffer size increase is capped by this
|
||||
// value.
|
||||
};
|
||||
|
||||
// Returns true if the experiment is enabled.
|
||||
static bool RttMultEnabled();
|
||||
|
||||
// Returns rtt_mult value and rtt_mult addition cap value from field trial.
|
||||
static absl::optional<RttMultExperiment::Settings> GetRttMultValue();
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_RTT_MULT_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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/stable_target_rate_experiment.h"
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr char kFieldTrialName[] = "WebRTC-StableTargetRate";
|
||||
} // namespace
|
||||
|
||||
StableTargetRateExperiment::StableTargetRateExperiment(
|
||||
const FieldTrialsView* const key_value_config,
|
||||
double default_video_hysteresis,
|
||||
double default_screenshare_hysteresis)
|
||||
: enabled_("enabled", false),
|
||||
video_hysteresis_factor_("video_hysteresis_factor",
|
||||
default_video_hysteresis),
|
||||
screenshare_hysteresis_factor_("screenshare_hysteresis_factor",
|
||||
default_screenshare_hysteresis) {
|
||||
ParseFieldTrial(
|
||||
{&enabled_, &video_hysteresis_factor_, &screenshare_hysteresis_factor_},
|
||||
key_value_config->Lookup(kFieldTrialName));
|
||||
}
|
||||
|
||||
StableTargetRateExperiment::StableTargetRateExperiment(
|
||||
const StableTargetRateExperiment&) = default;
|
||||
StableTargetRateExperiment::StableTargetRateExperiment(
|
||||
StableTargetRateExperiment&&) = default;
|
||||
|
||||
StableTargetRateExperiment StableTargetRateExperiment::ParseFromFieldTrials() {
|
||||
FieldTrialBasedConfig config;
|
||||
return ParseFromKeyValueConfig(&config);
|
||||
}
|
||||
|
||||
StableTargetRateExperiment StableTargetRateExperiment::ParseFromKeyValueConfig(
|
||||
const FieldTrialsView* const key_value_config) {
|
||||
return StableTargetRateExperiment(key_value_config,
|
||||
/*default_video_hysteresis=*/1.2,
|
||||
/*default_screenshare_hysteresis=*/1.35);
|
||||
}
|
||||
|
||||
bool StableTargetRateExperiment::IsEnabled() const {
|
||||
return enabled_.Get();
|
||||
}
|
||||
|
||||
double StableTargetRateExperiment::GetVideoHysteresisFactor() const {
|
||||
return video_hysteresis_factor_.Get();
|
||||
}
|
||||
|
||||
double StableTargetRateExperiment::GetScreenshareHysteresisFactor() const {
|
||||
return screenshare_hysteresis_factor_.Get();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_
|
||||
#define RTC_BASE_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_
|
||||
|
||||
#include "api/field_trials_view.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class StableTargetRateExperiment {
|
||||
public:
|
||||
StableTargetRateExperiment(const StableTargetRateExperiment&);
|
||||
StableTargetRateExperiment(StableTargetRateExperiment&&);
|
||||
static StableTargetRateExperiment ParseFromFieldTrials();
|
||||
static StableTargetRateExperiment ParseFromKeyValueConfig(
|
||||
const FieldTrialsView* const key_value_config);
|
||||
|
||||
bool IsEnabled() const;
|
||||
double GetVideoHysteresisFactor() const;
|
||||
double GetScreenshareHysteresisFactor() const;
|
||||
|
||||
private:
|
||||
explicit StableTargetRateExperiment(
|
||||
const FieldTrialsView* const key_value_config,
|
||||
double default_video_hysteresis,
|
||||
double default_screenshare_hysteresis);
|
||||
|
||||
FieldTrialParameter<bool> enabled_;
|
||||
FieldTrialParameter<double> video_hysteresis_factor_;
|
||||
FieldTrialParameter<double> screenshare_hysteresis_factor_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* 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/struct_parameters_parser.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
size_t FindOrEnd(absl::string_view str, size_t start, char delimiter) {
|
||||
size_t pos = str.find(delimiter, start);
|
||||
pos = (pos == absl::string_view::npos) ? str.length() : pos;
|
||||
return pos;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace struct_parser_impl {
|
||||
namespace {
|
||||
inline void StringEncode(std::string* target, bool val) {
|
||||
*target += rtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, double val) {
|
||||
*target += rtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, int val) {
|
||||
*target += rtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, unsigned val) {
|
||||
*target += rtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, DataRate val) {
|
||||
*target += webrtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, DataSize val) {
|
||||
*target += webrtc::ToString(val);
|
||||
}
|
||||
inline void StringEncode(std::string* target, TimeDelta val) {
|
||||
*target += webrtc::ToString(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void StringEncode(std::string* sb, absl::optional<T> val) {
|
||||
if (val)
|
||||
StringEncode(sb, *val);
|
||||
}
|
||||
} // namespace
|
||||
template <typename T>
|
||||
bool TypedParser<T>::Parse(absl::string_view src, void* target) {
|
||||
auto parsed = ParseTypedParameter<T>(std::string(src));
|
||||
if (parsed.has_value())
|
||||
*reinterpret_cast<T*>(target) = *parsed;
|
||||
return parsed.has_value();
|
||||
}
|
||||
template <typename T>
|
||||
void TypedParser<T>::Encode(const void* src, std::string* target) {
|
||||
StringEncode(target, *reinterpret_cast<const T*>(src));
|
||||
}
|
||||
|
||||
template class TypedParser<bool>;
|
||||
template class TypedParser<double>;
|
||||
template class TypedParser<int>;
|
||||
template class TypedParser<unsigned>;
|
||||
template class TypedParser<absl::optional<double>>;
|
||||
template class TypedParser<absl::optional<int>>;
|
||||
template class TypedParser<absl::optional<unsigned>>;
|
||||
|
||||
template class TypedParser<DataRate>;
|
||||
template class TypedParser<DataSize>;
|
||||
template class TypedParser<TimeDelta>;
|
||||
template class TypedParser<absl::optional<DataRate>>;
|
||||
template class TypedParser<absl::optional<DataSize>>;
|
||||
template class TypedParser<absl::optional<TimeDelta>>;
|
||||
} // namespace struct_parser_impl
|
||||
|
||||
StructParametersParser::StructParametersParser(
|
||||
std::vector<struct_parser_impl::MemberParameter> members)
|
||||
: members_(std::move(members)) {}
|
||||
|
||||
void StructParametersParser::Parse(absl::string_view src) {
|
||||
size_t i = 0;
|
||||
while (i < src.length()) {
|
||||
size_t val_end = FindOrEnd(src, i, ',');
|
||||
size_t colon_pos = FindOrEnd(src, i, ':');
|
||||
size_t key_end = std::min(val_end, colon_pos);
|
||||
size_t val_begin = key_end + 1u;
|
||||
absl::string_view key(src.substr(i, key_end - i));
|
||||
absl::string_view opt_value;
|
||||
if (val_end >= val_begin)
|
||||
opt_value = src.substr(val_begin, val_end - val_begin);
|
||||
i = val_end + 1u;
|
||||
bool found = false;
|
||||
for (auto& member : members_) {
|
||||
if (key == member.key) {
|
||||
found = true;
|
||||
if (!member.parser.parse(opt_value, member.member_ptr)) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
|
||||
<< "' in trial: \"" << src << "\"";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// "_" is be used to prefix keys that are part of the string for
|
||||
// debugging purposes but not neccessarily used.
|
||||
// e.g. WebRTC-Experiment/param: value, _DebuggingString
|
||||
if (!found && (key.empty() || key[0] != '_')) {
|
||||
RTC_LOG(LS_INFO) << "No field with key: '" << key
|
||||
<< "' (found in trial: \"" << src << "\")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string StructParametersParser::Encode() const {
|
||||
std::string res;
|
||||
bool first = true;
|
||||
for (const auto& member : members_) {
|
||||
if (!first)
|
||||
res += ",";
|
||||
res += member.key;
|
||||
res += ":";
|
||||
member.parser.encode(member.member_ptr, &res);
|
||||
first = false;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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_STRUCT_PARAMETERS_PARSER_H_
|
||||
#define RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/experiments/field_trial_units.h"
|
||||
#include "rtc_base/string_encode.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace struct_parser_impl {
|
||||
struct TypedMemberParser {
|
||||
public:
|
||||
bool (*parse)(absl::string_view src, void* target);
|
||||
void (*encode)(const void* src, std::string* target);
|
||||
};
|
||||
|
||||
struct MemberParameter {
|
||||
const char* key;
|
||||
void* member_ptr;
|
||||
TypedMemberParser parser;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypedParser {
|
||||
public:
|
||||
static bool Parse(absl::string_view src, void* target);
|
||||
static void Encode(const void* src, std::string* target);
|
||||
};
|
||||
|
||||
// Instantiated in cc file to avoid duplication during compile. Add additional
|
||||
// parsers as needed. Generally, try to use these suggested types even if the
|
||||
// context where the value is used might require a different type. For instance,
|
||||
// a size_t representing a packet size should use an int parameter as there's no
|
||||
// need to support packet sizes larger than INT32_MAX.
|
||||
extern template class TypedParser<bool>;
|
||||
extern template class TypedParser<double>;
|
||||
extern template class TypedParser<int>;
|
||||
extern template class TypedParser<unsigned>;
|
||||
extern template class TypedParser<absl::optional<double>>;
|
||||
extern template class TypedParser<absl::optional<int>>;
|
||||
extern template class TypedParser<absl::optional<unsigned>>;
|
||||
|
||||
extern template class TypedParser<DataRate>;
|
||||
extern template class TypedParser<DataSize>;
|
||||
extern template class TypedParser<TimeDelta>;
|
||||
extern template class TypedParser<absl::optional<DataRate>>;
|
||||
extern template class TypedParser<absl::optional<DataSize>>;
|
||||
extern template class TypedParser<absl::optional<TimeDelta>>;
|
||||
|
||||
template <typename T>
|
||||
void AddMembers(MemberParameter* out, const char* key, T* member) {
|
||||
*out = MemberParameter{
|
||||
key, member,
|
||||
TypedMemberParser{&TypedParser<T>::Parse, &TypedParser<T>::Encode}};
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
void AddMembers(MemberParameter* out,
|
||||
const char* key,
|
||||
T* member,
|
||||
Args... args) {
|
||||
AddMembers(out, key, member);
|
||||
AddMembers(++out, args...);
|
||||
}
|
||||
} // namespace struct_parser_impl
|
||||
|
||||
class StructParametersParser {
|
||||
public:
|
||||
template <typename T, typename... Args>
|
||||
static std::unique_ptr<StructParametersParser> Create(const char* first_key,
|
||||
T* first_member,
|
||||
Args... args) {
|
||||
std::vector<struct_parser_impl::MemberParameter> members(
|
||||
sizeof...(args) / 2 + 1);
|
||||
struct_parser_impl::AddMembers(&members.front(), std::move(first_key),
|
||||
first_member, args...);
|
||||
return absl::WrapUnique(new StructParametersParser(std::move(members)));
|
||||
}
|
||||
|
||||
void Parse(absl::string_view src);
|
||||
std::string Encode() const;
|
||||
|
||||
private:
|
||||
explicit StructParametersParser(
|
||||
std::vector<struct_parser_impl::MemberParameter> members);
|
||||
|
||||
std::vector<struct_parser_impl::MemberParameter> members_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue