910e62b5创建于 1月15日历史提交
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_GPU_H264_RATE_CONTROLLER_H_
#define MEDIA_GPU_H264_RATE_CONTROLLER_H_

#include <memory>
#include <vector>

#include "base/moving_window.h"
#include "media/gpu/frame_size_estimator.h"
#include "media/gpu/hrd_buffer.h"
#include "media/gpu/media_gpu_export.h"
#include "media/video/video_encode_accelerator.h"

namespace media {

struct MEDIA_GPU_EXPORT H264RateControllerLayerSettings {
  H264RateControllerLayerSettings() = default;
  ~H264RateControllerLayerSettings() = default;

  H264RateControllerLayerSettings(const H264RateControllerLayerSettings&) =
      default;
  H264RateControllerLayerSettings& operator=(
      const H264RateControllerLayerSettings&) = default;

  bool operator==(const H264RateControllerLayerSettings&) const = default;
  std::partial_ordering operator<=>(
      const H264RateControllerLayerSettings&) const = default;

  // Average bitrate of the layer in bits per second. The bitrate includes
  // the bits from all lower layers.
  uint32_t avg_bitrate = 0u;

  uint32_t peak_bitrate = 0u;

  // HRD buffer size in bytes.
  size_t hrd_buffer_size = 0u;

  // Minimum QP for the layer.
  uint32_t min_qp = 0;

  // Maximum QP for the layer.
  uint32_t max_qp = 0;

  // Layer frame rate.
  float frame_rate = 0.0f;
};

struct MEDIA_GPU_EXPORT H264RateControllerSettings {
  H264RateControllerSettings();
  ~H264RateControllerSettings();

  H264RateControllerSettings(const H264RateControllerSettings&);
  H264RateControllerSettings& operator=(const H264RateControllerSettings&);

  bool operator==(const H264RateControllerSettings& other) const = default;
  std::partial_ordering operator<=>(
      const H264RateControllerSettings& other) const;

  // Frame size.
  gfx::Size frame_size;

  // Fixed delta QP between layers.
  // When `fixed_delta_qp` is set and the video stream scalability mode is L1T2,
  // the QP of the higher layer is always increased by `fixed_delta_qp` compared
  // to the base layer. This parameter has no meaning in non scalable video
  // encoding.
  std::optional<int> fixed_delta_qp;

  // Maximum source frame rate.
  float frame_rate_max = 0.0f;

  // Number of temporal layers.
  size_t num_temporal_layers = 0u;

  // Maximum GOP duration. 0 for infinite.
  base::TimeDelta gop_max_duration;

  // Content type of the video source.
  VideoEncodeAccelerator::Config::ContentType content_type =
      VideoEncodeAccelerator::Config::ContentType::kCamera;

  bool ease_hrd_reduction = false;

  // Layer settings for each temporal layer.
  std::vector<H264RateControllerLayerSettings> layer_settings;
};

// H264RateController class implements a rate control algorithm for H.264 video
// encoder. The algorithm adjusts the QP for each frame, aiming to keep the
// video stream bitrate close to the target bitrate. The controller supports
// up to two temporal layers, each with its own HRD buffer. The HRD buffer
// stores the encoded frames from the current layer and all the lower layers
// that it depends on.
//
// The prediction of the QP parameter for intra encoded frames is based on the
// R-D model, using the expected size of the encoded frame as an input.
// For inter encoded frames, the QP is calculated based on the long-term and
// short-term statistics of the estimated QP and frame size, the prediction
// error of the frame size prediction for the previously encoded frames,
// and the HRD buffer fullness.
//
// The QP values used for encoding the inter predicted frames (P frames) are
// estimated from the statistics of the previous frames and the expected frame
// size. The estimation engine holds the short-term and long-term statistics for
// each temporal layer. The QP is further modified according to the HRD buffer
// fullness and the limits of the QP range. If rate controller is configured for
// the fixed delta QP between layers (Fixed Delta QP mode), the QP for the
// current layer is calculated by adding a constant value to the previous
// layer's QP.
class MEDIA_GPU_EXPORT H264RateController {
 public:
  enum class FrameSizeEstimatorType { kShortTerm, kLongTerm };

