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