Commit 9f9c3f7475 for aom
commit 9f9c3f7475793f1a80fc8fb811dbff84549a91df
Author: Wan-Teh Chang <wtc@google.com>
Date: Fri Sep 25 17:20:06 2026 -0700
Add a test for OSS-Fuzz Issue 559019046
Suggested by Yuan Tong in
https://github.com/AOMediaCodec/libavif/pull/1069#discussion_r4090282167
Bug: oss-fuzz:559019046
Change-Id: I1f7e280a1ec7c80a63cf3dee21c880e7d6f2fb23
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
index 56219335c3..2f470c25fd 100644
--- a/test/encode_api_test.cc
+++ b/test/encode_api_test.cc
@@ -775,6 +775,86 @@ TEST(EncodeAPI, Buganizer310548198) {
ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
}
+#if !CONFIG_REALTIME_ONLY
+// Test for OSS-Fuzz Issue 559019046. The bug triggers when we increase the
+// number of tiles after encoding a non-intra frame and then encode a key frame.
+// Based on Yuan Tong's example in
+// https://github.com/AOMediaCodec/libavif/pull/1069#discussion_r4090282167:
+// magick -size 128x1024 xc:gray -alpha set -channel A -evaluate set 60%
+// +channel flat.png
+// avifenc -s 6 -j 8 -k 2 flat.png flat.png --tilerowslog2:u 2 flat.png
+// -o flat.avif
+TEST(EncodeAPI, Issue559019046) {
+ aom_codec_iface_t *const iface = aom_codec_av1_cx();
+ aom_codec_enc_cfg_t cfg;
+ const unsigned int usage = AOM_USAGE_GOOD_QUALITY;
+ ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage), AOM_CODEC_OK);
+ cfg.g_threads = 8;
+ cfg.g_w = 128;
+ cfg.g_h = 1024;
+ cfg.g_lag_in_frames = 0;
+ cfg.kf_max_dist = 2;
+
+ aom_codec_ctx_t enc;
+ ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
+
+ const int speed = 6;
+ ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, speed), AOM_CODEC_OK);
+
+ const aom_enc_frame_flags_t flags = 0;
+ int frame_index = 0;
+
+ // Encode a key frame.
+ aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
+ ASSERT_NE(image, nullptr);
+ ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK);
+ frame_index++;
+ const aom_codec_cx_pkt_t *pkt;
+ aom_codec_iter_t iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ ASSERT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY);
+ }
+
+ // Encode a non-intra frame.
+ ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK);
+ frame_index++;
+ iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ ASSERT_EQ(
+ pkt->data.frame.flags & (AOM_FRAME_IS_KEY | AOM_FRAME_IS_INTRAONLY), 0);
+ }
+
+ // Increase the number of tiles.
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TILE_ROWS, 2), AOM_CODEC_OK);
+
+ // Encode a key frame.
+ ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK);
+ frame_index++;
+ iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ ASSERT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY);
+ }
+ aom_img_free(image);
+
+ // Flush the encoder.
+ bool got_data;
+ do {
+ ASSERT_EQ(aom_codec_encode(&enc, nullptr, 0, 0, 0), AOM_CODEC_OK);
+ got_data = false;
+ iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ got_data = true;
+ }
+ } while (got_data);
+
+ ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
+}
+#endif // !CONFIG_REALTIME_ONLY
+
// Emulates the WebCodecs VideoEncoder interface.
class AV1Encoder {
public: