97 lines
3.4 KiB
C++
97 lines
3.4 KiB
C++
/*
|
|
* Copyright (c) 2026, Alliance for Open Media. All rights reserved.
|
|
*
|
|
* This source code is subject to the terms of the BSD 2 Clause License and
|
|
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
|
* was not distributed with this source code in the LICENSE file, you can
|
|
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
|
* Media Patent License 1.0 was not distributed with this source code in the
|
|
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
|
*/
|
|
|
|
// Test for encoding frames with dimensions > 32768 pixels.
|
|
//
|
|
// pickcdef.c used FULLPEL_MV (int16_t row/col) to store pixel positions in
|
|
// get_filt_error(). For frames taller than 32768 pixels, the pixel row
|
|
// overflows int16_t, wrapping to a negative value and causing an out-of-bounds
|
|
// read. aom_codec_encode() should not crash or read out of bounds. See bug
|
|
// 489473886.
|
|
|
|
#include <memory>
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "aom/aom_encoder.h"
|
|
#include "aom/aom_image.h"
|
|
#include "aom/aomcx.h"
|
|
#include "config/aom_config.h"
|
|
#include "test/video_source.h"
|
|
|
|
namespace {
|
|
|
|
// Encode a single frame with the given dimensions and flush.
|
|
void EncodeSingleFrame(unsigned int width, unsigned int height,
|
|
unsigned int usage, int cpu_used) {
|
|
aom_codec_iface_t *iface = aom_codec_av1_cx();
|
|
aom_codec_enc_cfg_t cfg;
|
|
ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage), AOM_CODEC_OK);
|
|
cfg.g_w = width;
|
|
cfg.g_h = height;
|
|
cfg.g_lag_in_frames = 0;
|
|
cfg.g_pass = AOM_RC_ONE_PASS;
|
|
// Use VBR with moderate QP to ensure non-skip blocks, which is necessary
|
|
// to exercise the CDEF search path. AOM_Q with low cq_level triggers an
|
|
// early return in adaptive CDEF for ALL_INTRA mode.
|
|
cfg.rc_end_usage = AOM_VBR;
|
|
cfg.rc_target_bitrate = 1000;
|
|
|
|
aom_codec_ctx_t ctx;
|
|
ASSERT_EQ(aom_codec_enc_init(&ctx, iface, &cfg, 0), AOM_CODEC_OK);
|
|
std::unique_ptr<aom_codec_ctx_t, decltype(&aom_codec_destroy)> enc(
|
|
&ctx, &aom_codec_destroy);
|
|
ASSERT_EQ(aom_codec_control(enc.get(), AOME_SET_CPUUSED, cpu_used),
|
|
AOM_CODEC_OK);
|
|
|
|
libaom_test::RandomVideoSource video;
|
|
video.SetSize(width, height);
|
|
video.SetImageFormat(AOM_IMG_FMT_I420);
|
|
video.Begin();
|
|
|
|
ASSERT_EQ(aom_codec_encode(enc.get(), video.img(), video.pts(),
|
|
/*duration=*/1, /*flags=*/0),
|
|
AOM_CODEC_OK)
|
|
<< aom_codec_error_detail(enc.get());
|
|
ASSERT_EQ(aom_codec_encode(enc.get(), nullptr, 0, 0, 0), AOM_CODEC_OK)
|
|
<< aom_codec_error_detail(enc.get());
|
|
}
|
|
|
|
class EncodeBigDimension
|
|
: public testing::TestWithParam<unsigned int /*usage*/> {};
|
|
|
|
// Height > 32768: triggers the CDEF int16_t overflow at superblock row 512.
|
|
// 32832 = 513 * 64, giving 513 superblock rows (fbr 0..512).
|
|
// Use ALL_INTRA at speed 6 so the full CDEF search runs (not CDEF_PICK_FROM_Q)
|
|
// while keeping encode time reasonable.
|
|
TEST_P(EncodeBigDimension, TallFrame) {
|
|
EncodeSingleFrame(/*width=*/64, /*height=*/32832, /*usage=*/GetParam(),
|
|
/*cpu_used=*/5);
|
|
}
|
|
|
|
// Width > 32768: same int16_t overflow but in the column direction.
|
|
TEST_P(EncodeBigDimension, WideFrame) {
|
|
EncodeSingleFrame(/*width=*/32832, /*height=*/64, /*usage=*/GetParam(),
|
|
/*cpu_used=*/5);
|
|
}
|
|
|
|
constexpr unsigned int kUsages[] = {
|
|
AOM_USAGE_REALTIME,
|
|
#if !CONFIG_REALTIME_ONLY
|
|
AOM_USAGE_GOOD_QUALITY,
|
|
AOM_USAGE_ALL_INTRA,
|
|
#endif
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(All, EncodeBigDimension, testing::ValuesIn(kUsages));
|
|
|
|
} // namespace
|