  enum class FrameType { kPFrame, kIFrame };

  class MEDIA_GPU_EXPORT Layer {
   public:
    Layer(H264RateControllerLayerSettings settings,
          float expected_fps,
          base::TimeDelta short_term_window_size,
          base::TimeDelta long_term_window_size);
    ~Layer();

    Layer(const Layer&) = delete;
    Layer& operator=(const Layer&) = delete;

    uint32_t curr_frame_qp() const { return curr_frame_qp_; }
    void update_curr_frame_qp(uint32_t qp) { curr_frame_qp_ = qp; }

    uint32_t last_frame_qp() const { return last_frame_qp_; }
    void update_last_frame_qp(uint32_t qp) { last_frame_qp_ = qp; }

    uint32_t long_term_qp() const { return long_term_qp_; }
    void update_long_term_qp(uint32_t qp) { long_term_qp_ = qp; }

    uint32_t min_qp() const { return min_qp_; }
    uint32_t max_qp() const { return max_qp_; }

    int undershoot_delta_qp() const { return undershoot_delta_qp_; }
    void update_undershoot_delta_qp(int qp) { undershoot_delta_qp_ = qp; }

    // Returns true if the HRD buffer for the temporal layer is full.
    bool is_buffer_full() const { return hrd_buffer_.frame_overshooting(); }

    // Returns the current HRD buffer size.
    size_t buffer_size() const { return hrd_buffer_.buffer_size(); }

    // Returns the current HRD buffer bitrate.
    uint32_t average_bitrate() const { return hrd_buffer_.average_bitrate(); }

    FrameType last_frame_type() const { return last_frame_type_; }
    void update_last_frame_type(FrameType frame_type) {
      last_frame_type_ = frame_type;
    }

    size_t last_frame_buffer_bytes() const {
      return hrd_buffer_.last_frame_buffer_bytes();
    }

    base::TimeDelta previous_frame_timestamp() const {
      return previous_frame_timestamp_;
    }
    void update_previous_frame_timestamp(base::TimeDelta timestamp) {
      previous_frame_timestamp_ = timestamp;
    }

    size_t pred_p_frame_size() const { return pred_p_frame_size_; }
    void update_pred_p_frame_size(size_t size) { pred_p_frame_size_ = size; }

    size_t last_frame_size_target_for_testing() const {
      return last_frame_size_target_;
    }
    void update_last_frame_size_target(size_t size) {
      last_frame_size_target_ = size;
    }

    // Shrinks HRD buffer according to the current frame timestamp.
    void ShrinkHRDBuffer(base::TimeDelta timestamp);

    // Adds the size of the encoded frame to the HRD buffer.
    void AddFrameBytes(size_t frame_bytes, base::TimeDelta frame_timestamp);

    // Adds the timestamp of the encoded frame to the frame rate estimator.
    void AddFrameTimestamp(base::TimeDelta frame_timestamp);

    // Reconfigures the HRD buffer with the new parameters.
    void SetBufferParameters(size_t buffer_size,
                             uint32_t avg_bitrate,
                             uint32_t peak_bitrate,
                             bool ease_hrd_reduction);

    // Returns the HRD buffer fullness at the specified time.
    size_t GetBufferBytesAtTime(base::TimeDelta timestamp) const;

    // Returns the remaining space in HRD buffer at the given time.
    size_t GetBufferBytesRemainingAtTime(base::TimeDelta timestamp) const;

    // Returns the mean frame rate.
    float GetFrameRateMean() const;

    // Estimates the expected frame size for the next P frame using the
    // short-term and long-term statistics from the preceding frames.
    size_t EstimateShortTermFrameSize(uint32_t qp, uint32_t qp_prev) const;
    size_t EstimateLongTermFrameSize(uint32_t qp, uint32_t qp_prev) const;

    // Estimates the expected QP for the next P frame using the short-term and
    // long-term statistics from the preceding frames.
    uint32_t EstimateShortTermQP(size_t target_frame_bytes,
                                 uint32_t qp_prev) const;
    uint32_t EstimateLongTermQP(size_t target_frame_bytes,
                                uint32_t qp_prev) const;

