blob: fc21f99f66fe61c7809ad5d6043b3ec3f9b90db6 [file] [log] [blame]
buildbot@webrtc.orga8530772014-12-10 09:01:18 +00001/*
kjellander1afca732016-02-07 20:46:45 -08002 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
buildbot@webrtc.orga8530772014-12-10 09:01:18 +00003 *
kjellander1afca732016-02-07 20:46:45 -08004 * 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.
buildbot@webrtc.orga8530772014-12-10 09:01:18 +00009 */
10
sprang@webrtc.org46d4d292014-12-23 15:19:35 +000011#include <stdio.h>
Steve Antone78bcb92017-10-31 09:53:08 -070012#include <algorithm>
13#include <string>
sprang@webrtc.org46d4d292014-12-23 15:19:35 +000014
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "media/base/streamparams.h"
16#include "media/engine/constants.h"
17#include "media/engine/simulcast.h"
18#include "rtc_base/arraysize.h"
19#include "rtc_base/logging.h"
20#include "system_wrappers/include/field_trial.h"
tfarina5237aaf2015-11-10 23:44:30 -080021
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000022namespace cricket {
23
24struct SimulcastFormat {
25 int width;
26 int height;
27 // The maximum number of simulcast layers can be used for
28 // resolutions at |widthxheigh|.
29 size_t max_layers;
30 // The maximum bitrate for encoding stream at |widthxheight|, when we are
31 // not sending the next higher spatial stream.
pbosbe16f792015-10-16 12:49:39 -070032 int max_bitrate_kbps;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000033 // The target bitrate for encoding stream at |widthxheight|, when this layer
34 // is not the highest layer (i.e., when we are sending another higher spatial
35 // stream).
pbosbe16f792015-10-16 12:49:39 -070036 int target_bitrate_kbps;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000037 // The minimum bitrate needed for encoding stream at |widthxheight|.
pbosbe16f792015-10-16 12:49:39 -070038 int min_bitrate_kbps;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000039};
40
41// These tables describe from which resolution we can use how many
42// simulcast layers at what bitrates (maximum, target, and minimum).
43// Important!! Keep this table from high resolution to low resolution.
44const SimulcastFormat kSimulcastFormats[] = {
pbosbe16f792015-10-16 12:49:39 -070045 {1920, 1080, 3, 5000, 4000, 800},
46 {1280, 720, 3, 2500, 2500, 600},
47 {960, 540, 3, 900, 900, 450},
48 {640, 360, 2, 700, 500, 150},
49 {480, 270, 2, 450, 350, 150},
50 {320, 180, 1, 200, 150, 30},
51 {0, 0, 1, 200, 150, 30}
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000052};
53
Seth Hampson1370e302018-02-07 08:50:36 -080054const int kMaxScreenshareSimulcastLayers = 2;
sprang429600d2017-01-26 06:12:26 -080055
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000056// Multiway: Number of temporal layers for each simulcast stream, for maximum
57// possible number of simulcast streams |kMaxSimulcastStreams|. The array
58// goes from lowest resolution at position 0 to highest resolution.
59// For example, first three elements correspond to say: QVGA, VGA, WHD.
60static const int
61 kDefaultConferenceNumberOfTemporalLayers[webrtc::kMaxSimulcastStreams] =
62 {3, 3, 3, 3};
63
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000064int FindSimulcastFormatIndex(int width, int height) {
Seth Hampson438663e2018-01-09 11:14:14 -080065 RTC_DCHECK_GE(width, 0);
66 RTC_DCHECK_GE(height, 0);
kjellandera96e2d72016-02-04 23:52:28 -080067 for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) {
sprang429600d2017-01-26 06:12:26 -080068 if (width * height >=
69 kSimulcastFormats[i].width * kSimulcastFormats[i].height) {
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000070 return i;
71 }
72 }
Seth Hampson438663e2018-01-09 11:14:14 -080073 RTC_NOTREACHED();
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000074 return -1;
75}
76
77int FindSimulcastFormatIndex(int width, int height, size_t max_layers) {
Seth Hampson438663e2018-01-09 11:14:14 -080078 RTC_DCHECK_GE(width, 0);
79 RTC_DCHECK_GE(height, 0);
80 RTC_DCHECK_GT(max_layers, 0);
kjellandera96e2d72016-02-04 23:52:28 -080081 for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) {
sprang429600d2017-01-26 06:12:26 -080082 if (width * height >=
83 kSimulcastFormats[i].width * kSimulcastFormats[i].height &&
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000084 max_layers == kSimulcastFormats[i].max_layers) {
85 return i;
86 }
87 }
Seth Hampson438663e2018-01-09 11:14:14 -080088 RTC_NOTREACHED();
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000089 return -1;
90}
91
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000092// Simulcast stream width and height must both be dividable by
93// |2 ^ simulcast_layers - 1|.
94int NormalizeSimulcastSize(int size, size_t simulcast_layers) {
95 const int base2_exponent = static_cast<int>(simulcast_layers) - 1;
96 return ((size >> base2_exponent) << base2_exponent);
97}
98
99size_t FindSimulcastMaxLayers(int width, int height) {
100 int index = FindSimulcastFormatIndex(width, height);
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000101 return kSimulcastFormats[index].max_layers;
102}
103
sprang429600d2017-01-26 06:12:26 -0800104int FindSimulcastMaxBitrateBps(int width, int height) {
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000105 const int format_index = FindSimulcastFormatIndex(width, height);
pbosbe16f792015-10-16 12:49:39 -0700106 return kSimulcastFormats[format_index].max_bitrate_kbps * 1000;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000107}
108
sprang429600d2017-01-26 06:12:26 -0800109int FindSimulcastTargetBitrateBps(int width, int height) {
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000110 const int format_index = FindSimulcastFormatIndex(width, height);
pbosbe16f792015-10-16 12:49:39 -0700111 return kSimulcastFormats[format_index].target_bitrate_kbps * 1000;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000112}
113
sprang429600d2017-01-26 06:12:26 -0800114int FindSimulcastMinBitrateBps(int width, int height) {
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000115 const int format_index = FindSimulcastFormatIndex(width, height);
pbosbe16f792015-10-16 12:49:39 -0700116 return kSimulcastFormats[format_index].min_bitrate_kbps * 1000;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000117}
118
Seth Hampson438663e2018-01-09 11:14:14 -0800119void SlotSimulcastMaxResolution(size_t max_layers, int* width, int* height) {
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000120 int index = FindSimulcastFormatIndex(*width, *height, max_layers);
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000121 *width = kSimulcastFormats[index].width;
122 *height = kSimulcastFormats[index].height;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100123 RTC_LOG(LS_INFO) << "SlotSimulcastMaxResolution to width:" << *width
124 << " height:" << *height;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000125}
126
Seth Hampson1370e302018-02-07 08:50:36 -0800127void BoostMaxSimulcastLayer(int max_bitrate_bps,
128 std::vector<webrtc::VideoStream>* layers) {
129 // Spend additional bits to boost the max layer.
130 int bitrate_left_bps = max_bitrate_bps - GetTotalMaxBitrateBps(*layers);
131 if (bitrate_left_bps > 0) {
132 layers->back().max_bitrate_bps += bitrate_left_bps;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000133 }
Seth Hampson1370e302018-02-07 08:50:36 -0800134}
135
136int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& layers) {
137 int total_max_bitrate_bps = 0;
138 for (size_t s = 0; s < layers.size() - 1; ++s) {
139 total_max_bitrate_bps += layers[s].target_bitrate_bps;
140 }
141 total_max_bitrate_bps += layers.back().max_bitrate_bps;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000142 return total_max_bitrate_bps;
143}
144
Seth Hampson1370e302018-02-07 08:50:36 -0800145std::vector<webrtc::VideoStream> GetSimulcastConfig(size_t max_layers,
Seth Hampson24722b32017-12-22 09:36:42 -0800146 int width,
147 int height,
148 int max_bitrate_bps,
149 double bitrate_priority,
150 int max_qp,
151 int max_framerate,
Seth Hampson1370e302018-02-07 08:50:36 -0800152 bool is_screenshare) {
153 if (is_screenshare) {
154 return GetScreenshareLayers(max_layers, width, height, max_bitrate_bps,
155 bitrate_priority, max_qp, max_framerate,
156 ScreenshareSimulcastFieldTrialEnabled());
sprang429600d2017-01-26 06:12:26 -0800157 } else {
Seth Hampson1370e302018-02-07 08:50:36 -0800158 return GetNormalSimulcastLayers(max_layers, width, height, max_bitrate_bps,
159 bitrate_priority, max_qp, max_framerate);
sprang429600d2017-01-26 06:12:26 -0800160 }
Seth Hampson1370e302018-02-07 08:50:36 -0800161}
sprang429600d2017-01-26 06:12:26 -0800162
Seth Hampson1370e302018-02-07 08:50:36 -0800163std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
164 size_t max_layers,
165 int width,
166 int height,
167 int max_bitrate_bps,
168 double bitrate_priority,
169 int max_qp,
170 int max_framerate) {
171 // TODO(bugs.webrtc.org/8785): Currently if the resolution isn't large enough
172 // (defined in kSimulcastFormats) we scale down the number of simulcast
173 // layers. Consider changing this so that the application can have more
174 // control over exactly how many simulcast layers are used.
175 size_t num_simulcast_layers = FindSimulcastMaxLayers(width, height);
176 if (num_simulcast_layers > max_layers) {
177 // TODO(bugs.webrtc.org/8486): This scales down the resolution if the
178 // number of simulcast layers created by the application isn't sufficient
179 // (defined in kSimulcastFormats). For example if the input frame's
180 // resolution is HD, but there are only 2 simulcast layers, the
181 // resolution gets scaled down to VGA. Consider taking this logic out to
182 // allow the application more control over the resolutions.
183 SlotSimulcastMaxResolution(max_layers, &width, &height);
184 num_simulcast_layers = max_layers;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000185 }
Seth Hampson1370e302018-02-07 08:50:36 -0800186 std::vector<webrtc::VideoStream> layers(num_simulcast_layers);
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000187
Seth Hampson1370e302018-02-07 08:50:36 -0800188 // Format width and height has to be divisible by |2 ^ num_simulcast_layers -
189 // 1|.
190 width = NormalizeSimulcastSize(width, num_simulcast_layers);
191 height = NormalizeSimulcastSize(height, num_simulcast_layers);
192 // Add simulcast streams, from highest resolution (|s| = num_simulcast_layers
193 // -1) to lowest resolution at |s| = 0.
194 for (size_t s = num_simulcast_layers - 1;; --s) {
195 layers[s].width = width;
196 layers[s].height = height;
197 // TODO(pbos): Fill actual temporal-layer bitrate thresholds.
198 layers[s].max_qp = max_qp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100199 layers[s].num_temporal_layers = kDefaultConferenceNumberOfTemporalLayers[s];
Seth Hampson1370e302018-02-07 08:50:36 -0800200 layers[s].max_bitrate_bps = FindSimulcastMaxBitrateBps(width, height);
201 layers[s].target_bitrate_bps = FindSimulcastTargetBitrateBps(width, height);
202 layers[s].min_bitrate_bps = FindSimulcastMinBitrateBps(width, height);
203 layers[s].max_framerate = max_framerate;
sprang02569ad2017-07-06 05:05:50 -0700204
Seth Hampson1370e302018-02-07 08:50:36 -0800205 width /= 2;
206 height /= 2;
sprang02569ad2017-07-06 05:05:50 -0700207
Seth Hampson1370e302018-02-07 08:50:36 -0800208 if (s == 0) {
209 break;
sprang02569ad2017-07-06 05:05:50 -0700210 }
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000211 }
Seth Hampson1370e302018-02-07 08:50:36 -0800212 // If there is bitrate leftover, give it to the largest layer.
213 BoostMaxSimulcastLayer(max_bitrate_bps, &layers);
214 // Currently the relative bitrate priority of the sender is controlled by
215 // the value of the lowest VideoStream.
216 // TODO(bugs.webrtc.org/8630): The web specification describes being able to
217 // control relative bitrate for each individual simulcast layer, but this
218 // is currently just implemented per rtp sender.
219 layers[0].bitrate_priority = bitrate_priority;
220 return layers;
221}
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000222
Seth Hampson1370e302018-02-07 08:50:36 -0800223std::vector<webrtc::VideoStream> GetScreenshareLayers(
224 size_t max_layers,
225 int width,
226 int height,
227 int max_bitrate_bps,
228 double bitrate_priority,
229 int max_qp,
230 int max_framerate,
231 bool screenshare_simulcast_enabled) {
232 auto max_screenshare_layers =
233 screenshare_simulcast_enabled ? kMaxScreenshareSimulcastLayers : 1;
234 size_t num_simulcast_layers =
235 std::min<int>(max_layers, max_screenshare_layers);
236
237 std::vector<webrtc::VideoStream> layers(num_simulcast_layers);
238 ScreenshareLayerConfig config = ScreenshareLayerConfig::GetDefault();
239 // For legacy screenshare in conference mode, tl0 and tl1 bitrates are
240 // piggybacked on the VideoCodec struct as target and max bitrates,
241 // respectively. See eg. webrtc::VP8EncoderImpl::SetRates().
242 layers[0].width = width;
243 layers[0].height = height;
244 layers[0].max_qp = max_qp;
245 layers[0].max_framerate = 5;
246 layers[0].min_bitrate_bps = kMinVideoBitrateBps;
247 layers[0].target_bitrate_bps = config.tl0_bitrate_kbps * 1000;
248 layers[0].max_bitrate_bps = config.tl1_bitrate_kbps * 1000;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100249 layers[0].num_temporal_layers = 2;
Seth Hampson1370e302018-02-07 08:50:36 -0800250
251 // With simulcast enabled, add another spatial layer. This one will have a
252 // more normal layout, with the regular 3 temporal layer pattern and no fps
253 // restrictions. The base simulcast layer will still use legacy setup.
254 if (num_simulcast_layers == kMaxScreenshareSimulcastLayers) {
255 // Add optional upper simulcast layer.
256 // Lowest temporal layers of a 3 layer setup will have 40% of the total
257 // bitrate allocation for that simulcast layer. Make sure the gap between
258 // the target of the lower simulcast layer and first temporal layer of the
259 // higher one is at most 2x the bitrate, so that upswitching is not hampered
260 // by stalled bitrate estimates.
261 int max_bitrate_bps = 2 * ((layers[0].target_bitrate_bps * 10) / 4);
262 // Cap max bitrate so it isn't overly high for the given resolution.
263 max_bitrate_bps = std::min<int>(max_bitrate_bps,
264 FindSimulcastMaxBitrateBps(width, height));
265
266 layers[1].width = width;
267 layers[1].height = height;
268 layers[1].max_qp = max_qp;
269 layers[1].max_framerate = max_framerate;
270 // Three temporal layers means two thresholds.
Sergey Silkina796a7e2018-03-01 15:11:29 +0100271 layers[1].num_temporal_layers = 2;
Seth Hampson1370e302018-02-07 08:50:36 -0800272 layers[1].min_bitrate_bps = layers[0].target_bitrate_bps * 2;
273 layers[1].target_bitrate_bps = max_bitrate_bps;
274 layers[1].max_bitrate_bps = max_bitrate_bps;
275 }
276
Seth Hampson24722b32017-12-22 09:36:42 -0800277 // The bitrate priority currently implemented on a per-sender level, so we
Seth Hampson1370e302018-02-07 08:50:36 -0800278 // just set it for the first simulcast layer.
279 layers[0].bitrate_priority = bitrate_priority;
280 return layers;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000281}
282
sprang@webrtc.org46d4d292014-12-23 15:19:35 +0000283static const int kScreenshareMinBitrateKbps = 50;
284static const int kScreenshareMaxBitrateKbps = 6000;
Erik Språng2c4c9142015-06-24 11:24:44 +0200285static const int kScreenshareDefaultTl0BitrateKbps = 200;
sprang@webrtc.org46d4d292014-12-23 15:19:35 +0000286static const int kScreenshareDefaultTl1BitrateKbps = 1000;
287
Seth Hampson1370e302018-02-07 08:50:36 -0800288static const char* kScreenshareLayerFieldTrialName =
sprang@webrtc.org46d4d292014-12-23 15:19:35 +0000289 "WebRTC-ScreenshareLayerRates";
sprang429600d2017-01-26 06:12:26 -0800290static const char* kSimulcastScreenshareFieldTrialName =
291 "WebRTC-SimulcastScreenshare";
sprang@webrtc.org46d4d292014-12-23 15:19:35 +0000292
293ScreenshareLayerConfig::ScreenshareLayerConfig(int tl0_bitrate, int tl1_bitrate)
294 : tl0_bitrate_kbps(tl0_bitrate), tl1_bitrate_kbps(tl1_bitrate) {
295}
296
297ScreenshareLayerConfig ScreenshareLayerConfig::GetDefault() {
298 std::string group =
Seth Hampson1370e302018-02-07 08:50:36 -0800299 webrtc::field_trial::FindFullName(kScreenshareLayerFieldTrialName);
sprang@webrtc.org46d4d292014-12-23 15:19:35 +0000300
301 ScreenshareLayerConfig config(kScreenshareDefaultTl0BitrateKbps,
302 kScreenshareDefaultTl1BitrateKbps);
303 if (!group.empty() && !FromFieldTrialGroup(group, &config)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100304 RTC_LOG(LS_WARNING) << "Unable to parse WebRTC-ScreenshareLayerRates"
305 " field trial group: '"
306 << group << "'.";
sprang@webrtc.org46d4d292014-12-23 15:19:35 +0000307 }
308 return config;
309}
310
311bool ScreenshareLayerConfig::FromFieldTrialGroup(
312 const std::string& group,
313 ScreenshareLayerConfig* config) {
314 // Parse field trial group name, containing bitrates for tl0 and tl1.
315 int tl0_bitrate;
316 int tl1_bitrate;
317 if (sscanf(group.c_str(), "%d-%d", &tl0_bitrate, &tl1_bitrate) != 2) {
318 return false;
319 }
320
321 // Sanity check.
322 if (tl0_bitrate < kScreenshareMinBitrateKbps ||
323 tl0_bitrate > kScreenshareMaxBitrateKbps ||
324 tl1_bitrate < kScreenshareMinBitrateKbps ||
325 tl1_bitrate > kScreenshareMaxBitrateKbps || tl0_bitrate > tl1_bitrate) {
326 return false;
327 }
328
329 config->tl0_bitrate_kbps = tl0_bitrate;
330 config->tl1_bitrate_kbps = tl1_bitrate;
331
332 return true;
333}
334
Seth Hampson1370e302018-02-07 08:50:36 -0800335bool ScreenshareSimulcastFieldTrialEnabled() {
sprangc1b57a12017-02-28 08:50:47 -0800336 return webrtc::field_trial::IsEnabled(kSimulcastScreenshareFieldTrialName);
sprang429600d2017-01-26 06:12:26 -0800337}
338
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000339} // namespace cricket