1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198

media / gpu / h264_ratectrl_rtc_unittest.cc [blame]

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

#include "media/gpu/h264_ratectrl_rtc.h"

#include "testing/gtest/include/gtest/gtest.h"

namespace media {
namespace {
constexpr uint32_t kCommonAvgBitrate = 1000000;   // bits per second
constexpr uint32_t kCommonPeakBitrate = 2000000;  // bits per second
constexpr int kCommonFps = 30;
constexpr int kCommonFpsMax = 30;
constexpr uint32_t kCommonFrameHeight = 600;
constexpr uint32_t kCommonFrameWidth = 800;
constexpr size_t kCommonHRDBufferSize = 40000;  // bytes
constexpr base::TimeDelta kCommonGopMaxDuration = base::Seconds(4);
constexpr uint32_t kCommonQpMax = 51u;
constexpr uint32_t kCommonQpMin = 1u;
constexpr size_t kLayer0Index = 0;
constexpr size_t kLayer1Index = 1;

// Test H264RateCtrlRTCTest runs test cases for the class H264RateCtrlRTC.
class H264RateCtrlRTCTest : public testing::Test {
 public:
  H264RateCtrlRTCTest() = default;

  void SetUp() override {
    constexpr int kExpectedLoopFilterLevel = -1;

    rate_control_config_rtc_.content_type =
        VideoEncodeAccelerator::Config::ContentType::kCamera;
    rate_control_config_rtc_.frame_size.SetSize(kCommonFrameWidth,
                                                kCommonFrameHeight);
    rate_control_config_rtc_.fixed_delta_qp = 0;
    rate_control_config_rtc_.ease_hrd_reduction = true;
    rate_control_config_rtc_.num_temporal_layers = 2;
    rate_control_config_rtc_.gop_max_duration = kCommonGopMaxDuration;
    rate_control_config_rtc_.frame_rate_max = kCommonFpsMax;
    rate_control_config_rtc_.layer_settings.emplace_back();
    rate_control_config_rtc_.layer_settings[0].avg_bitrate =
        kCommonAvgBitrate * 2 / 3;
    rate_control_config_rtc_.layer_settings[0].peak_bitrate =
        kCommonPeakBitrate * 2 / 3;
    rate_control_config_rtc_.layer_settings[0].hrd_buffer_size =
        kCommonHRDBufferSize * 2 / 3;
    rate_control_config_rtc_.layer_settings[0].min_qp = kCommonQpMin;
    rate_control_config_rtc_.layer_settings[0].max_qp = kCommonQpMax;
    rate_control_config_rtc_.layer_settings[0].frame_rate = kCommonFps / 2;
    rate_control_config_rtc_.layer_settings.emplace_back();
    rate_control_config_rtc_.layer_settings[1].avg_bitrate = kCommonAvgBitrate;
    rate_control_config_rtc_.layer_settings[1].peak_bitrate =
        kCommonPeakBitrate;
    rate_control_config_rtc_.layer_settings[1].hrd_buffer_size =
        kCommonHRDBufferSize;
    rate_control_config_rtc_.layer_settings[1].min_qp = kCommonQpMin;
    rate_control_config_rtc_.layer_settings[1].max_qp = kCommonQpMax;
    rate_control_config_rtc_.layer_settings[1].frame_rate = kCommonFps;

    rate_ctrl_rtc_ = H264RateCtrlRTC::Create(rate_control_config_rtc_);

    auto rate_control_config_rtc = rate_control_config_rtc_;
    rate_control_config_rtc.layer_settings[1].max_qp = kCommonQpMax + 1;

    EXPECT_FALSE((rate_control_config_rtc == rate_control_config_rtc_));
    EXPECT_TRUE((rate_control_config_rtc <=> rate_control_config_rtc_ ==
                 std::partial_ordering::greater));

    EXPECT_EQ(kExpectedLoopFilterLevel, rate_ctrl_rtc_->GetLoopfilterLevel());
  }

 protected:
  int RunTestSequence(int fps,
                      int start_frame_index,
                      int& last_intra_frame_qp,
                      int& last_inter_frame_qp,
                      int& drop_frames) {
    constexpr size_t kFirstIntraFrameIndex = 0;
    std::vector<size_t> frames{12500, 3000, 4000, 3000, 4000,  3000,
                               8000,  6000, 8000, 6000, 10000, 8000,
                               10000, 8000, 8000, 0};

    base::TimeDelta timestamp = base::Microseconds(
        start_frame_index * base::Time::kMicrosecondsPerSecond / fps);
    size_t layer_index = 0;
    size_t frame_index = 0;
    for (size_t encoded_size : frames) {
      bool keyframe = false;
      if (frame_index == kFirstIntraFrameIndex) {
        keyframe = true;
      }
      if (keyframe || layer_index == 1) {
        layer_index = 0;
      } else {
        layer_index = 1;
      }

      H264FrameParamsRTC frame_params;
      frame_params.keyframe = keyframe;
      frame_params.temporal_layer_id = layer_index;
      frame_params.timestamp = timestamp;

      H264RateCtrlRTC::FrameDropDecision frame_drop_decision =
          rate_ctrl_rtc_->ComputeQP(frame_params);
      if (keyframe) {
        EXPECT_EQ(H264RateCtrlRTC::FrameDropDecision::kOk, frame_drop_decision);
        last_intra_frame_qp = rate_ctrl_rtc_->GetQP();
      } else {
        last_inter_frame_qp = rate_ctrl_rtc_->GetQP();
        if (frame_drop_decision == H264RateCtrlRTC::FrameDropDecision::kDrop) {
          drop_frames++;
        }
      }
      rate_ctrl_rtc_->PostEncodeUpdate(encoded_size, frame_params);

      ++frame_index;
      timestamp += base::Microseconds(base::Time::kMicrosecondsPerSecond / fps);
    }

    return start_frame_index + frames.size();
  }