    // Returns the standard deviation of the estimated size error for the
    // previous frames. The filter window matches the size of the long-term
    // window.
    size_t GetFrameSizeEstimatorError() const;

    // Updates the estimators with the QP and actual encoded size of the current
    // frame.
    void UpdateFrameSizeEstimator(size_t frame_bytes,
                                  uint32_t qp,
                                  uint32_t qp_prev,
                                  base::TimeDelta elapsed_time);

   private:
    // Returns the initial size correction for the estimators.
    float GetInitialSizeCorrection(
        H264RateControllerLayerSettings settings) const;

    // HRD buffer for the layer.
    HRDBuffer hrd_buffer_;

    // Moving min-max filter for the source frame rate estimation.
    base::MovingMinMax<base::TimeDelta> src_frame_rate_;

    // Expected frame rate for the layer.
    float expected_fps_;

    // Current frame QP.
    uint32_t curr_frame_qp_ = 0;

    // Last frame QP.
    uint32_t last_frame_qp_ = 0;

    // Estimated average QP for future frames.
    uint32_t long_term_qp_ = 0;

    // Minimum and maximum QPs for the layer.
    uint32_t min_qp_ = 0;
    uint32_t max_qp_ = 0;

    // An undershoot in QP estimation below the minimum QP.
    int undershoot_delta_qp_ = 0;

    // Frame type of last non-dropped frame.
    FrameType last_frame_type_ = FrameType::kPFrame;

    // Timestamp of the previous frame.
    base::TimeDelta previous_frame_timestamp_ = base::Microseconds(-1);

    // Predicted frame size using current frame QP.
    size_t pred_p_frame_size_ = 0u;

    // Frame size estimators for short-term and long-term frame size prediction.
    FrameSizeEstimator short_term_estimator_;
    FrameSizeEstimator long_term_estimator_;

    // Predicted vs actual encoded frame size.
    ExponentialMovingAverage estimator_error_;

    // Target frame size for the next inter encoded frame. This value is stored
    // for the testing purposes.
    size_t last_frame_size_target_ = 0u;
  };

  explicit H264RateController(H264RateControllerSettings settings);
  ~H264RateController();

  H264RateController(const H264RateController& other) = delete;
  H264RateController& operator=(const H264RateController& other) = delete;

  // Returns a temporal layer referenced by the index.
  Layer& temporal_layers(size_t index) {
    CHECK_LT(index, temporal_layers_.size());
    return *temporal_layers_[index];
  }

  float target_fps_for_testing() const { return target_fps_; }

  // The rate controller restarts the estimation from the initial state.
  void reset_frame_number() { frame_number_ = -1; }

  // The method estimates the QP parameter for the next intra encoded frame
  // based on the current buffer fullness. It uses a rate-distortion model
  // that assumes the following:
  //
  // - q_step - Quantizer step size
  //   q_step = 5 / 8 * 2^(qp / 6)
  //
  // - mad is the Mean Absolute Difference of the residuals in intra frame
  //   prediction. Since this value cannot be retrieved from the Media
  //   Foundation system, it is approximated by a constant value calculated for
  //   the average frame content complexity.
  //
  // - bpp - Bits per pixel
  //   bpp = frame_size_in_bits / (frame_width * frame_height)
  //
  // We assume that the binary logarithm of the bits per pixel value is linearly
  // dependent on the binary logarithm of the ratio between MAD and Q step.
  //
  // log2(bpp) = a * log2(mad / q_step) + b
  //
  // When a = 2^b, bpp can expressed as
  //
  // bpp = a * (mad / q_step)^m, and q_step is
  //
  // q_step = mad / ( (bpp/a)^(1/m) )
  //
  // The QP for the frame encoding is obtained from the q_step using the
  // formula:
  //   qp = 6 * log2(q_step * 8 / 5)
  //
  // For the first intra encoded frame, the minimum value of the QP is limited
  // to 34.
  //
  // The QP is further modified using the following rules:
  //   1. When the HRD buffer is full, the QP for the current frame equals to
  //        curr_qp = last_base_layer_qp + 2
  //          - when curr_qp <= last_base_layer_qp + 2
  //        curr_qp = (curr_qp + last_base_layer_qp + 2) / 2
  //          - when curr_qp > last_base_layer_qp + 2
  //   2. When the previous frame is a P frame
  //        min_qp_offset_for_idr = -3
  //        max_qp_offset_for_idr = 16 - 2 / 3 * base_layer_frame_rate
  //        last_frame_qp = max(long_term_qp, last_base_layer_qp)
  //      The lower and upper limits for intra frame QP are:
  //        qp_min = last_frame_qp + min_qp_offset_for_idr
  //        qp_max = last_frame_qp + max_qp_offset_for_idr
  //   3. When the previous frame is an IDR frame
  //      The limiting values for the QP are:
  //        qp_min = last_base_layer_qp - 1
  //        qp_max = last_base_layer_qp + 3
  void EstimateIntraFrameQP(base::TimeDelta frame_timestamp);

