blob: d55ab9f82a1fb707b46f82f0b4c819a3bb5d1812 [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"
Erik Språng79478ad2018-05-18 09:39:55 +020018#include "modules/video_coding/codecs/vp8/include/vp8_common_types.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/arraysize.h"
20#include "rtc_base/logging.h"
21#include "system_wrappers/include/field_trial.h"
tfarina5237aaf2015-11-10 23:44:30 -080022
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000023namespace cricket {
24
Rasmus Brandt195d1d72018-05-09 11:28:01 +020025namespace {
26
27constexpr int kScreenshareDefaultTl0BitrateKbps = 200;
28constexpr int kScreenshareDefaultTl1BitrateKbps = 1000;
29
30static const char* kSimulcastScreenshareFieldTrialName =
31 "WebRTC-SimulcastScreenshare";
32
33} // namespace
34
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000035struct SimulcastFormat {
36 int width;
37 int height;
38 // The maximum number of simulcast layers can be used for
39 // resolutions at |widthxheigh|.
40 size_t max_layers;
41 // The maximum bitrate for encoding stream at |widthxheight|, when we are
42 // not sending the next higher spatial stream.
pbosbe16f792015-10-16 12:49:39 -070043 int max_bitrate_kbps;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000044 // The target bitrate for encoding stream at |widthxheight|, when this layer
45 // is not the highest layer (i.e., when we are sending another higher spatial
46 // stream).
pbosbe16f792015-10-16 12:49:39 -070047 int target_bitrate_kbps;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000048 // The minimum bitrate needed for encoding stream at |widthxheight|.
pbosbe16f792015-10-16 12:49:39 -070049 int min_bitrate_kbps;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000050};
51
52// These tables describe from which resolution we can use how many
53// simulcast layers at what bitrates (maximum, target, and minimum).
54// Important!! Keep this table from high resolution to low resolution.
55const SimulcastFormat kSimulcastFormats[] = {
pbosbe16f792015-10-16 12:49:39 -070056 {1920, 1080, 3, 5000, 4000, 800},
57 {1280, 720, 3, 2500, 2500, 600},
58 {960, 540, 3, 900, 900, 450},
59 {640, 360, 2, 700, 500, 150},
60 {480, 270, 2, 450, 350, 150},
61 {320, 180, 1, 200, 150, 30},
62 {0, 0, 1, 200, 150, 30}
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000063};
64
Seth Hampson1370e302018-02-07 08:50:36 -080065const int kMaxScreenshareSimulcastLayers = 2;
sprang429600d2017-01-26 06:12:26 -080066
Erik Språngbfe3d852018-05-15 09:54:14 +020067// Multiway: Number of temporal layers for each simulcast stream.
68int DefaultNumberOfTemporalLayers(int simulcast_id) {
69 RTC_CHECK_GE(simulcast_id, 0);
70 RTC_CHECK_LT(simulcast_id, webrtc::kMaxSimulcastStreams);
71
72 const int kDefaultNumTemporalLayers = 3;
73
74 const std::string group_name =
75 webrtc::field_trial::FindFullName("WebRTC-VP8ConferenceTemporalLayers");
76 if (group_name.empty())
77 return kDefaultNumTemporalLayers;
78
79 int num_temporal_layers = kDefaultNumTemporalLayers;
80 if (sscanf(group_name.c_str(), "%d", &num_temporal_layers) == 1 &&
81 num_temporal_layers > 0 &&
82 num_temporal_layers <= webrtc::kMaxTemporalStreams) {
83 return num_temporal_layers;
84 }
85
86 RTC_LOG(LS_WARNING) << "Attempt to set number of temporal layers to "
87 "incorrect value: "
88 << group_name;
89
90 return kDefaultNumTemporalLayers;
91}
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000092
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000093int FindSimulcastFormatIndex(int width, int height) {
Seth Hampson438663e2018-01-09 11:14:14 -080094 RTC_DCHECK_GE(width, 0);
95 RTC_DCHECK_GE(height, 0);
kjellandera96e2d72016-02-04 23:52:28 -080096 for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) {
sprang429600d2017-01-26 06:12:26 -080097 if (width * height >=
98 kSimulcastFormats[i].width * kSimulcastFormats[i].height) {
buildbot@webrtc.orga8530772014-12-10 09:01:18 +000099 return i;
100 }
101 }
Seth Hampson438663e2018-01-09 11:14:14 -0800102 RTC_NOTREACHED();
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000103 return -1;
104}
105
106int FindSimulcastFormatIndex(int width, int height, size_t max_layers) {
Seth Hampson438663e2018-01-09 11:14:14 -0800107 RTC_DCHECK_GE(width, 0);
108 RTC_DCHECK_GE(height, 0);
109 RTC_DCHECK_GT(max_layers, 0);
kjellandera96e2d72016-02-04 23:52:28 -0800110 for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) {
sprang429600d2017-01-26 06:12:26 -0800111 if (width * height >=
112 kSimulcastFormats[i].width * kSimulcastFormats[i].height &&
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000113 max_layers == kSimulcastFormats[i].max_layers) {
114 return i;
115 }
116 }
Seth Hampson438663e2018-01-09 11:14:14 -0800117 RTC_NOTREACHED();
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000118 return -1;
119}
120
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000121// Simulcast stream width and height must both be dividable by
Rasmus Brandtefbdcb02018-04-26 17:47:42 +0200122// |2 ^ (simulcast_layers - 1)|.
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000123int NormalizeSimulcastSize(int size, size_t simulcast_layers) {
124 const int base2_exponent = static_cast<int>(simulcast_layers) - 1;
125 return ((size >> base2_exponent) << base2_exponent);
126}
127
128size_t FindSimulcastMaxLayers(int width, int height) {
129 int index = FindSimulcastFormatIndex(width, height);
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000130 return kSimulcastFormats[index].max_layers;
131}
132
sprang429600d2017-01-26 06:12:26 -0800133int FindSimulcastMaxBitrateBps(int width, int height) {
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000134 const int format_index = FindSimulcastFormatIndex(width, height);
pbosbe16f792015-10-16 12:49:39 -0700135 return kSimulcastFormats[format_index].max_bitrate_kbps * 1000;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000136}
137
sprang429600d2017-01-26 06:12:26 -0800138int FindSimulcastTargetBitrateBps(int width, int height) {
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000139 const int format_index = FindSimulcastFormatIndex(width, height);
pbosbe16f792015-10-16 12:49:39 -0700140 return kSimulcastFormats[format_index].target_bitrate_kbps * 1000;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000141}
142
sprang429600d2017-01-26 06:12:26 -0800143int FindSimulcastMinBitrateBps(int width, int height) {
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000144 const int format_index = FindSimulcastFormatIndex(width, height);
pbosbe16f792015-10-16 12:49:39 -0700145 return kSimulcastFormats[format_index].min_bitrate_kbps * 1000;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000146}
147
Seth Hampson438663e2018-01-09 11:14:14 -0800148void SlotSimulcastMaxResolution(size_t max_layers, int* width, int* height) {
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000149 int index = FindSimulcastFormatIndex(*width, *height, max_layers);
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000150 *width = kSimulcastFormats[index].width;
151 *height = kSimulcastFormats[index].height;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100152 RTC_LOG(LS_INFO) << "SlotSimulcastMaxResolution to width:" << *width
153 << " height:" << *height;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000154}
155
Seth Hampson1370e302018-02-07 08:50:36 -0800156void BoostMaxSimulcastLayer(int max_bitrate_bps,
157 std::vector<webrtc::VideoStream>* layers) {
158 // Spend additional bits to boost the max layer.
159 int bitrate_left_bps = max_bitrate_bps - GetTotalMaxBitrateBps(*layers);
160 if (bitrate_left_bps > 0) {
161 layers->back().max_bitrate_bps += bitrate_left_bps;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000162 }
Seth Hampson1370e302018-02-07 08:50:36 -0800163}
164
165int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& layers) {
166 int total_max_bitrate_bps = 0;
167 for (size_t s = 0; s < layers.size() - 1; ++s) {
168 total_max_bitrate_bps += layers[s].target_bitrate_bps;
169 }
170 total_max_bitrate_bps += layers.back().max_bitrate_bps;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000171 return total_max_bitrate_bps;
172}
173
Seth Hampson1370e302018-02-07 08:50:36 -0800174std::vector<webrtc::VideoStream> GetSimulcastConfig(size_t max_layers,
Seth Hampson24722b32017-12-22 09:36:42 -0800175 int width,
176 int height,
177 int max_bitrate_bps,
178 double bitrate_priority,
179 int max_qp,
180 int max_framerate,
Seth Hampson1370e302018-02-07 08:50:36 -0800181 bool is_screenshare) {
182 if (is_screenshare) {
183 return GetScreenshareLayers(max_layers, width, height, max_bitrate_bps,
184 bitrate_priority, max_qp, max_framerate,
185 ScreenshareSimulcastFieldTrialEnabled());
sprang429600d2017-01-26 06:12:26 -0800186 } else {
Seth Hampson1370e302018-02-07 08:50:36 -0800187 return GetNormalSimulcastLayers(max_layers, width, height, max_bitrate_bps,
188 bitrate_priority, max_qp, max_framerate);
sprang429600d2017-01-26 06:12:26 -0800189 }
Seth Hampson1370e302018-02-07 08:50:36 -0800190}
sprang429600d2017-01-26 06:12:26 -0800191
Seth Hampson1370e302018-02-07 08:50:36 -0800192std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
193 size_t max_layers,
194 int width,
195 int height,
196 int max_bitrate_bps,
197 double bitrate_priority,
198 int max_qp,
199 int max_framerate) {
200 // TODO(bugs.webrtc.org/8785): Currently if the resolution isn't large enough
201 // (defined in kSimulcastFormats) we scale down the number of simulcast
202 // layers. Consider changing this so that the application can have more
203 // control over exactly how many simulcast layers are used.
204 size_t num_simulcast_layers = FindSimulcastMaxLayers(width, height);
205 if (num_simulcast_layers > max_layers) {
206 // TODO(bugs.webrtc.org/8486): This scales down the resolution if the
207 // number of simulcast layers created by the application isn't sufficient
208 // (defined in kSimulcastFormats). For example if the input frame's
209 // resolution is HD, but there are only 2 simulcast layers, the
210 // resolution gets scaled down to VGA. Consider taking this logic out to
211 // allow the application more control over the resolutions.
212 SlotSimulcastMaxResolution(max_layers, &width, &height);
213 num_simulcast_layers = max_layers;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000214 }
Seth Hampson1370e302018-02-07 08:50:36 -0800215 std::vector<webrtc::VideoStream> layers(num_simulcast_layers);
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000216
Seth Hampson1370e302018-02-07 08:50:36 -0800217 // Format width and height has to be divisible by |2 ^ num_simulcast_layers -
218 // 1|.
219 width = NormalizeSimulcastSize(width, num_simulcast_layers);
220 height = NormalizeSimulcastSize(height, num_simulcast_layers);
221 // Add simulcast streams, from highest resolution (|s| = num_simulcast_layers
222 // -1) to lowest resolution at |s| = 0.
223 for (size_t s = num_simulcast_layers - 1;; --s) {
224 layers[s].width = width;
225 layers[s].height = height;
226 // TODO(pbos): Fill actual temporal-layer bitrate thresholds.
227 layers[s].max_qp = max_qp;
Erik Språngbfe3d852018-05-15 09:54:14 +0200228 layers[s].num_temporal_layers = DefaultNumberOfTemporalLayers(s);
Seth Hampson1370e302018-02-07 08:50:36 -0800229 layers[s].max_bitrate_bps = FindSimulcastMaxBitrateBps(width, height);
230 layers[s].target_bitrate_bps = FindSimulcastTargetBitrateBps(width, height);
Erik Språng79478ad2018-05-18 09:39:55 +0200231 int num_temporal_layers = DefaultNumberOfTemporalLayers(s);
232 if (s == 0 && num_temporal_layers != 3) {
233 // If alternative number temporal layers is selected, adjust the
234 // bitrate of the lowest simulcast stream so that absolute bitrate for the
235 // base temporal layer matches the bitrate for the base temporal layer
236 // with the default 3 simulcast streams. Otherwise we risk a higher
237 // threshold for receiving a feed at all.
238 const float rate_factor =
239 webrtc::kVp8LayerRateAlloction[3][0] /
240 webrtc::kVp8LayerRateAlloction[num_temporal_layers][0];
241 layers[s].max_bitrate_bps =
242 static_cast<int>(layers[s].max_bitrate_bps * rate_factor);
243 layers[s].target_bitrate_bps =
244 static_cast<int>(layers[s].target_bitrate_bps * rate_factor);
245 }
Seth Hampson1370e302018-02-07 08:50:36 -0800246 layers[s].min_bitrate_bps = FindSimulcastMinBitrateBps(width, height);
247 layers[s].max_framerate = max_framerate;
sprang02569ad2017-07-06 05:05:50 -0700248
Seth Hampson1370e302018-02-07 08:50:36 -0800249 width /= 2;
250 height /= 2;
sprang02569ad2017-07-06 05:05:50 -0700251
Seth Hampson1370e302018-02-07 08:50:36 -0800252 if (s == 0) {
253 break;
sprang02569ad2017-07-06 05:05:50 -0700254 }
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000255 }
Seth Hampson1370e302018-02-07 08:50:36 -0800256 // If there is bitrate leftover, give it to the largest layer.
257 BoostMaxSimulcastLayer(max_bitrate_bps, &layers);
258 // Currently the relative bitrate priority of the sender is controlled by
259 // the value of the lowest VideoStream.
260 // TODO(bugs.webrtc.org/8630): The web specification describes being able to
261 // control relative bitrate for each individual simulcast layer, but this
262 // is currently just implemented per rtp sender.
263 layers[0].bitrate_priority = bitrate_priority;
264 return layers;
265}
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000266
Seth Hampson1370e302018-02-07 08:50:36 -0800267std::vector<webrtc::VideoStream> GetScreenshareLayers(
268 size_t max_layers,
269 int width,
270 int height,
271 int max_bitrate_bps,
272 double bitrate_priority,
273 int max_qp,
274 int max_framerate,
275 bool screenshare_simulcast_enabled) {
276 auto max_screenshare_layers =
277 screenshare_simulcast_enabled ? kMaxScreenshareSimulcastLayers : 1;
278 size_t num_simulcast_layers =
279 std::min<int>(max_layers, max_screenshare_layers);
280
281 std::vector<webrtc::VideoStream> layers(num_simulcast_layers);
Seth Hampson1370e302018-02-07 08:50:36 -0800282 // For legacy screenshare in conference mode, tl0 and tl1 bitrates are
283 // piggybacked on the VideoCodec struct as target and max bitrates,
Erik Språngcc681cc2018-03-14 17:52:55 +0100284 // respectively. See eg. webrtc::LibvpxVp8Encoder::SetRates().
Seth Hampson1370e302018-02-07 08:50:36 -0800285 layers[0].width = width;
286 layers[0].height = height;
287 layers[0].max_qp = max_qp;
288 layers[0].max_framerate = 5;
289 layers[0].min_bitrate_bps = kMinVideoBitrateBps;
Rasmus Brandt195d1d72018-05-09 11:28:01 +0200290 layers[0].target_bitrate_bps = kScreenshareDefaultTl0BitrateKbps * 1000;
291 layers[0].max_bitrate_bps = kScreenshareDefaultTl1BitrateKbps * 1000;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100292 layers[0].num_temporal_layers = 2;
Seth Hampson1370e302018-02-07 08:50:36 -0800293
294 // With simulcast enabled, add another spatial layer. This one will have a
295 // more normal layout, with the regular 3 temporal layer pattern and no fps
296 // restrictions. The base simulcast layer will still use legacy setup.
297 if (num_simulcast_layers == kMaxScreenshareSimulcastLayers) {
298 // Add optional upper simulcast layer.
299 // Lowest temporal layers of a 3 layer setup will have 40% of the total
300 // bitrate allocation for that simulcast layer. Make sure the gap between
301 // the target of the lower simulcast layer and first temporal layer of the
302 // higher one is at most 2x the bitrate, so that upswitching is not hampered
303 // by stalled bitrate estimates.
304 int max_bitrate_bps = 2 * ((layers[0].target_bitrate_bps * 10) / 4);
305 // Cap max bitrate so it isn't overly high for the given resolution.
306 max_bitrate_bps = std::min<int>(max_bitrate_bps,
307 FindSimulcastMaxBitrateBps(width, height));
308
309 layers[1].width = width;
310 layers[1].height = height;
311 layers[1].max_qp = max_qp;
312 layers[1].max_framerate = max_framerate;
Sergey Silkinca091252018-03-14 17:00:50 +0100313 layers[1].num_temporal_layers = 3;
Seth Hampson1370e302018-02-07 08:50:36 -0800314 layers[1].min_bitrate_bps = layers[0].target_bitrate_bps * 2;
315 layers[1].target_bitrate_bps = max_bitrate_bps;
316 layers[1].max_bitrate_bps = max_bitrate_bps;
317 }
318
Seth Hampson24722b32017-12-22 09:36:42 -0800319 // The bitrate priority currently implemented on a per-sender level, so we
Seth Hampson1370e302018-02-07 08:50:36 -0800320 // just set it for the first simulcast layer.
321 layers[0].bitrate_priority = bitrate_priority;
322 return layers;
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000323}
324
Seth Hampson1370e302018-02-07 08:50:36 -0800325bool ScreenshareSimulcastFieldTrialEnabled() {
sprangc1b57a12017-02-28 08:50:47 -0800326 return webrtc::field_trial::IsEnabled(kSimulcastScreenshareFieldTrialName);
sprang429600d2017-01-26 06:12:26 -0800327}
328
buildbot@webrtc.orga8530772014-12-10 09:01:18 +0000329} // namespace cricket