xref: /aosp_15_r20/external/libaom/test/avif_progressive_test.cc (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
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