blob: 884a6693826768d71d16de2526e35ed2044f56e9 [file] [log] [blame]
Åsa Perssonf3d828e2019-05-06 12:22:49 +02001/*
2 * Copyright 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "rtc_base/experiments/balanced_degradation_settings.h"
12#include <limits>
13
14#include "rtc_base/experiments/field_trial_list.h"
15#include "rtc_base/experiments/field_trial_parser.h"
16#include "rtc_base/logging.h"
17#include "system_wrappers/include/field_trial.h"
18
19namespace webrtc {
20namespace {
21constexpr char kFieldTrial[] = "WebRTC-Video-BalancedDegradationSettings";
22constexpr int kMinFps = 1;
23constexpr int kMaxFps = 100;
24
25std::vector<BalancedDegradationSettings::Config> DefaultConfigs() {
Åsa Persson48284b82019-07-08 10:01:12 +020026 return {{320 * 240, 7, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
27 {480 * 270, 10, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
28 {640 * 480, 15, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}};
Åsa Persson12314192019-06-20 15:45:07 +020029}
30
Åsa Persson48284b82019-07-08 10:01:12 +020031bool IsValidConfig(
32 const BalancedDegradationSettings::CodecTypeSpecific& config) {
33 if (config.GetQpLow().has_value() != config.GetQpHigh().has_value()) {
34 RTC_LOG(LS_WARNING) << "Neither or both thresholds should be set.";
Åsa Persson12314192019-06-20 15:45:07 +020035 return false;
36 }
Åsa Persson48284b82019-07-08 10:01:12 +020037 if (config.GetQpLow().has_value() && config.GetQpHigh().has_value() &&
38 config.GetQpLow().value() >= config.GetQpHigh().value()) {
Åsa Persson12314192019-06-20 15:45:07 +020039 RTC_LOG(LS_WARNING) << "Invalid threshold value, low >= high threshold.";
40 return false;
41 }
Åsa Persson48284b82019-07-08 10:01:12 +020042 if (config.GetFps().has_value() && (config.GetFps().value() < kMinFps ||
43 config.GetFps().value() > kMaxFps)) {
44 RTC_LOG(LS_WARNING) << "Unsupported fps setting, value ignored.";
45 return false;
46 }
47 return true;
48}
49
50bool IsValid(const BalancedDegradationSettings::CodecTypeSpecific& config1,
51 const BalancedDegradationSettings::CodecTypeSpecific& config2) {
52 bool both_or_none_set = ((config1.qp_low > 0) == (config2.qp_low > 0) &&
53 (config1.qp_high > 0) == (config2.qp_high > 0) &&
54 (config1.fps > 0) == (config2.fps > 0));
55 if (!both_or_none_set) {
56 RTC_LOG(LS_WARNING) << "Invalid value, all/none should be set.";
57 return false;
58 }
59 if (config1.fps > 0 && config1.fps < config2.fps) {
60 RTC_LOG(LS_WARNING) << "Invalid fps/pixel value provided.";
61 return false;
62 }
Åsa Persson12314192019-06-20 15:45:07 +020063 return true;
Åsa Perssonf3d828e2019-05-06 12:22:49 +020064}
65
66bool IsValid(const std::vector<BalancedDegradationSettings::Config>& configs) {
67 if (configs.size() <= 1) {
68 RTC_LOG(LS_WARNING) << "Unsupported size, value ignored.";
69 return false;
70 }
71 for (const auto& config : configs) {
72 if (config.fps < kMinFps || config.fps > kMaxFps) {
73 RTC_LOG(LS_WARNING) << "Unsupported fps setting, value ignored.";
74 return false;
75 }
76 }
77 for (size_t i = 1; i < configs.size(); ++i) {
78 if (configs[i].pixels < configs[i - 1].pixels ||
79 configs[i].fps < configs[i - 1].fps) {
Åsa Persson12314192019-06-20 15:45:07 +020080 RTC_LOG(LS_WARNING) << "Invalid fps/pixel value provided.";
81 return false;
82 }
Åsa Persson48284b82019-07-08 10:01:12 +020083 if (!IsValid(configs[i].vp8, configs[i - 1].vp8) ||
84 !IsValid(configs[i].vp9, configs[i - 1].vp9) ||
85 !IsValid(configs[i].h264, configs[i - 1].h264) ||
86 !IsValid(configs[i].generic, configs[i - 1].generic)) {
Åsa Persson12314192019-06-20 15:45:07 +020087 return false;
88 }
89 }
90 for (const auto& config : configs) {
Åsa Persson48284b82019-07-08 10:01:12 +020091 if (!IsValidConfig(config.vp8) || !IsValidConfig(config.vp9) ||
92 !IsValidConfig(config.h264) || !IsValidConfig(config.generic)) {
Åsa Perssonf3d828e2019-05-06 12:22:49 +020093 return false;
94 }
95 }
96 return true;
97}
98
99std::vector<BalancedDegradationSettings::Config> GetValidOrDefault(
100 const std::vector<BalancedDegradationSettings::Config>& configs) {
101 if (IsValid(configs)) {
102 return configs;
103 }
104 return DefaultConfigs();
105}
Åsa Persson12314192019-06-20 15:45:07 +0200106
107absl::optional<VideoEncoder::QpThresholds> GetThresholds(
108 VideoCodecType type,
109 const BalancedDegradationSettings::Config& config) {
110 absl::optional<int> low;
111 absl::optional<int> high;
112
113 switch (type) {
114 case kVideoCodecVP8:
Åsa Persson48284b82019-07-08 10:01:12 +0200115 low = config.vp8.GetQpLow();
116 high = config.vp8.GetQpHigh();
Åsa Persson12314192019-06-20 15:45:07 +0200117 break;
118 case kVideoCodecVP9:
Åsa Persson48284b82019-07-08 10:01:12 +0200119 low = config.vp9.GetQpLow();
120 high = config.vp9.GetQpHigh();
Åsa Persson12314192019-06-20 15:45:07 +0200121 break;
122 case kVideoCodecH264:
Åsa Persson48284b82019-07-08 10:01:12 +0200123 low = config.h264.GetQpLow();
124 high = config.h264.GetQpHigh();
Åsa Persson12314192019-06-20 15:45:07 +0200125 break;
126 case kVideoCodecGeneric:
Åsa Persson48284b82019-07-08 10:01:12 +0200127 low = config.generic.GetQpLow();
128 high = config.generic.GetQpHigh();
Åsa Persson12314192019-06-20 15:45:07 +0200129 break;
130 default:
131 break;
132 }
133
134 if (low && high) {
135 RTC_LOG(LS_INFO) << "QP thresholds: low: " << *low << ", high: " << *high;
136 return absl::optional<VideoEncoder::QpThresholds>(
137 VideoEncoder::QpThresholds(*low, *high));
138 }
139 return absl::nullopt;
140}
Åsa Persson48284b82019-07-08 10:01:12 +0200141
142int GetFps(VideoCodecType type,
143 const absl::optional<BalancedDegradationSettings::Config>& config) {
144 if (!config.has_value()) {
145 return std::numeric_limits<int>::max();
146 }
147
148 absl::optional<int> fps;
149 switch (type) {
150 case kVideoCodecVP8:
151 fps = config->vp8.GetFps();
152 break;
153 case kVideoCodecVP9:
154 fps = config->vp9.GetFps();
155 break;
156 case kVideoCodecH264:
157 fps = config->h264.GetFps();
158 break;
159 case kVideoCodecGeneric:
160 fps = config->generic.GetFps();
161 break;
162 default:
163 break;
164 }
165
166 return fps.value_or(config->fps);
167}
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200168} // namespace
169
Åsa Persson48284b82019-07-08 10:01:12 +0200170absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetQpLow()
171 const {
172 return (qp_low > 0) ? absl::optional<int>(qp_low) : absl::nullopt;
Åsa Persson12314192019-06-20 15:45:07 +0200173}
174
Åsa Persson48284b82019-07-08 10:01:12 +0200175absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetQpHigh()
176 const {
177 return (qp_high > 0) ? absl::optional<int>(qp_high) : absl::nullopt;
178}
179
180absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetFps()
181 const {
182 return (fps > 0) ? absl::optional<int>(fps) : absl::nullopt;
Åsa Persson12314192019-06-20 15:45:07 +0200183}
184
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200185BalancedDegradationSettings::Config::Config() = default;
186
Åsa Persson12314192019-06-20 15:45:07 +0200187BalancedDegradationSettings::Config::Config(int pixels,
188 int fps,
Åsa Persson48284b82019-07-08 10:01:12 +0200189 CodecTypeSpecific vp8,
190 CodecTypeSpecific vp9,
191 CodecTypeSpecific h264,
192 CodecTypeSpecific generic)
Åsa Persson12314192019-06-20 15:45:07 +0200193 : pixels(pixels),
194 fps(fps),
195 vp8(vp8),
196 vp9(vp9),
197 h264(h264),
198 generic(generic) {}
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200199
200BalancedDegradationSettings::BalancedDegradationSettings() {
201 FieldTrialStructList<Config> configs(
202 {FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }),
Åsa Persson12314192019-06-20 15:45:07 +0200203 FieldTrialStructMember("fps", [](Config* c) { return &c->fps; }),
204 FieldTrialStructMember("vp8_qp_low",
Åsa Persson48284b82019-07-08 10:01:12 +0200205 [](Config* c) { return &c->vp8.qp_low; }),
Åsa Persson12314192019-06-20 15:45:07 +0200206 FieldTrialStructMember("vp8_qp_high",
Åsa Persson48284b82019-07-08 10:01:12 +0200207 [](Config* c) { return &c->vp8.qp_high; }),
208 FieldTrialStructMember("vp8_fps", [](Config* c) { return &c->vp8.fps; }),
Åsa Persson12314192019-06-20 15:45:07 +0200209 FieldTrialStructMember("vp9_qp_low",
Åsa Persson48284b82019-07-08 10:01:12 +0200210 [](Config* c) { return &c->vp9.qp_low; }),
Åsa Persson12314192019-06-20 15:45:07 +0200211 FieldTrialStructMember("vp9_qp_high",
Åsa Persson48284b82019-07-08 10:01:12 +0200212 [](Config* c) { return &c->vp9.qp_high; }),
213 FieldTrialStructMember("vp9_fps", [](Config* c) { return &c->vp9.fps; }),
Åsa Persson12314192019-06-20 15:45:07 +0200214 FieldTrialStructMember("h264_qp_low",
Åsa Persson48284b82019-07-08 10:01:12 +0200215 [](Config* c) { return &c->h264.qp_low; }),
Åsa Persson12314192019-06-20 15:45:07 +0200216 FieldTrialStructMember("h264_qp_high",
Åsa Persson48284b82019-07-08 10:01:12 +0200217 [](Config* c) { return &c->h264.qp_high; }),
218 FieldTrialStructMember("h264_fps",
219 [](Config* c) { return &c->h264.fps; }),
Åsa Persson12314192019-06-20 15:45:07 +0200220 FieldTrialStructMember("generic_qp_low",
Åsa Persson48284b82019-07-08 10:01:12 +0200221 [](Config* c) { return &c->generic.qp_low; }),
Åsa Persson12314192019-06-20 15:45:07 +0200222 FieldTrialStructMember("generic_qp_high",
Åsa Persson48284b82019-07-08 10:01:12 +0200223 [](Config* c) { return &c->generic.qp_high; }),
224 FieldTrialStructMember("generic_fps",
225 [](Config* c) { return &c->generic.fps; })},
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200226 {});
227
228 ParseFieldTrial({&configs}, field_trial::FindFullName(kFieldTrial));
229
230 configs_ = GetValidOrDefault(configs.Get());
231 RTC_DCHECK_GT(configs_.size(), 1);
232}
233
234BalancedDegradationSettings::~BalancedDegradationSettings() {}
235
236std::vector<BalancedDegradationSettings::Config>
237BalancedDegradationSettings::GetConfigs() const {
238 return configs_;
239}
240
Åsa Persson48284b82019-07-08 10:01:12 +0200241int BalancedDegradationSettings::MinFps(VideoCodecType type, int pixels) const {
242 return GetFps(type, GetMinFpsConfig(pixels));
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200243}
244
Åsa Persson48284b82019-07-08 10:01:12 +0200245absl::optional<BalancedDegradationSettings::Config>
246BalancedDegradationSettings::GetMinFpsConfig(int pixels) const {
247 for (const auto& config : configs_) {
248 if (pixels <= config.pixels)
249 return config;
250 }
251 return absl::nullopt;
252}
253
254int BalancedDegradationSettings::MaxFps(VideoCodecType type, int pixels) const {
255 return GetFps(type, GetMaxFpsConfig(pixels));
256}
257
258absl::optional<BalancedDegradationSettings::Config>
259BalancedDegradationSettings::GetMaxFpsConfig(int pixels) const {
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200260 for (size_t i = 0; i < configs_.size() - 1; ++i) {
261 if (pixels <= configs_[i].pixels)
Åsa Persson48284b82019-07-08 10:01:12 +0200262 return configs_[i + 1];
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200263 }
Åsa Persson48284b82019-07-08 10:01:12 +0200264 return absl::nullopt;
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200265}
266
Åsa Persson12314192019-06-20 15:45:07 +0200267absl::optional<VideoEncoder::QpThresholds>
268BalancedDegradationSettings::GetQpThresholds(VideoCodecType type,
269 int pixels) const {
270 return GetThresholds(type, GetConfig(pixels));
271}
272
273BalancedDegradationSettings::Config BalancedDegradationSettings::GetConfig(
274 int pixels) const {
275 for (const auto& config : configs_) {
276 if (pixels <= config.pixels)
277 return config;
278 }
279 return configs_.back(); // Use last above highest pixels.
280}
281
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200282} // namespace webrtc