• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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