forced_max_frame_width_height_test.cc (10087B)
1 /* 2 * Copyright (c) 2022, 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 // Tests for https://crbug.com/aomedia/3326. 13 // 14 // Set cfg.g_forced_max_frame_width and cfg.g_forced_max_frame_height and 15 // encode two frames of increasing sizes. The second aom_codec_encode() should 16 // not crash or have memory errors. 17 18 #include <algorithm> 19 #include <memory> 20 #include <vector> 21 22 #include "aom/aomcx.h" 23 #include "aom/aom_encoder.h" 24 #include "config/aom_config.h" 25 #include "gtest/gtest.h" 26 27 namespace { 28 29 // cfg.g_lag_in_frames must be set to 0 or 1 to allow the frame size to change, 30 // as required by the following check in encoder_set_config() in 31 // av1/av1_cx_iface.c: 32 // 33 // if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h) { 34 // if (cfg->g_lag_in_frames > 1 || cfg->g_pass != AOM_RC_ONE_PASS) 35 // ERROR("Cannot change width or height after initialization"); 36 // ... 37 // } 38 39 void RunTest(unsigned int usage, unsigned int lag_in_frames, 40 const char *tune_metric) { 41 // A buffer of gray samples. Large enough for 128x128 and 256x256, YUV 4:2:0. 42 constexpr size_t kImageDataSize = 256 * 256 + 2 * 128 * 128; 43 std::unique_ptr<unsigned char[]> img_data(new unsigned char[kImageDataSize]); 44 ASSERT_NE(img_data, nullptr); 45 memset(img_data.get(), 128, kImageDataSize); 46 47 aom_codec_iface_t *iface = aom_codec_av1_cx(); 48 aom_codec_enc_cfg_t cfg; 49 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, usage)); 50 cfg.g_w = 128; 51 cfg.g_h = 128; 52 cfg.g_forced_max_frame_width = 256; 53 cfg.g_forced_max_frame_height = 256; 54 cfg.g_lag_in_frames = lag_in_frames; 55 aom_codec_ctx_t enc; 56 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 57 EXPECT_EQ(AOM_CODEC_OK, aom_codec_set_option(&enc, "tune", tune_metric)); 58 59 aom_image_t img; 60 EXPECT_EQ(&img, 61 aom_img_wrap(&img, AOM_IMG_FMT_I420, 128, 128, 1, img_data.get())); 62 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0)); 63 64 cfg.g_w = 256; 65 cfg.g_h = 256; 66 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg)); 67 68 EXPECT_EQ(&img, 69 aom_img_wrap(&img, AOM_IMG_FMT_I420, 256, 256, 1, img_data.get())); 70 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0)); 71 72 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 0, 0)); 73 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 74 } 75 76 #if !CONFIG_REALTIME_ONLY 77 78 TEST(EncodeForcedMaxFrameWidthHeight, GoodQualityLag0TunePSNR) { 79 RunTest(AOM_USAGE_GOOD_QUALITY, /*lag_in_frames=*/0, "psnr"); 80 } 81 82 TEST(EncodeForcedMaxFrameWidthHeight, GoodQualityLag0TuneSSIM) { 83 RunTest(AOM_USAGE_GOOD_QUALITY, /*lag_in_frames=*/0, "ssim"); 84 } 85 86 TEST(EncodeForcedMaxFrameWidthHeight, GoodQualityLag1TunePSNR) { 87 RunTest(AOM_USAGE_GOOD_QUALITY, /*lag_in_frames=*/1, "psnr"); 88 } 89 90 TEST(EncodeForcedMaxFrameWidthHeight, GoodQualityLag1TuneSSIM) { 91 RunTest(AOM_USAGE_GOOD_QUALITY, /*lag_in_frames=*/1, "ssim"); 92 } 93 94 void FillImageGradient(aom_image_t *image, int bit_depth) { 95 assert(image->range == AOM_CR_FULL_RANGE); 96 for (int plane = 0; plane < 3; plane++) { 97 const int plane_width = aom_img_plane_width(image, plane); 98 const int plane_height = aom_img_plane_height(image, plane); 99 unsigned char *row = image->planes[plane]; 100 const int stride = image->stride[plane]; 101 for (int y = 0; y < plane_height; ++y) { 102 for (int x = 0; x < plane_width; ++x) { 103 const int value = (x + y) * ((1 << bit_depth) - 1) / 104 std::max(1, plane_width + plane_height - 2); 105 assert(value >= 0 && value <= (1 << bit_depth) - 1); 106 if (bit_depth > 8) { 107 reinterpret_cast<uint16_t *>(row)[x] = static_cast<uint16_t>(value); 108 } else { 109 row[x] = static_cast<unsigned char>(value); 110 } 111 } 112 row += stride; 113 } 114 } 115 } 116 117 TEST(EncodeForcedMaxFrameWidthHeight, DimensionDecreasing) { 118 constexpr int kWidth = 128; 119 constexpr int kHeight = 128; 120 constexpr size_t kBufferSize = 3 * kWidth * kHeight; 121 std::vector<unsigned char> buffer(kBufferSize); 122 123 aom_image_t img; 124 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidth, kHeight, 1, 125 buffer.data())); 126 img.cp = AOM_CICP_CP_UNSPECIFIED; 127 img.tc = AOM_CICP_TC_UNSPECIFIED; 128 img.mc = AOM_CICP_MC_UNSPECIFIED; 129 img.range = AOM_CR_FULL_RANGE; 130 FillImageGradient(&img, 8); 131 132 aom_codec_iface_t *iface = aom_codec_av1_cx(); 133 aom_codec_enc_cfg_t cfg; 134 EXPECT_EQ(AOM_CODEC_OK, 135 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY)); 136 cfg.rc_end_usage = AOM_Q; 137 cfg.g_profile = 0; 138 cfg.g_bit_depth = AOM_BITS_8; 139 cfg.g_input_bit_depth = 8; 140 cfg.g_w = kWidth; 141 cfg.g_h = kHeight; 142 cfg.g_forced_max_frame_width = kWidth; 143 cfg.g_forced_max_frame_height = kHeight; 144 cfg.g_lag_in_frames = 1; 145 cfg.rc_min_quantizer = 20; 146 cfg.rc_max_quantizer = 40; 147 aom_codec_ctx_t enc; 148 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 149 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 30)); 150 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 6)); 151 EXPECT_EQ(AOM_CODEC_OK, 152 aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_FULL_RANGE)); 153 EXPECT_EQ(AOM_CODEC_OK, 154 aom_codec_control(&enc, AOME_SET_TUNING, AOM_TUNE_SSIM)); 155 156 // First frame 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_NE(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u); 164 pkt = aom_codec_get_cx_data(&enc, &iter); 165 EXPECT_EQ(pkt, nullptr); 166 167 // Second frame 168 constexpr int kWidthSmall = 64; 169 constexpr int kHeightSmall = 64; 170 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidthSmall, 171 kHeightSmall, 1, buffer.data())); 172 img.cp = AOM_CICP_CP_UNSPECIFIED; 173 img.tc = AOM_CICP_TC_UNSPECIFIED; 174 img.mc = AOM_CICP_MC_UNSPECIFIED; 175 img.range = AOM_CR_FULL_RANGE; 176 FillImageGradient(&img, 8); 177 cfg.g_w = kWidthSmall; 178 cfg.g_h = kHeightSmall; 179 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg)); 180 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0)); 181 iter = nullptr; 182 pkt = aom_codec_get_cx_data(&enc, &iter); 183 ASSERT_NE(pkt, nullptr); 184 EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); 185 // pkt->data.frame.flags is 0. 186 EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u); 187 pkt = aom_codec_get_cx_data(&enc, &iter); 188 EXPECT_EQ(pkt, nullptr); 189 190 // Flush encoder 191 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0)); 192 iter = nullptr; 193 pkt = aom_codec_get_cx_data(&enc, &iter); 194 EXPECT_EQ(pkt, nullptr); 195 196 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 197 } 198 199 #endif // !CONFIG_REALTIME_ONLY 200 201 TEST(EncodeForcedMaxFrameWidthHeight, RealtimeLag0TunePSNR) { 202 RunTest(AOM_USAGE_REALTIME, /*lag_in_frames=*/0, "psnr"); 203 } 204 205 TEST(EncodeForcedMaxFrameWidthHeight, RealtimeLag0TuneSSIM) { 206 RunTest(AOM_USAGE_REALTIME, /*lag_in_frames=*/0, "ssim"); 207 } 208 209 TEST(EncodeForcedMaxFrameWidthHeight, RealtimeLag1TunePSNR) { 210 RunTest(AOM_USAGE_REALTIME, /*lag_in_frames=*/1, "psnr"); 211 } 212 213 TEST(EncodeForcedMaxFrameWidthHeight, RealtimeLag1TuneSSIM) { 214 RunTest(AOM_USAGE_REALTIME, /*lag_in_frames=*/1, "ssim"); 215 } 216 217 TEST(EncodeForcedMaxFrameWidthHeight, MaxFrameSizeTooBig) { 218 aom_codec_iface_t *iface = aom_codec_av1_cx(); 219 aom_codec_enc_cfg_t cfg; 220 EXPECT_EQ(AOM_CODEC_OK, 221 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME)); 222 cfg.g_w = 256; 223 cfg.g_h = 256; 224 cfg.g_forced_max_frame_width = 131072; 225 cfg.g_forced_max_frame_height = 131072; 226 aom_codec_ctx_t enc; 227 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0)); 228 } 229 230 TEST(EncodeForcedMaxFrameWidthHeight, FirstFrameTooBig) { 231 aom_codec_iface_t *iface = aom_codec_av1_cx(); 232 aom_codec_enc_cfg_t cfg; 233 EXPECT_EQ(AOM_CODEC_OK, 234 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME)); 235 cfg.g_w = 258; 236 cfg.g_h = 256; 237 cfg.g_forced_max_frame_width = 256; 238 cfg.g_forced_max_frame_height = 256; 239 aom_codec_ctx_t enc; 240 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0)); 241 cfg.g_w = 256; 242 cfg.g_h = 258; 243 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0)); 244 cfg.g_w = 256; 245 cfg.g_h = 256; 246 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 247 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 248 } 249 250 TEST(EncodeForcedMaxFrameWidthHeight, SecondFrameTooBig) { 251 // A buffer of gray samples. Large enough for 128x128 and 256x256, YUV 4:2:0. 252 constexpr size_t kImageDataSize = 256 * 256 + 2 * 128 * 128; 253 std::unique_ptr<unsigned char[]> img_data(new unsigned char[kImageDataSize]); 254 ASSERT_NE(img_data, nullptr); 255 memset(img_data.get(), 128, kImageDataSize); 256 257 aom_codec_iface_t *iface = aom_codec_av1_cx(); 258 aom_codec_enc_cfg_t cfg; 259 EXPECT_EQ(AOM_CODEC_OK, 260 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME)); 261 cfg.g_w = 128; 262 cfg.g_h = 128; 263 cfg.g_forced_max_frame_width = 255; 264 cfg.g_forced_max_frame_height = 256; 265 aom_codec_ctx_t enc; 266 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 267 268 aom_image_t img; 269 EXPECT_EQ(&img, 270 aom_img_wrap(&img, AOM_IMG_FMT_I420, 128, 128, 1, img_data.get())); 271 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0)); 272 273 cfg.g_w = 256; 274 cfg.g_h = 256; 275 EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_config_set(&enc, &cfg)); 276 277 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 278 } 279 280 } // namespace