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: