avif_progressive_test.cc (14300B)
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. 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. 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. 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. 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