tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

svc_config.cc (10637B)


      1 /*
      2 *  Copyright (c) 2018 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 "modules/video_coding/codecs/vp9/svc_config.h"
     12 
     13 #include <algorithm>
     14 #include <cmath>
     15 #include <cstddef>
     16 #include <numeric>
     17 #include <optional>
     18 #include <vector>
     19 
     20 #include "api/video/video_codec_type.h"
     21 #include "api/video_codecs/scalability_mode.h"
     22 #include "api/video_codecs/spatial_layer.h"
     23 #include "api/video_codecs/video_codec.h"
     24 #include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
     25 #include "modules/video_coding/svc/create_scalability_structure.h"
     26 #include "modules/video_coding/svc/scalability_mode_util.h"
     27 #include "modules/video_coding/svc/scalable_video_controller.h"
     28 #include "rtc_base/checks.h"
     29 #include "rtc_base/logging.h"
     30 
     31 namespace webrtc {
     32 
     33 namespace {
     34 const size_t kMinVp9SvcBitrateKbps = 30;
     35 
     36 const size_t kMaxNumLayersForScreenSharing = 3;
     37 const float kMaxScreenSharingLayerFramerateFps[] = {5.0, 10.0, 30.0};
     38 const size_t kMinScreenSharingLayerBitrateKbps[] = {30, 200, 500};
     39 const size_t kTargetScreenSharingLayerBitrateKbps[] = {150, 350, 950};
     40 const size_t kMaxScreenSharingLayerBitrateKbps[] = {250, 500, 950};
     41 
     42 // Gets limited number of layers for given resolution.
     43 size_t GetLimitedNumSpatialLayers(size_t width, size_t height) {
     44  const bool is_landscape = width >= height;
     45  const size_t min_width = is_landscape ? kMinVp9SpatialLayerLongSideLength
     46                                        : kMinVp9SpatialLayerShortSideLength;
     47  const size_t min_height = is_landscape ? kMinVp9SpatialLayerShortSideLength
     48                                         : kMinVp9SpatialLayerLongSideLength;
     49  const size_t num_layers_fit_horz = static_cast<size_t>(
     50      std::floor(1 + std::max(0.0f, std::log2(1.0f * width / min_width))));
     51  const size_t num_layers_fit_vert = static_cast<size_t>(
     52      std::floor(1 + std::max(0.0f, std::log2(1.0f * height / min_height))));
     53  return std::min(num_layers_fit_horz, num_layers_fit_vert);
     54 }
     55 }  // namespace
     56 
     57 std::vector<SpatialLayer> ConfigureSvcScreenSharing(size_t input_width,
     58                                                    size_t input_height,
     59                                                    float max_framerate_fps,
     60                                                    size_t num_spatial_layers) {
     61  num_spatial_layers =
     62      std::min(num_spatial_layers, kMaxNumLayersForScreenSharing);
     63  std::vector<SpatialLayer> spatial_layers;
     64 
     65  for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) {
     66    SpatialLayer spatial_layer = {0};
     67    spatial_layer.width = input_width;
     68    spatial_layer.height = input_height;
     69    spatial_layer.maxFramerate =
     70        std::min(kMaxScreenSharingLayerFramerateFps[sl_idx], max_framerate_fps);
     71    spatial_layer.numberOfTemporalLayers = 1;
     72    spatial_layer.minBitrate =
     73        static_cast<int>(kMinScreenSharingLayerBitrateKbps[sl_idx]);
     74    spatial_layer.maxBitrate =
     75        static_cast<int>(kMaxScreenSharingLayerBitrateKbps[sl_idx]);
     76    spatial_layer.targetBitrate =
     77        static_cast<int>(kTargetScreenSharingLayerBitrateKbps[sl_idx]);
     78    spatial_layer.active = true;
     79    spatial_layers.push_back(spatial_layer);
     80  }
     81 
     82  return spatial_layers;
     83 }
     84 
     85 std::vector<SpatialLayer> ConfigureSvcNormalVideo(
     86    size_t input_width,
     87    size_t input_height,
     88    float max_framerate_fps,
     89    size_t first_active_layer,
     90    size_t num_spatial_layers,
     91    size_t num_temporal_layers,
     92    std::optional<ScalableVideoController::StreamLayersConfig> config) {
     93  RTC_DCHECK_LT(first_active_layer, num_spatial_layers);
     94 
     95  // Limit number of layers for given resolution.
     96  size_t limited_num_spatial_layers =
     97      GetLimitedNumSpatialLayers(input_width, input_height);
     98  if (limited_num_spatial_layers < num_spatial_layers) {
     99    RTC_LOG(LS_WARNING) << "Reducing number of spatial layers from "
    100                        << num_spatial_layers << " to "
    101                        << limited_num_spatial_layers
    102                        << " due to low input resolution.";
    103    num_spatial_layers = limited_num_spatial_layers;
    104  }
    105 
    106  // First active layer must be configured.
    107  num_spatial_layers = std::max(num_spatial_layers, first_active_layer + 1);
    108 
    109  // Ensure top layer is even enough.
    110  int required_divisiblity = 1 << (num_spatial_layers - first_active_layer - 1);
    111  if (config) {
    112    required_divisiblity = 1;
    113    for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) {
    114      required_divisiblity =
    115          std::lcm(required_divisiblity, config->scaling_factor_den[sl_idx]);
    116    }
    117  }
    118  input_width = input_width - input_width % required_divisiblity;
    119  input_height = input_height - input_height % required_divisiblity;
    120 
    121  std::vector<SpatialLayer> spatial_layers;
    122  for (size_t sl_idx = first_active_layer; sl_idx < num_spatial_layers;
    123       ++sl_idx) {
    124    SpatialLayer spatial_layer = {0};
    125    spatial_layer.width = input_width >> (num_spatial_layers - sl_idx - 1);
    126    spatial_layer.height = input_height >> (num_spatial_layers - sl_idx - 1);
    127    spatial_layer.maxFramerate = max_framerate_fps;
    128    spatial_layer.numberOfTemporalLayers = num_temporal_layers;
    129    spatial_layer.active = true;
    130 
    131    if (config) {
    132      spatial_layer.width = input_width * config->scaling_factor_num[sl_idx] /
    133                            config->scaling_factor_den[sl_idx];
    134      spatial_layer.height = input_height * config->scaling_factor_num[sl_idx] /
    135                             config->scaling_factor_den[sl_idx];
    136    }
    137 
    138    // minBitrate and maxBitrate formulas were derived from
    139    // subjective-quality data to determing bit rates below which video
    140    // quality is unacceptable and above which additional bits do not provide
    141    // benefit. The formulas express rate in units of kbps.
    142 
    143    // TODO(ssilkin): Add to the comment PSNR/SSIM we get at encoding certain
    144    // video to min/max bitrate specified by those formulas.
    145    const size_t num_pixels = spatial_layer.width * spatial_layer.height;
    146    int min_bitrate =
    147        static_cast<int>((600. * std::sqrt(num_pixels) - 95000.) / 1000.);
    148    min_bitrate = std::max(min_bitrate, 0);
    149    spatial_layer.minBitrate =
    150        std::max(static_cast<size_t>(min_bitrate), kMinVp9SvcBitrateKbps);
    151    spatial_layer.maxBitrate =
    152        static_cast<int>((1.6 * num_pixels + 50 * 1000) / 1000);
    153    spatial_layer.targetBitrate =
    154        (spatial_layer.minBitrate + spatial_layer.maxBitrate) / 2;
    155    spatial_layers.push_back(spatial_layer);
    156  }
    157 
    158  // A workaround for situation when single HD layer is left with minBitrate
    159  // about 500kbps. This would mean that there will always be at least 500kbps
    160  // allocated to video regardless of how low is the actual BWE.
    161  // Also, boost maxBitrate for the first layer to account for lost ability to
    162  // predict from previous layers.
    163  if (first_active_layer > 0) {
    164    spatial_layers[0].minBitrate = kMinVp9SvcBitrateKbps;
    165    // TODO(ilnik): tune this value or come up with a different formula to
    166    // ensure that all singlecast configurations look good and not too much
    167    // bitrate is added.
    168    spatial_layers[0].maxBitrate *= 1.1;
    169  }
    170 
    171  return spatial_layers;
    172 }
    173 
    174 // Uses scalability mode to configure spatial layers.
    175 std::vector<SpatialLayer> GetVp9SvcConfig(VideoCodec& codec) {
    176  RTC_DCHECK_EQ(codec.codecType, kVideoCodecVP9);
    177 
    178  std::optional<ScalabilityMode> scalability_mode = codec.GetScalabilityMode();
    179  RTC_DCHECK(scalability_mode.has_value());
    180 
    181  bool requested_single_spatial_layer =
    182      ScalabilityModeToNumSpatialLayers(*scalability_mode) == 1;
    183 
    184  // Limit number of spatial layers for given resolution.
    185  int limited_num_spatial_layers =
    186      GetLimitedNumSpatialLayers(codec.width, codec.height);
    187  if (limited_num_spatial_layers <
    188      ScalabilityModeToNumSpatialLayers(*scalability_mode)) {
    189    ScalabilityMode limited_scalability_mode =
    190        LimitNumSpatialLayers(*scalability_mode, limited_num_spatial_layers);
    191    RTC_LOG(LS_WARNING)
    192        << "Reducing number of spatial layers due to low input resolution: "
    193        << ScalabilityModeToString(*scalability_mode) << " to "
    194        << ScalabilityModeToString(limited_scalability_mode);
    195    scalability_mode = limited_scalability_mode;
    196    codec.SetScalabilityMode(limited_scalability_mode);
    197  }
    198 
    199  codec.VP9()->interLayerPred =
    200      ScalabilityModeToInterLayerPredMode(*scalability_mode);
    201 
    202  std::optional<ScalableVideoController::StreamLayersConfig> info =
    203      ScalabilityStructureConfig(*scalability_mode);
    204  if (!info.has_value()) {
    205    RTC_LOG(LS_WARNING) << "Failed to create structure "
    206                        << ScalabilityModeToString(*scalability_mode);
    207    return {};
    208  }
    209 
    210  // TODO(bugs.webrtc.org/11607): Add support for screensharing.
    211  std::vector<SpatialLayer> spatial_layers =
    212      GetSvcConfig(codec.width, codec.height, codec.maxFramerate,
    213                   /*first_active_layer=*/0, info->num_spatial_layers,
    214                   info->num_temporal_layers, /*is_screen_sharing=*/false,
    215                   codec.GetScalabilityMode() ? info : std::nullopt);
    216  RTC_DCHECK(!spatial_layers.empty());
    217 
    218  spatial_layers[0].minBitrate = kMinVp9SvcBitrateKbps;
    219 
    220  // Use codec bitrate limits if spatial layering is not requested.
    221  if (requested_single_spatial_layer) {
    222    SpatialLayer& spatial_layer = spatial_layers[0];
    223    spatial_layer.minBitrate = codec.minBitrate;
    224    spatial_layer.maxBitrate = codec.maxBitrate;
    225    spatial_layer.targetBitrate = codec.maxBitrate;
    226  }
    227 
    228  return spatial_layers;
    229 }
    230 
    231 std::vector<SpatialLayer> GetSvcConfig(
    232    size_t input_width,
    233    size_t input_height,
    234    float max_framerate_fps,
    235    size_t first_active_layer,
    236    size_t num_spatial_layers,
    237    size_t num_temporal_layers,
    238    bool is_screen_sharing,
    239    std::optional<ScalableVideoController::StreamLayersConfig> config) {
    240  RTC_DCHECK_GT(input_width, 0);
    241  RTC_DCHECK_GT(input_height, 0);
    242  RTC_DCHECK_GT(num_spatial_layers, 0);
    243  RTC_DCHECK_GT(num_temporal_layers, 0);
    244 
    245  if (is_screen_sharing) {
    246    return ConfigureSvcScreenSharing(input_width, input_height,
    247                                     max_framerate_fps, num_spatial_layers);
    248  } else {
    249    return ConfigureSvcNormalVideo(input_width, input_height, max_framerate_fps,
    250                                   first_active_layer, num_spatial_layers,
    251                                   num_temporal_layers, config);
    252  }
    253 }
    254 
    255 }  // namespace webrtc