1 /*
2 * Copyright(c) 2019 Netflix, Inc.
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at https://www.aomedia.org/license/software-license. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at https://www.aomedia.org/license/patent-license.
10 */
11
12 /******************************************************************************
13 * @file SvtAv1E2EParamsTest.cc
14 *
15 * @brief Implementation of encoder parameter coverage test in E2E test
16 *
17 * @author Cidana-Edmond
18 *
19 ******************************************************************************/
20
21 #include <map>
22 #include <cmath>
23 #include "gtest/gtest.h"
24 #include "SvtAv1E2EFramework.h"
25 #include "../api_test/params.h"
26 #include "RefDecoder.h"
27
28 /**
29 * @brief SVT-AV1 encoder parameter coverage E2E test
30 *
31 * Test strategy:
32 * Config SVT-AV1 encoder with individual parameter, run the
33 * conformance test and analyze the Bitstream to check if the params
34 * take effect.
35 *
36 * Expected result:
37 * No error is reported in encoding progress. The reconstructed frame
38 * data is same as the output frame from reference decoder.
39 *
40 * Test coverage:
41 * Almost all the encoder parameters except frame_rate_numerator and
42 * frame_rate_denominator.
43 */
44
45 using namespace svt_av1_e2e_test;
46 using namespace svt_av1_e2e_test_vector;
47 using std::map;
48 using std::stoul;
49 using std::string;
50 using std::to_string;
51
52 /** copied from EbRateControlProcess.c */
53 static const uint8_t quantizer_to_qindex[] = {
54 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48,
55 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100,
56 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152,
57 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204,
58 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 249, 255,
59 };
60
61 /** get qp value with the given qindex */
get_qp(const int16_t qindex)62 static uint32_t get_qp(const int16_t qindex) {
63 if (qindex > 255) {
64 printf("qindex is larger than 255!\n");
65 return 63;
66 }
67
68 uint32_t qp = 0;
69 for (const uint8_t index : quantizer_to_qindex) {
70 if (index == qindex)
71 return qp;
72 else if (index > qindex) {
73 if ((index - qindex) > (qindex - quantizer_to_qindex[qp - 1]))
74 return qp - 1;
75 break;
76 }
77 qp++;
78 }
79 return qp;
80 }
81
82 /* clang-format off */
83 static const std::vector<EncTestSetting> default_enc_settings = {
84 // test intra period length
85 {"IntraPeriodTest1", {{"IntraPeriod", "3"}}, default_test_vectors},
86
87 // test different qp
88 {"QpTest1",
89 {{"RateControlMode", "0"}, {"QP", "20"}}, default_test_vectors},
90 {"QpTest2",
91 {{"RateControlMode", "0"}, {"QP", "32"}}, default_test_vectors},
92 {"QpTest3",
93 {{"RateControlMode", "0"}, {"QP", "44"}}, default_test_vectors},
94
95 // test rc mode {2, 3}, with {1Mbps, 0.75Mbps, 0.5Mbps} setting with
96 // 480p
97 {"RcTest1",
98 {{"RateControlMode", "2"}, {"TargetBitRate", "1000000"}},
99 default_test_vectors},
100 {"RcTest2",
101 {{"RateControlMode", "2"}, {"TargetBitRate", "750000"}},
102 res_480p_test_vectors},
103 {"RcTest3",
104 {{"RateControlMode", "2"}, {"TargetBitRate", "500000"}},
105 res_480p_test_vectors},
106 {"RcTest4",
107 {{"RateControlMode", "1"}, {"TargetBitRate", "1000000"}},
108 res_480p_test_vectors},
109 {"RcTest5",
110 {{"RateControlMode", "1"}, {"TargetBitRate", "750000"}},
111 res_480p_test_vectors},
112 {"RcTest6",
113 {{"RateControlMode", "1"}, {"TargetBitRate", "500000"}},
114 res_480p_test_vectors},
115
116 // test high bitrate with big min_qp, or low bitrate with small max_qp
117 {"RcQpTest1",
118 {{"RateControlMode", "2"}, {"TargetBitRate", "1000000"}, {"MinQpAllowed", "20"}},
119 res_480p_test_vectors},
120 {"RcQpTest2",
121 {{"RateControlMode", "2"}, {"TargetBitRate", "500000"}, {"MaxQpAllowed", "50"}},
122 res_480p_test_vectors},
123 {"RcQpTest3",
124 {{"RateControlMode", "2"}, {"TargetBitRate", "750000"}, {"MaxQpAllowed", "50"}, {"MinQpAllowed", "20"}},
125 res_480p_test_vectors},
126 {"RcQpTest4",
127 {{"RateControlMode", "1"}, {"TargetBitRate", "1000000"}, {"MinQpAllowed", "20"}},
128 res_480p_test_vectors},
129 {"RcQpTest5",
130 {{"RateControlMode", "1"}, {"TargetBitRate", "500000"}, {"MaxQpAllowed", "50"}},
131 res_480p_test_vectors},
132 {"RcQpTest6",
133 {{"RateControlMode", "1"}, {"TargetBitRate", "750000"}, {"MaxQpAllowed", "50"}, {"MinQpAllowed", "20"}},
134 res_480p_test_vectors},
135 };
136 /* clang-format on */
137
138 class CodingOptionTest : public SvtAv1E2ETestFramework {
139 public:
config_test()140 void config_test() override {
141 enable_recon = true;
142 enable_decoder = true;
143 enable_analyzer = true;
144 enable_config = true;
145 SvtAv1E2ETestFramework::config_test();
146 }
147
post_process()148 void post_process() override {
149 if (refer_dec_) {
150 RefDecoder::StreamInfo *stream_info = refer_dec_->get_stream_info();
151 validate_enc_setting(stream_info);
152 }
153 }
154
155 protected:
validate_enc_setting(RefDecoder::StreamInfo * stream_info)156 void validate_enc_setting(RefDecoder::StreamInfo *stream_info) {
157 EbSvtAv1EncConfiguration *config = &av1enc_ctx_.enc_params;
158
159 // check profile, level and tier
160 EXPECT_EQ(config->profile, stream_info->profile)
161 << "config profile: " << config->profile << "got "
162 << stream_info->profile;
163
164 // verify the superblock size
165 EXPECT_EQ(config->super_block_size, stream_info->sb_size)
166 << "config sb size: " << config->super_block_size << " got "
167 << stream_info->sb_size;
168
169 // Verify bit depth
170 EXPECT_EQ(config->encoder_bit_depth, stream_info->bit_depth)
171 << "config bitdepth: " << config->encoder_bit_depth << " got "
172 << stream_info->bit_depth;
173
174 // verify the color format
175 EXPECT_EQ(config->encoder_color_format,
176 setup_video_format(stream_info->format))
177 << "color format is mismatch";
178
179 if (config->intra_period_length > 0) {
180 EXPECT_EQ(config->intra_period_length,
181 stream_info->max_intra_period)
182 << "config intra period " << config->intra_period_length
183 << " got " << stream_info->max_intra_period;
184 }
185
186 // verify QP Setting
187 uint32_t actual_min_qp = get_qp(stream_info->min_qindex);
188 uint32_t actual_max_qp = get_qp(stream_info->max_qindex);
189 EXPECT_LE(config->min_qp_allowed, actual_min_qp)
190 << "Min qp allowd " << config->min_qp_allowed << " actual "
191 << actual_min_qp;
192 EXPECT_GE(config->max_qp_allowed, actual_max_qp)
193 << "Max qp allowd " << config->max_qp_allowed << " actual "
194 << actual_max_qp;
195 if (config->rate_control_mode == 0) {
196 EXPECT_EQ(actual_min_qp, actual_max_qp)
197 << "QP fluctuate in const qp mode";
198 }
199
200 // verify the bitrate
201 if (config->rate_control_mode == 3) {
202 uint32_t avg_bit_rate =
203 (config->frame_rate > 1000 ? config->frame_rate >> 16
204 : config->frame_rate) *
205 stream_info->frame_bit_rate;
206 printf("%d--%d\n", config->target_bit_rate, avg_bit_rate);
207 EXPECT_GE(config->target_bit_rate, avg_bit_rate)
208 << "target bit-rate is less than actual: "
209 << config->target_bit_rate << "--" << avg_bit_rate;
210 }
211
212 // verify tile row and tile column
213 uint32_t expect_cols =
214 (uint32_t)((video_src_->get_width_with_padding() >> 2) /
215 (1 << config->tile_columns));
216 uint32_t expect_rows =
217 (uint32_t)((video_src_->get_height_with_padding() >> 2) /
218 (1 << config->tile_rows));
219 printf("expect_cols %d, expect_rows %d\n", expect_cols, expect_rows);
220 printf("tile_cols %d, tile_rows %d\n",
221 stream_info->tile_cols,
222 stream_info->tile_rows);
223 EXPECT_EQ(expect_cols, stream_info->tile_cols)
224 << "Tile columns " << stream_info->tile_cols << " actual"
225 << expect_cols;
226 EXPECT_EQ(expect_rows, stream_info->tile_rows)
227 << "Tile rows " << stream_info->tile_rows << " actual"
228 << expect_rows;
229
230 //
231 // Verify the coding tools by checking the sps header
232 //
233 EXPECT_EQ(stream_info->enable_warped_motion,
234 config->enable_warped_motion);
235 }
236
is_valid_profile_setting()237 bool is_valid_profile_setting() {
238 /** check the color format according to spec 6.4.1 */
239 if (av1enc_ctx_.enc_params.profile == 0) {
240 /** main profile requires YUV420 or YUV400 Annex A */
241 if (av1enc_ctx_.enc_params.encoder_bit_depth == 12)
242 return false;
243 if (av1enc_ctx_.enc_params.encoder_color_format != EB_YUV420 &&
244 av1enc_ctx_.enc_params.encoder_color_format != EB_YUV400) {
245 return false;
246 }
247 } else if (av1enc_ctx_.enc_params.profile == 1) {
248 /** high profile requires 8bit/10bit YUV444 */
249 if (av1enc_ctx_.enc_params.encoder_bit_depth == 12)
250 return false;
251 if (av1enc_ctx_.enc_params.encoder_color_format != EB_YUV444)
252 return false;
253 } else if (av1enc_ctx_.enc_params.profile == 2) {
254 /** professional profile requires 8-bit/10-bit YUV422 or 12-bit
255 * YUV400, YUV420, YUV422 and YUV444
256 */
257 if (av1enc_ctx_.enc_params.encoder_bit_depth != 12 &&
258 av1enc_ctx_.enc_params.encoder_color_format != EB_YUV422) {
259 return false;
260 }
261 }
262 return true;
263 }
264 };
265
TEST_P(CodingOptionTest,CheckEncOptionsUsingBitstream)266 TEST_P(CodingOptionTest, CheckEncOptionsUsingBitstream) {
267 run_death_test();
268 }
269
270 INSTANTIATE_TEST_CASE_P(SvtAv1, CodingOptionTest,
271 ::testing::ValuesIn(default_enc_settings),
272 EncTestSetting::GetSettingName);
273