tor-browser

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

libaom_av1_encoder.cc (42991B)


      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 #include "modules/video_coding/codecs/av1/libaom_av1_encoder.h"
     11 
     12 #include <cstddef>
     13 #include <cstdint>
     14 #include <map>
     15 #include <memory>
     16 #include <numeric>
     17 #include <optional>
     18 #include <utility>
     19 #include <variant>
     20 #include <vector>
     21 
     22 #include "absl/algorithm/container.h"
     23 #include "absl/base/nullability.h"
     24 #include "absl/container/inlined_vector.h"
     25 #include "api/environment/environment.h"
     26 #include "api/field_trials_view.h"
     27 #include "api/scoped_refptr.h"
     28 #include "api/video/encoded_image.h"
     29 #include "api/video/render_resolution.h"
     30 #include "api/video/video_codec_constants.h"
     31 #include "api/video/video_codec_type.h"
     32 #include "api/video/video_content_type.h"
     33 #include "api/video/video_frame.h"
     34 #include "api/video/video_frame_buffer.h"
     35 #include "api/video/video_frame_type.h"
     36 #include "api/video/video_timing.h"
     37 #include "api/video_codecs/scalability_mode.h"
     38 #include "api/video_codecs/video_codec.h"
     39 #include "api/video_codecs/video_encoder.h"
     40 #include "common_video/generic_frame_descriptor/generic_frame_info.h"
     41 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
     42 #include "modules/video_coding/include/video_codec_interface.h"
     43 #include "modules/video_coding/include/video_error_codes.h"
     44 #include "modules/video_coding/svc/create_scalability_structure.h"
     45 #include "modules/video_coding/svc/scalable_video_controller.h"
     46 #include "modules/video_coding/utility/frame_sampler.h"
     47 #include "rtc_base/checks.h"
     48 #include "rtc_base/experiments/encoder_info_settings.h"
     49 #include "rtc_base/logging.h"
     50 #include "third_party/libaom/source/libaom/aom/aom_codec.h"
     51 #include "third_party/libaom/source/libaom/aom/aom_encoder.h"
     52 #include "third_party/libaom/source/libaom/aom/aom_image.h"
     53 #include "third_party/libaom/source/libaom/aom/aomcx.h"
     54 
     55 #if (defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64)) && \
     56    (defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS))
     57 #define MOBILE_ARM
     58 #endif
     59 
     60 #define SET_ENCODER_PARAM_OR_RETURN_ERROR(param_id, param_value) \
     61  do {                                                           \
     62    if (!SetEncoderControlParameters(param_id, param_value)) {   \
     63      return WEBRTC_VIDEO_CODEC_ERROR;                           \
     64    }                                                            \
     65  } while (0)
     66 
     67 namespace webrtc {
     68 namespace {
     69 
     70 // Encoder configuration parameters
     71 constexpr int kMinQp = 10;
     72 constexpr int kMinQindex = 40;  // Min qindex corresponding to kMinQp.
     73 constexpr int kUsageProfile = AOM_USAGE_REALTIME;
     74 constexpr int kLowQindex = 145;   // Low qindex threshold for QP scaling.
     75 constexpr int kHighQindex = 205;  // High qindex threshold for QP scaling.
     76 constexpr int kBitDepth = 8;
     77 constexpr int kLagInFrames = 0;  // No look ahead.
     78 constexpr double kMinFrameRateFps = 1.0;
     79 
     80 aom_superblock_size_t GetSuperblockSize(int width, int height, int threads) {
     81  int resolution = width * height;
     82  if (threads >= 4 && resolution >= 960 * 540 && resolution < 1920 * 1080)
     83    return AOM_SUPERBLOCK_SIZE_64X64;
     84  else
     85    return AOM_SUPERBLOCK_SIZE_DYNAMIC;
     86 }
     87 
     88 void PopulateEncodedImageFromVideoFrame(const VideoFrame& frame,
     89                                        EncodedImage& encoded_image) {
     90  encoded_image.SetRtpTimestamp(frame.rtp_timestamp());
     91  encoded_image.SetPresentationTimestamp(frame.presentation_timestamp());
     92  encoded_image.capture_time_ms_ = frame.render_time_ms();
     93  encoded_image.rotation_ = frame.rotation();
     94  encoded_image.SetColorSpace(frame.color_space());
     95 }
     96 class LibaomAv1Encoder final : public VideoEncoder {
     97 public:
     98  LibaomAv1Encoder(const Environment& env, LibaomAv1EncoderSettings settings);
     99  ~LibaomAv1Encoder() override;
    100 
    101  int InitEncode(const VideoCodec* codec_settings,
    102                 const Settings& settings) override;
    103 
    104  int32_t RegisterEncodeCompleteCallback(
    105      EncodedImageCallback* encoded_image_callback) override;
    106 
    107  int32_t Release() override;
    108 
    109  int32_t Encode(const VideoFrame& frame,
    110                 const std::vector<VideoFrameType>* frame_types) override;
    111 
    112  void SetRates(const RateControlParameters& parameters) override;
    113 
    114  EncoderInfo GetEncoderInfo() const override;
    115 
    116 private:
    117  template <typename P>
    118  bool SetEncoderControlParameters(int param_id, P param_value);
    119 
    120  // Get value to be used for encoder cpu_speed setting
    121  int GetCpuSpeed(int width, int height);
    122 
    123  // Determine number of encoder threads to use.
    124  int NumberOfThreads(int width, int height, int number_of_cores);
    125 
    126  bool SvcEnabled() const { return svc_params_.has_value(); }
    127  // Fills svc_params_ memeber value. Returns false on error.
    128  bool SetSvcParams(ScalableVideoController::StreamLayersConfig svc_config,
    129                    const aom_codec_enc_cfg_t& encoder_config);
    130  // Configures the encoder with layer for the next frame.
    131  void SetSvcLayerId(
    132      const ScalableVideoController::LayerFrameConfig& layer_frame);
    133  // Configures the encoder which buffers next frame updates and can reference.
    134  void SetSvcRefFrameConfig(
    135      const ScalableVideoController::LayerFrameConfig& layer_frame);
    136  // If pixel format doesn't match, then reallocate.
    137  void MaybeRewrapImgWithFormat(const aom_img_fmt_t fmt,
    138                                unsigned int width,
    139                                unsigned int height);
    140 
    141  // Adjust sclaing factors assuming that the top active SVC layer
    142  // will be the input resolution.
    143  void AdjustScalingFactorsForTopActiveLayer();
    144 
    145  using EncodeResult = std::variant<aom_codec_err_t, EncodedImage>;
    146 
    147  // Duration is specified in ticks based on aom_codec_enc_cfg_t::g_timebase,
    148  // in practice that that is kVideoPayloadTypeFrequency (90kHz).
    149  EncodeResult DoEncode(uint32_t duration,
    150                        aom_enc_frame_flags_t flags,
    151                        ScalableVideoController::LayerFrameConfig* layer_frame);
    152 
    153  CodecSpecificInfo CreateCodecSpecificInfo(
    154      const EncodedImage& image,
    155      const ScalableVideoController::LayerFrameConfig& layer_frame,
    156      bool end_of_picture);
    157 
    158  std::unique_ptr<ScalableVideoController> svc_controller_;
    159  std::optional<ScalabilityMode> scalability_mode_;
    160  // Original scaling factors for all configured layers active and inactive.
    161  // `svc_params_` stores factors ignoring top inactive layers.
    162  std::vector<int> scaling_factors_num_;
    163  std::vector<int> scaling_factors_den_;
    164  int last_active_layer_ = 0;
    165 
    166  bool inited_;
    167  bool rates_configured_;
    168  std::optional<aom_svc_params_t> svc_params_;
    169  VideoCodec encoder_settings_;
    170  LibaomAv1EncoderSettings settings_;
    171  aom_image_t* frame_for_encode_;
    172  aom_codec_ctx_t ctx_;
    173  aom_codec_enc_cfg_t cfg_;
    174  EncodedImageCallback* encoded_image_callback_;
    175  double framerate_fps_;  // Current target frame rate.
    176  int64_t timestamp_;
    177  const LibaomAv1EncoderInfoSettings encoder_info_override_;
    178  // TODO(webrtc:351644568): Remove this kill-switch after the feature is fully
    179  // deployed.
    180  const bool post_encode_frame_drop_;
    181 
    182  // Determine whether the frame should be sampled for PSNR.
    183  FrameSampler psnr_frame_sampler_;
    184  // TODO(webrtc:388070060): Remove after rollout.
    185  const bool calculate_psnr_;
    186  const bool drop_repeat_frames_on_enhancement_layers_;
    187  std::map<int, uint32_t> last_encoded_timestamp_by_sid_;
    188 };
    189 
    190 int32_t VerifyCodecSettings(const VideoCodec& codec_settings) {
    191  if (codec_settings.width < 1) {
    192    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    193  }
    194  if (codec_settings.height < 1) {
    195    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    196  }
    197  // maxBitrate == 0 represents an unspecified maxBitRate.
    198  if (codec_settings.maxBitrate > 0 &&
    199      codec_settings.minBitrate > codec_settings.maxBitrate) {
    200    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    201  }
    202  if (codec_settings.maxBitrate > 0 &&
    203      codec_settings.startBitrate > codec_settings.maxBitrate) {
    204    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    205  }
    206  if (codec_settings.startBitrate < codec_settings.minBitrate) {
    207    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    208  }
    209  if (codec_settings.maxFramerate < 1) {
    210    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    211  }
    212  if (codec_settings.qpMax < kMinQp || codec_settings.qpMax > 63) {
    213    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    214  }
    215  return WEBRTC_VIDEO_CODEC_OK;
    216 }
    217 
    218 LibaomAv1Encoder::LibaomAv1Encoder(const Environment& env,
    219                                   LibaomAv1EncoderSettings settings)
    220    : inited_(false),
    221      rates_configured_(false),
    222      settings_(std::move(settings)),
    223      frame_for_encode_(nullptr),
    224      encoded_image_callback_(nullptr),
    225      framerate_fps_(0),
    226      timestamp_(0),
    227      encoder_info_override_(env.field_trials()),
    228      post_encode_frame_drop_(!env.field_trials().IsDisabled(
    229          "WebRTC-LibaomAv1Encoder-PostEncodeFrameDrop")),
    230      calculate_psnr_(
    231          env.field_trials().IsEnabled("WebRTC-Video-CalculatePsnr")),
    232      drop_repeat_frames_on_enhancement_layers_(env.field_trials().IsEnabled(
    233          "WebRTC-LibaomAv1Encoder-DropRepeatFramesOnEnhancementLayers")) {}
    234 
    235 LibaomAv1Encoder::~LibaomAv1Encoder() {
    236  Release();
    237 }
    238 
    239 int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings,
    240                                 const Settings& settings) {
    241  if (codec_settings == nullptr) {
    242    RTC_LOG(LS_WARNING) << "No codec settings provided to "
    243                           "LibaomAv1Encoder.";
    244    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    245  }
    246  if (settings.number_of_cores < 1) {
    247    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    248  }
    249  if (inited_) {
    250    RTC_LOG(LS_WARNING) << "Initing LibaomAv1Encoder without first releasing.";
    251    Release();
    252  }
    253  encoder_settings_ = *codec_settings;
    254 
    255  // Sanity checks for encoder configuration.
    256  const int32_t result = VerifyCodecSettings(encoder_settings_);
    257  if (result < 0) {
    258    RTC_LOG(LS_WARNING) << "Incorrect codec settings provided to "
    259                           "LibaomAv1Encoder.";
    260    return result;
    261  }
    262  if (encoder_settings_.numberOfSimulcastStreams > 1) {
    263    RTC_LOG(LS_WARNING) << "Simulcast is not implemented by LibaomAv1Encoder.";
    264    return result;
    265  }
    266  scalability_mode_ = encoder_settings_.GetScalabilityMode();
    267  if (!scalability_mode_.has_value()) {
    268    RTC_LOG(LS_WARNING) << "Scalability mode is not set, using 'L1T1'.";
    269    scalability_mode_ = ScalabilityMode::kL1T1;
    270  }
    271  svc_controller_ = CreateScalabilityStructure(*scalability_mode_);
    272  if (svc_controller_ == nullptr) {
    273    RTC_LOG(LS_WARNING) << "Failed to set scalability mode "
    274                        << static_cast<int>(*scalability_mode_);
    275    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    276  }
    277 
    278  // Initialize encoder configuration structure with default values
    279  aom_codec_err_t ret =
    280      aom_codec_enc_config_default(aom_codec_av1_cx(), &cfg_, kUsageProfile);
    281  if (ret != AOM_CODEC_OK) {
    282    RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
    283                        << " on aom_codec_enc_config_default.";
    284    return WEBRTC_VIDEO_CODEC_ERROR;
    285  }
    286 
    287  // Overwrite default config with input encoder settings & RTC-relevant values.
    288  cfg_.g_w = encoder_settings_.width;
    289  cfg_.g_h = encoder_settings_.height;
    290  cfg_.g_threads =
    291      NumberOfThreads(cfg_.g_w, cfg_.g_h, settings.number_of_cores);
    292  cfg_.g_timebase.num = 1;
    293  cfg_.g_timebase.den = kVideoPayloadTypeFrequency;
    294  cfg_.rc_target_bitrate = encoder_settings_.startBitrate;  // kilobits/sec.
    295  cfg_.rc_dropframe_thresh = encoder_settings_.GetFrameDropEnabled() ? 30 : 0;
    296  cfg_.g_input_bit_depth = kBitDepth;
    297  cfg_.kf_mode = AOM_KF_DISABLED;
    298  cfg_.rc_min_quantizer = kMinQp;
    299  cfg_.rc_max_quantizer = encoder_settings_.qpMax;
    300  cfg_.rc_undershoot_pct = 50;
    301  cfg_.rc_overshoot_pct = 50;
    302  cfg_.rc_buf_initial_sz = 600;
    303  cfg_.rc_buf_optimal_sz = 600;
    304  cfg_.rc_buf_sz = 1000;
    305  cfg_.g_usage = kUsageProfile;
    306  cfg_.g_error_resilient = 0;
    307  // Low-latency settings.
    308  cfg_.rc_end_usage = AOM_CBR;          // Constant Bit Rate (CBR) mode
    309  cfg_.g_pass = AOM_RC_ONE_PASS;        // One-pass rate control
    310  cfg_.g_lag_in_frames = kLagInFrames;  // No look ahead when lag equals 0.
    311 
    312  if (frame_for_encode_ != nullptr) {
    313    aom_img_free(frame_for_encode_);
    314    frame_for_encode_ = nullptr;
    315  }
    316 
    317  // Flag options: AOM_EFLAG_CALCULATE_PSNR and AOM_CODEC_USE_HIGHBITDEPTH
    318  aom_codec_flags_t flags = 0;
    319 
    320  // Initialize an encoder instance.
    321  ret = aom_codec_enc_init(&ctx_, aom_codec_av1_cx(), &cfg_, flags);
    322  if (ret != AOM_CODEC_OK) {
    323    RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::EncodeInit returned " << ret
    324                        << " on aom_codec_enc_init.";
    325    return WEBRTC_VIDEO_CODEC_ERROR;
    326  }
    327 
    328  if (!SetSvcParams(svc_controller_->StreamConfig(), cfg_)) {
    329    return WEBRTC_VIDEO_CODEC_ERROR;
    330  }
    331 
    332  inited_ = true;
    333 
    334  // Set control parameters
    335  SET_ENCODER_PARAM_OR_RETURN_ERROR(AOME_SET_CPUUSED,
    336                                    GetCpuSpeed(cfg_.g_w, cfg_.g_h));
    337  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_CDEF, 1);
    338  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_TPL_MODEL, 0);
    339  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_DELTAQ_MODE, 0);
    340  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_ORDER_HINT, 0);
    341  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_AQ_MODE, 3);
    342  SET_ENCODER_PARAM_OR_RETURN_ERROR(AOME_SET_MAX_INTRA_BITRATE_PCT, 300);
    343  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_COEFF_COST_UPD_FREQ, 3);
    344  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_MODE_COST_UPD_FREQ, 3);
    345  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_MV_COST_UPD_FREQ, 3);
    346 
    347  if (codec_settings->mode == VideoCodecMode::kScreensharing) {
    348    SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_TUNE_CONTENT,
    349                                      AOM_CONTENT_SCREEN);
    350    SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_PALETTE, 1);
    351  } else {
    352    SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_PALETTE, 0);
    353  }
    354 
    355  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_AUTO_TILES, 1);
    356  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ROW_MT, 1);
    357  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_OBMC, 0);
    358  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_NOISE_SENSITIVITY, 0);
    359  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_WARPED_MOTION, 0);
    360  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_GLOBAL_MOTION, 0);
    361  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_REF_FRAME_MVS, 0);
    362  SET_ENCODER_PARAM_OR_RETURN_ERROR(
    363      AV1E_SET_SUPERBLOCK_SIZE,
    364      GetSuperblockSize(cfg_.g_w, cfg_.g_h, cfg_.g_threads));
    365  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_CFL_INTRA, 0);
    366  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_SMOOTH_INTRA, 0);
    367  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_ANGLE_DELTA, 0);
    368  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_FILTER_INTRA, 0);
    369  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_INTRA_DEFAULT_TX_ONLY, 1);
    370  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_DISABLE_TRELLIS_QUANT, 1);
    371  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_DIST_WTD_COMP, 0);
    372  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_DIFF_WTD_COMP, 0);
    373  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_DUAL_FILTER, 0);
    374  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_INTERINTRA_COMP, 0);
    375  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_INTERINTRA_WEDGE, 0);
    376  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_INTRA_EDGE_FILTER, 0);
    377  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_INTRABC, 0);
    378  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_MASKED_COMP, 0);
    379  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_PAETH_INTRA, 0);
    380  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_QM, 0);
    381  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_RECT_PARTITIONS, 0);
    382  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_RESTORATION, 0);
    383  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_SMOOTH_INTERINTRA, 0);
    384  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_TX64, 0);
    385  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_MAX_REFERENCE_FRAMES, 3);
    386  SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_MAX_CONSEC_FRAME_DROP_MS_CBR, 250);
    387 
    388  if (post_encode_frame_drop_) {
    389    SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_POSTENCODE_DROP_RTC, 1);
    390  }
    391 
    392  return WEBRTC_VIDEO_CODEC_OK;
    393 }
    394 
    395 template <typename P>
    396 bool LibaomAv1Encoder::SetEncoderControlParameters(int param_id,
    397                                                   P param_value) {
    398  aom_codec_err_t error_code = aom_codec_control(&ctx_, param_id, param_value);
    399  if (error_code != AOM_CODEC_OK) {
    400    RTC_LOG(LS_WARNING)
    401        << "LibaomAv1Encoder::SetEncoderControlParameters returned "
    402        << error_code << " on id:  " << param_id << ".";
    403  }
    404  return error_code == AOM_CODEC_OK;
    405 }
    406 
    407 // Only positive speeds, range for real-time coding currently is: 6 - 10.
    408 // Speed 11 is used for screen sharing.
    409 // Lower means slower/better quality, higher means fastest/lower quality.
    410 int LibaomAv1Encoder::GetCpuSpeed(int width, int height) {
    411  if (!settings_.max_pixel_count_to_cpu_speed.empty()) {
    412    if (auto it =
    413            settings_.max_pixel_count_to_cpu_speed.lower_bound(width * height);
    414        it != settings_.max_pixel_count_to_cpu_speed.end()) {
    415      return it->second;
    416    }
    417 
    418    return 10;
    419  } else {
    420    if (encoder_settings_.mode == VideoCodecMode::kScreensharing) {
    421      return 11;
    422    }
    423    // For smaller resolutions, use lower speed setting (get some coding gain at
    424    // the cost of increased encoding complexity).
    425    switch (encoder_settings_.GetVideoEncoderComplexity()) {
    426      case VideoCodecComplexity::kComplexityHigh:
    427        if (width * height <= 320 * 180)
    428          return 8;
    429        else if (width * height <= 640 * 360)
    430          return 9;
    431        else
    432          return 10;
    433      case VideoCodecComplexity::kComplexityHigher:
    434        if (width * height <= 320 * 180)
    435          return 7;
    436        else if (width * height <= 640 * 360)
    437          return 8;
    438        else if (width * height <= 1280 * 720)
    439          return 9;
    440        else
    441          return 10;
    442      case VideoCodecComplexity::kComplexityMax:
    443        if (width * height <= 320 * 180)
    444          return 6;
    445        else if (width * height <= 640 * 360)
    446          return 7;
    447        else if (width * height <= 1280 * 720)
    448          return 8;
    449        else
    450          return 9;
    451      default:
    452        return 10;
    453    }
    454  }
    455 }
    456 
    457 int LibaomAv1Encoder::NumberOfThreads(int width,
    458                                      int height,
    459                                      int number_of_cores) {
    460  // Keep the number of encoder threads equal to the possible number of
    461  // column/row tiles, which is (1, 2, 4, 8). See comments below for
    462  // AV1E_SET_TILE_COLUMNS/ROWS.
    463  if (width * height > 1280 * 720 && number_of_cores > 8) {
    464    return 8;
    465  } else if (width * height >= 640 * 360 && number_of_cores > 4) {
    466    return 4;
    467  } else if (width * height >= 320 * 180 && number_of_cores > 2) {
    468    return 2;
    469  } else {
    470 // Use 2 threads for low res on ARM.
    471 #ifdef MOBILE_ARM
    472    if (width * height >= 320 * 180 && number_of_cores > 2) {
    473      return 2;
    474    }
    475 #endif
    476    // 1 thread less than VGA.
    477    return 1;
    478  }
    479 }
    480 
    481 bool LibaomAv1Encoder::SetSvcParams(
    482    ScalableVideoController::StreamLayersConfig svc_config,
    483    const aom_codec_enc_cfg_t& encoder_config) {
    484  bool svc_enabled =
    485      svc_config.num_spatial_layers > 1 || svc_config.num_temporal_layers > 1;
    486  if (!svc_enabled) {
    487    svc_params_ = std::nullopt;
    488    return true;
    489  }
    490  if (svc_config.num_spatial_layers < 1 || svc_config.num_spatial_layers > 4) {
    491    RTC_LOG(LS_WARNING) << "Av1 supports up to 4 spatial layers. "
    492                        << svc_config.num_spatial_layers << " configured.";
    493    return false;
    494  }
    495  if (svc_config.num_temporal_layers < 1 ||
    496      svc_config.num_temporal_layers > 8) {
    497    RTC_LOG(LS_WARNING) << "Av1 supports up to 8 temporal layers. "
    498                        << svc_config.num_temporal_layers << " configured.";
    499    return false;
    500  }
    501  aom_svc_params_t& svc_params = svc_params_.emplace();
    502  svc_params.number_spatial_layers = svc_config.num_spatial_layers;
    503  svc_params.number_temporal_layers = svc_config.num_temporal_layers;
    504 
    505  int num_layers =
    506      svc_config.num_spatial_layers * svc_config.num_temporal_layers;
    507  for (int i = 0; i < num_layers; ++i) {
    508    svc_params.min_quantizers[i] = encoder_config.rc_min_quantizer;
    509    svc_params.max_quantizers[i] = encoder_config.rc_max_quantizer;
    510  }
    511 
    512  // Assume each temporal layer doubles framerate.
    513  for (int tid = 0; tid < svc_config.num_temporal_layers; ++tid) {
    514    svc_params.framerate_factor[tid] =
    515        1 << (svc_config.num_temporal_layers - tid - 1);
    516  }
    517 
    518  scaling_factors_den_.resize(svc_config.num_spatial_layers);
    519  scaling_factors_num_.resize(svc_config.num_spatial_layers);
    520  for (int sid = 0; sid < svc_config.num_spatial_layers; ++sid) {
    521    scaling_factors_num_[sid] = svc_config.scaling_factor_num[sid];
    522    svc_params.scaling_factor_num[sid] = svc_config.scaling_factor_num[sid];
    523    scaling_factors_den_[sid] = svc_config.scaling_factor_den[sid];
    524    svc_params.scaling_factor_den[sid] = svc_config.scaling_factor_den[sid];
    525    encoder_settings_.spatialLayers[sid].width = encoder_settings_.width *
    526                                                 scaling_factors_num_[sid] /
    527                                                 scaling_factors_den_[sid];
    528    encoder_settings_.spatialLayers[sid].height = encoder_settings_.height *
    529                                                  scaling_factors_num_[sid] /
    530                                                  scaling_factors_den_[sid];
    531  }
    532 
    533  // svc_params.layer_target_bitrate is set in SetRates() before svc_params is
    534  // passed to SetEncoderControlParameters(AV1E_SET_SVC_PARAMS).
    535 
    536  return true;
    537 }
    538 
    539 void LibaomAv1Encoder::SetSvcLayerId(
    540    const ScalableVideoController::LayerFrameConfig& layer_frame) {
    541  aom_svc_layer_id_t layer_id = {};
    542  layer_id.spatial_layer_id = layer_frame.SpatialId();
    543  layer_id.temporal_layer_id = layer_frame.TemporalId();
    544  SetEncoderControlParameters(AV1E_SET_SVC_LAYER_ID, &layer_id);
    545 }
    546 
    547 void LibaomAv1Encoder::SetSvcRefFrameConfig(
    548    const ScalableVideoController::LayerFrameConfig& layer_frame) {
    549  // Buffer name to use for each layer_frame.buffers position. In particular
    550  // when there are 2 buffers are referenced, prefer name them last and golden,
    551  // because av1 bitstream format has dedicated fields for these two names.
    552  // See last_frame_idx and golden_frame_idx in the av1 spec
    553  // https://aomediacodec.github.io/av1-spec/av1-spec.pdf
    554  static constexpr int kPreferedSlotName[] = {0,  // Last
    555                                              3,  // Golden
    556                                              1, 2, 4, 5, 6};
    557  static constexpr int kAv1NumBuffers = 8;
    558 
    559  aom_svc_ref_frame_config_t ref_frame_config = {};
    560  RTC_CHECK_LE(layer_frame.Buffers().size(), std::size(kPreferedSlotName));
    561  for (size_t i = 0; i < layer_frame.Buffers().size(); ++i) {
    562    const CodecBufferUsage& buffer = layer_frame.Buffers()[i];
    563    int slot_name = kPreferedSlotName[i];
    564    RTC_CHECK_GE(buffer.id, 0);
    565    RTC_CHECK_LT(buffer.id, kAv1NumBuffers);
    566    ref_frame_config.ref_idx[slot_name] = buffer.id;
    567    if (buffer.referenced) {
    568      ref_frame_config.reference[slot_name] = 1;
    569    }
    570    if (buffer.updated) {
    571      ref_frame_config.refresh[buffer.id] = 1;
    572    }
    573  }
    574 
    575  SetEncoderControlParameters(AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config);
    576 }
    577 
    578 int32_t LibaomAv1Encoder::RegisterEncodeCompleteCallback(
    579    EncodedImageCallback* encoded_image_callback) {
    580  encoded_image_callback_ = encoded_image_callback;
    581  return WEBRTC_VIDEO_CODEC_OK;
    582 }
    583 
    584 int32_t LibaomAv1Encoder::Release() {
    585  if (frame_for_encode_ != nullptr) {
    586    aom_img_free(frame_for_encode_);
    587    frame_for_encode_ = nullptr;
    588  }
    589  if (inited_) {
    590    if (aom_codec_destroy(&ctx_)) {
    591      return WEBRTC_VIDEO_CODEC_MEMORY;
    592    }
    593    inited_ = false;
    594  }
    595  rates_configured_ = false;
    596  return WEBRTC_VIDEO_CODEC_OK;
    597 }
    598 
    599 void LibaomAv1Encoder::MaybeRewrapImgWithFormat(const aom_img_fmt_t fmt,
    600                                                unsigned int width,
    601                                                unsigned int height) {
    602  if (!frame_for_encode_) {
    603    RTC_LOG(LS_INFO) << "Configuring AV1 encoder pixel format to "
    604                     << (fmt == AOM_IMG_FMT_NV12 ? "NV12" : "I420") << " "
    605                     << width << "x" << height;
    606    frame_for_encode_ = aom_img_wrap(nullptr, fmt, width, height, 1, nullptr);
    607  } else if (frame_for_encode_->fmt != fmt || frame_for_encode_->d_w != width ||
    608             frame_for_encode_->d_h != height) {
    609    RTC_LOG(LS_INFO) << "Switching AV1 encoder pixel format to "
    610                     << (fmt == AOM_IMG_FMT_NV12 ? "NV12" : "I420") << " "
    611                     << width << "x" << height;
    612    aom_img_free(frame_for_encode_);
    613    frame_for_encode_ = aom_img_wrap(nullptr, fmt, width, height, 1, nullptr);
    614  }
    615  // else no-op since the image is already in the right format.
    616 }
    617 
    618 void LibaomAv1Encoder::AdjustScalingFactorsForTopActiveLayer() {
    619  if (!SvcEnabled())
    620    return;
    621  last_active_layer_ = svc_params_->number_spatial_layers - 1;
    622  for (int sid = 0; sid < svc_params_->number_spatial_layers; ++sid) {
    623    for (int tid = 0; tid < svc_params_->number_temporal_layers; ++tid) {
    624      int layer_index = sid * svc_params_->number_temporal_layers + tid;
    625      if (svc_params_->layer_target_bitrate[layer_index] > 0) {
    626        last_active_layer_ = sid;
    627      }
    628    }
    629  }
    630  if (static_cast<int>(cfg_.g_w) ==
    631      encoder_settings_.spatialLayers[last_active_layer_].width) {
    632    return;
    633  }
    634 
    635  cfg_.g_w = encoder_settings_.spatialLayers[last_active_layer_].width;
    636  cfg_.g_h = encoder_settings_.spatialLayers[last_active_layer_].height;
    637 
    638  // Recalculate scaling factors ignoring top inactive layers.
    639  // Divide all by scaling factor of the last active layer.
    640  for (int i = 0; i <= last_active_layer_; ++i) {
    641    int n = scaling_factors_num_[i] * scaling_factors_den_[last_active_layer_];
    642    int d = scaling_factors_den_[i] * scaling_factors_num_[last_active_layer_];
    643    int gcd = std::gcd(n, d);
    644    svc_params_->scaling_factor_num[i] = n / gcd;
    645    svc_params_->scaling_factor_den[i] = d / gcd;
    646  }
    647  for (int i = last_active_layer_ + 1; i < svc_params_->number_spatial_layers;
    648       ++i) {
    649    svc_params_->scaling_factor_num[i] = 1;
    650    svc_params_->scaling_factor_den[i] = 1;
    651  }
    652 }
    653 
    654 int32_t LibaomAv1Encoder::Encode(
    655    const VideoFrame& frame,
    656    const std::vector<VideoFrameType>* frame_types) {
    657  if (!inited_ || encoded_image_callback_ == nullptr || !rates_configured_) {
    658    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
    659  }
    660 
    661  bool keyframe_required =
    662      frame_types != nullptr &&
    663      absl::c_linear_search(*frame_types, VideoFrameType::kVideoFrameKey);
    664 
    665  std::vector<ScalableVideoController::LayerFrameConfig> layer_frames =
    666      svc_controller_->NextFrameConfig(keyframe_required);
    667 
    668  if (layer_frames.empty()) {
    669    RTC_LOG(LS_ERROR) << "SVCController returned no configuration for a frame.";
    670    return WEBRTC_VIDEO_CODEC_ERROR;
    671  }
    672 
    673  if (drop_repeat_frames_on_enhancement_layers_ && frame.is_repeat_frame()) {
    674    bool all_layers_droppable = !layer_frames.empty();
    675    for (const auto& layer_frame : layer_frames) {
    676      if (layer_frame.TemporalId() == 0) {
    677        all_layers_droppable = false;
    678        break;
    679      }
    680      if (auto it =
    681              last_encoded_timestamp_by_sid_.find(layer_frame.SpatialId());
    682          it != last_encoded_timestamp_by_sid_.end()) {
    683        // Get the time since the last encoded frame for this spatial layer.
    684        // Don't drop enhancement layer repeat frame if last encode was more
    685        // than one second ago.
    686        if ((frame.rtp_timestamp() - it->second) > kVideoPayloadTypeFrequency) {
    687          all_layers_droppable = false;
    688          break;
    689        }
    690      }
    691    }
    692 
    693    if (all_layers_droppable) {
    694      RTC_LOG(LS_VERBOSE) << "Dropping repeat frame on enhancement layers.";
    695      for (const auto& layer_frame : layer_frames) {
    696        svc_controller_->OnEncodeDone(layer_frame);
    697      }
    698      return WEBRTC_VIDEO_CODEC_OK;  // Frame dropped
    699    }
    700  }
    701 
    702  scoped_refptr<VideoFrameBuffer> buffer = frame.video_frame_buffer();
    703  absl::InlinedVector<VideoFrameBuffer::Type, kMaxPreferredPixelFormats>
    704      supported_formats = {VideoFrameBuffer::Type::kI420,
    705                           VideoFrameBuffer::Type::kNV12};
    706 
    707  scoped_refptr<VideoFrameBuffer> scaled_image;
    708  if (!SvcEnabled() ||
    709      last_active_layer_ + 1 == svc_params_->number_spatial_layers) {
    710    scaled_image = buffer;
    711  } else {
    712    scaled_image = buffer->Scale(
    713        encoder_settings_.spatialLayers[last_active_layer_].width,
    714        encoder_settings_.spatialLayers[last_active_layer_].height);
    715  }
    716 
    717  scoped_refptr<VideoFrameBuffer> mapped_buffer;
    718  if (scaled_image->type() != VideoFrameBuffer::Type::kNative) {
    719    // `buffer` is already mapped.
    720    mapped_buffer = scaled_image;
    721  } else {
    722    // Attempt to map to one of the supported formats.
    723    mapped_buffer = scaled_image->GetMappedFrameBuffer(supported_formats);
    724  }
    725 
    726  // Convert input frame to I420, if needed.
    727  if (!mapped_buffer ||
    728      (absl::c_find(supported_formats, mapped_buffer->type()) ==
    729           supported_formats.end() &&
    730       mapped_buffer->type() != VideoFrameBuffer::Type::kI420A)) {
    731    scoped_refptr<I420BufferInterface> converted_buffer(buffer->ToI420());
    732    if (!converted_buffer) {
    733      RTC_LOG(LS_ERROR) << "Failed to convert "
    734                        << VideoFrameBufferTypeToString(
    735                               frame.video_frame_buffer()->type())
    736                        << " image to I420. Can't encode frame.";
    737      return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
    738    }
    739    RTC_CHECK(converted_buffer->type() == VideoFrameBuffer::Type::kI420 ||
    740              converted_buffer->type() == VideoFrameBuffer::Type::kI420A);
    741 
    742    mapped_buffer = converted_buffer;
    743  }
    744 
    745  switch (mapped_buffer->type()) {
    746    case VideoFrameBuffer::Type::kI420:
    747    case VideoFrameBuffer::Type::kI420A: {
    748      // Set frame_for_encode_ data pointers and strides.
    749      MaybeRewrapImgWithFormat(AOM_IMG_FMT_I420, mapped_buffer->width(),
    750                               mapped_buffer->height());
    751      auto i420_buffer = mapped_buffer->GetI420();
    752      RTC_DCHECK(i420_buffer);
    753      RTC_CHECK_EQ(i420_buffer->width(), frame_for_encode_->d_w);
    754      RTC_CHECK_EQ(i420_buffer->height(), frame_for_encode_->d_h);
    755      frame_for_encode_->planes[AOM_PLANE_Y] =
    756          const_cast<unsigned char*>(i420_buffer->DataY());
    757      frame_for_encode_->planes[AOM_PLANE_U] =
    758          const_cast<unsigned char*>(i420_buffer->DataU());
    759      frame_for_encode_->planes[AOM_PLANE_V] =
    760          const_cast<unsigned char*>(i420_buffer->DataV());
    761      frame_for_encode_->stride[AOM_PLANE_Y] = i420_buffer->StrideY();
    762      frame_for_encode_->stride[AOM_PLANE_U] = i420_buffer->StrideU();
    763      frame_for_encode_->stride[AOM_PLANE_V] = i420_buffer->StrideV();
    764      break;
    765    }
    766    case VideoFrameBuffer::Type::kNV12: {
    767      MaybeRewrapImgWithFormat(AOM_IMG_FMT_NV12, mapped_buffer->width(),
    768                               mapped_buffer->height());
    769      const NV12BufferInterface* nv12_buffer = mapped_buffer->GetNV12();
    770      RTC_DCHECK(nv12_buffer);
    771      RTC_CHECK_EQ(nv12_buffer->width(), frame_for_encode_->d_w);
    772      RTC_CHECK_EQ(nv12_buffer->height(), frame_for_encode_->d_h);
    773      frame_for_encode_->planes[AOM_PLANE_Y] =
    774          const_cast<unsigned char*>(nv12_buffer->DataY());
    775      frame_for_encode_->planes[AOM_PLANE_U] =
    776          const_cast<unsigned char*>(nv12_buffer->DataUV());
    777      frame_for_encode_->planes[AOM_PLANE_V] = nullptr;
    778      frame_for_encode_->stride[AOM_PLANE_Y] = nv12_buffer->StrideY();
    779      frame_for_encode_->stride[AOM_PLANE_U] = nv12_buffer->StrideUV();
    780      frame_for_encode_->stride[AOM_PLANE_V] = 0;
    781      break;
    782    }
    783    default:
    784      return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
    785  }
    786 
    787  const uint32_t duration = kVideoPayloadTypeFrequency / framerate_fps_;
    788  timestamp_ += duration;
    789 
    790  const size_t num_spatial_layers =
    791      svc_params_ ? svc_params_->number_spatial_layers : 1;
    792  auto next_layer_frame = layer_frames.begin();
    793  std::vector<std::pair<EncodedImage, CodecSpecificInfo>> encoded_images;
    794  for (size_t i = 0; i < num_spatial_layers; ++i) {
    795    // The libaom AV1 encoder requires that `aom_codec_encode` is called for
    796    // every spatial layer, even if the configured bitrate for that layer is
    797    // zero. For zero bitrate spatial layers no frames will be produced.
    798    std::optional<ScalableVideoController::LayerFrameConfig>
    799        non_encoded_layer_frame;
    800    ScalableVideoController::LayerFrameConfig* layer_frame;
    801    if (next_layer_frame != layer_frames.end() &&
    802        next_layer_frame->SpatialId() == static_cast<int>(i)) {
    803      layer_frame = &*next_layer_frame;
    804      ++next_layer_frame;
    805    } else {
    806      // For layers that are not encoded only the spatial id matters.
    807      non_encoded_layer_frame.emplace().S(i);
    808      layer_frame = &*non_encoded_layer_frame;
    809    }
    810    const bool end_of_picture = (next_layer_frame == layer_frames.end());
    811 
    812    aom_enc_frame_flags_t flags =
    813        layer_frame->IsKeyframe() ? AOM_EFLAG_FORCE_KF : 0;
    814 #if defined(WEBRTC_ENCODER_PSNR_STATS) && defined(AOM_EFLAG_CALCULATE_PSNR)
    815    if (calculate_psnr_ && psnr_frame_sampler_.ShouldBeSampled(frame)) {
    816      flags |= AOM_EFLAG_CALCULATE_PSNR;
    817    }
    818 #endif
    819 
    820    if (SvcEnabled()) {
    821      SetSvcLayerId(*layer_frame);
    822      SetSvcRefFrameConfig(*layer_frame);
    823    }
    824 
    825    EncodeResult result = DoEncode(duration, flags, layer_frame);
    826    if (aom_codec_err_t* status = std::get_if<aom_codec_err_t>(&result);
    827        status != nullptr) {
    828      if (*status == AOM_CODEC_OK) {
    829        // AOM_CODEC_OK means success with no image, so do nothing.
    830        continue;
    831      } else {
    832        RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encode returned " << status
    833                            << " on aom_codec_encode.";
    834        return WEBRTC_VIDEO_CODEC_ERROR;
    835      }
    836    }
    837 
    838    if (non_encoded_layer_frame) {
    839      continue;
    840    }
    841 
    842    RTC_DCHECK(std::holds_alternative<EncodedImage>(result));
    843    EncodedImage encoded_image = std::get<EncodedImage>(std::move(result));
    844 
    845    RTC_DCHECK_GT(encoded_image.size(), 0u);
    846    PopulateEncodedImageFromVideoFrame(frame, encoded_image);
    847    CodecSpecificInfo codec_specifics =
    848        CreateCodecSpecificInfo(encoded_image, *layer_frame, end_of_picture);
    849 
    850    encoded_images.emplace_back(std::move(encoded_image),
    851                                std::move(codec_specifics));
    852  }
    853 
    854  if (!encoded_images.empty()) {
    855    encoded_images.back().second.end_of_picture = true;
    856  }
    857  for (auto& [encoded_image, codec_specifics] : encoded_images) {
    858    encoded_image_callback_->OnEncodedImage(encoded_image, &codec_specifics);
    859    if (encoded_image.SpatialIndex().has_value()) {
    860      last_encoded_timestamp_by_sid_[*encoded_image.SpatialIndex()] =
    861          frame.rtp_timestamp();
    862    }
    863  }
    864 
    865  return WEBRTC_VIDEO_CODEC_OK;
    866 }
    867 
    868 LibaomAv1Encoder::EncodeResult LibaomAv1Encoder::DoEncode(
    869    uint32_t duration,
    870    aom_enc_frame_flags_t flags,
    871    ScalableVideoController::LayerFrameConfig* layer_frame) {
    872  // Encode a frame. The presentation timestamp `pts` should not use real
    873  // timestamps from frames or the wall clock, as that can cause the rate
    874  // controller to misbehave.
    875  aom_codec_err_t ret =
    876      aom_codec_encode(&ctx_, frame_for_encode_, timestamp_, duration, flags);
    877  if (ret != AOM_CODEC_OK) {
    878    return ret;
    879  }
    880 
    881  // Get encoded image data.
    882  aom_codec_iter_t iter = nullptr;
    883  int data_pkt_count = 0;
    884  EncodedImage encoded_image;
    885  const aom_codec_cx_pkt_t* pkt = nullptr;
    886  while ((pkt = aom_codec_get_cx_data(&ctx_, &iter)) != nullptr) {
    887    if (pkt->kind == AOM_CODEC_CX_FRAME_PKT && pkt->data.frame.sz > 0) {
    888      if (data_pkt_count > 0) {
    889        RTC_LOG(LS_WARNING) << "LibaomAv1Encoder::Encoder returned more than "
    890                               "one data packet for an input video frame.";
    891        Release();
    892        return AOM_CODEC_ERROR;
    893      }
    894      encoded_image.SetEncodedData(EncodedImageBuffer::Create(
    895          /*data=*/static_cast<const uint8_t*>(pkt->data.frame.buf),
    896          /*size=*/pkt->data.frame.sz));
    897 
    898      if ((pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0) {
    899        layer_frame->Keyframe();
    900      }
    901 
    902      encoded_image._frameType = layer_frame->IsKeyframe()
    903                                     ? VideoFrameType::kVideoFrameKey
    904                                     : VideoFrameType::kVideoFrameDelta;
    905 
    906      encoded_image.content_type_ = VideoContentType::UNSPECIFIED;
    907      // If encoded image width/height info are added to aom_codec_cx_pkt_t,
    908      // use those values in lieu of the values in frame.
    909      if (svc_params_) {
    910        int n = scaling_factors_num_[layer_frame->SpatialId()];
    911        int d = scaling_factors_den_[layer_frame->SpatialId()];
    912        encoded_image._encodedWidth = encoder_settings_.width * n / d;
    913        encoded_image._encodedHeight = encoder_settings_.height * n / d;
    914        encoded_image.SetSpatialIndex(layer_frame->SpatialId());
    915        encoded_image.SetTemporalIndex(layer_frame->TemporalId());
    916      } else {
    917        encoded_image._encodedWidth = cfg_.g_w;
    918        encoded_image._encodedHeight = cfg_.g_h;
    919      }
    920      encoded_image.timing_.flags = VideoSendTiming::kInvalid;
    921 
    922      if (!SetEncoderControlParameters(AOME_GET_LAST_QUANTIZER,
    923                                       &encoded_image.qp_)) {
    924        RTC_LOG(LS_WARNING) << "Unable to fetch QP for frame.";
    925        return AOM_CODEC_ERROR;
    926      }
    927 
    928      ++data_pkt_count;
    929    } else if (pkt->kind == AOM_CODEC_PSNR_PKT) {
    930      // PSNR index: 0: total, 1: Y, 2: U, 3: V
    931      encoded_image.set_psnr(EncodedImage::Psnr({.y = pkt->data.psnr.psnr[1],
    932                                                 .u = pkt->data.psnr.psnr[2],
    933                                                 .v = pkt->data.psnr.psnr[3]}));
    934    }
    935  }
    936 
    937  if (encoded_image.size() == 0) {
    938    // Encode success, but no image produced.
    939    return AOM_CODEC_OK;
    940  }
    941 
    942  return encoded_image;
    943 }
    944 
    945 CodecSpecificInfo LibaomAv1Encoder::CreateCodecSpecificInfo(
    946    const EncodedImage& image,
    947    const ScalableVideoController::LayerFrameConfig& layer_frame,
    948    bool end_of_picture) {
    949  CodecSpecificInfo codec_specific_info;
    950  codec_specific_info.codecType = kVideoCodecAV1;
    951  codec_specific_info.end_of_picture = end_of_picture;
    952  codec_specific_info.scalability_mode = scalability_mode_;
    953  bool is_keyframe = layer_frame.IsKeyframe();
    954  codec_specific_info.generic_frame_info =
    955      svc_controller_->OnEncodeDone(layer_frame);
    956  if (is_keyframe && codec_specific_info.generic_frame_info) {
    957    codec_specific_info.template_structure =
    958        svc_controller_->DependencyStructure();
    959    auto& resolutions = codec_specific_info.template_structure->resolutions;
    960    if (SvcEnabled()) {
    961      resolutions.resize(svc_params_->number_spatial_layers);
    962      for (int sid = 0; sid < svc_params_->number_spatial_layers; ++sid) {
    963        int n = scaling_factors_num_[sid];
    964        int d = scaling_factors_den_[sid];
    965        resolutions[sid] = RenderResolution(encoder_settings_.width * n / d,
    966                                            encoder_settings_.height * n / d);
    967      }
    968    } else {
    969      resolutions = {RenderResolution(cfg_.g_w, cfg_.g_h)};
    970    }
    971  }
    972  return codec_specific_info;
    973 }
    974 
    975 void LibaomAv1Encoder::SetRates(const RateControlParameters& parameters) {
    976  if (!inited_) {
    977    RTC_LOG(LS_WARNING) << "SetRates() while encoder is not initialized";
    978    return;
    979  }
    980  if (parameters.framerate_fps < kMinFrameRateFps) {
    981    RTC_LOG(LS_WARNING) << "Unsupported framerate (must be >= "
    982                        << kMinFrameRateFps
    983                        << " ): " << parameters.framerate_fps;
    984    return;
    985  }
    986  if (parameters.bitrate.get_sum_bps() == 0) {
    987    RTC_LOG(LS_WARNING) << "Attempt to set target bit rate to zero";
    988    return;
    989  }
    990 
    991  // The bitrates caluclated internally in libaom when `AV1E_SET_SVC_PARAMS` is
    992  // called depends on the currently configured `rc_target_bitrate`. If the
    993  // total target bitrate is not updated first a division by zero could happen.
    994  svc_controller_->OnRatesUpdated(parameters.bitrate);
    995  cfg_.rc_target_bitrate = parameters.bitrate.get_sum_kbps();
    996 
    997  if (SvcEnabled()) {
    998    for (int sid = 0; sid < svc_params_->number_spatial_layers; ++sid) {
    999      // libaom bitrate for spatial id S and temporal id T means bitrate
   1000      // of frames with spatial_id=S and temporal_id<=T.
   1001      for (int tid = 0; tid < svc_params_->number_temporal_layers; ++tid) {
   1002        int layer_index = sid * svc_params_->number_temporal_layers + tid;
   1003        // `svc_params_->layer_target_bitrate` expects bitrate in kbps.
   1004        svc_params_->layer_target_bitrate[layer_index] =
   1005            parameters.bitrate.GetTemporalLayerSum(sid, tid) / 1000;
   1006      }
   1007    }
   1008    AdjustScalingFactorsForTopActiveLayer();
   1009    SetEncoderControlParameters(AV1E_SET_SVC_PARAMS, &*svc_params_);
   1010  }
   1011 
   1012  // AdjustScalingFactorsForTopActiveLayer() may update `cfg_`.
   1013  aom_codec_err_t error_code = aom_codec_enc_config_set(&ctx_, &cfg_);
   1014  if (error_code != AOM_CODEC_OK) {
   1015    RTC_LOG(LS_WARNING) << "Error configuring encoder, error code: "
   1016                        << error_code;
   1017  }
   1018 
   1019  framerate_fps_ = parameters.framerate_fps;
   1020 
   1021  rates_configured_ = true;
   1022 }
   1023 
   1024 VideoEncoder::EncoderInfo LibaomAv1Encoder::GetEncoderInfo() const {
   1025  EncoderInfo info;
   1026  info.supports_native_handle = false;
   1027  info.implementation_name = "libaom";
   1028  info.has_trusted_rate_controller = true;
   1029  info.is_hardware_accelerated = false;
   1030  info.scaling_settings =
   1031      (inited_ && !encoder_settings_.AV1().automatic_resize_on)
   1032          ? VideoEncoder::ScalingSettings::kOff
   1033          : VideoEncoder::ScalingSettings(kLowQindex, kHighQindex);
   1034  info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420,
   1035                                  VideoFrameBuffer::Type::kNV12};
   1036  if (inited_) {
   1037    info.mapped_resolution = VideoEncoder::Resolution(cfg_.g_w, cfg_.g_h);
   1038  }
   1039  if (SvcEnabled()) {
   1040    for (int sid = 0; sid < svc_params_->number_spatial_layers; ++sid) {
   1041      info.fps_allocation[sid].resize(svc_params_->number_temporal_layers);
   1042      for (int tid = 0; tid < svc_params_->number_temporal_layers; ++tid) {
   1043        info.fps_allocation[sid][tid] = EncoderInfo::kMaxFramerateFraction /
   1044                                        svc_params_->framerate_factor[tid];
   1045      }
   1046    }
   1047  }
   1048  if (!encoder_info_override_.resolution_bitrate_limits().empty()) {
   1049    info.resolution_bitrate_limits =
   1050        encoder_info_override_.resolution_bitrate_limits();
   1051  }
   1052 
   1053  info.min_qp = kMinQindex;
   1054  return info;
   1055 }
   1056 
   1057 }  // namespace
   1058 
   1059 absl_nonnull std::unique_ptr<VideoEncoder> CreateLibaomAv1Encoder(
   1060    const Environment& env,
   1061    LibaomAv1EncoderSettings settings) {
   1062  return std::make_unique<LibaomAv1Encoder>(env, std::move(settings));
   1063 }
   1064 
   1065 }  // namespace webrtc