frame_size_tests.cc (13592B)
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 <array> 13 #include <memory> 14 15 #include "gtest/gtest.h" 16 #include "test/codec_factory.h" 17 #include "test/video_source.h" 18 #include "test/util.h" 19 20 namespace { 21 22 class AV1FrameSizeTests : public ::testing::Test, 23 public ::libaom_test::EncoderTest { 24 protected: 25 AV1FrameSizeTests() 26 : EncoderTest(&::libaom_test::kAV1), expected_res_(AOM_CODEC_OK) {} 27 ~AV1FrameSizeTests() override = default; 28 29 void SetUp() override { InitializeConfig(::libaom_test::kRealTime); } 30 31 bool HandleDecodeResult(const aom_codec_err_t res_dec, 32 libaom_test::Decoder *decoder) override { 33 EXPECT_EQ(expected_res_, res_dec) << decoder->DecodeError(); 34 return !::testing::Test::HasFailure(); 35 } 36 37 void PreEncodeFrameHook(::libaom_test::VideoSource *video, 38 ::libaom_test::Encoder *encoder) override { 39 if (video->frame() == 0) { 40 encoder->Control(AOME_SET_CPUUSED, 7); 41 encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1); 42 encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7); 43 encoder->Control(AOME_SET_ARNR_STRENGTH, 5); 44 } 45 } 46 47 int expected_res_; 48 }; 49 50 #if CONFIG_SIZE_LIMIT 51 // TODO(Casey.Smalley@arm.com) fails due to newer bounds checks that get caught 52 // before the assert below added in ebc2714d71a834fc32a19eef0a81f51fbc47db01 53 TEST_F(AV1FrameSizeTests, DISABLED_TestInvalidSizes) { 54 ::libaom_test::RandomVideoSource video; 55 56 video.SetSize(DECODE_WIDTH_LIMIT + 16, DECODE_HEIGHT_LIMIT + 16); 57 video.set_limit(2); 58 expected_res_ = AOM_CODEC_CORRUPT_FRAME; 59 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 60 } 61 62 // TODO(Casey.Smalley@arm.com) similar to the above test, needs to be 63 // updated for the new rejection case 64 TEST_F(AV1FrameSizeTests, DISABLED_LargeValidSizes) { 65 ::libaom_test::RandomVideoSource video; 66 67 video.SetSize(DECODE_WIDTH_LIMIT, DECODE_HEIGHT_LIMIT); 68 video.set_limit(2); 69 expected_res_ = AOM_CODEC_OK; 70 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 71 } 72 #endif 73 74 TEST_F(AV1FrameSizeTests, OneByOneVideo) { 75 ::libaom_test::RandomVideoSource video; 76 77 video.SetSize(1, 1); 78 video.set_limit(2); 79 expected_res_ = AOM_CODEC_OK; 80 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 81 } 82 83 // Parameters: AOM_USAGE_*, aom_rc_mode, cpu-used. 84 class AV1ResolutionChange 85 : public testing::TestWithParam<std::tuple<int, aom_rc_mode, int>> { 86 public: 87 AV1ResolutionChange() 88 : usage_(std::get<0>(GetParam())), rc_mode_(std::get<1>(GetParam())), 89 cpu_used_(std::get<2>(GetParam())) {} 90 AV1ResolutionChange(const AV1ResolutionChange &) = delete; 91 AV1ResolutionChange &operator=(const AV1ResolutionChange &) = delete; 92 ~AV1ResolutionChange() override = default; 93 94 protected: 95 int usage_; 96 aom_rc_mode rc_mode_; 97 int cpu_used_; 98 }; 99 100 TEST_P(AV1ResolutionChange, InvalidRefSize) { 101 struct FrameSize { 102 unsigned int width; 103 unsigned int height; 104 }; 105 static constexpr std::array<FrameSize, 3> kFrameSizes = { { 106 { 1768, 200 }, 107 { 50, 200 }, 108 { 850, 200 }, 109 } }; 110 111 aom_codec_iface_t *iface = aom_codec_av1_cx(); 112 aom_codec_enc_cfg_t cfg; 113 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage_), AOM_CODEC_OK); 114 115 // Resolution changes are only permitted with one pass encoding with no lag. 116 cfg.g_pass = AOM_RC_ONE_PASS; 117 cfg.g_lag_in_frames = 0; 118 cfg.rc_end_usage = rc_mode_; 119 120 aom_codec_ctx_t ctx; 121 EXPECT_EQ(aom_codec_enc_init(&ctx, iface, &cfg, 0), AOM_CODEC_OK); 122 std::unique_ptr<aom_codec_ctx_t, decltype(&aom_codec_destroy)> enc( 123 &ctx, &aom_codec_destroy); 124 EXPECT_EQ(aom_codec_control(enc.get(), AOME_SET_CPUUSED, cpu_used_), 125 AOM_CODEC_OK); 126 127 size_t frame_count = 0; 128 ::libaom_test::RandomVideoSource video; 129 video.Begin(); 130 constexpr int kNumFramesPerResolution = 2; 131 for (const auto &frame_size : kFrameSizes) { 132 cfg.g_w = frame_size.width; 133 cfg.g_h = frame_size.height; 134 EXPECT_EQ(aom_codec_enc_config_set(enc.get(), &cfg), AOM_CODEC_OK); 135 video.SetSize(cfg.g_w, cfg.g_h); 136 137 aom_codec_iter_t iter; 138 const aom_codec_cx_pkt_t *pkt; 139 140 for (int i = 0; i < kNumFramesPerResolution; ++i) { 141 video.Next(); // SetSize() does not call FillFrame(). 142 EXPECT_EQ(aom_codec_encode(enc.get(), video.img(), video.pts(), 143 video.duration(), /*flags=*/0), 144 AOM_CODEC_OK); 145 146 iter = nullptr; 147 while ((pkt = aom_codec_get_cx_data(enc.get(), &iter)) != nullptr) { 148 ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); 149 // The frame following a resolution change should be a keyframe as the 150 // change is too extreme to allow previous references to be used. 151 if (i == 0 || usage_ == AOM_USAGE_ALL_INTRA) { 152 EXPECT_NE(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u) 153 << "frame " << frame_count; 154 } 155 frame_count++; 156 } 157 } 158 } 159 160 EXPECT_EQ(frame_count, kNumFramesPerResolution * kFrameSizes.size()); 161 } 162 163 TEST_P(AV1ResolutionChange, RandomInput) { 164 struct FrameSize { 165 unsigned int width; 166 unsigned int height; 167 }; 168 static constexpr std::array<FrameSize, 4> kFrameSizes = { { 169 { 50, 200 }, 170 { 100, 200 }, 171 { 100, 300 }, 172 { 200, 400 }, 173 } }; 174 175 aom_codec_iface_t *iface = aom_codec_av1_cx(); 176 aom_codec_enc_cfg_t cfg; 177 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage_), AOM_CODEC_OK); 178 179 // Resolution changes are only permitted with one pass encoding with no lag. 180 cfg.g_pass = AOM_RC_ONE_PASS; 181 cfg.g_lag_in_frames = 0; 182 cfg.rc_end_usage = rc_mode_; 183 // For random input source, if max frame sizes are not set, the first encoded 184 // frame size will be locked as the max frame size, and the encoder will 185 // identify it as unsupported bitstream. 186 unsigned int max_width = cfg.g_w; // default frame width 187 unsigned int max_height = cfg.g_h; // default frame height 188 for (const auto &frame_size : kFrameSizes) { 189 max_width = frame_size.width > max_width ? frame_size.width : max_width; 190 max_height = 191 frame_size.height > max_height ? frame_size.height : max_height; 192 } 193 cfg.g_forced_max_frame_width = max_width; 194 cfg.g_forced_max_frame_height = max_height; 195 196 aom_codec_ctx_t ctx; 197 EXPECT_EQ(aom_codec_enc_init(&ctx, iface, &cfg, 0), AOM_CODEC_OK); 198 std::unique_ptr<aom_codec_ctx_t, decltype(&aom_codec_destroy)> enc( 199 &ctx, &aom_codec_destroy); 200 EXPECT_EQ(aom_codec_control(enc.get(), AOME_SET_CPUUSED, cpu_used_), 201 AOM_CODEC_OK); 202 203 size_t frame_count = 0; 204 ::libaom_test::RandomVideoSource video; 205 video.Begin(); 206 constexpr int kNumFramesPerResolution = 2; 207 for (const auto &frame_size : kFrameSizes) { 208 cfg.g_w = frame_size.width; 209 cfg.g_h = frame_size.height; 210 EXPECT_EQ(aom_codec_enc_config_set(enc.get(), &cfg), AOM_CODEC_OK); 211 video.SetSize(cfg.g_w, cfg.g_h); 212 213 aom_codec_iter_t iter; 214 const aom_codec_cx_pkt_t *pkt; 215 216 for (int i = 0; i < kNumFramesPerResolution; ++i) { 217 video.Next(); // SetSize() does not call FillFrame(). 218 EXPECT_EQ(aom_codec_encode(enc.get(), video.img(), video.pts(), 219 video.duration(), /*flags=*/0), 220 AOM_CODEC_OK); 221 222 iter = nullptr; 223 while ((pkt = aom_codec_get_cx_data(enc.get(), &iter)) != nullptr) { 224 ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); 225 // The frame following a resolution change should be a keyframe as the 226 // change is too extreme to allow previous references to be used. 227 if (i == 0 || usage_ == AOM_USAGE_ALL_INTRA) { 228 EXPECT_NE(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u) 229 << "frame " << frame_count; 230 } 231 frame_count++; 232 } 233 } 234 } 235 236 EXPECT_EQ(frame_count, kNumFramesPerResolution * kFrameSizes.size()); 237 } 238 239 TEST_P(AV1ResolutionChange, InvalidInputSize) { 240 struct FrameSize { 241 unsigned int width; 242 unsigned int height; 243 }; 244 static constexpr std::array<FrameSize, 3> kFrameSizes = { { 245 { 1768, 0 }, 246 { 0, 200 }, 247 { 850, 200 }, 248 } }; 249 250 aom_codec_iface_t *iface = aom_codec_av1_cx(); 251 aom_codec_enc_cfg_t cfg; 252 ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage_), AOM_CODEC_OK); 253 254 // Resolution changes are only permitted with one pass encoding with no lag. 255 cfg.g_pass = AOM_RC_ONE_PASS; 256 cfg.g_lag_in_frames = 0; 257 cfg.rc_end_usage = rc_mode_; 258 259 aom_codec_ctx_t ctx; 260 EXPECT_EQ(aom_codec_enc_init(&ctx, iface, &cfg, 0), AOM_CODEC_OK); 261 std::unique_ptr<aom_codec_ctx_t, decltype(&aom_codec_destroy)> enc( 262 &ctx, &aom_codec_destroy); 263 EXPECT_EQ(aom_codec_control(enc.get(), AOME_SET_CPUUSED, cpu_used_), 264 AOM_CODEC_OK); 265 266 int frame_count = 0; 267 ::libaom_test::RandomVideoSource video; 268 video.Begin(); 269 constexpr int kNumFramesPerResolution = 2; 270 for (const auto &frame_size : kFrameSizes) { 271 cfg.g_w = frame_size.width; 272 cfg.g_h = frame_size.height; 273 if (cfg.g_w < 1 || cfg.g_w > 65536 || cfg.g_h < 1 || cfg.g_h > 65536) { 274 EXPECT_EQ(aom_codec_enc_config_set(enc.get(), &cfg), 275 AOM_CODEC_INVALID_PARAM); 276 continue; 277 } 278 279 EXPECT_EQ(aom_codec_enc_config_set(enc.get(), &cfg), AOM_CODEC_OK); 280 video.SetSize(cfg.g_w, cfg.g_h); 281 282 aom_codec_iter_t iter; 283 const aom_codec_cx_pkt_t *pkt; 284 285 for (int i = 0; i < kNumFramesPerResolution; ++i) { 286 video.Next(); // SetSize() does not call FillFrame(). 287 EXPECT_EQ(aom_codec_encode(enc.get(), video.img(), video.pts(), 288 video.duration(), /*flags=*/0), 289 AOM_CODEC_OK); 290 291 iter = nullptr; 292 while ((pkt = aom_codec_get_cx_data(enc.get(), &iter)) != nullptr) { 293 ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT); 294 // The frame following a resolution change should be a keyframe as the 295 // change is too extreme to allow previous references to be used. 296 if (i == 0 || usage_ == AOM_USAGE_ALL_INTRA) { 297 EXPECT_NE(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u) 298 << "frame " << frame_count; 299 } 300 frame_count++; 301 } 302 } 303 } 304 305 EXPECT_EQ(frame_count, 2); 306 } 307 308 INSTANTIATE_TEST_SUITE_P( 309 Realtime, AV1ResolutionChange, 310 ::testing::Combine(::testing::Values(AOM_USAGE_REALTIME), 311 ::testing::Values(AOM_VBR, AOM_CBR), 312 ::testing::Range(6, 11))); 313 314 #if !CONFIG_REALTIME_ONLY 315 INSTANTIATE_TEST_SUITE_P( 316 GoodQuality, AV1ResolutionChange, 317 ::testing::Combine(::testing::Values(AOM_USAGE_GOOD_QUALITY), 318 ::testing::Values(AOM_VBR, AOM_CBR, AOM_CQ, AOM_Q), 319 ::testing::Range(2, 6))); 320 INSTANTIATE_TEST_SUITE_P( 321 GoodQualityLarge, AV1ResolutionChange, 322 ::testing::Combine(::testing::Values(AOM_USAGE_GOOD_QUALITY), 323 ::testing::Values(AOM_VBR, AOM_CBR, AOM_CQ, AOM_Q), 324 ::testing::Range(0, 2))); 325 INSTANTIATE_TEST_SUITE_P( 326 AllIntra, AV1ResolutionChange, 327 ::testing::Combine(::testing::Values(AOM_USAGE_ALL_INTRA), 328 ::testing::Values(AOM_Q), ::testing::Range(6, 10))); 329 330 struct FrameSizeParam { 331 unsigned int width; 332 unsigned int height; 333 }; 334 335 const FrameSizeParam FrameSizeTestParams[] = { { 96, 96 }, { 176, 144 } }; 336 337 // This unit test is used to validate the allocated size of compressed data 338 // (ctx->cx_data) buffer, by feeding pseudo random input to the encoder in 339 // lossless encoding mode. 340 // 341 // If compressed data buffer is not large enough, the av1_get_compressed_data() 342 // call in av1/av1_cx_iface.c will overflow the buffer. 343 class AV1LosslessFrameSizeTests 344 : public ::libaom_test::CodecTestWith2Params<FrameSizeParam, 345 ::libaom_test::TestMode>, 346 public ::libaom_test::EncoderTest { 347 protected: 348 AV1LosslessFrameSizeTests() 349 : EncoderTest(GET_PARAM(0)), frame_size_param_(GET_PARAM(1)), 350 encoding_mode_(GET_PARAM(2)) {} 351 ~AV1LosslessFrameSizeTests() override = default; 352 353 void SetUp() override { InitializeConfig(encoding_mode_); } 354 355 bool HandleDecodeResult(const aom_codec_err_t res_dec, 356 libaom_test::Decoder *decoder) override { 357 EXPECT_EQ(expected_res_, res_dec) << decoder->DecodeError(); 358 return !::testing::Test::HasFailure(); 359 } 360 361 void PreEncodeFrameHook(::libaom_test::VideoSource *video, 362 ::libaom_test::Encoder *encoder) override { 363 if (video->frame() == 0) { 364 encoder->Control(AOME_SET_CPUUSED, 6); 365 encoder->Control(AV1E_SET_LOSSLESS, 1); 366 } 367 } 368 369 const FrameSizeParam frame_size_param_; 370 const ::libaom_test::TestMode encoding_mode_; 371 int expected_res_; 372 }; 373 374 TEST_P(AV1LosslessFrameSizeTests, LosslessEncode) { 375 ::libaom_test::RandomVideoSource video; 376 377 video.SetSize(frame_size_param_.width, frame_size_param_.height); 378 video.set_limit(10); 379 expected_res_ = AOM_CODEC_OK; 380 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 381 } 382 383 AV1_INSTANTIATE_TEST_SUITE(AV1LosslessFrameSizeTests, 384 ::testing::ValuesIn(FrameSizeTestParams), 385 testing::Values(::libaom_test::kAllIntra)); 386 #endif // !CONFIG_REALTIME_ONLY 387 388 } // namespace