  // Estimates Quantization Parameter for inter encoded frames. The estimation
  // procedure has the following steps:
  //
  // 1. Estimate long-term QP based on stats from the previous frames
  //   The long-term QP is derived from the target frame size, the QP from the
  //   previous frame, and the long-term QP stats. The target frame size
  //   represents available budget per frame, which depends on the average
  //   bitrate and the current framerate.
  //   After long-term QP estimation, the QP parameter is used to predict the
  //   size of the next encoded frame. If the frame size doesn't satisfy the
  //   bitrate requirements for the current layer, the method makes up to ten
  //   attempts to find the correct QP by increasing the QP value by one in
  //   each iteration.
  //
  // 2. Calculate QP in fixed delta QP mode for the enhanced layer
  //    When the fixed delta QP mode is enabled, the QP for the enhancement
  //    layer is a fixed difference to the base layer's QP. The QP value is
  //    obtained using the statistical model if buffer overrun is detected for
  //    the current layer.
  //
  // 3. Calculate the target frame size for the current frame
  //   To calculate the target frame size, we first obtain the following
  //   parameters:
  //     - frame_size_long_term - the estimated frame size based on long-term
  //     parameters and short-term stats;
  //     - frame_size_budget - the average budget in the HRD buffer for one
  //     frame.
  //
  //    These expression are used to calculate the initial target frame size:
  //
  //    frame_size_deviation = abs(frame_size_long_term - frame_size_budget) /
  //                           frame_size_budget
  //
  //    frame_size_compress - the value is derived from frame_size_deviation by
  //    applying clamped linear interpolation from range [0.5, 3] to range
  //    [0.1, 0.9].
  //
  //    frame_size_target = frame_size_budget + (1 - frame_size_compress) *
  //        (frame_size_long_term - frame_size_budget)
  //
  //    The target frame size is corrected to keep the buffer fullness within
  //    predefined limits. The remaining time to the end of the GOP affects the
  //    correction, so that a smaller frame size is estimated when the IDR
  //    frame is about to occur soon. We use these calculations to obtain the
  //    correction:
  //
  //    buffer_target_low = frame_size_budget
  //    buffer_target_high = 0.2 * buffer_size
  //
  //    size_correction_window - remaining time to the end of the GOP is
  //    transformed from the range [0, 2000] to the range [200, 800]
  //
  //    frame_duration = 1 / frame_rate
  //
  //    In overflow case
  //        overflow_size =
  //            frame_size_target + buffer_level_current - buffer_target_high
  //        size_correction =
  //            -overflow_size * frame_duration / size_correction_window
  //
  //    In underflow case
  //        underflow_size =
  //            buffer_target_low - (frame_size_target + buffer_level_current)
  //        size_correction =
  //            underflow_size * frame_duration / size_correction_window
  //
  //    frame_size_target += size_correction
  //
  //    In the final step, the instantaneous buffer undershoot and overshoot are
  //    prevented.
  //
  //    Undershoot prevention
  //    buf_level_pre_fill_next_frame is the buffer level just before the next
  //    frame is encoded.
  //    buf_level_pre_fill_next_frame =
  //        buffer_level_current + frame_size_target - frame_size_budget
  //    If the possibility for undershoot is detected, the frame size is
  //    frame_size_target +=
  //        frame_size_error - buf_level_pre_fill_next_frame
  //
  //    Overshoot prevention
  //    buf_level_post_fill is the buffer level right after adding the current
  //    frame to the buffer.
  //    buf_level_post_fill = buffer_level_current + frame_size_target
  //    If there is a possibility for overshoot, the frame size is
  //    frame_size_target -=
  //        buf_level_post_fill - buffer_size + frame_size_error
  //
  //    frame_size_error is obtained from the stats of the difference between
  //    the predicted and the actual frame size.
  //
  // 4. Calculate the current QP from the target frame size and the short-term
  //   stats
  //   The short-term frame size estimator component calculates the QP based on
  //   the target frame size and the QP value used for encoding of the previous
  //   frame.
  //
  // 5. Clip the current QP to fulfill the HRD buffer fullness requirements
  //   In the final step, the upper and lower bounds for the QP value are
  //   determined.
  //   The initial values for the QP limits are obtained through the following
  //   calculations:
  //   - base layer
  //     qp_min = last_base_layer_qp - 1 if FPS >= 3
  //     qp_min = last_base_layer_qp - 2 if FPS < 3
  //     qp_max = max(last_base_layer_qp + 3,
  //                  (base_layer_qp_min + base_layer_qp_max) / 2)
  //   - enhancement layers
  //     qp_min = last_base_layer_qp
  //     qp_max = last_base_layer_qp + 6
  //
  //   The min_qp is further adjusted to align with the HRD buffer fullness
  //   requirements when two temporal layers are encoded.
  //   If the rate controller is not in fixed delta QP mode and the enhancement
  //   layer's buffer exceeds 60% capacity, with a QP difference between the
  //   base and enhancement layers greater than 6, and an increment in the
  //   enhancement layer's QP is observed, the QP clipping process shifts to
  //   Limit Base QP mode. Here, the base layer's minimum QP value is adjusted
  //   based on the enhancement layer's buffer fullness, adhering to these
  //   rules:
  //   - buffer_fullness > 95% -> base_layer_min_qp = enhance_layer_qp - 2
  //   - buffer_fullness > 90% -> base_layer_min_qp = enhance_layer_qp - 3
  //   - buffer_fullness > 80% -> base_layer_min_qp = enhance_layer_qp - 4
  //   - buffer_fullness > 70% -> base_layer_min_qp = enhance_layer_qp - 5
  //   - otherwise             -> base_layer_min_qp = enhance_layer_qp - 6
  //   The QP clipping reverts to normal mode once the enhancement layer's
  //   buffer fullness drops below 35% and a QP decrease is detected in the
  //   enhancement layer.
  //   In fixed delta QP mode, when the QP difference between the enhancement
  //   and the base layer exceeds 4, the the min_qp for the base layer is
  //   computed with the following expression:
  //     qp_min = last_enhance_layer_qp - 4.
  //   A QP difference greater than 4 indicates that the frame's QP in the
  //   enhancement layer has been elevated beyond the upper limit due to HRD
  //   buffer overflow.
  //
  //   If an HRD buffer overflow is detected in the current layer, the min_qp is
  //   set to the last QP value used for that layer incremented by 2.
  //
  //   The minimum value of max_qp is limited to 28.
  //
  //   When an HRD buffer overflow occurs, the frame's timestamp is captured in
  //   the `last_ts_overshooting_frame_` variable. For each 33 milliseconds that
  //   pass following this timestamp, both the min_qp and max_qp are increased
  //   by 1.
  void EstimateInterFrameQP(size_t temporal_id,
                            base::TimeDelta frame_timestamp);

