1 /*
2 * Copyright (c) 2023, Alliance for Open Media. All rights reserved.
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 www.aomedia.org/license/software. 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 www.aomedia.org/license/patent.
10 */
11
12 #include <cstddef>
13 #include <vector>
14
15 #include "aom/aomcx.h"
16 #include "aom/aom_codec.h"
17 #include "aom/aom_encoder.h"
18 #include "aom/aom_image.h"
19 #include "gtest/gtest.h"
20
21 namespace {
22
23 // This test emulates how libavif calls libaom functions to encode a
24 // progressive AVIF image in libavif's ProgressiveTest.QualityChange test.
TEST(AVIFProgressiveTest,QualityChange)25 TEST(AVIFProgressiveTest, QualityChange) {
26 constexpr int kWidth = 256;
27 constexpr int kHeight = 256;
28 // A buffer of neutral gray samples.
29 constexpr size_t kBufferSize = 3 * kWidth * kHeight;
30 std::vector<unsigned char> buffer(kBufferSize,
31 static_cast<unsigned char>(128));
32
33 aom_image_t img;
34 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I444, kWidth, kHeight, 1,
35 buffer.data()));
36 img.cp = AOM_CICP_CP_UNSPECIFIED;
37 img.tc = AOM_CICP_TC_UNSPECIFIED;
38 img.mc = AOM_CICP_MC_UNSPECIFIED;
39 img.range = AOM_CR_FULL_RANGE;
40
41 aom_codec_iface_t *iface = aom_codec_av1_cx();
42 aom_codec_enc_cfg_t cfg;
43 EXPECT_EQ(AOM_CODEC_OK,
44 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY));
45 cfg.g_profile = 1;
46 cfg.g_w = kWidth;
47 cfg.g_h = kHeight;
48 cfg.g_bit_depth = AOM_BITS_8;
49 cfg.g_input_bit_depth = 8;
50 cfg.g_lag_in_frames = 0;
51 cfg.rc_end_usage = AOM_Q;
52 cfg.rc_min_quantizer = 50;
53 cfg.rc_max_quantizer = 50;
54 aom_codec_ctx_t enc;
55 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0));
56 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 50));
57 EXPECT_EQ(AOM_CODEC_OK,
58 aom_codec_control(&enc, AOME_SET_NUMBER_SPATIAL_LAYERS, 2));
59 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 6));
60 EXPECT_EQ(AOM_CODEC_OK,
61 aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_FULL_RANGE));
62 EXPECT_EQ(AOM_CODEC_OK,
63 aom_codec_control(&enc, AOME_SET_TUNING, AOM_TUNE_SSIM));
64
65 // First frame (layer 0)
66 EXPECT_EQ(AOM_CODEC_OK,
67 aom_codec_control(&enc, AOME_SET_SPATIAL_LAYER_ID, 0));
68 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0));
69 aom_codec_iter_t iter = nullptr;
70 const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter);
71 ASSERT_NE(pkt, nullptr);
72 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
73 // pkt->data.frame.flags is 0x1f0011.
74 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY);
75 pkt = aom_codec_get_cx_data(&enc, &iter);
76 EXPECT_EQ(pkt, nullptr);
77
78 // Second frame (layer 1)
79 cfg.rc_min_quantizer = 0;
80 cfg.rc_max_quantizer = 0;
81 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg));
82 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 0));
83 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AV1E_SET_LOSSLESS, 1));
84 EXPECT_EQ(AOM_CODEC_OK,
85 aom_codec_control(&enc, AOME_SET_SPATIAL_LAYER_ID, 1));
86 aom_enc_frame_flags_t encode_flags =
87 AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD |
88 AOM_EFLAG_NO_REF_ARF2 | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
89 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, encode_flags));
90 iter = nullptr;
91 pkt = aom_codec_get_cx_data(&enc, &iter);
92 ASSERT_NE(pkt, nullptr);
93 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
94 // pkt->data.frame.flags is 0.
95 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u);
96 pkt = aom_codec_get_cx_data(&enc, &iter);
97 EXPECT_EQ(pkt, nullptr);
98
99 // Flush encoder
100 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0));
101 iter = nullptr;
102 pkt = aom_codec_get_cx_data(&enc, &iter);
103 EXPECT_EQ(pkt, nullptr);
104
105 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
106 }
107
108 // This test emulates how libavif calls libaom functions to encode a
109 // progressive AVIF image in libavif's ProgressiveTest.DimensionChange test.
TEST(AVIFProgressiveTest,DimensionChange)110 TEST(AVIFProgressiveTest, DimensionChange) {
111 constexpr int kWidth = 256;
112 constexpr int kHeight = 256;
113 // A buffer of neutral gray samples.
114 constexpr size_t kBufferSize = 3 * kWidth * kHeight;
115 std::vector<unsigned char> buffer(kBufferSize,
116 static_cast<unsigned char>(128));
117
118 aom_image_t img;
119 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I444, kWidth, kHeight, 1,
120 buffer.data()));
121 img.cp = AOM_CICP_CP_UNSPECIFIED;
122 img.tc = AOM_CICP_TC_UNSPECIFIED;
123 img.mc = AOM_CICP_MC_UNSPECIFIED;
124 img.range = AOM_CR_FULL_RANGE;
125
126 aom_codec_iface_t *iface = aom_codec_av1_cx();
127 aom_codec_enc_cfg_t cfg;
128 EXPECT_EQ(AOM_CODEC_OK,
129 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY));
130 cfg.g_profile = 1;
131 cfg.g_w = kWidth;
132 cfg.g_h = kHeight;
133 cfg.g_bit_depth = AOM_BITS_8;
134 cfg.g_input_bit_depth = 8;
135 cfg.g_lag_in_frames = 0;
136 cfg.rc_end_usage = AOM_Q;
137 cfg.rc_min_quantizer = 0;
138 cfg.rc_max_quantizer = 0;
139 aom_codec_ctx_t enc;
140 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0));
141 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 0));
142 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AV1E_SET_LOSSLESS, 1));
143 EXPECT_EQ(AOM_CODEC_OK,
144 aom_codec_control(&enc, AOME_SET_NUMBER_SPATIAL_LAYERS, 2));
145 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 6));
146 EXPECT_EQ(AOM_CODEC_OK,
147 aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_FULL_RANGE));
148 EXPECT_EQ(AOM_CODEC_OK,
149 aom_codec_control(&enc, AOME_SET_TUNING, AOM_TUNE_SSIM));
150
151 // First frame (layer 0)
152 EXPECT_EQ(AOM_CODEC_OK,
153 aom_codec_control(&enc, AOME_SET_SPATIAL_LAYER_ID, 0));
154 const aom_scaling_mode_t scaling_mode = { AOME_ONETWO, AOME_ONETWO };
155 EXPECT_EQ(AOM_CODEC_OK,
156 aom_codec_control(&enc, AOME_SET_SCALEMODE, &scaling_mode));
157 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0));
158 aom_codec_iter_t iter = nullptr;
159 const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter);
160 ASSERT_NE(pkt, nullptr);
161 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
162 // pkt->data.frame.flags is 0x1f0011.
163 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY);
164 pkt = aom_codec_get_cx_data(&enc, &iter);
165 EXPECT_EQ(pkt, nullptr);
166
167 // Second frame (layer 1)
168 EXPECT_EQ(AOM_CODEC_OK,
169 aom_codec_control(&enc, AOME_SET_SPATIAL_LAYER_ID, 1));
170 aom_enc_frame_flags_t encode_flags =
171 AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD |
172 AOM_EFLAG_NO_REF_ARF2 | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
173 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, encode_flags));
174 iter = nullptr;
175 pkt = aom_codec_get_cx_data(&enc, &iter);
176 ASSERT_NE(pkt, nullptr);
177 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
178 // pkt->data.frame.flags is 0.
179 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u);
180 pkt = aom_codec_get_cx_data(&enc, &iter);
181 EXPECT_EQ(pkt, nullptr);
182
183 // Flush encoder
184 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0));
185 iter = nullptr;
186 pkt = aom_codec_get_cx_data(&enc, &iter);
187 EXPECT_EQ(pkt, nullptr);
188
189 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
190 }
191
192 // This test reproduces bug aomedia:3382. Certain parameters such as width,
193 // height, g_threads, usage, etc. were carefully chosen based on the
194 // complicated logic of av1_select_sb_size() to cause an inconsistent sb_size.
TEST(AVIFProgressiveTest,DimensionChangeBigImageMultiThread)195 TEST(AVIFProgressiveTest, DimensionChangeBigImageMultiThread) {
196 constexpr int kWidth = 1920;
197 constexpr int kHeight = 1080;
198 // A buffer of neutral gray samples.
199 constexpr size_t kBufferSize = 2 * kWidth * kHeight;
200 std::vector<unsigned char> buffer(kBufferSize,
201 static_cast<unsigned char>(128));
202
203 aom_image_t img;
204 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidth, kHeight, 1,
205 buffer.data()));
206 img.cp = AOM_CICP_CP_UNSPECIFIED;
207 img.tc = AOM_CICP_TC_UNSPECIFIED;
208 img.mc = AOM_CICP_MC_UNSPECIFIED;
209 img.range = AOM_CR_FULL_RANGE;
210
211 aom_codec_iface_t *iface = aom_codec_av1_cx();
212 aom_codec_enc_cfg_t cfg;
213 EXPECT_EQ(AOM_CODEC_OK,
214 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY));
215 cfg.g_profile = 0;
216 cfg.g_w = img.w;
217 cfg.g_h = img.h;
218 cfg.g_bit_depth = AOM_BITS_8;
219 cfg.g_input_bit_depth = 8;
220 cfg.g_lag_in_frames = 0;
221 cfg.g_threads = 2; // MultiThread
222 cfg.rc_end_usage = AOM_Q;
223 cfg.rc_min_quantizer = 0;
224 cfg.rc_max_quantizer = 63;
225 aom_codec_ctx_t enc;
226 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0));
227 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 31));
228 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 6));
229 EXPECT_EQ(AOM_CODEC_OK,
230 aom_codec_control(&enc, AV1E_SET_ROW_MT, 1)); // MultiThread
231 EXPECT_EQ(AOM_CODEC_OK,
232 aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_FULL_RANGE));
233 EXPECT_EQ(AOM_CODEC_OK,
234 aom_codec_control(&enc, AOME_SET_TUNING, AOM_TUNE_SSIM));
235 EXPECT_EQ(AOM_CODEC_OK,
236 aom_codec_control(&enc, AOME_SET_NUMBER_SPATIAL_LAYERS, 2));
237
238 // First frame (layer 0)
239 EXPECT_EQ(AOM_CODEC_OK,
240 aom_codec_control(&enc, AOME_SET_SPATIAL_LAYER_ID, 0));
241 const aom_scaling_mode_t scaling_mode = { AOME_ONETWO, AOME_ONETWO };
242 EXPECT_EQ(AOM_CODEC_OK,
243 aom_codec_control(&enc, AOME_SET_SCALEMODE, &scaling_mode));
244 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0));
245 aom_codec_iter_t iter = nullptr;
246 const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter);
247 ASSERT_NE(pkt, nullptr);
248 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
249 // pkt->data.frame.flags is 0x1f0011.
250 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY);
251 pkt = aom_codec_get_cx_data(&enc, &iter);
252 EXPECT_EQ(pkt, nullptr);
253
254 // Second frame (layer 1)
255 EXPECT_EQ(AOM_CODEC_OK,
256 aom_codec_control(&enc, AOME_SET_SPATIAL_LAYER_ID, 1));
257 aom_enc_frame_flags_t encode_flags =
258 AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD |
259 AOM_EFLAG_NO_REF_ARF2 | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
260 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, encode_flags));
261 iter = nullptr;
262 pkt = aom_codec_get_cx_data(&enc, &iter);
263 ASSERT_NE(pkt, nullptr);
264 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
265 // pkt->data.frame.flags is 0.
266 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u);
267 pkt = aom_codec_get_cx_data(&enc, &iter);
268 EXPECT_EQ(pkt, nullptr);
269
270 // Flush encoder
271 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0));
272 iter = nullptr;
273 pkt = aom_codec_get_cx_data(&enc, &iter);
274 EXPECT_EQ(pkt, nullptr);
275
276 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
277 }
278
279 // A variant of the previous test, without the spatial layers.
TEST(AVIFProgressiveTest,DimensionChangeBigImageMultiThread2)280 TEST(AVIFProgressiveTest, DimensionChangeBigImageMultiThread2) {
281 constexpr int kWidth = 1920;
282 constexpr int kHeight = 1080;
283 // A buffer of neutral gray samples.
284 constexpr size_t kBufferSize = 2 * kWidth * kHeight;
285 std::vector<unsigned char> buffer(kBufferSize,
286 static_cast<unsigned char>(128));
287
288 aom_image_t img;
289 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidth, kHeight, 1,
290 buffer.data()));
291 img.cp = AOM_CICP_CP_UNSPECIFIED;
292 img.tc = AOM_CICP_TC_UNSPECIFIED;
293 img.mc = AOM_CICP_MC_UNSPECIFIED;
294 img.range = AOM_CR_FULL_RANGE;
295
296 aom_codec_iface_t *iface = aom_codec_av1_cx();
297 aom_codec_enc_cfg_t cfg;
298 EXPECT_EQ(AOM_CODEC_OK,
299 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY));
300 cfg.g_profile = 0;
301 cfg.g_w = img.w;
302 cfg.g_h = img.h;
303 cfg.g_bit_depth = AOM_BITS_8;
304 cfg.g_input_bit_depth = 8;
305 cfg.g_lag_in_frames = 0;
306 cfg.g_threads = 2; // MultiThread
307 cfg.rc_end_usage = AOM_Q;
308 cfg.rc_min_quantizer = 0;
309 cfg.rc_max_quantizer = 63;
310 aom_codec_ctx_t enc;
311 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0));
312 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 31));
313 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 6));
314 EXPECT_EQ(AOM_CODEC_OK,
315 aom_codec_control(&enc, AV1E_SET_ROW_MT, 1)); // MultiThread
316 EXPECT_EQ(AOM_CODEC_OK,
317 aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_FULL_RANGE));
318 EXPECT_EQ(AOM_CODEC_OK,
319 aom_codec_control(&enc, AOME_SET_TUNING, AOM_TUNE_SSIM));
320
321 // First frame
322 const aom_scaling_mode_t scaling_mode = { AOME_ONETWO, AOME_ONETWO };
323 EXPECT_EQ(AOM_CODEC_OK,
324 aom_codec_control(&enc, AOME_SET_SCALEMODE, &scaling_mode));
325 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0));
326 aom_codec_iter_t iter = nullptr;
327 const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter);
328 ASSERT_NE(pkt, nullptr);
329 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
330 // pkt->data.frame.flags is 0x1f0011.
331 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY);
332 pkt = aom_codec_get_cx_data(&enc, &iter);
333 EXPECT_EQ(pkt, nullptr);
334
335 // Second frame
336 aom_enc_frame_flags_t encode_flags =
337 AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD |
338 AOM_EFLAG_NO_REF_ARF2 | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
339 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, encode_flags));
340 iter = nullptr;
341 pkt = aom_codec_get_cx_data(&enc, &iter);
342 ASSERT_NE(pkt, nullptr);
343 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
344 // pkt->data.frame.flags is 0.
345 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u);
346 pkt = aom_codec_get_cx_data(&enc, &iter);
347 EXPECT_EQ(pkt, nullptr);
348
349 // Flush encoder
350 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0));
351 iter = nullptr;
352 pkt = aom_codec_get_cx_data(&enc, &iter);
353 EXPECT_EQ(pkt, nullptr);
354
355 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
356 }
357
358 } // namespace
359