tor-browser

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

av1_svc_config.cc (6060B)


      1 /*
      2 *  Copyright (c) 2020 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/av1/av1_svc_config.h"
     12 
     13 #include <algorithm>
     14 #include <cmath>
     15 #include <memory>
     16 #include <optional>
     17 
     18 #include "absl/container/inlined_vector.h"
     19 #include "api/video/video_codec_type.h"
     20 #include "api/video_codecs/scalability_mode.h"
     21 #include "api/video_codecs/spatial_layer.h"
     22 #include "api/video_codecs/video_codec.h"
     23 #include "modules/video_coding/svc/create_scalability_structure.h"
     24 #include "modules/video_coding/svc/scalability_mode_util.h"
     25 #include "modules/video_coding/svc/scalable_video_controller.h"
     26 #include "rtc_base/checks.h"
     27 #include "rtc_base/logging.h"
     28 #include "rtc_base/strings/string_builder.h"
     29 
     30 namespace webrtc {
     31 namespace {
     32 const int kMinAv1SpatialLayerLongSideLength = 240;
     33 const int kMinAv1SpatialLayerShortSideLength = 135;
     34 
     35 int GetLimitedNumSpatialLayers(int width, int height) {
     36  const bool is_landscape = width >= height;
     37  const int min_width = is_landscape ? kMinAv1SpatialLayerLongSideLength
     38                                     : kMinAv1SpatialLayerShortSideLength;
     39  const int min_height = is_landscape ? kMinAv1SpatialLayerShortSideLength
     40                                      : kMinAv1SpatialLayerLongSideLength;
     41  const int num_layers_fit_horz = static_cast<int>(
     42      std::floor(1 + std::max(0.0f, std::log2(1.0f * width / min_width))));
     43  const int num_layers_fit_vert = static_cast<int>(
     44      std::floor(1 + std::max(0.0f, std::log2(1.0f * height / min_height))));
     45  return std::min(num_layers_fit_horz, num_layers_fit_vert);
     46 }
     47 
     48 std::optional<ScalabilityMode> BuildScalabilityMode(int num_temporal_layers,
     49                                                    int num_spatial_layers) {
     50  char name[20];
     51  SimpleStringBuilder ss(name);
     52  ss << "L" << num_spatial_layers << "T" << num_temporal_layers;
     53  if (num_spatial_layers > 1) {
     54    ss << "_KEY";
     55  }
     56 
     57  return ScalabilityModeFromString(name);
     58 }
     59 }  // namespace
     60 
     61 absl::InlinedVector<ScalabilityMode, kScalabilityModeCount>
     62 LibaomAv1EncoderSupportedScalabilityModes() {
     63  absl::InlinedVector<ScalabilityMode, kScalabilityModeCount> scalability_modes;
     64  for (ScalabilityMode scalability_mode : kAllScalabilityModes) {
     65    if (ScalabilityStructureConfig(scalability_mode) != std::nullopt) {
     66      scalability_modes.push_back(scalability_mode);
     67    }
     68  }
     69  return scalability_modes;
     70 }
     71 
     72 bool LibaomAv1EncoderSupportsScalabilityMode(ScalabilityMode scalability_mode) {
     73  // For libaom AV1, the scalability mode is supported if we can create the
     74  // scalability structure.
     75  return ScalabilityStructureConfig(scalability_mode) != std::nullopt;
     76 }
     77 
     78 bool SetAv1SvcConfig(VideoCodec& video_codec,
     79                     int num_temporal_layers,
     80                     int num_spatial_layers) {
     81  RTC_DCHECK_EQ(video_codec.codecType, kVideoCodecAV1);
     82 
     83  std::optional<ScalabilityMode> scalability_mode =
     84      video_codec.GetScalabilityMode();
     85  if (!scalability_mode.has_value()) {
     86    scalability_mode =
     87        BuildScalabilityMode(num_temporal_layers, num_spatial_layers);
     88    if (!scalability_mode) {
     89      RTC_LOG(LS_WARNING) << "Scalability mode is not set, using 'L1T1'.";
     90      scalability_mode = ScalabilityMode::kL1T1;
     91    }
     92  }
     93 
     94  bool requested_single_spatial_layer =
     95      ScalabilityModeToNumSpatialLayers(*scalability_mode) == 1;
     96 
     97  if (ScalabilityMode reduced = LimitNumSpatialLayers(
     98          *scalability_mode,
     99          GetLimitedNumSpatialLayers(video_codec.width, video_codec.height));
    100      *scalability_mode != reduced) {
    101    RTC_LOG(LS_WARNING) << "Reduced number of spatial layers from "
    102                        << ScalabilityModeToString(*scalability_mode) << " to "
    103                        << ScalabilityModeToString(reduced);
    104    scalability_mode = reduced;
    105  }
    106 
    107  std::unique_ptr<ScalableVideoController> structure =
    108      CreateScalabilityStructure(*scalability_mode);
    109  if (structure == nullptr) {
    110    RTC_LOG(LS_WARNING) << "Failed to create structure "
    111                        << static_cast<int>(*scalability_mode);
    112    return false;
    113  }
    114 
    115  video_codec.SetScalabilityMode(*scalability_mode);
    116 
    117  ScalableVideoController::StreamLayersConfig info = structure->StreamConfig();
    118  for (int sl_idx = 0; sl_idx < info.num_spatial_layers; ++sl_idx) {
    119    SpatialLayer& spatial_layer = video_codec.spatialLayers[sl_idx];
    120    spatial_layer.width = video_codec.width * info.scaling_factor_num[sl_idx] /
    121                          info.scaling_factor_den[sl_idx];
    122    spatial_layer.height = video_codec.height *
    123                           info.scaling_factor_num[sl_idx] /
    124                           info.scaling_factor_den[sl_idx];
    125    spatial_layer.maxFramerate = video_codec.maxFramerate;
    126    spatial_layer.numberOfTemporalLayers = info.num_temporal_layers;
    127    spatial_layer.active = true;
    128  }
    129 
    130  if (requested_single_spatial_layer) {
    131    SpatialLayer& spatial_layer = video_codec.spatialLayers[0];
    132    spatial_layer.minBitrate = video_codec.minBitrate;
    133    spatial_layer.maxBitrate = video_codec.maxBitrate;
    134    spatial_layer.targetBitrate =
    135        (video_codec.minBitrate + video_codec.maxBitrate) / 2;
    136    return true;
    137  }
    138 
    139  for (int sl_idx = 0; sl_idx < info.num_spatial_layers; ++sl_idx) {
    140    SpatialLayer& spatial_layer = video_codec.spatialLayers[sl_idx];
    141    const int num_pixels = spatial_layer.width * spatial_layer.height;
    142    int min_bitrate_kbps = (480.0 * std::sqrt(num_pixels) - 95'000.0) / 1000.0;
    143    spatial_layer.minBitrate = std::max(min_bitrate_kbps, 20);
    144    spatial_layer.maxBitrate = 50 + static_cast<int>(1.6 * num_pixels / 1000.0);
    145    spatial_layer.targetBitrate =
    146        (spatial_layer.minBitrate + spatial_layer.maxBitrate) / 2;
    147  }
    148  return true;
    149 }
    150 
    151 }  // namespace webrtc