1 /*
2 * Copyright (c) 2014 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 "video/config/simulcast.h"
12
13 #include <stdint.h>
14 #include <stdio.h>
15
16 #include <algorithm>
17 #include <string>
18 #include <vector>
19
20 #include "absl/strings/match.h"
21 #include "absl/types/optional.h"
22 #include "api/video/video_codec_constants.h"
23 #include "media/base/media_constants.h"
24 #include "modules/video_coding/utility/simulcast_rate_allocator.h"
25 #include "rtc_base/checks.h"
26 #include "rtc_base/experiments/field_trial_parser.h"
27 #include "rtc_base/experiments/min_video_bitrate_experiment.h"
28 #include "rtc_base/experiments/normalize_simulcast_size_experiment.h"
29 #include "rtc_base/experiments/rate_control_settings.h"
30 #include "rtc_base/logging.h"
31
32 namespace cricket {
33
34 namespace {
35
36 constexpr char kUseLegacySimulcastLayerLimitFieldTrial[] =
37 "WebRTC-LegacySimulcastLayerLimit";
38
39 constexpr double kDefaultMaxRoundupRate = 0.1;
40
41 // Limits for legacy conference screensharing mode. Currently used for the
42 // lower of the two simulcast streams.
43 constexpr webrtc::DataRate kScreenshareDefaultTl0Bitrate =
44 webrtc::DataRate::KilobitsPerSec(200);
45 constexpr webrtc::DataRate kScreenshareDefaultTl1Bitrate =
46 webrtc::DataRate::KilobitsPerSec(1000);
47
48 // Min/max bitrate for the higher one of the two simulcast stream used for
49 // screen content.
50 constexpr webrtc::DataRate kScreenshareHighStreamMinBitrate =
51 webrtc::DataRate::KilobitsPerSec(600);
52 constexpr webrtc::DataRate kScreenshareHighStreamMaxBitrate =
53 webrtc::DataRate::KilobitsPerSec(1250);
54
55 constexpr int kDefaultNumTemporalLayers = 3;
56 constexpr int kScreenshareMaxSimulcastLayers = 2;
57 constexpr int kScreenshareTemporalLayers = 2;
58
59 struct SimulcastFormat {
60 int width;
61 int height;
62 // The maximum number of simulcast layers can be used for
63 // resolutions at `widthxheight` for legacy applications.
64 size_t max_layers;
65 // The maximum bitrate for encoding stream at `widthxheight`, when we are
66 // not sending the next higher spatial stream.
67 webrtc::DataRate max_bitrate;
68 // The target bitrate for encoding stream at `widthxheight`, when this layer
69 // is not the highest layer (i.e., when we are sending another higher spatial
70 // stream).
71 webrtc::DataRate target_bitrate;
72 // The minimum bitrate needed for encoding stream at `widthxheight`.
73 webrtc::DataRate min_bitrate;
74 };
75
76 // These tables describe from which resolution we can use how many
77 // simulcast layers at what bitrates (maximum, target, and minimum).
78 // Important!! Keep this table from high resolution to low resolution.
79 constexpr const SimulcastFormat kSimulcastFormats[] = {
80 {1920, 1080, 3, webrtc::DataRate::KilobitsPerSec(5000),
81 webrtc::DataRate::KilobitsPerSec(4000),
82 webrtc::DataRate::KilobitsPerSec(800)},
83 {1280, 720, 3, webrtc::DataRate::KilobitsPerSec(2500),
84 webrtc::DataRate::KilobitsPerSec(2500),
85 webrtc::DataRate::KilobitsPerSec(600)},
86 {960, 540, 3, webrtc::DataRate::KilobitsPerSec(1200),
87 webrtc::DataRate::KilobitsPerSec(1200),
88 webrtc::DataRate::KilobitsPerSec(350)},
89 {640, 360, 2, webrtc::DataRate::KilobitsPerSec(700),
90 webrtc::DataRate::KilobitsPerSec(500),
91 webrtc::DataRate::KilobitsPerSec(150)},
92 {480, 270, 2, webrtc::DataRate::KilobitsPerSec(450),
93 webrtc::DataRate::KilobitsPerSec(350),
94 webrtc::DataRate::KilobitsPerSec(150)},
95 {320, 180, 1, webrtc::DataRate::KilobitsPerSec(200),
96 webrtc::DataRate::KilobitsPerSec(150),
97 webrtc::DataRate::KilobitsPerSec(30)},
98 // As the resolution goes down, interpolate the target and max bitrates down
99 // towards zero. The min bitrate is still limited at 30 kbps and the target
100 // and the max will be capped from below accordingly.
101 {0, 0, 1, webrtc::DataRate::KilobitsPerSec(0),
102 webrtc::DataRate::KilobitsPerSec(0),
103 webrtc::DataRate::KilobitsPerSec(30)}};
104
Interpolate(const webrtc::DataRate & a,const webrtc::DataRate & b,float rate)105 constexpr webrtc::DataRate Interpolate(const webrtc::DataRate& a,
106 const webrtc::DataRate& b,
107 float rate) {
108 return a * (1.0 - rate) + b * rate;
109 }
110
111 // TODO(webrtc:12415): Flip this to a kill switch when this feature launches.
EnableLowresBitrateInterpolation(const webrtc::FieldTrialsView & trials)112 bool EnableLowresBitrateInterpolation(const webrtc::FieldTrialsView& trials) {
113 return absl::StartsWith(
114 trials.Lookup("WebRTC-LowresSimulcastBitrateInterpolation"), "Enabled");
115 }
116
GetSimulcastFormats(bool enable_lowres_bitrate_interpolation)117 std::vector<SimulcastFormat> GetSimulcastFormats(
118 bool enable_lowres_bitrate_interpolation) {
119 std::vector<SimulcastFormat> formats;
120 formats.insert(formats.begin(), std::begin(kSimulcastFormats),
121 std::end(kSimulcastFormats));
122 if (!enable_lowres_bitrate_interpolation) {
123 RTC_CHECK_GE(formats.size(), 2u);
124 SimulcastFormat& format0x0 = formats[formats.size() - 1];
125 const SimulcastFormat& format_prev = formats[formats.size() - 2];
126 format0x0.max_bitrate = format_prev.max_bitrate;
127 format0x0.target_bitrate = format_prev.target_bitrate;
128 format0x0.min_bitrate = format_prev.min_bitrate;
129 }
130 return formats;
131 }
132
133 // Multiway: Number of temporal layers for each simulcast stream.
DefaultNumberOfTemporalLayers(const webrtc::FieldTrialsView & trials)134 int DefaultNumberOfTemporalLayers(const webrtc::FieldTrialsView& trials) {
135 const std::string group_name =
136 trials.Lookup("WebRTC-VP8ConferenceTemporalLayers");
137 if (group_name.empty())
138 return kDefaultNumTemporalLayers;
139
140 int num_temporal_layers = kDefaultNumTemporalLayers;
141 if (sscanf(group_name.c_str(), "%d", &num_temporal_layers) == 1 &&
142 num_temporal_layers > 0 &&
143 num_temporal_layers <= webrtc::kMaxTemporalStreams) {
144 return num_temporal_layers;
145 }
146
147 RTC_LOG(LS_WARNING) << "Attempt to set number of temporal layers to "
148 "incorrect value: "
149 << group_name;
150
151 return kDefaultNumTemporalLayers;
152 }
153
FindSimulcastFormatIndex(int width,int height,bool enable_lowres_bitrate_interpolation)154 int FindSimulcastFormatIndex(int width,
155 int height,
156 bool enable_lowres_bitrate_interpolation) {
157 RTC_DCHECK_GE(width, 0);
158 RTC_DCHECK_GE(height, 0);
159 const auto formats = GetSimulcastFormats(enable_lowres_bitrate_interpolation);
160 for (uint32_t i = 0; i < formats.size(); ++i) {
161 if (width * height >= formats[i].width * formats[i].height) {
162 return i;
163 }
164 }
165 RTC_DCHECK_NOTREACHED();
166 return -1;
167 }
168
169 } // namespace
170
171 // Round size to nearest simulcast-friendly size.
172 // Simulcast stream width and height must both be dividable by
173 // |2 ^ (simulcast_layers - 1)|.
NormalizeSimulcastSize(int size,size_t simulcast_layers)174 int NormalizeSimulcastSize(int size, size_t simulcast_layers) {
175 int base2_exponent = static_cast<int>(simulcast_layers) - 1;
176 const absl::optional<int> experimental_base2_exponent =
177 webrtc::NormalizeSimulcastSizeExperiment::GetBase2Exponent();
178 if (experimental_base2_exponent &&
179 (size > (1 << *experimental_base2_exponent))) {
180 base2_exponent = *experimental_base2_exponent;
181 }
182 return ((size >> base2_exponent) << base2_exponent);
183 }
184
InterpolateSimulcastFormat(int width,int height,absl::optional<double> max_roundup_rate,bool enable_lowres_bitrate_interpolation)185 SimulcastFormat InterpolateSimulcastFormat(
186 int width,
187 int height,
188 absl::optional<double> max_roundup_rate,
189 bool enable_lowres_bitrate_interpolation) {
190 const auto formats = GetSimulcastFormats(enable_lowres_bitrate_interpolation);
191 const int index = FindSimulcastFormatIndex(
192 width, height, enable_lowres_bitrate_interpolation);
193 if (index == 0)
194 return formats[index];
195 const int total_pixels_up =
196 formats[index - 1].width * formats[index - 1].height;
197 const int total_pixels_down = formats[index].width * formats[index].height;
198 const int total_pixels = width * height;
199 const float rate = (total_pixels_up - total_pixels) /
200 static_cast<float>(total_pixels_up - total_pixels_down);
201
202 // Use upper resolution if `rate` is below the configured threshold.
203 size_t max_layers = (rate < max_roundup_rate.value_or(kDefaultMaxRoundupRate))
204 ? formats[index - 1].max_layers
205 : formats[index].max_layers;
206 webrtc::DataRate max_bitrate = Interpolate(formats[index - 1].max_bitrate,
207 formats[index].max_bitrate, rate);
208 webrtc::DataRate target_bitrate = Interpolate(
209 formats[index - 1].target_bitrate, formats[index].target_bitrate, rate);
210 webrtc::DataRate min_bitrate = Interpolate(formats[index - 1].min_bitrate,
211 formats[index].min_bitrate, rate);
212
213 return {width, height, max_layers, max_bitrate, target_bitrate, min_bitrate};
214 }
215
InterpolateSimulcastFormat(int width,int height,bool enable_lowres_bitrate_interpolation)216 SimulcastFormat InterpolateSimulcastFormat(
217 int width,
218 int height,
219 bool enable_lowres_bitrate_interpolation) {
220 return InterpolateSimulcastFormat(width, height, absl::nullopt,
221 enable_lowres_bitrate_interpolation);
222 }
223
FindSimulcastMaxBitrate(int width,int height,bool enable_lowres_bitrate_interpolation)224 webrtc::DataRate FindSimulcastMaxBitrate(
225 int width,
226 int height,
227 bool enable_lowres_bitrate_interpolation) {
228 return InterpolateSimulcastFormat(width, height,
229 enable_lowres_bitrate_interpolation)
230 .max_bitrate;
231 }
232
FindSimulcastTargetBitrate(int width,int height,bool enable_lowres_bitrate_interpolation)233 webrtc::DataRate FindSimulcastTargetBitrate(
234 int width,
235 int height,
236 bool enable_lowres_bitrate_interpolation) {
237 return InterpolateSimulcastFormat(width, height,
238 enable_lowres_bitrate_interpolation)
239 .target_bitrate;
240 }
241
FindSimulcastMinBitrate(int width,int height,bool enable_lowres_bitrate_interpolation)242 webrtc::DataRate FindSimulcastMinBitrate(
243 int width,
244 int height,
245 bool enable_lowres_bitrate_interpolation) {
246 return InterpolateSimulcastFormat(width, height,
247 enable_lowres_bitrate_interpolation)
248 .min_bitrate;
249 }
250
BoostMaxSimulcastLayer(webrtc::DataRate max_bitrate,std::vector<webrtc::VideoStream> * layers)251 void BoostMaxSimulcastLayer(webrtc::DataRate max_bitrate,
252 std::vector<webrtc::VideoStream>* layers) {
253 if (layers->empty())
254 return;
255
256 const webrtc::DataRate total_bitrate = GetTotalMaxBitrate(*layers);
257
258 // We're still not using all available bits.
259 if (total_bitrate < max_bitrate) {
260 // Spend additional bits to boost the max layer.
261 const webrtc::DataRate bitrate_left = max_bitrate - total_bitrate;
262 layers->back().max_bitrate_bps += bitrate_left.bps();
263 }
264 }
265
GetTotalMaxBitrate(const std::vector<webrtc::VideoStream> & layers)266 webrtc::DataRate GetTotalMaxBitrate(
267 const std::vector<webrtc::VideoStream>& layers) {
268 if (layers.empty())
269 return webrtc::DataRate::Zero();
270
271 int total_max_bitrate_bps = 0;
272 for (size_t s = 0; s < layers.size() - 1; ++s) {
273 total_max_bitrate_bps += layers[s].target_bitrate_bps;
274 }
275 total_max_bitrate_bps += layers.back().max_bitrate_bps;
276 return webrtc::DataRate::BitsPerSec(total_max_bitrate_bps);
277 }
278
LimitSimulcastLayerCount(int width,int height,size_t need_layers,size_t layer_count,const webrtc::FieldTrialsView & trials)279 size_t LimitSimulcastLayerCount(int width,
280 int height,
281 size_t need_layers,
282 size_t layer_count,
283 const webrtc::FieldTrialsView& trials) {
284 if (!absl::StartsWith(trials.Lookup(kUseLegacySimulcastLayerLimitFieldTrial),
285 "Disabled")) {
286 // Max layers from one higher resolution in kSimulcastFormats will be used
287 // if the ratio (pixels_up - pixels) / (pixels_up - pixels_down) is less
288 // than configured `max_ratio`. pixels_down is the selected index in
289 // kSimulcastFormats based on pixels.
290 webrtc::FieldTrialOptional<double> max_ratio("max_ratio");
291 webrtc::ParseFieldTrial({&max_ratio},
292 trials.Lookup("WebRTC-SimulcastLayerLimitRoundUp"));
293
294 const bool enable_lowres_bitrate_interpolation =
295 EnableLowresBitrateInterpolation(trials);
296 size_t adaptive_layer_count = std::max(
297 need_layers,
298 InterpolateSimulcastFormat(width, height, max_ratio.GetOptional(),
299 enable_lowres_bitrate_interpolation)
300 .max_layers);
301 if (layer_count > adaptive_layer_count) {
302 RTC_LOG(LS_WARNING) << "Reducing simulcast layer count from "
303 << layer_count << " to " << adaptive_layer_count;
304 layer_count = adaptive_layer_count;
305 }
306 }
307 return layer_count;
308 }
309
GetSimulcastConfig(size_t min_layers,size_t max_layers,int width,int height,double bitrate_priority,int max_qp,bool is_screenshare_with_conference_mode,bool temporal_layers_supported,const webrtc::FieldTrialsView & trials)310 std::vector<webrtc::VideoStream> GetSimulcastConfig(
311 size_t min_layers,
312 size_t max_layers,
313 int width,
314 int height,
315 double bitrate_priority,
316 int max_qp,
317 bool is_screenshare_with_conference_mode,
318 bool temporal_layers_supported,
319 const webrtc::FieldTrialsView& trials) {
320 RTC_DCHECK_LE(min_layers, max_layers);
321 RTC_DCHECK(max_layers > 1 || is_screenshare_with_conference_mode);
322
323 const bool base_heavy_tl3_rate_alloc =
324 webrtc::RateControlSettings::ParseFromKeyValueConfig(&trials)
325 .Vp8BaseHeavyTl3RateAllocation();
326 if (is_screenshare_with_conference_mode) {
327 return GetScreenshareLayers(max_layers, width, height, bitrate_priority,
328 max_qp, temporal_layers_supported,
329 base_heavy_tl3_rate_alloc, trials);
330 } else {
331 // Some applications rely on the old behavior limiting the simulcast layer
332 // count based on the resolution automatically, which they can get through
333 // the WebRTC-LegacySimulcastLayerLimit field trial until they update.
334 max_layers =
335 LimitSimulcastLayerCount(width, height, min_layers, max_layers, trials);
336
337 return GetNormalSimulcastLayers(max_layers, width, height, bitrate_priority,
338 max_qp, temporal_layers_supported,
339 base_heavy_tl3_rate_alloc, trials);
340 }
341 }
342
GetNormalSimulcastLayers(size_t layer_count,int width,int height,double bitrate_priority,int max_qp,bool temporal_layers_supported,bool base_heavy_tl3_rate_alloc,const webrtc::FieldTrialsView & trials)343 std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
344 size_t layer_count,
345 int width,
346 int height,
347 double bitrate_priority,
348 int max_qp,
349 bool temporal_layers_supported,
350 bool base_heavy_tl3_rate_alloc,
351 const webrtc::FieldTrialsView& trials) {
352 std::vector<webrtc::VideoStream> layers(layer_count);
353
354 const bool enable_lowres_bitrate_interpolation =
355 EnableLowresBitrateInterpolation(trials);
356
357 // Format width and height has to be divisible by |2 ^ num_simulcast_layers -
358 // 1|.
359 width = NormalizeSimulcastSize(width, layer_count);
360 height = NormalizeSimulcastSize(height, layer_count);
361 // Add simulcast streams, from highest resolution (`s` = num_simulcast_layers
362 // -1) to lowest resolution at `s` = 0.
363 for (size_t s = layer_count - 1;; --s) {
364 layers[s].width = width;
365 layers[s].height = height;
366 // TODO(pbos): Fill actual temporal-layer bitrate thresholds.
367 layers[s].max_qp = max_qp;
368 layers[s].num_temporal_layers =
369 temporal_layers_supported ? DefaultNumberOfTemporalLayers(trials) : 1;
370 layers[s].max_bitrate_bps =
371 FindSimulcastMaxBitrate(width, height,
372 enable_lowres_bitrate_interpolation)
373 .bps();
374 layers[s].target_bitrate_bps =
375 FindSimulcastTargetBitrate(width, height,
376 enable_lowres_bitrate_interpolation)
377 .bps();
378 int num_temporal_layers = DefaultNumberOfTemporalLayers(trials);
379 if (s == 0) {
380 // If alternative temporal rate allocation is selected, adjust the
381 // bitrate of the lowest simulcast stream so that absolute bitrate for
382 // the base temporal layer matches the bitrate for the base temporal
383 // layer with the default 3 simulcast streams. Otherwise we risk a
384 // higher threshold for receiving a feed at all.
385 float rate_factor = 1.0;
386 if (num_temporal_layers == 3) {
387 if (base_heavy_tl3_rate_alloc) {
388 // Base heavy allocation increases TL0 bitrate from 40% to 60%.
389 rate_factor = 0.4 / 0.6;
390 }
391 } else {
392 rate_factor =
393 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
394 3, 0, /*base_heavy_tl3_rate_alloc=*/false) /
395 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
396 num_temporal_layers, 0, /*base_heavy_tl3_rate_alloc=*/false);
397 }
398
399 layers[s].max_bitrate_bps =
400 static_cast<int>(layers[s].max_bitrate_bps * rate_factor);
401 layers[s].target_bitrate_bps =
402 static_cast<int>(layers[s].target_bitrate_bps * rate_factor);
403 }
404 layers[s].min_bitrate_bps =
405 FindSimulcastMinBitrate(width, height,
406 enable_lowres_bitrate_interpolation)
407 .bps();
408
409 // Ensure consistency.
410 layers[s].max_bitrate_bps =
411 std::max(layers[s].min_bitrate_bps, layers[s].max_bitrate_bps);
412 layers[s].target_bitrate_bps =
413 std::max(layers[s].min_bitrate_bps, layers[s].target_bitrate_bps);
414
415 layers[s].max_framerate = kDefaultVideoMaxFramerate;
416
417 width /= 2;
418 height /= 2;
419
420 if (s == 0) {
421 break;
422 }
423 }
424 // Currently the relative bitrate priority of the sender is controlled by
425 // the value of the lowest VideoStream.
426 // TODO(bugs.webrtc.org/8630): The web specification describes being able to
427 // control relative bitrate for each individual simulcast layer, but this
428 // is currently just implemented per rtp sender.
429 layers[0].bitrate_priority = bitrate_priority;
430 return layers;
431 }
432
GetScreenshareLayers(size_t max_layers,int width,int height,double bitrate_priority,int max_qp,bool temporal_layers_supported,bool base_heavy_tl3_rate_alloc,const webrtc::FieldTrialsView & trials)433 std::vector<webrtc::VideoStream> GetScreenshareLayers(
434 size_t max_layers,
435 int width,
436 int height,
437 double bitrate_priority,
438 int max_qp,
439 bool temporal_layers_supported,
440 bool base_heavy_tl3_rate_alloc,
441 const webrtc::FieldTrialsView& trials) {
442 size_t num_simulcast_layers =
443 std::min<int>(max_layers, kScreenshareMaxSimulcastLayers);
444
445 std::vector<webrtc::VideoStream> layers(num_simulcast_layers);
446 // For legacy screenshare in conference mode, tl0 and tl1 bitrates are
447 // piggybacked on the VideoCodec struct as target and max bitrates,
448 // respectively. See eg. webrtc::LibvpxVp8Encoder::SetRates().
449 layers[0].width = width;
450 layers[0].height = height;
451 layers[0].max_qp = max_qp;
452 layers[0].max_framerate = 5;
453 layers[0].min_bitrate_bps = webrtc::kDefaultMinVideoBitrateBps;
454 layers[0].target_bitrate_bps = kScreenshareDefaultTl0Bitrate.bps();
455 layers[0].max_bitrate_bps = kScreenshareDefaultTl1Bitrate.bps();
456 layers[0].num_temporal_layers = temporal_layers_supported ? 2 : 1;
457
458 // With simulcast enabled, add another spatial layer. This one will have a
459 // more normal layout, with the regular 3 temporal layer pattern and no fps
460 // restrictions. The base simulcast layer will still use legacy setup.
461 if (num_simulcast_layers == kScreenshareMaxSimulcastLayers) {
462 // Add optional upper simulcast layer.
463 int max_bitrate_bps;
464 bool using_boosted_bitrate = false;
465 if (!temporal_layers_supported) {
466 // Set the max bitrate to where the base layer would have been if temporal
467 // layers were enabled.
468 max_bitrate_bps = static_cast<int>(
469 kScreenshareHighStreamMaxBitrate.bps() *
470 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
471 kScreenshareTemporalLayers, 0, base_heavy_tl3_rate_alloc));
472 } else {
473 // Experimental temporal layer mode used, use increased max bitrate.
474 max_bitrate_bps = kScreenshareHighStreamMaxBitrate.bps();
475 using_boosted_bitrate = true;
476 }
477
478 layers[1].width = width;
479 layers[1].height = height;
480 layers[1].max_qp = max_qp;
481 layers[1].max_framerate = kDefaultVideoMaxFramerate;
482 layers[1].num_temporal_layers =
483 temporal_layers_supported ? kScreenshareTemporalLayers : 1;
484 layers[1].min_bitrate_bps = using_boosted_bitrate
485 ? kScreenshareHighStreamMinBitrate.bps()
486 : layers[0].target_bitrate_bps * 2;
487 layers[1].target_bitrate_bps = max_bitrate_bps;
488 layers[1].max_bitrate_bps = max_bitrate_bps;
489 }
490
491 // The bitrate priority currently implemented on a per-sender level, so we
492 // just set it for the first simulcast layer.
493 layers[0].bitrate_priority = bitrate_priority;
494 return layers;
495 }
496
497 } // namespace cricket
498