  std::unique_ptr<H264RateCtrlRTC> rate_ctrl_rtc_;
  H264RateControlConfigRTC rate_control_config_rtc_;
};

// Test Cases

// The test case runs a test sequence and validates QP and buffer fullness
// values. During the test, an HRD buffer overflow and frame drop condition are
// triggered. The test verifies the controller configuration update procedure.
TEST_F(H264RateCtrlRTCTest, RunBasicRateCtrlRTCTest) {
  constexpr int kExpectedBufferFullness01 = 0;
  constexpr int kExpectedBufferFullness11 = 0;
  constexpr int kExpectedIntraFrameQP2 = 34;
  constexpr int kExpectedInterFrameQP2 = 49;
  constexpr int kExpectedBufferFullness02 = 75;
  constexpr int kExpectedBufferFullness12 = 87;
  constexpr int kExpectedIntraFrameQP3 = 39;
  constexpr int kExpectedInterFrameQP3 = -1;
  constexpr int kExpectedBufferFullness03 = 56;
  constexpr int kExpectedBufferFullness13 = 111;
  constexpr int kExpectedDropFrames = 4;

  std::array<int, 2> buffer_fullness_array = {0, 0};
  base::span<int> buffer_fullness_values(buffer_fullness_array);

  rate_ctrl_rtc_->GetBufferFullness(buffer_fullness_values, base::TimeDelta());
  EXPECT_EQ(kExpectedBufferFullness01, buffer_fullness_values[kLayer0Index]);
  EXPECT_EQ(kExpectedBufferFullness11, buffer_fullness_values[kLayer1Index]);

  int start_frame_index = 0;
  int last_intra_frame_qp;
  int last_inter_frame_qp;
  int drop_frames = 0;
  int last_frame_index =
      RunTestSequence(kCommonFps, start_frame_index, last_intra_frame_qp,
                      last_inter_frame_qp, drop_frames);
  base::TimeDelta timestamp = base::Microseconds(
      last_frame_index * base::Time::kMicrosecondsPerSecond / kCommonFps);

  EXPECT_EQ(kExpectedIntraFrameQP2, last_intra_frame_qp);
  EXPECT_EQ(kExpectedInterFrameQP2, last_inter_frame_qp);

  rate_ctrl_rtc_->GetBufferFullness(buffer_fullness_values, timestamp);
  EXPECT_EQ(kExpectedBufferFullness02, buffer_fullness_values[kLayer0Index]);
  EXPECT_EQ(kExpectedBufferFullness12, buffer_fullness_values[kLayer1Index]);
  EXPECT_EQ(0, drop_frames);

  rate_control_config_rtc_.layer_settings[0].avg_bitrate = kCommonAvgBitrate;
  rate_control_config_rtc_.layer_settings[0].peak_bitrate = kCommonPeakBitrate;
  rate_control_config_rtc_.layer_settings[1].avg_bitrate =
      kCommonAvgBitrate * 4 / 3;
  rate_control_config_rtc_.layer_settings[1].peak_bitrate =
      kCommonPeakBitrate * 4 / 3;

  rate_ctrl_rtc_->UpdateRateControl(rate_control_config_rtc_);

  start_frame_index = last_frame_index;
  last_frame_index =
      RunTestSequence(kCommonFps, start_frame_index, last_intra_frame_qp,
                      last_inter_frame_qp, drop_frames);
  timestamp = base::Microseconds(
      last_frame_index * base::Time::kMicrosecondsPerSecond / kCommonFps);

  EXPECT_EQ(kExpectedIntraFrameQP3, last_intra_frame_qp);
  EXPECT_EQ(kExpectedInterFrameQP3, last_inter_frame_qp);

  rate_ctrl_rtc_->GetBufferFullness(buffer_fullness_values, timestamp);
  EXPECT_EQ(kExpectedBufferFullness03, buffer_fullness_values[kLayer0Index]);
  EXPECT_EQ(kExpectedBufferFullness13, buffer_fullness_values[kLayer1Index]);
  EXPECT_EQ(kExpectedDropFrames, drop_frames);
}

}  // namespace

}  // namespace media