chromium/media/gpu/windows/vp9_video_rate_control_wrapper.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "vp9_video_rate_control_wrapper.h"

#include "third_party/libvpx/source/libvpx/vp9/ratectrl_rtc.h"

namespace {

// The return value is expressed as a percentage of the average. For example,
// to allocate no more than 4.5 frames worth of bitrate to a keyframe, the
// return value is 450.
uint32_t MaxSizeOfKeyframeAsPercentage(uint32_t optimal_buffer_size,
                                       uint32_t max_framerate) {
  // Set max to the optimal buffer level (normalized by target BR),
  // and scaled by a scale_par.
  // Max target size = scale_par * optimal_buffer_size * targetBR[Kbps].
  // This value is presented in percentage of perFrameBw:
  // perFrameBw = targetBR[Kbps] * 1000 / framerate.
  // The target in % is as follows:
  const double target_size_byte_per_frame = optimal_buffer_size * 0.5;
  const uint32_t target_size_kbyte =
      target_size_byte_per_frame * max_framerate / 1000;
  const uint32_t target_size_kbyte_as_percent = target_size_kbyte * 100;

  // Don't go below 3 times the per frame bandwidth.
  constexpr uint32_t kMinIntraSizePercentage = 300u;
  return kMinIntraSizePercentage > target_size_kbyte_as_percent
             ? kMinIntraSizePercentage
             : target_size_kbyte_as_percent;
}

}  // namespace

namespace media {

template <>
int VP9RateControl::GetLoopfilterLevel() const {
  DCHECK(impl_);
  return impl_->GetLoopfilterLevel();
}

template <>
void VP9RateControl::PostEncodeUpdate(uint64_t encoded_frame_size,
                                      const FrameParams& frame_params) {
  DCHECK(impl_);
  return impl_->PostEncodeUpdate(encoded_frame_size,
                                 ConvertFrameParams(frame_params));
}

template <>
libvpx::VP9RateControlRtcConfig VP9RateControl::ConvertControlConfig(
    const RateControlConfig& config) {
  libvpx::VP9RateControlRtcConfig rc_config;
  rc_config.width = config.width;
  rc_config.height = config.height;
  rc_config.target_bandwidth = config.target_bandwidth;
  rc_config.framerate = config.framerate;
  rc_config.max_quantizer = config.max_quantizer;
  rc_config.min_quantizer = config.min_quantizer;
  // These default values come from
  // //third_party/webrtc/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc.
  rc_config.buf_initial_sz = 500;
  rc_config.buf_optimal_sz = 600;
  rc_config.buf_sz = 1000;
  rc_config.undershoot_pct = 50;
  rc_config.overshoot_pct = 50;
  rc_config.aq_mode = 0;
  rc_config.rc_mode = VPX_CBR;
  rc_config.max_intra_bitrate_pct = MaxSizeOfKeyframeAsPercentage(
      rc_config.buf_optimal_sz, rc_config.framerate);
  rc_config.max_inter_bitrate_pct = 0;
  rc_config.ss_number_layers = config.ss_number_layers;
  rc_config.ts_number_layers = config.ts_number_layers;
  for (int tid = 0; tid < config.ts_number_layers; ++tid) {
    rc_config.ts_rate_decimator[tid] = config.ts_rate_decimator[tid];
  }
  for (int sid = 0; sid < config.ss_number_layers; ++sid) {
    rc_config.scaling_factor_num[sid] = config.scaling_factor_num[sid];
    rc_config.scaling_factor_den[sid] = config.scaling_factor_den[sid];
    for (int tid = 0; tid < config.ts_number_layers; ++tid) {
      const int i = sid * config.ts_number_layers + tid;
      rc_config.max_quantizers[i] = config.max_quantizers[i];
      rc_config.min_quantizers[i] = config.min_quantizers[i];
      rc_config.layer_target_bitrate[i] = config.layer_target_bitrate[i];
    }
  }
  return rc_config;
}

template <>
libvpx::VP9FrameParamsQpRTC VP9RateControl::ConvertFrameParams(
    const FrameParams& frame_params) {
  libvpx::VP9FrameParamsQpRTC rc_params;
  rc_params.spatial_layer_id = frame_params.spatial_layer_id;
  rc_params.temporal_layer_id = frame_params.temporal_layer_id;
  rc_params.frame_type =
      frame_params.frame_type == FrameParams::FrameType::kKeyFrame
          ? libvpx::RcFrameType::kKeyFrame
          : libvpx::RcFrameType::kInterFrame;
  return rc_params;
}

}  // namespace media