1 /*
2 * Copyright (c) 2022 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 #include "video/config/encoder_stream_factory.h"
11
12 #include <algorithm>
13 #include <limits>
14 #include <set>
15 #include <string>
16 #include <utility>
17
18 #include "absl/algorithm/container.h"
19 #include "absl/strings/match.h"
20 #include "api/video/video_codec_constants.h"
21 #include "media/base/media_constants.h"
22 #include "media/base/video_adapter.h"
23 #include "modules/video_coding/codecs/vp9/svc_config.h"
24 #include "rtc_base/experiments/min_video_bitrate_experiment.h"
25 #include "rtc_base/experiments/normalize_simulcast_size_experiment.h"
26 #include "rtc_base/logging.h"
27 #include "video/config/simulcast.h"
28
29 namespace cricket {
30 namespace {
31
32 const int kMinLayerSize = 16;
33
ScaleDownResolution(int resolution,double scale_down_by,int min_resolution)34 int ScaleDownResolution(int resolution,
35 double scale_down_by,
36 int min_resolution) {
37 // Resolution is never scalied down to smaller than min_resolution.
38 // If the input resolution is already smaller than min_resolution,
39 // no scaling should be done at all.
40 if (resolution <= min_resolution)
41 return resolution;
42 return std::max(static_cast<int>(resolution / scale_down_by + 0.5),
43 min_resolution);
44 }
45
PowerOfTwo(int value)46 bool PowerOfTwo(int value) {
47 return (value > 0) && ((value & (value - 1)) == 0);
48 }
49
IsScaleFactorsPowerOfTwo(const webrtc::VideoEncoderConfig & config)50 bool IsScaleFactorsPowerOfTwo(const webrtc::VideoEncoderConfig& config) {
51 for (const auto& layer : config.simulcast_layers) {
52 double scale = std::max(layer.scale_resolution_down_by, 1.0);
53 if (std::round(scale) != scale || !PowerOfTwo(scale)) {
54 return false;
55 }
56 }
57 return true;
58 }
59
IsTemporalLayersSupported(const std::string & codec_name)60 bool IsTemporalLayersSupported(const std::string& codec_name) {
61 return absl::EqualsIgnoreCase(codec_name, kVp8CodecName) ||
62 absl::EqualsIgnoreCase(codec_name, kVp9CodecName) ||
63 absl::EqualsIgnoreCase(codec_name, kAv1CodecName);
64 }
65
FindRequiredActiveLayers(const webrtc::VideoEncoderConfig & encoder_config)66 size_t FindRequiredActiveLayers(
67 const webrtc::VideoEncoderConfig& encoder_config) {
68 // Need enough layers so that at least the first active one is present.
69 for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
70 if (encoder_config.simulcast_layers[i].active) {
71 return i + 1;
72 }
73 }
74 return 0;
75 }
76
77 // The selected thresholds for QVGA and VGA corresponded to a QP around 10.
78 // The change in QP declined above the selected bitrates.
GetMaxDefaultVideoBitrateKbps(int width,int height,bool is_screenshare)79 static int GetMaxDefaultVideoBitrateKbps(int width,
80 int height,
81 bool is_screenshare) {
82 int max_bitrate;
83 if (width * height <= 320 * 240) {
84 max_bitrate = 600;
85 } else if (width * height <= 640 * 480) {
86 max_bitrate = 1700;
87 } else if (width * height <= 960 * 540) {
88 max_bitrate = 2000;
89 } else {
90 max_bitrate = 2500;
91 }
92 if (is_screenshare)
93 max_bitrate = std::max(max_bitrate, 1200);
94 return max_bitrate;
95 }
96
97 } // namespace
98
99 // TODO(bugs.webrtc.org/8785): Consider removing max_qp as member of
100 // EncoderStreamFactory and instead set this value individually for each stream
101 // in the VideoEncoderConfig.simulcast_layers.
EncoderStreamFactory(std::string codec_name,int max_qp,bool is_screenshare,bool conference_mode)102 EncoderStreamFactory::EncoderStreamFactory(std::string codec_name,
103 int max_qp,
104 bool is_screenshare,
105 bool conference_mode)
106 : codec_name_(codec_name),
107 max_qp_(max_qp),
108 is_screenshare_(is_screenshare),
109 conference_mode_(conference_mode),
110 trials_(fallback_trials_),
111 encoder_info_requested_resolution_alignment_(1) {}
112
EncoderStreamFactory(std::string codec_name,int max_qp,bool is_screenshare,bool conference_mode,const webrtc::VideoEncoder::EncoderInfo & encoder_info,absl::optional<webrtc::VideoSourceRestrictions> restrictions,const webrtc::FieldTrialsView * trials)113 EncoderStreamFactory::EncoderStreamFactory(
114 std::string codec_name,
115 int max_qp,
116 bool is_screenshare,
117 bool conference_mode,
118 const webrtc::VideoEncoder::EncoderInfo& encoder_info,
119 absl::optional<webrtc::VideoSourceRestrictions> restrictions,
120 const webrtc::FieldTrialsView* trials)
121 : codec_name_(codec_name),
122 max_qp_(max_qp),
123 is_screenshare_(is_screenshare),
124 conference_mode_(conference_mode),
125 trials_(trials ? *trials : fallback_trials_),
126 encoder_info_requested_resolution_alignment_(
127 encoder_info.requested_resolution_alignment),
128 restrictions_(restrictions) {}
129
CreateEncoderStreams(int frame_width,int frame_height,const webrtc::VideoEncoderConfig & encoder_config)130 std::vector<webrtc::VideoStream> EncoderStreamFactory::CreateEncoderStreams(
131 int frame_width,
132 int frame_height,
133 const webrtc::VideoEncoderConfig& encoder_config) {
134 RTC_DCHECK_GT(encoder_config.number_of_streams, 0);
135 RTC_DCHECK_GE(encoder_config.simulcast_layers.size(),
136 encoder_config.number_of_streams);
137
138 const absl::optional<webrtc::DataRate> experimental_min_bitrate =
139 GetExperimentalMinVideoBitrate(encoder_config.codec_type);
140
141 if (encoder_config.number_of_streams > 1 ||
142 ((absl::EqualsIgnoreCase(codec_name_, kVp8CodecName) ||
143 absl::EqualsIgnoreCase(codec_name_, kH264CodecName)) &&
144 is_screenshare_ && conference_mode_)) {
145 return CreateSimulcastOrConferenceModeScreenshareStreams(
146 frame_width, frame_height, encoder_config, experimental_min_bitrate);
147 }
148
149 return CreateDefaultVideoStreams(frame_width, frame_height, encoder_config,
150 experimental_min_bitrate);
151 }
152
153 std::vector<webrtc::VideoStream>
CreateDefaultVideoStreams(int width,int height,const webrtc::VideoEncoderConfig & encoder_config,const absl::optional<webrtc::DataRate> & experimental_min_bitrate) const154 EncoderStreamFactory::CreateDefaultVideoStreams(
155 int width,
156 int height,
157 const webrtc::VideoEncoderConfig& encoder_config,
158 const absl::optional<webrtc::DataRate>& experimental_min_bitrate) const {
159 std::vector<webrtc::VideoStream> layers;
160
161 // For unset max bitrates set default bitrate for non-simulcast.
162 int max_bitrate_bps =
163 (encoder_config.max_bitrate_bps > 0)
164 ? encoder_config.max_bitrate_bps
165 : GetMaxDefaultVideoBitrateKbps(width, height, is_screenshare_) *
166 1000;
167
168 int min_bitrate_bps =
169 experimental_min_bitrate
170 ? rtc::saturated_cast<int>(experimental_min_bitrate->bps())
171 : webrtc::kDefaultMinVideoBitrateBps;
172 if (encoder_config.simulcast_layers[0].min_bitrate_bps > 0) {
173 // Use set min bitrate.
174 min_bitrate_bps = encoder_config.simulcast_layers[0].min_bitrate_bps;
175 // If only min bitrate is configured, make sure max is above min.
176 if (encoder_config.max_bitrate_bps <= 0)
177 max_bitrate_bps = std::max(min_bitrate_bps, max_bitrate_bps);
178 }
179 int max_framerate = (encoder_config.simulcast_layers[0].max_framerate > 0)
180 ? encoder_config.simulcast_layers[0].max_framerate
181 : kDefaultVideoMaxFramerate;
182
183 webrtc::VideoStream layer;
184 layer.width = width;
185 layer.height = height;
186 layer.max_framerate = max_framerate;
187 layer.requested_resolution =
188 encoder_config.simulcast_layers[0].requested_resolution;
189 // Note: VP9 seems to have be sending if any layer is active,
190 // (see `UpdateSendState`) and still use parameters only from
191 // encoder_config.simulcast_layers[0].
192 layer.active = absl::c_any_of(encoder_config.simulcast_layers,
193 [](const auto& layer) { return layer.active; });
194
195 if (encoder_config.simulcast_layers[0].requested_resolution) {
196 auto res = GetLayerResolutionFromRequestedResolution(
197 width, height,
198 *encoder_config.simulcast_layers[0].requested_resolution);
199 layer.width = res.width;
200 layer.height = res.height;
201 } else if (encoder_config.simulcast_layers[0].scale_resolution_down_by > 1.) {
202 layer.width = ScaleDownResolution(
203 layer.width,
204 encoder_config.simulcast_layers[0].scale_resolution_down_by,
205 kMinLayerSize);
206 layer.height = ScaleDownResolution(
207 layer.height,
208 encoder_config.simulcast_layers[0].scale_resolution_down_by,
209 kMinLayerSize);
210 }
211
212 if (absl::EqualsIgnoreCase(codec_name_, kVp9CodecName)) {
213 RTC_DCHECK(encoder_config.encoder_specific_settings);
214 // Use VP9 SVC layering from codec settings which might be initialized
215 // though field trial in ConfigureVideoEncoderSettings.
216 webrtc::VideoCodecVP9 vp9_settings;
217 encoder_config.encoder_specific_settings->FillVideoCodecVp9(&vp9_settings);
218 layer.num_temporal_layers = vp9_settings.numberOfTemporalLayers;
219
220 // Number of spatial layers is signalled differently from different call
221 // sites (sigh), pick the max as we are interested in the upper bound.
222 int num_spatial_layers =
223 std::max({encoder_config.simulcast_layers.size(),
224 encoder_config.spatial_layers.size(),
225 size_t{vp9_settings.numberOfSpatialLayers}});
226
227 if (width * height > 0 &&
228 (layer.num_temporal_layers > 1u || num_spatial_layers > 1)) {
229 // In SVC mode, the VP9 max bitrate is determined by SvcConfig, instead of
230 // GetMaxDefaultVideoBitrateKbps().
231 std::vector<webrtc::SpatialLayer> svc_layers =
232 webrtc::GetSvcConfig(width, height, max_framerate,
233 /*first_active_layer=*/0, num_spatial_layers,
234 *layer.num_temporal_layers, is_screenshare_);
235 int sum_max_bitrates_kbps = 0;
236 for (const webrtc::SpatialLayer& spatial_layer : svc_layers) {
237 sum_max_bitrates_kbps += spatial_layer.maxBitrate;
238 }
239 RTC_DCHECK_GE(sum_max_bitrates_kbps, 0);
240 if (encoder_config.max_bitrate_bps <= 0) {
241 max_bitrate_bps = sum_max_bitrates_kbps * 1000;
242 } else {
243 max_bitrate_bps =
244 std::min(max_bitrate_bps, sum_max_bitrates_kbps * 1000);
245 }
246 max_bitrate_bps = std::max(min_bitrate_bps, max_bitrate_bps);
247 }
248 }
249
250 // In the case that the application sets a max bitrate that's lower than the
251 // min bitrate, we adjust it down (see bugs.webrtc.org/9141).
252 layer.min_bitrate_bps = std::min(min_bitrate_bps, max_bitrate_bps);
253 if (encoder_config.simulcast_layers[0].target_bitrate_bps <= 0) {
254 layer.target_bitrate_bps = max_bitrate_bps;
255 } else {
256 layer.target_bitrate_bps = std::min(
257 encoder_config.simulcast_layers[0].target_bitrate_bps, max_bitrate_bps);
258 }
259 layer.max_bitrate_bps = max_bitrate_bps;
260 layer.max_qp = max_qp_;
261 layer.bitrate_priority = encoder_config.bitrate_priority;
262
263 if (IsTemporalLayersSupported(codec_name_)) {
264 // Use configured number of temporal layers if set.
265 if (encoder_config.simulcast_layers[0].num_temporal_layers) {
266 layer.num_temporal_layers =
267 *encoder_config.simulcast_layers[0].num_temporal_layers;
268 }
269 }
270 layer.scalability_mode = encoder_config.simulcast_layers[0].scalability_mode;
271 layers.push_back(layer);
272 return layers;
273 }
274
275 std::vector<webrtc::VideoStream>
CreateSimulcastOrConferenceModeScreenshareStreams(int width,int height,const webrtc::VideoEncoderConfig & encoder_config,const absl::optional<webrtc::DataRate> & experimental_min_bitrate) const276 EncoderStreamFactory::CreateSimulcastOrConferenceModeScreenshareStreams(
277 int width,
278 int height,
279 const webrtc::VideoEncoderConfig& encoder_config,
280 const absl::optional<webrtc::DataRate>& experimental_min_bitrate) const {
281 std::vector<webrtc::VideoStream> layers;
282
283 const bool temporal_layers_supported =
284 absl::EqualsIgnoreCase(codec_name_, kVp8CodecName) ||
285 absl::EqualsIgnoreCase(codec_name_, kH264CodecName);
286 // Use legacy simulcast screenshare if conference mode is explicitly enabled
287 // or use the regular simulcast configuration path which is generic.
288 layers = GetSimulcastConfig(FindRequiredActiveLayers(encoder_config),
289 encoder_config.number_of_streams, width, height,
290 encoder_config.bitrate_priority, max_qp_,
291 is_screenshare_ && conference_mode_,
292 temporal_layers_supported, trials_);
293 // Allow an experiment to override the minimum bitrate for the lowest
294 // spatial layer. The experiment's configuration has the lowest priority.
295 if (experimental_min_bitrate) {
296 layers[0].min_bitrate_bps =
297 rtc::saturated_cast<int>(experimental_min_bitrate->bps());
298 }
299 // Update the active simulcast layers and configured bitrates.
300 bool is_highest_layer_max_bitrate_configured = false;
301 const bool has_scale_resolution_down_by = absl::c_any_of(
302 encoder_config.simulcast_layers, [](const webrtc::VideoStream& layer) {
303 return layer.scale_resolution_down_by != -1.;
304 });
305
306 bool default_scale_factors_used = true;
307 if (has_scale_resolution_down_by) {
308 default_scale_factors_used = IsScaleFactorsPowerOfTwo(encoder_config);
309 }
310 const bool norm_size_configured =
311 webrtc::NormalizeSimulcastSizeExperiment::GetBase2Exponent().has_value();
312 const int normalized_width =
313 (default_scale_factors_used || norm_size_configured) &&
314 (width >= kMinLayerSize)
315 ? NormalizeSimulcastSize(width, encoder_config.number_of_streams)
316 : width;
317 const int normalized_height =
318 (default_scale_factors_used || norm_size_configured) &&
319 (height >= kMinLayerSize)
320 ? NormalizeSimulcastSize(height, encoder_config.number_of_streams)
321 : height;
322 for (size_t i = 0; i < layers.size(); ++i) {
323 layers[i].active = encoder_config.simulcast_layers[i].active;
324 layers[i].scalability_mode =
325 encoder_config.simulcast_layers[i].scalability_mode;
326 layers[i].requested_resolution =
327 encoder_config.simulcast_layers[i].requested_resolution;
328 // Update with configured num temporal layers if supported by codec.
329 if (encoder_config.simulcast_layers[i].num_temporal_layers &&
330 IsTemporalLayersSupported(codec_name_)) {
331 layers[i].num_temporal_layers =
332 *encoder_config.simulcast_layers[i].num_temporal_layers;
333 }
334 if (encoder_config.simulcast_layers[i].max_framerate > 0) {
335 layers[i].max_framerate =
336 encoder_config.simulcast_layers[i].max_framerate;
337 }
338 if (encoder_config.simulcast_layers[i].requested_resolution.has_value()) {
339 auto res = GetLayerResolutionFromRequestedResolution(
340 normalized_width, normalized_height,
341 *encoder_config.simulcast_layers[i].requested_resolution);
342 layers[i].width = res.width;
343 layers[i].height = res.height;
344 } else if (has_scale_resolution_down_by) {
345 const double scale_resolution_down_by = std::max(
346 encoder_config.simulcast_layers[i].scale_resolution_down_by, 1.0);
347 layers[i].width = ScaleDownResolution(
348 normalized_width, scale_resolution_down_by, kMinLayerSize);
349 layers[i].height = ScaleDownResolution(
350 normalized_height, scale_resolution_down_by, kMinLayerSize);
351 }
352 // Update simulcast bitrates with configured min and max bitrate.
353 if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0) {
354 layers[i].min_bitrate_bps =
355 encoder_config.simulcast_layers[i].min_bitrate_bps;
356 }
357 if (encoder_config.simulcast_layers[i].max_bitrate_bps > 0) {
358 layers[i].max_bitrate_bps =
359 encoder_config.simulcast_layers[i].max_bitrate_bps;
360 }
361 if (encoder_config.simulcast_layers[i].target_bitrate_bps > 0) {
362 layers[i].target_bitrate_bps =
363 encoder_config.simulcast_layers[i].target_bitrate_bps;
364 }
365 if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0 &&
366 encoder_config.simulcast_layers[i].max_bitrate_bps > 0) {
367 // Min and max bitrate are configured.
368 // Set target to 3/4 of the max bitrate (or to max if below min).
369 if (encoder_config.simulcast_layers[i].target_bitrate_bps <= 0)
370 layers[i].target_bitrate_bps = layers[i].max_bitrate_bps * 3 / 4;
371 if (layers[i].target_bitrate_bps < layers[i].min_bitrate_bps)
372 layers[i].target_bitrate_bps = layers[i].max_bitrate_bps;
373 } else if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0) {
374 // Only min bitrate is configured, make sure target/max are above min.
375 layers[i].target_bitrate_bps =
376 std::max(layers[i].target_bitrate_bps, layers[i].min_bitrate_bps);
377 layers[i].max_bitrate_bps =
378 std::max(layers[i].max_bitrate_bps, layers[i].min_bitrate_bps);
379 } else if (encoder_config.simulcast_layers[i].max_bitrate_bps > 0) {
380 // Only max bitrate is configured, make sure min/target are below max.
381 // Keep target bitrate if it is set explicitly in encoding config.
382 // Otherwise set target bitrate to 3/4 of the max bitrate
383 // or the one calculated from GetSimulcastConfig() which is larger.
384 layers[i].min_bitrate_bps =
385 std::min(layers[i].min_bitrate_bps, layers[i].max_bitrate_bps);
386 if (encoder_config.simulcast_layers[i].target_bitrate_bps <= 0) {
387 layers[i].target_bitrate_bps = std::max(
388 layers[i].target_bitrate_bps, layers[i].max_bitrate_bps * 3 / 4);
389 }
390 layers[i].target_bitrate_bps = std::max(
391 std::min(layers[i].target_bitrate_bps, layers[i].max_bitrate_bps),
392 layers[i].min_bitrate_bps);
393 }
394 if (i == layers.size() - 1) {
395 is_highest_layer_max_bitrate_configured =
396 encoder_config.simulcast_layers[i].max_bitrate_bps > 0;
397 }
398 }
399 if (!is_screenshare_ && !is_highest_layer_max_bitrate_configured &&
400 encoder_config.max_bitrate_bps > 0) {
401 // No application-configured maximum for the largest layer.
402 // If there is bitrate leftover, give it to the largest layer.
403 BoostMaxSimulcastLayer(
404 webrtc::DataRate::BitsPerSec(encoder_config.max_bitrate_bps), &layers);
405 }
406
407 // Sort the layers by max_bitrate_bps, they might not always be from
408 // smallest to biggest
409 std::vector<size_t> index(layers.size());
410 std::iota(index.begin(), index.end(), 0);
411 std::stable_sort(index.begin(), index.end(), [&layers](size_t a, size_t b) {
412 return layers[a].max_bitrate_bps < layers[b].max_bitrate_bps;
413 });
414
415 if (!layers[index[0]].active) {
416 // Adjust min bitrate of the first active layer to allow it to go as low as
417 // the lowest (now inactive) layer could.
418 // Otherwise, if e.g. a single HD stream is active, it would have 600kbps
419 // min bitrate, which would always be allocated to the stream.
420 // This would lead to congested network, dropped frames and overall bad
421 // experience.
422
423 const int min_configured_bitrate = layers[index[0]].min_bitrate_bps;
424 for (size_t i = 0; i < layers.size(); ++i) {
425 if (layers[index[i]].active) {
426 layers[index[i]].min_bitrate_bps = min_configured_bitrate;
427 break;
428 }
429 }
430 }
431
432 return layers;
433 }
434
435 webrtc::Resolution
GetLayerResolutionFromRequestedResolution(int frame_width,int frame_height,webrtc::Resolution requested_resolution) const436 EncoderStreamFactory::GetLayerResolutionFromRequestedResolution(
437 int frame_width,
438 int frame_height,
439 webrtc::Resolution requested_resolution) const {
440 VideoAdapter adapter(encoder_info_requested_resolution_alignment_);
441 adapter.OnOutputFormatRequest(requested_resolution.ToPair(),
442 requested_resolution.PixelCount(),
443 absl::nullopt);
444 if (restrictions_) {
445 rtc::VideoSinkWants wants;
446 wants.is_active = true;
447 wants.target_pixel_count = restrictions_->target_pixels_per_frame();
448 wants.max_pixel_count =
449 rtc::dchecked_cast<int>(restrictions_->max_pixels_per_frame().value_or(
450 std::numeric_limits<int>::max()));
451 wants.aggregates.emplace(rtc::VideoSinkWants::Aggregates());
452 wants.resolution_alignment = encoder_info_requested_resolution_alignment_;
453 adapter.OnSinkWants(wants);
454 }
455 int cropped_width, cropped_height;
456 int out_width = 0, out_height = 0;
457 if (!adapter.AdaptFrameResolution(frame_width, frame_height, 0,
458 &cropped_width, &cropped_height, &out_width,
459 &out_height)) {
460 RTC_LOG(LS_ERROR) << "AdaptFrameResolution returned false!";
461 }
462 return {.width = out_width, .height = out_height};
463 }
464
465 } // namespace cricket
466