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