  // The method executes the following operations:
  // - appends the lengths of the encoded bytes to the HRD buffers,
  // - updates the layer data,
  // - adjusts the target frames per second following the encoding of the first
  //   frame.
  void FinishIntraFrame(size_t access_unit_bytes,
                        base::TimeDelta frame_timestamp);

  // The method passes through the following steps:
  // - updates the HRD buffers, the short-term and long-term frame size
  //   estimators, with the size of the encoded frame,
  // - calculates the frame size estimation error and adds it to the error
  //   stats,
  // - updates additional layer data.
  void FinishInterFrame(size_t temporal_id,
                        size_t access_unit_bytes,
                        base::TimeDelta frame_timestamp);

  // Updates the frame size. The frame size is used in QP estimation for intra
  // encoded frames.
  void UpdateFrameSize(const gfx::Size& frame_size);

  // The array passed as a parameter stores the HRD buffer fullness for each
  // temporal layer as a percentage of the HRD buffer size.
  void GetHRDBufferFullness(base::span<int> buffer_fullness,
                            base::TimeDelta picture_timestamp) const;

 private:
  // The HRD buffers are updated with the encoded frame size. Last frame QP and
  // last frame type for the current layer are updated. The method updates all
  // HRD buffers for the layers that depend on the current layer.
  void FinishLayerData(size_t temporal_id,
                       FrameType frame_type,
                       size_t frame_bytes,
                       base::TimeDelta frame_timestamp);

