blob: 7b2bffcf96dab6d8835fa7c59f8d53bd3fb716b1 [file] [log] [blame] [edit]
// 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