encode_api_test.cc (44399B)
1 /* 2 * Copyright (c) 2016, 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 <cassert> 13 #include <climits> 14 #include <cstdint> 15 #include <cstdlib> 16 #include <cstring> 17 #include <tuple> 18 19 #include "gtest/gtest.h" 20 21 #include "config/aom_config.h" 22 23 #include "aom/aomcx.h" 24 #include "aom/aom_encoder.h" 25 #include "aom/aom_image.h" 26 27 namespace { 28 29 #if CONFIG_REALTIME_ONLY 30 const unsigned int kUsage = AOM_USAGE_REALTIME; 31 #else 32 const unsigned int kUsage = AOM_USAGE_GOOD_QUALITY; 33 #endif 34 35 static void *Memset16(void *dest, int val, size_t length) { 36 uint16_t *dest16 = (uint16_t *)dest; 37 for (size_t i = 0; i < length; ++i) *dest16++ = val; 38 return dest; 39 } 40 41 TEST(EncodeAPI, InvalidParams) { 42 uint8_t buf[1] = { 0 }; 43 aom_image_t img; 44 aom_codec_ctx_t enc; 45 aom_codec_enc_cfg_t cfg; 46 47 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, 1, 1, 1, buf)); 48 49 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, 50 aom_codec_enc_init(nullptr, nullptr, nullptr, 0)); 51 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, 52 aom_codec_enc_init(&enc, nullptr, nullptr, 0)); 53 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, 54 aom_codec_encode(nullptr, nullptr, 0, 0, 0)); 55 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_encode(nullptr, &img, 0, 0, 0)); 56 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_destroy(nullptr)); 57 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, 58 aom_codec_enc_config_default(nullptr, nullptr, 0)); 59 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, 60 aom_codec_enc_config_default(nullptr, &cfg, 0)); 61 EXPECT_NE(aom_codec_error(nullptr), nullptr); 62 63 aom_codec_iface_t *iface = aom_codec_av1_cx(); 64 SCOPED_TRACE(aom_codec_iface_name(iface)); 65 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, 66 aom_codec_enc_init(nullptr, iface, nullptr, 0)); 67 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, 68 aom_codec_enc_init(&enc, iface, nullptr, 0)); 69 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, 70 aom_codec_enc_config_default(iface, &cfg, 3)); 71 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, kUsage)); 72 cfg.g_w = 1 << 16; 73 cfg.g_h = (1 << 14) + 1; 74 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0)); 75 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, kUsage)); 76 cfg.g_w = (1 << 14) + 1; 77 cfg.g_h = 1 << 16; 78 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0)); 79 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, kUsage)); 80 cfg.g_forced_max_frame_width = 1 << 16; 81 cfg.g_forced_max_frame_height = (1 << 14) + 1; 82 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0)); 83 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, kUsage)); 84 cfg.g_forced_max_frame_width = (1 << 14) + 1; 85 cfg.g_forced_max_frame_height = 1 << 16; 86 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0)); 87 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, kUsage)); 88 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 89 EXPECT_EQ(nullptr, aom_codec_get_global_headers(nullptr)); 90 91 aom_fixed_buf_t *glob_headers = aom_codec_get_global_headers(&enc); 92 EXPECT_NE(glob_headers->buf, nullptr); 93 if (glob_headers) { 94 free(glob_headers->buf); 95 free(glob_headers); 96 } 97 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 0, 0)); 98 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 99 } 100 101 TEST(EncodeAPI, InvalidSvcParams) { 102 uint8_t buf[6] = { 0 }; 103 aom_image_t img; 104 aom_codec_ctx_t enc; 105 aom_codec_enc_cfg_t cfg; 106 107 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, 1, 1, 1, buf)); 108 109 aom_codec_iface_t *iface = aom_codec_av1_cx(); 110 EXPECT_EQ(AOM_CODEC_OK, 111 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME)); 112 cfg.g_w = 1; 113 cfg.g_h = 1; 114 EXPECT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 115 EXPECT_EQ(aom_codec_encode(&enc, &img, 0, 1, 0), AOM_CODEC_OK); 116 117 EXPECT_EQ(aom_codec_control(&enc, AOME_SET_NUMBER_SPATIAL_LAYERS, -1), 118 AOM_CODEC_INVALID_PARAM); 119 EXPECT_EQ(aom_codec_control(&enc, AOME_SET_NUMBER_SPATIAL_LAYERS, 120 AOM_MAX_SS_LAYERS + 1), 121 AOM_CODEC_INVALID_PARAM); 122 123 aom_svc_params_t svc_params = {}; 124 svc_params.framerate_factor[0] = 2; 125 svc_params.framerate_factor[1] = 1; 126 svc_params.layer_target_bitrate[0] = 60 * cfg.rc_target_bitrate / 100; 127 svc_params.layer_target_bitrate[1] = cfg.rc_target_bitrate; 128 for (const bool use_flexible_mode : { false, true }) { 129 if (use_flexible_mode) { 130 aom_svc_ref_frame_config_t ref_frame_config = {}; 131 ref_frame_config.refresh[0] = 1; 132 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_REF_FRAME_CONFIG, 133 &ref_frame_config), 134 AOM_CODEC_OK); 135 } 136 137 const int max_valid_num_spatial = use_flexible_mode ? AOM_MAX_SS_LAYERS : 3; 138 const int max_valid_num_temporal = 139 use_flexible_mode ? AOM_MAX_TS_LAYERS : 3; 140 for (int num_spatial = AOM_MAX_SS_LAYERS; 141 num_spatial <= AOM_MAX_SS_LAYERS + 1; ++num_spatial) { 142 for (int num_temporal = AOM_MAX_TS_LAYERS; 143 num_temporal <= AOM_MAX_TS_LAYERS + 1; ++num_temporal) { 144 svc_params.number_spatial_layers = num_spatial; 145 svc_params.number_temporal_layers = num_temporal; 146 if (num_spatial > 0 && num_spatial <= AOM_MAX_SS_LAYERS && 147 num_temporal > 0 && num_temporal <= AOM_MAX_TS_LAYERS) { 148 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_PARAMS, &svc_params), 149 AOM_CODEC_OK) 150 << "num_spatial: " << num_spatial 151 << " num_temporal: " << num_temporal 152 << " use_flexible_mode: " << use_flexible_mode; 153 } else { 154 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_PARAMS, &svc_params), 155 AOM_CODEC_INVALID_PARAM) 156 << "num_spatial: " << num_spatial 157 << " num_temporal: " << num_temporal 158 << " use_flexible_mode: " << use_flexible_mode; 159 } 160 if (use_flexible_mode || (num_spatial <= max_valid_num_spatial && 161 num_temporal <= max_valid_num_temporal)) { 162 EXPECT_EQ(aom_codec_encode(&enc, &img, 0, 1, 0), AOM_CODEC_OK); 163 } else { 164 EXPECT_EQ(aom_codec_encode(&enc, &img, 0, 1, 0), 165 AOM_CODEC_INVALID_PARAM); 166 } 167 } 168 } 169 } 170 171 EXPECT_EQ(aom_codec_encode(&enc, &img, 0, 1, 0), AOM_CODEC_OK); 172 EXPECT_EQ(aom_codec_encode(&enc, nullptr, 0, 0, 0), AOM_CODEC_OK); 173 EXPECT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 174 } 175 176 TEST(EncodeAPI, InvalidControlId) { 177 aom_codec_iface_t *iface = aom_codec_av1_cx(); 178 aom_codec_ctx_t enc; 179 aom_codec_enc_cfg_t cfg; 180 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, kUsage)); 181 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 182 EXPECT_EQ(AOM_CODEC_ERROR, aom_codec_control(&enc, -1, 0)); 183 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_control(&enc, 0, 0)); 184 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 185 } 186 187 TEST(EncodeAPI, TuneIqNotAllIntra) { 188 aom_codec_iface_t *iface = aom_codec_av1_cx(); 189 aom_codec_enc_cfg_t cfg; 190 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), 191 AOM_CODEC_OK); 192 193 aom_codec_ctx_t enc; 194 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 195 196 ASSERT_EQ(aom_codec_control(&enc, AOME_SET_TUNING, AOM_TUNE_SSIMULACRA2), 197 AOM_CODEC_INCAPABLE); 198 199 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 200 } 201 202 void EncodeSetSFrameOnFirstFrame(aom_img_fmt fmt, aom_codec_flags_t flag) { 203 constexpr int kWidth = 2; 204 constexpr int kHeight = 128; 205 unsigned char kBuffer[kWidth * kHeight * 3] = { 0 }; 206 aom_image_t img; 207 ASSERT_EQ(aom_img_wrap(&img, fmt, kWidth, kHeight, 1, kBuffer), &img); 208 209 aom_codec_iface_t *iface = aom_codec_av1_cx(); 210 aom_codec_enc_cfg_t cfg; 211 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, kUsage), AOM_CODEC_OK); 212 cfg.g_w = kWidth; 213 cfg.g_h = kHeight; 214 215 aom_codec_ctx_t enc; 216 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, flag), AOM_CODEC_OK); 217 // One of these aom_codec_encode() calls should fail. 218 if (aom_codec_encode(&enc, &img, 0, 1, AOM_EFLAG_SET_S_FRAME) == 219 AOM_CODEC_OK) { 220 EXPECT_NE(aom_codec_encode(&enc, nullptr, 0, 0, 0), AOM_CODEC_OK); 221 } 222 EXPECT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 223 } 224 225 TEST(EncodeAPI, SetSFrameOnFirstFrame) { 226 EncodeSetSFrameOnFirstFrame(AOM_IMG_FMT_I420, 0); 227 } 228 229 #if CONFIG_AV1_HIGHBITDEPTH 230 TEST(EncodeAPI, SetSFrameOnFirstFrameHighbd) { 231 EncodeSetSFrameOnFirstFrame(AOM_IMG_FMT_I42016, AOM_CODEC_USE_HIGHBITDEPTH); 232 } 233 #endif // CONFIG_AV1_HIGHBITDEPTH 234 235 TEST(EncodeAPI, MonochromeInProfiles) { 236 aom_codec_iface_t *iface = aom_codec_av1_cx(); 237 aom_codec_enc_cfg_t cfg; 238 ASSERT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, kUsage)); 239 cfg.g_w = 128; 240 cfg.g_h = 128; 241 cfg.monochrome = 1; 242 aom_codec_ctx_t enc; 243 244 // Test Profile 0 245 cfg.g_profile = 0; 246 ASSERT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 247 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 248 249 // Test Profile 1 250 cfg.g_profile = 1; 251 ASSERT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0)); 252 253 // Test Profile 3 254 cfg.g_profile = 2; 255 ASSERT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 256 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 257 } 258 259 TEST(EncodeAPI, LowBDEncoderLowBDImage) { 260 aom_codec_iface_t *iface = aom_codec_av1_cx(); 261 aom_codec_enc_cfg_t cfg; 262 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, kUsage), AOM_CODEC_OK); 263 264 aom_codec_ctx_t enc; 265 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 266 267 aom_image_t *image = 268 aom_img_alloc(nullptr, AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h, 0); 269 ASSERT_NE(image, nullptr); 270 271 // Set the image to two colors so that av1_set_screen_content_options() will 272 // call av1_get_perpixel_variance(). 273 int luma_value = 0; 274 for (unsigned int i = 0; i < image->d_h; ++i) { 275 memset(image->planes[0] + i * image->stride[0], luma_value, image->d_w); 276 luma_value = 255 - luma_value; 277 } 278 unsigned int uv_h = (image->d_h + 1) / 2; 279 unsigned int uv_w = (image->d_w + 1) / 2; 280 for (unsigned int i = 0; i < uv_h; ++i) { 281 memset(image->planes[1] + i * image->stride[1], 128, uv_w); 282 memset(image->planes[2] + i * image->stride[2], 128, uv_w); 283 } 284 285 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK); 286 287 aom_img_free(image); 288 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 289 } 290 291 TEST(EncodeAPI, HighBDEncoderHighBDImage) { 292 aom_codec_iface_t *iface = aom_codec_av1_cx(); 293 aom_codec_enc_cfg_t cfg; 294 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, kUsage), AOM_CODEC_OK); 295 296 aom_codec_ctx_t enc; 297 aom_codec_err_t init_status = 298 aom_codec_enc_init(&enc, iface, &cfg, AOM_CODEC_USE_HIGHBITDEPTH); 299 #if !CONFIG_AV1_HIGHBITDEPTH 300 ASSERT_EQ(init_status, AOM_CODEC_INCAPABLE); 301 #else 302 ASSERT_EQ(init_status, AOM_CODEC_OK); 303 304 aom_image_t *image = 305 aom_img_alloc(nullptr, AOM_IMG_FMT_I42016, cfg.g_w, cfg.g_h, 0); 306 ASSERT_NE(image, nullptr); 307 308 // Set the image to two colors so that av1_set_screen_content_options() will 309 // call av1_get_perpixel_variance(). 310 int luma_value = 0; 311 for (unsigned int i = 0; i < image->d_h; ++i) { 312 Memset16(image->planes[0] + i * image->stride[0], luma_value, image->d_w); 313 luma_value = 255 - luma_value; 314 } 315 unsigned int uv_h = (image->d_h + 1) / 2; 316 unsigned int uv_w = (image->d_w + 1) / 2; 317 for (unsigned int i = 0; i < uv_h; ++i) { 318 Memset16(image->planes[1] + i * image->stride[1], 128, uv_w); 319 Memset16(image->planes[2] + i * image->stride[2], 128, uv_w); 320 } 321 322 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK); 323 324 aom_img_free(image); 325 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 326 #endif 327 } 328 329 TEST(EncodeAPI, HighBDEncoderLowBDImage) { 330 aom_codec_iface_t *iface = aom_codec_av1_cx(); 331 aom_codec_enc_cfg_t cfg; 332 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, kUsage), AOM_CODEC_OK); 333 334 aom_codec_ctx_t enc; 335 aom_codec_err_t init_status = 336 aom_codec_enc_init(&enc, iface, &cfg, AOM_CODEC_USE_HIGHBITDEPTH); 337 #if !CONFIG_AV1_HIGHBITDEPTH 338 ASSERT_EQ(init_status, AOM_CODEC_INCAPABLE); 339 #else 340 ASSERT_EQ(init_status, AOM_CODEC_OK); 341 342 aom_image_t *image = 343 aom_img_alloc(nullptr, AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h, 0); 344 ASSERT_NE(image, nullptr); 345 346 // Set the image to two colors so that av1_set_screen_content_options() will 347 // call av1_get_perpixel_variance(). 348 int luma_value = 0; 349 for (unsigned int i = 0; i < image->d_h; ++i) { 350 memset(image->planes[0] + i * image->stride[0], luma_value, image->d_w); 351 luma_value = 255 - luma_value; 352 } 353 unsigned int uv_h = (image->d_h + 1) / 2; 354 unsigned int uv_w = (image->d_w + 1) / 2; 355 for (unsigned int i = 0; i < uv_h; ++i) { 356 memset(image->planes[1] + i * image->stride[1], 128, uv_w); 357 memset(image->planes[2] + i * image->stride[2], 128, uv_w); 358 } 359 360 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_INVALID_PARAM); 361 362 aom_img_free(image); 363 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 364 #endif 365 } 366 367 TEST(EncodeAPI, LowBDEncoderHighBDImage) { 368 aom_codec_iface_t *iface = aom_codec_av1_cx(); 369 aom_codec_enc_cfg_t cfg; 370 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, kUsage), AOM_CODEC_OK); 371 372 aom_codec_ctx_t enc; 373 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 374 375 aom_image_t *image = 376 aom_img_alloc(nullptr, AOM_IMG_FMT_I42016, cfg.g_w, cfg.g_h, 0); 377 ASSERT_NE(image, nullptr); 378 379 // Set the image to two colors so that av1_set_screen_content_options() will 380 // call av1_get_perpixel_variance(). 381 int luma_value = 0; 382 for (unsigned int i = 0; i < image->d_h; ++i) { 383 Memset16(image->planes[0] + i * image->stride[0], luma_value, image->d_w); 384 luma_value = 255 - luma_value; 385 } 386 unsigned int uv_h = (image->d_h + 1) / 2; 387 unsigned int uv_w = (image->d_w + 1) / 2; 388 for (unsigned int i = 0; i < uv_h; ++i) { 389 Memset16(image->planes[1] + i * image->stride[1], 128, uv_w); 390 Memset16(image->planes[2] + i * image->stride[2], 128, uv_w); 391 } 392 393 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_INVALID_PARAM); 394 395 aom_img_free(image); 396 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 397 } 398 399 aom_image_t *CreateGrayImage(aom_img_fmt_t fmt, unsigned int w, 400 unsigned int h) { 401 aom_image_t *const image = aom_img_alloc(nullptr, fmt, w, h, 1); 402 if (!image) return image; 403 404 for (unsigned int i = 0; i < image->d_h; ++i) { 405 memset(image->planes[0] + i * image->stride[0], 128, image->d_w); 406 } 407 const unsigned int uv_h = (image->d_h + 1) / 2; 408 const unsigned int uv_w = (image->d_w + 1) / 2; 409 for (unsigned int i = 0; i < uv_h; ++i) { 410 memset(image->planes[1] + i * image->stride[1], 128, uv_w); 411 memset(image->planes[2] + i * image->stride[2], 128, uv_w); 412 } 413 return image; 414 } 415 416 TEST(EncodeAPI, Buganizer310548198) { 417 aom_codec_iface_t *const iface = aom_codec_av1_cx(); 418 aom_codec_enc_cfg_t cfg; 419 const unsigned int usage = AOM_USAGE_REALTIME; 420 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage), AOM_CODEC_OK); 421 cfg.g_w = 1; 422 cfg.g_h = 444; 423 cfg.g_pass = AOM_RC_ONE_PASS; 424 cfg.g_lag_in_frames = 0; 425 426 aom_codec_ctx_t enc; 427 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 428 429 const int speed = 6; 430 ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, speed), AOM_CODEC_OK); 431 432 const aom_enc_frame_flags_t flags = 0; 433 int frame_index = 0; 434 435 // Encode a frame. 436 aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 437 ASSERT_NE(image, nullptr); 438 ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK); 439 frame_index++; 440 const aom_codec_cx_pkt_t *pkt; 441 aom_codec_iter_t iter = nullptr; 442 while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) { 443 ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); 444 } 445 aom_img_free(image); 446 447 cfg.g_w = 1; 448 cfg.g_h = 254; 449 ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK) 450 << aom_codec_error_detail(&enc); 451 452 cfg.g_w = 1; 453 cfg.g_h = 154; 454 ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK) 455 << aom_codec_error_detail(&enc); 456 457 // Encode a frame. 458 image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 459 ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK); 460 frame_index++; 461 iter = nullptr; 462 while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) { 463 ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); 464 } 465 aom_img_free(image); 466 467 // Flush the encoder. 468 bool got_data; 469 do { 470 ASSERT_EQ(aom_codec_encode(&enc, nullptr, 0, 0, 0), AOM_CODEC_OK); 471 got_data = false; 472 iter = nullptr; 473 while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) { 474 ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); 475 got_data = true; 476 } 477 } while (got_data); 478 479 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 480 } 481 482 // Emulates the WebCodecs VideoEncoder interface. 483 class AV1Encoder { 484 public: 485 explicit AV1Encoder(int speed) : speed_(speed) {} 486 ~AV1Encoder(); 487 488 void Configure(unsigned int threads, unsigned int width, unsigned int height, 489 aom_rc_mode end_usage, unsigned int usage); 490 void Encode(bool key_frame); 491 492 private: 493 // Flushes the encoder. Should be called after all the Encode() calls. 494 void Flush(); 495 496 const int speed_; 497 bool initialized_ = false; 498 aom_codec_enc_cfg_t cfg_; 499 aom_codec_ctx_t enc_; 500 int frame_index_ = 0; 501 }; 502 503 AV1Encoder::~AV1Encoder() { 504 if (initialized_) { 505 Flush(); 506 EXPECT_EQ(aom_codec_destroy(&enc_), AOM_CODEC_OK); 507 } 508 } 509 510 void AV1Encoder::Configure(unsigned int threads, unsigned int width, 511 unsigned int height, aom_rc_mode end_usage, 512 unsigned int usage) { 513 if (!initialized_) { 514 aom_codec_iface_t *const iface = aom_codec_av1_cx(); 515 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg_, usage), AOM_CODEC_OK); 516 cfg_.g_threads = threads; 517 cfg_.g_w = width; 518 cfg_.g_h = height; 519 cfg_.g_forced_max_frame_width = cfg_.g_w; 520 cfg_.g_forced_max_frame_height = cfg_.g_h; 521 cfg_.g_timebase.num = 1; 522 cfg_.g_timebase.den = 1000 * 1000; // microseconds 523 cfg_.g_pass = AOM_RC_ONE_PASS; 524 cfg_.g_lag_in_frames = 0; 525 cfg_.rc_end_usage = end_usage; 526 cfg_.rc_min_quantizer = 2; 527 cfg_.rc_max_quantizer = 58; 528 ASSERT_EQ(aom_codec_enc_init(&enc_, iface, &cfg_, 0), AOM_CODEC_OK); 529 ASSERT_EQ(aom_codec_control(&enc_, AOME_SET_CPUUSED, speed_), AOM_CODEC_OK); 530 initialized_ = true; 531 return; 532 } 533 534 ASSERT_EQ(usage, cfg_.g_usage); 535 cfg_.g_threads = threads; 536 cfg_.g_w = width; 537 cfg_.g_h = height; 538 cfg_.rc_end_usage = end_usage; 539 ASSERT_EQ(aom_codec_enc_config_set(&enc_, &cfg_), AOM_CODEC_OK) 540 << aom_codec_error_detail(&enc_); 541 } 542 543 void AV1Encoder::Encode(bool key_frame) { 544 assert(initialized_); 545 // TODO(wtc): Support high bit depths and other YUV formats. 546 aom_image_t *const image = 547 CreateGrayImage(AOM_IMG_FMT_I420, cfg_.g_w, cfg_.g_h); 548 ASSERT_NE(image, nullptr); 549 const aom_enc_frame_flags_t flags = key_frame ? AOM_EFLAG_FORCE_KF : 0; 550 ASSERT_EQ(aom_codec_encode(&enc_, image, frame_index_, 1, flags), 551 AOM_CODEC_OK); 552 frame_index_++; 553 const aom_codec_cx_pkt_t *pkt; 554 aom_codec_iter_t iter = nullptr; 555 while ((pkt = aom_codec_get_cx_data(&enc_, &iter)) != nullptr) { 556 ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); 557 if (key_frame) { 558 ASSERT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY); 559 } 560 } 561 aom_img_free(image); 562 } 563 564 void AV1Encoder::Flush() { 565 bool got_data; 566 do { 567 ASSERT_EQ(aom_codec_encode(&enc_, nullptr, 0, 0, 0), AOM_CODEC_OK); 568 got_data = false; 569 const aom_codec_cx_pkt_t *pkt; 570 aom_codec_iter_t iter = nullptr; 571 while ((pkt = aom_codec_get_cx_data(&enc_, &iter)) != nullptr) { 572 ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); 573 got_data = true; 574 } 575 } while (got_data); 576 } 577 578 TEST(EncodeAPI, Buganizer314858909) { 579 AV1Encoder encoder(7); 580 581 encoder.Configure(6, 1582, 750, AOM_CBR, AOM_USAGE_REALTIME); 582 583 // Encode a frame. 584 encoder.Encode(false); 585 586 encoder.Configure(0, 1582, 23, AOM_CBR, AOM_USAGE_REALTIME); 587 588 // Encode a frame.. 589 encoder.Encode(false); 590 591 encoder.Configure(16, 1542, 363, AOM_CBR, AOM_USAGE_REALTIME); 592 593 // Encode a frame.. 594 encoder.Encode(false); 595 } 596 597 // Run this test to reproduce the bug in fuzz test: ASSERT: cpi->rec_sse != 598 // UINT64_MAX in av1_rc_bits_per_mb. 599 TEST(EncodeAPI, Buganizer310766628) { 600 AV1Encoder encoder(7); 601 602 encoder.Configure(16, 759, 383, AOM_CBR, AOM_USAGE_REALTIME); 603 604 // Encode a frame. 605 encoder.Encode(false); 606 607 encoder.Configure(2, 759, 383, AOM_VBR, AOM_USAGE_REALTIME); 608 609 // Encode a frame. This will trigger the assertion failure. 610 encoder.Encode(false); 611 } 612 613 // This test covers a possible use case where the change of frame sizes and 614 // thread numbers happens before and after the first frame coding. 615 TEST(EncodeAPI, Buganizer310455204) { 616 AV1Encoder encoder(7); 617 618 encoder.Configure(0, 1915, 503, AOM_VBR, AOM_USAGE_REALTIME); 619 620 encoder.Configure(4, 1, 1, AOM_VBR, AOM_USAGE_REALTIME); 621 622 encoder.Configure(6, 559, 503, AOM_CBR, AOM_USAGE_REALTIME); 623 624 // Encode a frame. 625 encoder.Encode(false); 626 627 // Increase the number of threads. 628 encoder.Configure(16, 1915, 503, AOM_CBR, AOM_USAGE_REALTIME); 629 630 // Encode a frame. 631 encoder.Encode(false); 632 } 633 634 // Run this test to reproduce the bug in fuzz test: Float-cast-overflow in 635 // av1_rc_bits_per_mb. 636 TEST(EncodeAPI, Buganizer310457427) { 637 AV1Encoder encoder(7); 638 639 encoder.Configure(12, 896, 1076, AOM_CBR, AOM_USAGE_REALTIME); 640 641 encoder.Configure(6, 609, 1076, AOM_VBR, AOM_USAGE_REALTIME); 642 643 // Encode a frame. 644 encoder.Encode(false); 645 646 // Encode a frame. This will trigger the float-cast-overflow bug which was 647 // caused by division by zero. 648 encoder.Encode(false); 649 } 650 651 TEST(EncodeAPI, PtsSmallerThanInitialPts) { 652 // Initialize libaom encoder. 653 aom_codec_iface_t *const iface = aom_codec_av1_cx(); 654 aom_codec_ctx_t enc; 655 aom_codec_enc_cfg_t cfg; 656 657 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), 658 AOM_CODEC_OK); 659 660 cfg.g_w = 1280; 661 cfg.g_h = 720; 662 cfg.rc_target_bitrate = 1000; 663 664 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 665 666 // Create input image. 667 aom_image_t *const image = 668 CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 669 ASSERT_NE(image, nullptr); 670 671 // Encode frame. 672 ASSERT_EQ(aom_codec_encode(&enc, image, 12, 1, 0), AOM_CODEC_OK); 673 ASSERT_EQ(aom_codec_encode(&enc, image, 13, 1, 0), AOM_CODEC_OK); 674 // pts (10) is smaller than the initial pts (12). 675 ASSERT_EQ(aom_codec_encode(&enc, image, 10, 1, 0), AOM_CODEC_INVALID_PARAM); 676 677 // Free resources. 678 aom_img_free(image); 679 aom_codec_destroy(&enc); 680 } 681 682 TEST(EncodeAPI, PtsOrDurationTooBig) { 683 // Initialize libaom encoder. 684 aom_codec_iface_t *const iface = aom_codec_av1_cx(); 685 aom_codec_ctx_t enc; 686 aom_codec_enc_cfg_t cfg; 687 688 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), 689 AOM_CODEC_OK); 690 691 cfg.g_w = 1280; 692 cfg.g_h = 720; 693 cfg.rc_target_bitrate = 1000; 694 695 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 696 697 // Create input image. 698 aom_image_t *const image = 699 CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 700 ASSERT_NE(image, nullptr); 701 702 // Encode frame. 703 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK); 704 // pts, when converted to ticks, is too big. 705 ASSERT_EQ(aom_codec_encode(&enc, image, INT64_MAX / 1000000 + 1, 1, 0), 706 AOM_CODEC_INVALID_PARAM); 707 #if ULONG_MAX > INT64_MAX 708 // duration is too big. 709 ASSERT_EQ(aom_codec_encode(&enc, image, 0, (1ul << 63), 0), 710 AOM_CODEC_INVALID_PARAM); 711 // pts + duration is too big. 712 ASSERT_EQ(aom_codec_encode(&enc, image, 1, INT64_MAX, 0), 713 AOM_CODEC_INVALID_PARAM); 714 #endif 715 // pts + duration, when converted to ticks, is too big. 716 #if ULONG_MAX > INT64_MAX 717 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 0x1c0a0a1a3232, 0), 718 AOM_CODEC_INVALID_PARAM); 719 #endif 720 ASSERT_EQ(aom_codec_encode(&enc, image, INT64_MAX / 1000000, 1, 0), 721 AOM_CODEC_INVALID_PARAM); 722 723 // Free resources. 724 aom_img_free(image); 725 aom_codec_destroy(&enc); 726 } 727 728 // Reproduces https://crbug.com/339877165. 729 TEST(EncodeAPI, Buganizer339877165) { 730 // Initialize libaom encoder. 731 aom_codec_iface_t *const iface = aom_codec_av1_cx(); 732 aom_codec_ctx_t enc; 733 aom_codec_enc_cfg_t cfg; 734 735 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), 736 AOM_CODEC_OK); 737 738 cfg.g_w = 2560; 739 cfg.g_h = 1600; 740 cfg.rc_target_bitrate = 231; 741 cfg.rc_end_usage = AOM_CBR; 742 cfg.g_threads = 8; 743 744 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 745 746 // From libaom_av1_encoder.cc in WebRTC. 747 ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, 11), AOM_CODEC_OK); 748 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_CDEF, 1), AOM_CODEC_OK); 749 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_TPL_MODEL, 0), 750 AOM_CODEC_OK); 751 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_DELTAQ_MODE, 0), AOM_CODEC_OK); 752 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_ORDER_HINT, 0), 753 AOM_CODEC_OK); 754 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_AQ_MODE, 3), AOM_CODEC_OK); 755 ASSERT_EQ(aom_codec_control(&enc, AOME_SET_MAX_INTRA_BITRATE_PCT, 300), 756 AOM_CODEC_OK); 757 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_COEFF_COST_UPD_FREQ, 3), 758 AOM_CODEC_OK); 759 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MODE_COST_UPD_FREQ, 3), 760 AOM_CODEC_OK); 761 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MV_COST_UPD_FREQ, 3), 762 AOM_CODEC_OK); 763 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN), 764 AOM_CODEC_OK); 765 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_PALETTE, 1), AOM_CODEC_OK); 766 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TILE_ROWS, 1), AOM_CODEC_OK); 767 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TILE_COLUMNS, 2), AOM_CODEC_OK); 768 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_OBMC, 0), AOM_CODEC_OK); 769 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_NOISE_SENSITIVITY, 0), 770 AOM_CODEC_OK); 771 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_WARPED_MOTION, 0), 772 AOM_CODEC_OK); 773 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_GLOBAL_MOTION, 0), 774 AOM_CODEC_OK); 775 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_REF_FRAME_MVS, 0), 776 AOM_CODEC_OK); 777 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SUPERBLOCK_SIZE, 778 AOM_SUPERBLOCK_SIZE_DYNAMIC), 779 AOM_CODEC_OK); 780 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_CFL_INTRA, 0), 781 AOM_CODEC_OK); 782 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_SMOOTH_INTRA, 0), 783 AOM_CODEC_OK); 784 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_ANGLE_DELTA, 0), 785 AOM_CODEC_OK); 786 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_FILTER_INTRA, 0), 787 AOM_CODEC_OK); 788 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_INTRA_DEFAULT_TX_ONLY, 1), 789 AOM_CODEC_OK); 790 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_DISABLE_TRELLIS_QUANT, 1), 791 AOM_CODEC_OK); 792 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DIST_WTD_COMP, 0), 793 AOM_CODEC_OK); 794 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DIFF_WTD_COMP, 0), 795 AOM_CODEC_OK); 796 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DUAL_FILTER, 0), 797 AOM_CODEC_OK); 798 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTERINTRA_COMP, 0), 799 AOM_CODEC_OK); 800 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTERINTRA_WEDGE, 0), 801 AOM_CODEC_OK); 802 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTRA_EDGE_FILTER, 0), 803 AOM_CODEC_OK); 804 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTRABC, 0), AOM_CODEC_OK); 805 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_MASKED_COMP, 0), 806 AOM_CODEC_OK); 807 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_PAETH_INTRA, 0), 808 AOM_CODEC_OK); 809 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_QM, 0), AOM_CODEC_OK); 810 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_RECT_PARTITIONS, 0), 811 AOM_CODEC_OK); 812 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_RESTORATION, 0), 813 AOM_CODEC_OK); 814 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_SMOOTH_INTERINTRA, 0), 815 AOM_CODEC_OK); 816 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_TX64, 0), AOM_CODEC_OK); 817 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MAX_REFERENCE_FRAMES, 3), 818 AOM_CODEC_OK); 819 ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK); 820 821 aom_svc_params_t svc_params = {}; 822 svc_params.number_spatial_layers = 2; 823 svc_params.number_temporal_layers = 1; 824 svc_params.max_quantizers[0] = svc_params.max_quantizers[1] = 56; 825 svc_params.min_quantizers[0] = svc_params.min_quantizers[1] = 10; 826 svc_params.scaling_factor_num[0] = svc_params.scaling_factor_num[1] = 1; 827 svc_params.scaling_factor_den[0] = 2; 828 svc_params.scaling_factor_den[1] = 1; 829 svc_params.layer_target_bitrate[0] = cfg.rc_target_bitrate; 830 svc_params.framerate_factor[0] = 1; 831 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_PARAMS, &svc_params), 832 AOM_CODEC_OK); 833 834 aom_svc_layer_id_t layer_id = {}; 835 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id), 836 AOM_CODEC_OK); 837 838 aom_svc_ref_frame_config_t ref_frame_config = {}; 839 ref_frame_config.refresh[0] = 1; 840 ASSERT_EQ( 841 aom_codec_control(&enc, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config), 842 AOM_CODEC_OK); 843 844 // Create input image. 845 aom_image_t *const image = 846 CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 847 ASSERT_NE(image, nullptr); 848 849 // Encode layer 0. 850 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK); 851 852 layer_id.spatial_layer_id = 1; 853 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id), 854 AOM_CODEC_OK); 855 856 ref_frame_config.refresh[0] = 0; 857 ASSERT_EQ( 858 aom_codec_control(&enc, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config), 859 AOM_CODEC_OK); 860 861 // Encode layer 1. 862 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK); 863 864 // Free resources. 865 aom_img_free(image); 866 aom_codec_destroy(&enc); 867 } 868 869 TEST(EncodeAPI, AomediaIssue3509VbrMinSection2Percent) { 870 // Initialize libaom encoder. 871 aom_codec_iface_t *const iface = aom_codec_av1_cx(); 872 aom_codec_ctx_t enc; 873 aom_codec_enc_cfg_t cfg; 874 875 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), 876 AOM_CODEC_OK); 877 878 cfg.g_w = 1920; 879 cfg.g_h = 1080; 880 cfg.rc_target_bitrate = 1000000; 881 // Set this to more than 1 percent to cause a signed integer overflow in the 882 // multiplication rc->avg_frame_bandwidth * oxcf->rc_cfg.vbrmin_section in 883 // av1_rc_update_framerate() if the multiplication is done in the `int` type. 884 cfg.rc_2pass_vbr_minsection_pct = 2; 885 886 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 887 888 // Create input image. 889 aom_image_t *const image = 890 CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 891 ASSERT_NE(image, nullptr); 892 893 // Encode frame. 894 // `duration` can go as high as 300, but the UBSan error is gone if 895 // `duration` is 301 or higher. 896 ASSERT_EQ(aom_codec_encode(&enc, image, 0, /*duration=*/300, 0), 897 AOM_CODEC_OK); 898 899 // Free resources. 900 aom_img_free(image); 901 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 902 } 903 904 TEST(EncodeAPI, AomediaIssue3509VbrMinSection101Percent) { 905 // Initialize libaom encoder. 906 aom_codec_iface_t *const iface = aom_codec_av1_cx(); 907 aom_codec_ctx_t enc; 908 aom_codec_enc_cfg_t cfg; 909 910 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), 911 AOM_CODEC_OK); 912 913 cfg.g_w = 1920; 914 cfg.g_h = 1080; 915 cfg.rc_target_bitrate = 1000000; 916 // Set this to more than 100 percent to cause an error when vbr_min_bits is 917 // cast to `int` in av1_rc_update_framerate() if vbr_min_bits is not clamped 918 // to INT_MAX. 919 cfg.rc_2pass_vbr_minsection_pct = 101; 920 921 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 922 923 // Create input image. 924 aom_image_t *const image = 925 CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 926 ASSERT_NE(image, nullptr); 927 928 // Encode frame. 929 // `duration` can go as high as 300, but the UBSan error is gone if 930 // `duration` is 301 or higher. 931 ASSERT_EQ(aom_codec_encode(&enc, image, 0, /*duration=*/300, 0), 932 AOM_CODEC_OK); 933 934 // Free resources. 935 aom_img_free(image); 936 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 937 } 938 939 TEST(EncodeAPI, Buganizer392929025) { 940 // Initialize libaom encoder. 941 aom_codec_iface_t *const iface = aom_codec_av1_cx(); 942 aom_codec_ctx_t enc; 943 aom_codec_enc_cfg_t cfg; 944 945 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), 946 AOM_CODEC_OK); 947 948 cfg.g_w = 16; 949 cfg.g_h = 16; 950 951 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 952 953 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MATRIX_COEFFICIENTS, 954 AOM_CICP_MC_IDENTITY), 955 AOM_CODEC_OK); 956 957 // Create input image. 958 aom_image_t *const image = 959 CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 960 ASSERT_NE(image, nullptr); 961 962 // Encode frame. 963 // AOM_CICP_MC_IDENTITY requires subsampling to be 0. 964 EXPECT_EQ( 965 aom_codec_encode(&enc, image, /*pts=*/0, /*duration=*/1, /*flags=*/0), 966 AOM_CODEC_INVALID_PARAM); 967 968 // Attempt to reconfigure with non-zero subsampling. 969 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_CHROMA_SUBSAMPLING_X, 1), 970 AOM_CODEC_INVALID_PARAM); 971 EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_CHROMA_SUBSAMPLING_Y, 1), 972 AOM_CODEC_INVALID_PARAM); 973 974 // Free resources. 975 aom_img_free(image); 976 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 977 } 978 979 class EncodeAPIParameterized 980 : public testing::TestWithParam<std::tuple< 981 /*usage=*/unsigned int, /*speed=*/int, /*aq_mode=*/unsigned int>> {}; 982 983 // Encodes two frames at a given usage, speed, and aq_mode setting. 984 // Reproduces b/303023614 985 TEST_P(EncodeAPIParameterized, HighBDEncoderHighBDFrames) { 986 const unsigned int usage = std::get<0>(GetParam()); 987 int speed = std::get<1>(GetParam()); 988 989 if (speed == 10 && usage != AOM_USAGE_REALTIME) { 990 speed = 9; // 10 is only allowed in AOM_USAGE_REALTIME 991 } 992 993 aom_codec_iface_t *iface = aom_codec_av1_cx(); 994 aom_codec_enc_cfg_t cfg; 995 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage), AOM_CODEC_OK); 996 cfg.g_w = 500; 997 cfg.g_h = 400; 998 999 aom_codec_ctx_t enc; 1000 aom_codec_err_t init_status = 1001 aom_codec_enc_init(&enc, iface, &cfg, AOM_CODEC_USE_HIGHBITDEPTH); 1002 #if !CONFIG_AV1_HIGHBITDEPTH 1003 ASSERT_EQ(init_status, AOM_CODEC_INCAPABLE); 1004 #else 1005 ASSERT_EQ(init_status, AOM_CODEC_OK); 1006 1007 const unsigned int aq_mode = std::get<2>(GetParam()); 1008 1009 ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, speed), AOM_CODEC_OK); 1010 ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_AQ_MODE, aq_mode), AOM_CODEC_OK); 1011 1012 aom_image_t *image = 1013 aom_img_alloc(nullptr, AOM_IMG_FMT_I42016, cfg.g_w, cfg.g_h, 0); 1014 ASSERT_NE(image, nullptr); 1015 1016 for (unsigned int i = 0; i < image->d_h; ++i) { 1017 Memset16(image->planes[0] + i * image->stride[0], 128, image->d_w); 1018 } 1019 unsigned int uv_h = (image->d_h + 1) / 2; 1020 unsigned int uv_w = (image->d_w + 1) / 2; 1021 for (unsigned int i = 0; i < uv_h; ++i) { 1022 Memset16(image->planes[1] + i * image->stride[1], 128, uv_w); 1023 Memset16(image->planes[2] + i * image->stride[2], 128, uv_w); 1024 } 1025 1026 // Encode two frames. 1027 ASSERT_EQ( 1028 aom_codec_encode(&enc, image, /*pts=*/0, /*duration=*/1, /*flags=*/0), 1029 AOM_CODEC_OK); 1030 ASSERT_EQ( 1031 aom_codec_encode(&enc, image, /*pts=*/1, /*duration=*/1, /*flags=*/0), 1032 AOM_CODEC_OK); 1033 1034 aom_img_free(image); 1035 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 1036 #endif 1037 } 1038 1039 const unsigned int kUsages[] = { 1040 AOM_USAGE_REALTIME, 1041 #if !CONFIG_REALTIME_ONLY 1042 AOM_USAGE_GOOD_QUALITY, 1043 AOM_USAGE_ALL_INTRA, 1044 #endif 1045 }; 1046 1047 INSTANTIATE_TEST_SUITE_P(All, EncodeAPIParameterized, 1048 testing::Combine( 1049 /*usage=*/testing::ValuesIn(kUsages), 1050 /*speed=*/testing::Values(6, 7, 10), 1051 /*aq_mode=*/testing::Values(0, 1, 2, 3))); 1052 1053 #if !CONFIG_REALTIME_ONLY 1054 TEST(EncodeAPI, AllIntraMode) { 1055 aom_codec_iface_t *iface = aom_codec_av1_cx(); 1056 aom_codec_ctx_t enc; 1057 aom_codec_enc_cfg_t cfg; 1058 EXPECT_EQ(AOM_CODEC_OK, 1059 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_ALL_INTRA)); 1060 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 1061 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 1062 1063 // Set g_lag_in_frames to a nonzero value. This should cause 1064 // aom_codec_enc_init() to fail. 1065 EXPECT_EQ(AOM_CODEC_OK, 1066 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_ALL_INTRA)); 1067 cfg.g_lag_in_frames = 1; 1068 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0)); 1069 1070 // Set kf_max_dist to a nonzero value. This should cause aom_codec_enc_init() 1071 // to fail. 1072 EXPECT_EQ(AOM_CODEC_OK, 1073 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_ALL_INTRA)); 1074 cfg.kf_max_dist = 1; 1075 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0)); 1076 } 1077 1078 TEST(EncodeAPI, AllIntraAndUsePsnr) { 1079 aom_codec_iface_t *iface = aom_codec_av1_cx(); 1080 aom_codec_enc_cfg_t cfg; 1081 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_ALL_INTRA), 1082 AOM_CODEC_OK); 1083 1084 aom_codec_ctx_t enc; 1085 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, AOM_CODEC_USE_PSNR), 1086 AOM_CODEC_OK); 1087 1088 aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 1089 ASSERT_NE(image, nullptr); 1090 1091 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK); 1092 const aom_codec_cx_pkt_t *pkt; 1093 aom_codec_iter_t iter = nullptr; 1094 while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) { 1095 if (pkt->kind != AOM_CODEC_CX_FRAME_PKT) { 1096 ASSERT_EQ(pkt->kind, AOM_CODEC_PSNR_PKT); 1097 } 1098 } 1099 1100 aom_img_free(image); 1101 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 1102 } 1103 1104 TEST(EncodeAPI, AllIntraAndTuneIq) { 1105 aom_codec_iface_t *iface = aom_codec_av1_cx(); 1106 aom_codec_enc_cfg_t cfg; 1107 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_ALL_INTRA), 1108 AOM_CODEC_OK); 1109 1110 aom_codec_ctx_t enc; 1111 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 1112 1113 ASSERT_EQ(aom_codec_control(&enc, AOME_SET_TUNING, AOM_TUNE_SSIMULACRA2), 1114 AOM_CODEC_OK); 1115 1116 aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 1117 ASSERT_NE(image, nullptr); 1118 1119 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK); 1120 const aom_codec_cx_pkt_t *pkt; 1121 aom_codec_iter_t iter = nullptr; 1122 pkt = aom_codec_get_cx_data(&enc, &iter); 1123 ASSERT_NE(pkt, nullptr); 1124 ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); 1125 pkt = aom_codec_get_cx_data(&enc, &iter); 1126 ASSERT_EQ(pkt, nullptr); 1127 1128 // Flush the encoder. 1129 ASSERT_EQ(aom_codec_encode(&enc, nullptr, 0, 0, 0), AOM_CODEC_OK); 1130 iter = nullptr; 1131 pkt = aom_codec_get_cx_data(&enc, &iter); 1132 ASSERT_EQ(pkt, nullptr); 1133 1134 aom_img_free(image); 1135 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 1136 } 1137 1138 // A test that reproduces bug aomedia:3534. 1139 TEST(EncodeAPI, AllIntraAndNoRefLast) { 1140 aom_codec_iface_t *iface = aom_codec_av1_cx(); 1141 aom_codec_enc_cfg_t cfg; 1142 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_ALL_INTRA), 1143 AOM_CODEC_OK); 1144 1145 aom_codec_ctx_t enc; 1146 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 1147 1148 aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 1149 ASSERT_NE(image, nullptr); 1150 1151 ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, AOM_EFLAG_NO_REF_LAST), 1152 AOM_CODEC_OK); 1153 1154 aom_img_free(image); 1155 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 1156 } 1157 #endif // !CONFIG_REALTIME_ONLY 1158 1159 TEST(EncodeAPI, PerFramePsnr) { 1160 aom_codec_iface_t *iface = aom_codec_av1_cx(); 1161 aom_codec_enc_cfg_t cfg; 1162 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), 1163 AOM_CODEC_OK); 1164 ASSERT_EQ(cfg.g_lag_in_frames, 0); 1165 1166 aom_codec_ctx_t enc; 1167 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 1168 1169 aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 1170 ASSERT_NE(image, nullptr); 1171 1172 aom_enc_frame_flags_t psnr_flags = AOM_EFLAG_CALCULATE_PSNR; 1173 ASSERT_EQ( 1174 aom_codec_encode(&enc, image, /*pts=*/0, /*duration=*/1, psnr_flags), 1175 AOM_CODEC_OK); 1176 1177 const aom_codec_cx_pkt_t *pkt; 1178 aom_codec_iter_t iter = nullptr; 1179 bool had_psnr = false; 1180 while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) { 1181 if (pkt->kind != AOM_CODEC_CX_FRAME_PKT) { 1182 ASSERT_EQ(pkt->kind, AOM_CODEC_PSNR_PKT); 1183 had_psnr = true; 1184 } 1185 } 1186 EXPECT_TRUE(had_psnr); 1187 1188 aom_enc_frame_flags_t no_psnr_flags = 0; 1189 ASSERT_EQ( 1190 aom_codec_encode(&enc, image, /*pts=*/1, /*duration=*/1, no_psnr_flags), 1191 AOM_CODEC_OK); 1192 1193 iter = nullptr; 1194 had_psnr = false; 1195 while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) { 1196 if (pkt->kind != AOM_CODEC_CX_FRAME_PKT) { 1197 ASSERT_EQ(pkt->kind, AOM_CODEC_PSNR_PKT); 1198 had_psnr = true; 1199 } 1200 } 1201 #if CONFIG_INTERNAL_STATS 1202 // CONFIG_INTERNAL_STATS unconditionally generates PSNR. 1203 EXPECT_TRUE(had_psnr); 1204 #else 1205 EXPECT_FALSE(had_psnr); 1206 #endif // CONFIG_INTERNAL_STATS 1207 1208 aom_img_free(image); 1209 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 1210 } 1211 1212 #if !CONFIG_REALTIME_ONLY 1213 TEST(EncodeAPI, PerFramePsnrGoodQualityZeroLagInFrames) { 1214 aom_codec_iface_t *iface = aom_codec_av1_cx(); 1215 aom_codec_enc_cfg_t cfg; 1216 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY), 1217 AOM_CODEC_OK); 1218 ASSERT_NE(cfg.g_lag_in_frames, 0); 1219 cfg.g_lag_in_frames = 0; 1220 1221 aom_codec_ctx_t enc; 1222 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 1223 1224 aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 1225 ASSERT_NE(image, nullptr); 1226 1227 aom_enc_frame_flags_t psnr_flags = AOM_EFLAG_CALCULATE_PSNR; 1228 ASSERT_EQ( 1229 aom_codec_encode(&enc, image, /*pts=*/0, /*duration=*/1, psnr_flags), 1230 AOM_CODEC_OK); 1231 const aom_codec_cx_pkt_t *pkt; 1232 aom_codec_iter_t iter = nullptr; 1233 bool had_psnr = false; 1234 while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) { 1235 if (pkt->kind != AOM_CODEC_CX_FRAME_PKT) { 1236 ASSERT_EQ(pkt->kind, AOM_CODEC_PSNR_PKT); 1237 had_psnr = true; 1238 } 1239 } 1240 EXPECT_TRUE(had_psnr); 1241 1242 aom_enc_frame_flags_t no_psnr_flags = 0; 1243 ASSERT_EQ( 1244 aom_codec_encode(&enc, image, /*pts=*/1, /*duration=*/1, no_psnr_flags), 1245 AOM_CODEC_OK); 1246 iter = nullptr; 1247 had_psnr = false; 1248 while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) { 1249 if (pkt->kind != AOM_CODEC_CX_FRAME_PKT) { 1250 ASSERT_EQ(pkt->kind, AOM_CODEC_PSNR_PKT); 1251 had_psnr = true; 1252 } 1253 } 1254 #if CONFIG_INTERNAL_STATS 1255 // CONFIG_INTERNAL_STATS unconditionally generates PSNR. 1256 EXPECT_TRUE(had_psnr); 1257 #else 1258 EXPECT_FALSE(had_psnr); 1259 #endif // CONFIG_INTERNAL_STATS 1260 aom_img_free(image); 1261 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 1262 } 1263 1264 TEST(EncodeAPI, PerFramePsnrNotSupportedWithLagInFrames) { 1265 aom_codec_iface_t *iface = aom_codec_av1_cx(); 1266 aom_codec_enc_cfg_t cfg; 1267 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY), 1268 AOM_CODEC_OK); 1269 ASSERT_NE(cfg.g_lag_in_frames, 0); 1270 1271 aom_codec_ctx_t enc; 1272 ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); 1273 1274 aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h); 1275 ASSERT_NE(image, nullptr); 1276 1277 aom_enc_frame_flags_t psnr_flags = AOM_EFLAG_CALCULATE_PSNR; 1278 ASSERT_EQ( 1279 aom_codec_encode(&enc, image, /*pts=*/0, /*duration=*/1, psnr_flags), 1280 AOM_CODEC_INCAPABLE); 1281 1282 aom_img_free(image); 1283 ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); 1284 } 1285 #endif // !CONFIG_REALTIME_ONLY 1286 1287 } // namespace