  // Updates the timestamp of the previous frame for the current layer.
  void FinishLayerPreviousFrameTimestamp(size_t temporal_id,
                                         base::TimeDelta frame_timestamp);

  // Captures the timestamp of the frame if HRD buffer overflow occurred.
  void SetLastTsOvershootingFrame(size_t temporal_id,
                                  base::TimeDelta frame_timestamp);

  // The method calculates the target bytes for the intra encoded frame, which
  // are used to estimate the QP value. The target bytes depend on the remaining
  // HRD buffer size and the available budget per frame.
  size_t GetTargetBytesForIntraFrame(base::TimeDelta frame_timestamp) const;

  // Returns the target bytes for the next inter encoded frame. The target bytes
  // depend on the fullness of the HRD buffer, the average bitrate for the
  // layer, and the remaining time to the end of the GOP.
  size_t GetTargetBytesForInterFrame(size_t temporal_id,
                                     uint32_t max_rate_bytes_per_sec,
                                     size_t buffer_size,
                                     int buffer_level_current,
                                     base::TimeDelta frame_timestamp) const;

  // Estimates the QP for the current frame based on the target frame size.
  uint32_t GetInterFrameShortTermQP(size_t temporal_id,
                                    size_t frame_size_target);

  // The method estimates the QP for the current frame based on the target frame
  // size and the long-term QP. The QP is clipped to fulfill the HRD buffer
  // fullness requirements.
  uint32_t GetInterFrameLongTermQP(size_t temporal_id);

  // Applying the constraints to the final QP value based on the HRD buffer
  // fullness.
  uint32_t ClipInterFrameQP(uint32_t curr_qp,
                            size_t temporal_id,
                            base::TimeDelta picture_timestamp);

  // Returns target FPS extracted from layer settings.
  float GetTargetFps(H264RateControllerSettings settings) const;

  // Temporal layers configured for the current video stream.
  std::vector<std::unique_ptr<Layer>> temporal_layers_;

  // FPS that the rate controller recommends.
  float target_fps_;

  // Maximum source frame rate.
  const float frame_rate_max_;

  // Frame size of the video stream.
  gfx::Size frame_size_;

  // QP delta value in Fixed Delta QP mode. It's not defined in non Fixed Delta
  // QP mode.
  const std::optional<int> fixed_delta_qp_;

  // Indicates base QP should be raised due to upper layer HRD constraints.
  bool limit_base_qp_ = false;

  // Number of temporal layers.
  const size_t num_temporal_layers_;

  // Maximum duration of the Group of Pictures.
  const base::TimeDelta gop_max_duration_;

  // Video content type: camera or display.
  const VideoEncodeAccelerator::Config::ContentType content_type_;

  // Timestamp of the latest IDR frame.
  base::TimeDelta last_idr_timestamp_;

  // Timestamp of the latest frame which overshoots buffer.
  base::TimeDelta last_ts_overshooting_frame_ = base::TimeDelta::Max();

  // Current frame number. The initial value is -1. It is incremented by 1 with
  // every call to QP estimation method for the video frames.
  int frame_number_ = -1;
};

}  // namespace media

#endif  // MEDIA_GPU_H264_RATE_CONTROLLER_H_