blob: a8d7d4d1caed030684314661e9aa00840922f250 [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 Persson12314192019-06-20 15:45:07 +020026 return {{320 * 240, 7, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
27 {480 * 270, 10, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
28 {640 * 480, 15, {0, 0}, {0, 0}, {0, 0}, {0, 0}}};
29}
30
31bool IsValidThreshold(
32 const BalancedDegradationSettings::QpThreshold& threshold) {
33 if (threshold.GetLow().has_value() != threshold.GetHigh().has_value()) {
34 RTC_LOG(LS_WARNING) << "Neither or both values should be set.";
35 return false;
36 }
37 if (threshold.GetLow().has_value() && threshold.GetHigh().has_value() &&
38 threshold.GetLow().value() >= threshold.GetHigh().value()) {
39 RTC_LOG(LS_WARNING) << "Invalid threshold value, low >= high threshold.";
40 return false;
41 }
42 return true;
Åsa Perssonf3d828e2019-05-06 12:22:49 +020043}
44
45bool IsValid(const std::vector<BalancedDegradationSettings::Config>& configs) {
46 if (configs.size() <= 1) {
47 RTC_LOG(LS_WARNING) << "Unsupported size, value ignored.";
48 return false;
49 }
50 for (const auto& config : configs) {
51 if (config.fps < kMinFps || config.fps > kMaxFps) {
52 RTC_LOG(LS_WARNING) << "Unsupported fps setting, value ignored.";
53 return false;
54 }
55 }
56 for (size_t i = 1; i < configs.size(); ++i) {
57 if (configs[i].pixels < configs[i - 1].pixels ||
58 configs[i].fps < configs[i - 1].fps) {
Åsa Persson12314192019-06-20 15:45:07 +020059 RTC_LOG(LS_WARNING) << "Invalid fps/pixel value provided.";
60 return false;
61 }
62 if (((configs[i].vp8.low > 0) != (configs[i - 1].vp8.low > 0)) ||
63 ((configs[i].vp9.low > 0) != (configs[i - 1].vp9.low > 0)) ||
64 ((configs[i].h264.low > 0) != (configs[i - 1].h264.low > 0)) ||
65 ((configs[i].generic.low > 0) != (configs[i - 1].generic.low > 0)) ||
66 ((configs[i].vp8.high > 0) != (configs[i - 1].vp8.high > 0)) ||
67 ((configs[i].vp9.high > 0) != (configs[i - 1].vp9.high > 0)) ||
68 ((configs[i].h264.high > 0) != (configs[i - 1].h264.high > 0)) ||
69 ((configs[i].generic.high > 0) != (configs[i - 1].generic.high > 0))) {
70 RTC_LOG(LS_WARNING) << "Invalid threshold value, all/none should be set.";
71 return false;
72 }
73 }
74 for (const auto& config : configs) {
75 if (!IsValidThreshold(config.vp8) || !IsValidThreshold(config.vp9) ||
76 !IsValidThreshold(config.h264) || !IsValidThreshold(config.generic)) {
Åsa Perssonf3d828e2019-05-06 12:22:49 +020077 return false;
78 }
79 }
80 return true;
81}
82
83std::vector<BalancedDegradationSettings::Config> GetValidOrDefault(
84 const std::vector<BalancedDegradationSettings::Config>& configs) {
85 if (IsValid(configs)) {
86 return configs;
87 }
88 return DefaultConfigs();
89}
Åsa Persson12314192019-06-20 15:45:07 +020090
91absl::optional<VideoEncoder::QpThresholds> GetThresholds(
92 VideoCodecType type,
93 const BalancedDegradationSettings::Config& config) {
94 absl::optional<int> low;
95 absl::optional<int> high;
96
97 switch (type) {
98 case kVideoCodecVP8:
99 low = config.vp8.GetLow();
100 high = config.vp8.GetHigh();
101 break;
102 case kVideoCodecVP9:
103 low = config.vp9.GetLow();
104 high = config.vp9.GetHigh();
105 break;
106 case kVideoCodecH264:
107 low = config.h264.GetLow();
108 high = config.h264.GetHigh();
109 break;
110 case kVideoCodecGeneric:
111 low = config.generic.GetLow();
112 high = config.generic.GetHigh();
113 break;
114 default:
115 break;
116 }
117
118 if (low && high) {
119 RTC_LOG(LS_INFO) << "QP thresholds: low: " << *low << ", high: " << *high;
120 return absl::optional<VideoEncoder::QpThresholds>(
121 VideoEncoder::QpThresholds(*low, *high));
122 }
123 return absl::nullopt;
124}
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200125} // namespace
126
Åsa Persson12314192019-06-20 15:45:07 +0200127absl::optional<int> BalancedDegradationSettings::QpThreshold::GetLow() const {
128 return (low > 0) ? absl::optional<int>(low) : absl::nullopt;
129}
130
131absl::optional<int> BalancedDegradationSettings::QpThreshold::GetHigh() const {
132 return (high > 0) ? absl::optional<int>(high) : absl::nullopt;
133}
134
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200135BalancedDegradationSettings::Config::Config() = default;
136
Åsa Persson12314192019-06-20 15:45:07 +0200137BalancedDegradationSettings::Config::Config(int pixels,
138 int fps,
139 QpThreshold vp8,
140 QpThreshold vp9,
141 QpThreshold h264,
142 QpThreshold generic)
143 : pixels(pixels),
144 fps(fps),
145 vp8(vp8),
146 vp9(vp9),
147 h264(h264),
148 generic(generic) {}
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200149
150BalancedDegradationSettings::BalancedDegradationSettings() {
151 FieldTrialStructList<Config> configs(
152 {FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }),
Åsa Persson12314192019-06-20 15:45:07 +0200153 FieldTrialStructMember("fps", [](Config* c) { return &c->fps; }),
154 FieldTrialStructMember("vp8_qp_low",
155 [](Config* c) { return &c->vp8.low; }),
156 FieldTrialStructMember("vp8_qp_high",
157 [](Config* c) { return &c->vp8.high; }),
158 FieldTrialStructMember("vp9_qp_low",
159 [](Config* c) { return &c->vp9.low; }),
160 FieldTrialStructMember("vp9_qp_high",
161 [](Config* c) { return &c->vp9.high; }),
162 FieldTrialStructMember("h264_qp_low",
163 [](Config* c) { return &c->h264.low; }),
164 FieldTrialStructMember("h264_qp_high",
165 [](Config* c) { return &c->h264.high; }),
166 FieldTrialStructMember("generic_qp_low",
167 [](Config* c) { return &c->generic.low; }),
168 FieldTrialStructMember("generic_qp_high",
169 [](Config* c) { return &c->generic.high; })},
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200170 {});
171
172 ParseFieldTrial({&configs}, field_trial::FindFullName(kFieldTrial));
173
174 configs_ = GetValidOrDefault(configs.Get());
175 RTC_DCHECK_GT(configs_.size(), 1);
176}
177
178BalancedDegradationSettings::~BalancedDegradationSettings() {}
179
180std::vector<BalancedDegradationSettings::Config>
181BalancedDegradationSettings::GetConfigs() const {
182 return configs_;
183}
184
185int BalancedDegradationSettings::MinFps(int pixels) const {
186 for (const auto& config : configs_) {
187 if (pixels <= config.pixels)
188 return config.fps;
189 }
190 return std::numeric_limits<int>::max();
191}
192
193int BalancedDegradationSettings::MaxFps(int pixels) const {
194 for (size_t i = 0; i < configs_.size() - 1; ++i) {
195 if (pixels <= configs_[i].pixels)
196 return configs_[i + 1].fps;
197 }
198 return std::numeric_limits<int>::max();
199}
200
Åsa Persson12314192019-06-20 15:45:07 +0200201absl::optional<VideoEncoder::QpThresholds>
202BalancedDegradationSettings::GetQpThresholds(VideoCodecType type,
203 int pixels) const {
204 return GetThresholds(type, GetConfig(pixels));
205}
206
207BalancedDegradationSettings::Config BalancedDegradationSettings::GetConfig(
208 int pixels) const {
209 for (const auto& config : configs_) {
210 if (pixels <= config.pixels)
211 return config;
212 }
213 return configs_.back(); // Use last above highest pixels.
214}
215
Åsa Perssonf3d828e2019-05-06 12:22:49 +0200216} // namespace webrtc