diff --git a/doc/APIchanges b/doc/APIchanges
index 59216231f9..85060768b3 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -4,6 +4,7 @@ API changes, most recent first:
 
 2023-04-11 - xxxxxxxxxx - lavc 60.10.100 - avcodec.h
   Add event_flags to AVCodecContext.
+  Add AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED.
 
 2023-04-04 - xxxxxxxxxx - lavu 58.6.100 - hdr_dynamic_metadata.h
   Add AV_HDR_PLUS_MAX_PAYLOAD_SIZE.
diff --git a/libavcodec/8bps.c b/libavcodec/8bps.c
index 90d6c96fd1..c6709e9569 100644
--- a/libavcodec/8bps.c
+++ b/libavcodec/8bps.c
@@ -123,7 +123,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
     }
 
     if (avctx->bits_per_coded_sample <= 8) {
-        frame->palette_has_changed = ff_copy_palette(c->pal, avpkt, avctx);
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(c->pal, avpkt, avctx);
 
         memcpy (frame->data[1], c->pal, AVPALETTE_SIZE);
     }
diff --git a/libavcodec/ansi.c b/libavcodec/ansi.c
index c1e31266ec..0e65591470 100644
--- a/libavcodec/ansi.c
+++ b/libavcodec/ansi.c
@@ -262,7 +262,7 @@ static int execute_code(AVCodecContext * avctx, int c)
                                      AV_GET_BUFFER_FLAG_REF)) < 0)
                 return ret;
             s->frame->pict_type           = AV_PICTURE_TYPE_I;
-            s->frame->palette_has_changed = 1;
+            avctx->event_flags           |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
             set_palette((uint32_t *)s->frame->data[1]);
             erase_screen(avctx);
         } else if (c == 'l') {
@@ -371,7 +371,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
     }
 
     s->frame->pict_type           = AV_PICTURE_TYPE_I;
-    s->frame->palette_has_changed = 1;
+    avctx->event_flags           |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     set_palette((uint32_t *)s->frame->data[1]);
     if (!s->first_frame) {
         erase_screen(avctx);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 6cc54edab9..7083fb704a 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2103,6 +2103,11 @@ typedef struct AVCodecContext {
     int event_flags;
 } AVCodecContext;
 
+/**
+ * - decoding: the palette has changed in between returned frames.
+ */
+#define AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED (1 << 0)
+
 /**
  * @defgroup lavc_hwaccel AVHWAccel
  *
diff --git a/libavcodec/bethsoftvideo.c b/libavcodec/bethsoftvideo.c
index e095d04fa5..d54aa7a5d1 100644
--- a/libavcodec/bethsoftvideo.c
+++ b/libavcodec/bethsoftvideo.c
@@ -51,8 +51,9 @@ static av_cold int bethsoftvid_decode_init(AVCodecContext *avctx)
     return 0;
 }
 
-static int set_palette(BethsoftvidContext *ctx, GetByteContext *g)
+static int set_palette(AVCodecContext *avctx, GetByteContext *g)
 {
+    BethsoftvidContext *ctx = avctx->priv_data;
     uint32_t *palette = (uint32_t *)ctx->frame->data[1];
     int a;
 
@@ -63,7 +64,7 @@ static int set_palette(BethsoftvidContext *ctx, GetByteContext *g)
         palette[a] = 0xFFU << 24 | bytestream2_get_be24u(g) * 4;
         palette[a] |= palette[a] >> 6 & 0x30303;
     }
-    ctx->frame->palette_has_changed = 1;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     return 0;
 }
 
@@ -93,7 +94,7 @@ static int bethsoftvid_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
         GetByteContext g;
         bytestream2_init(&g, avpkt->side_data[0].data,
                          avpkt->side_data[0].size);
-        if ((ret = set_palette(vid, &g)) < 0)
+        if ((ret = set_palette(avctx, &g)) < 0)
             return ret;
     }
 
@@ -103,7 +104,7 @@ static int bethsoftvid_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
     switch(block_type){
         case PALETTE_BLOCK: {
             *got_frame = 0;
-            if ((ret = set_palette(vid, &vid->g)) < 0) {
+            if ((ret = set_palette(avctx, &vid->g)) < 0) {
                 av_log(avctx, AV_LOG_ERROR, "error reading palette\n");
                 return ret;
             }
diff --git a/libavcodec/bfi.c b/libavcodec/bfi.c
index c268272451..0aa1bb3954 100644
--- a/libavcodec/bfi.c
+++ b/libavcodec/bfi.c
@@ -84,11 +84,10 @@ static int bfi_decode_frame(AVCodecContext *avctx, AVFrame *frame,
             pal++;
         }
         memcpy(bfi->pal, frame->data[1], sizeof(bfi->pal));
-        frame->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     } else {
         frame->pict_type = AV_PICTURE_TYPE_P;
         frame->key_frame = 0;
-        frame->palette_has_changed = 0;
         memcpy(frame->data[1], bfi->pal, sizeof(bfi->pal));
     }
 
diff --git a/libavcodec/bintext.c b/libavcodec/bintext.c
index ce814f7693..e0dc7bfa66 100644
--- a/libavcodec/bintext.c
+++ b/libavcodec/bintext.c
@@ -157,7 +157,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
     if ((ret = ff_get_buffer(avctx, s->frame, 0)) < 0)
         return ret;
     s->frame->pict_type           = AV_PICTURE_TYPE_I;
-    s->frame->palette_has_changed = 1;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     memcpy(s->frame->data[1], s->palette, 16 * 4);
 
     if (avctx->codec_id == AV_CODEC_ID_XBIN) {
diff --git a/libavcodec/bmvvideo.c b/libavcodec/bmvvideo.c
index 92ce41c836..ee394886d5 100644
--- a/libavcodec/bmvvideo.c
+++ b/libavcodec/bmvvideo.c
@@ -251,7 +251,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
     }
 
     memcpy(frame->data[1], c->pal, AVPALETTE_SIZE);
-    frame->palette_has_changed = type & BMV_PALETTE;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * (type & BMV_PALETTE);
 
     outptr = frame->data[0];
     srcptr = c->frame;
diff --git a/libavcodec/brenderpix.c b/libavcodec/brenderpix.c
index e95ab3d4af..da436fb4c9 100644
--- a/libavcodec/brenderpix.c
+++ b/libavcodec/brenderpix.c
@@ -245,7 +245,7 @@ static int pix_decode_frame(AVCodecContext *avctx, AVFrame *frame,
             *pal_out++ = (0xFFU << 24) | bytestream2_get_be32u(&gb);
         bytestream2_skip(&gb, 8);
 
-        frame->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
 
         chunk_type = bytestream2_get_be32(&gb);
     } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
@@ -257,7 +257,7 @@ static int pix_decode_frame(AVCodecContext *avctx, AVFrame *frame,
                "Using default palette, colors might be off.\n");
         memcpy(pal_out, std_pal_table, sizeof(uint32_t) * 256);
 
-        frame->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     }
 
     data_len = bytestream2_get_be32(&gb);
diff --git a/libavcodec/c93.c b/libavcodec/c93.c
index bfcbc7c150..c229910daa 100644
--- a/libavcodec/c93.c
+++ b/libavcodec/c93.c
@@ -246,7 +246,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
         for (i = 0; i < 256; i++) {
             palette[i] = 0xFFU << 24 | bytestream2_get_be24(&gb);
         }
-        newpic->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     } else {
         if (oldpic->data[1])
             memcpy(newpic->data[1], oldpic->data[1], 256 * 4);
diff --git a/libavcodec/cdgraphics.c b/libavcodec/cdgraphics.c
index 431e99cd76..9c5dbcb5e0 100644
--- a/libavcodec/cdgraphics.c
+++ b/libavcodec/cdgraphics.c
@@ -66,6 +66,7 @@
 #define CDG_PALETTE_SIZE          16
 
 typedef struct CDGraphicsContext {
+    AVCodecContext *avctx;
     AVFrame *frame;
     int hscroll;
     int vscroll;
@@ -77,6 +78,7 @@ static av_cold int cdg_decode_init(AVCodecContext *avctx)
 {
     CDGraphicsContext *cc = avctx->priv_data;
 
+    cc->avctx = avctx;
     cc->frame = av_frame_alloc();
     if (!cc->frame)
         return AVERROR(ENOMEM);
@@ -125,7 +127,7 @@ static void cdg_load_palette(CDGraphicsContext *cc, uint8_t *data, int low)
         b = ((color     ) & 0x000F) * 17;
         palette[i + array_offset] = (uint32_t)cc->alpha[i + array_offset] << 24 | r << 16 | g << 8 | b;
     }
-    cc->frame->palette_has_changed = 1;
+    cc->avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
 }
 
 static int cdg_tile_block(CDGraphicsContext *cc, uint8_t *data, int b)
diff --git a/libavcodec/cdtoons.c b/libavcodec/cdtoons.c
index 3ebed2267c..3a28bd8a72 100644
--- a/libavcodec/cdtoons.c
+++ b/libavcodec/cdtoons.c
@@ -384,7 +384,7 @@ static int cdtoons_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
             }
             /* first palette entry indicates transparency */
             c->pal[0]                     = 0;
-            c->frame->palette_has_changed = 1;
+            avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
         }
     }
 
diff --git a/libavcodec/cinepak.c b/libavcodec/cinepak.c
index 282614fd1d..c37587e8ee 100644
--- a/libavcodec/cinepak.c
+++ b/libavcodec/cinepak.c
@@ -476,7 +476,7 @@ static int cinepak_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
         return ret;
 
     if (s->palette_video) {
-        s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(s->pal, avpkt, avctx);
     }
 
     if ((ret = cinepak_decode(s)) < 0) {
diff --git a/libavcodec/dds.c b/libavcodec/dds.c
index 4bb425dbb3..b742998191 100644
--- a/libavcodec/dds.c
+++ b/libavcodec/dds.c
@@ -651,7 +651,7 @@ static int dds_decode(AVCodecContext *avctx, AVFrame *frame,
                     ((unsigned)frame->data[1][3+i*4]<<24)
             );
         }
-        frame->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
 
         if (bytestream2_get_bytes_left(gbc) < frame->height * frame->width / 2) {
             av_log(avctx, AV_LOG_ERROR, "Buffer is too small (%d < %d).\n",
@@ -682,7 +682,7 @@ static int dds_decode(AVCodecContext *avctx, AVFrame *frame,
                         ((unsigned)frame->data[1][3+i*4]<<24)
                 );
 
-            frame->palette_has_changed = 1;
+            avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
         }
 
         if (bytestream2_get_bytes_left(gbc) < frame->height * linesize) {
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 40f5a3ba59..e3d803da3b 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -570,6 +570,7 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
     }
 
     if (!ret) {
+        frame->palette_has_changed = !!(avctx->event_flags & AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED);
         frame->best_effort_timestamp = guess_correct_pts(avctx,
                                                          frame->pts,
                                                          frame->pkt_dts);
diff --git a/libavcodec/dfa.c b/libavcodec/dfa.c
index 114c803f32..8177aa46b5 100644
--- a/libavcodec/dfa.c
+++ b/libavcodec/dfa.c
@@ -367,7 +367,7 @@ static int dfa_decode_frame(AVCodecContext *avctx, AVFrame *frame,
                 s->pal[i] = bytestream2_get_be24(&gb) << 2;
                 s->pal[i] |= 0xFFU << 24 | (s->pal[i] >> 6) & 0x30303;
             }
-            frame->palette_has_changed = 1;
+            avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
         } else if (chunk_type <= 9) {
             if (decoder[chunk_type - 2](&gb, s->frame_buf, avctx->width, avctx->height)) {
                 av_log(avctx, AV_LOG_ERROR, "Error decoding %s chunk\n",
diff --git a/libavcodec/dsicinvideo.c b/libavcodec/dsicinvideo.c
index 222044d125..4beea39cd5 100644
--- a/libavcodec/dsicinvideo.c
+++ b/libavcodec/dsicinvideo.c
@@ -293,7 +293,7 @@ static int cinvideo_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
         return res;
 
     memcpy(cin->frame->data[1], cin->palette, sizeof(cin->palette));
-    cin->frame->palette_has_changed = 1;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     for (y = 0; y < cin->avctx->height; ++y)
         memcpy(cin->frame->data[0] + (cin->avctx->height - 1 - y) * cin->frame->linesize[0],
                cin->bitmap_table[CIN_CUR_BMP] + y * cin->avctx->width,
diff --git a/libavcodec/dxa.c b/libavcodec/dxa.c
index 8d2d2d771b..a1b4224eba 100644
--- a/libavcodec/dxa.c
+++ b/libavcodec/dxa.c
@@ -230,7 +230,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
     if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
         return ret;
     memcpy(frame->data[1], c->pal, AVPALETTE_SIZE);
-    frame->palette_has_changed = pc;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * pc;
 
     outptr = frame->data[0];
     srcptr = c->decomp_buf;
diff --git a/libavcodec/flicvideo.c b/libavcodec/flicvideo.c
index 228f652775..1d27cc6bbd 100644
--- a/libavcodec/flicvideo.c
+++ b/libavcodec/flicvideo.c
@@ -473,7 +473,7 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
     /* make the palette available on the way out */
     memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE);
     if (s->new_palette) {
-        s->frame->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
         s->new_palette = 0;
     }
 
diff --git a/libavcodec/gemdec.c b/libavcodec/gemdec.c
index c8fd8dcdcd..96c0afaf34 100644
--- a/libavcodec/gemdec.c
+++ b/libavcodec/gemdec.c
@@ -181,7 +181,7 @@ static int gem_decode_frame(AVCodecContext *avctx, AVFrame *p,
 
     p->pict_type = AV_PICTURE_TYPE_I;
     p->key_frame = 1;
-    p->palette_has_changed = 1;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     palette = (uint32_t  *)p->data[1];
 
     if (tag == AV_RB32("STTT")) {
diff --git a/libavcodec/idcinvideo.c b/libavcodec/idcinvideo.c
index f6b8b3cd69..1f1ad09f96 100644
--- a/libavcodec/idcinvideo.c
+++ b/libavcodec/idcinvideo.c
@@ -224,7 +224,7 @@ static int idcin_decode_frame(AVCodecContext *avctx, AVFrame *frame,
     if (idcin_decode_vlcs(s, frame))
         return AVERROR_INVALIDDATA;
 
-    frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(s->pal, avpkt, avctx);
     /* make the palette available on the way out */
     memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
 
diff --git a/libavcodec/imx.c b/libavcodec/imx.c
index 44bab23c27..e11239c28c 100644
--- a/libavcodec/imx.c
+++ b/libavcodec/imx.c
@@ -58,11 +58,10 @@ static int imx_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
         return ret;
 
     if (ff_copy_palette(imx->pal, avpkt, avctx)) {
-        frame->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
         frame->key_frame = 1;
     } else {
         frame->key_frame = 0;
-        frame->palette_has_changed = 0;
     }
 
     bytestream2_init(&gb, avpkt->data, avpkt->size);
diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c
index 1a3461bf10..6c9ec3f7a2 100644
--- a/libavcodec/interplayvideo.c
+++ b/libavcodec/interplayvideo.c
@@ -1315,7 +1315,7 @@ static int ipvideo_decode_frame(AVCodecContext *avctx, AVFrame *frame,
         return ret;
 
     if (!s->is_16bpp) {
-        frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(s->pal, avpkt, avctx);
     }
 
     switch (frame_format) {
diff --git a/libavcodec/jvdec.c b/libavcodec/jvdec.c
index e0287a9cb9..72ac78f87a 100644
--- a/libavcodec/jvdec.c
+++ b/libavcodec/jvdec.c
@@ -213,7 +213,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
     if (video_size) {
         s->frame->key_frame           = 1;
         s->frame->pict_type           = AV_PICTURE_TYPE_I;
-        s->frame->palette_has_changed = s->palette_has_changed;
+        avctx->event_flags           |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * s->palette_has_changed;
         s->palette_has_changed        = 0;
         memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE);
 
diff --git a/libavcodec/kmvc.c b/libavcodec/kmvc.c
index 153cea03b9..a9645c608e 100644
--- a/libavcodec/kmvc.c
+++ b/libavcodec/kmvc.c
@@ -273,7 +273,7 @@ static int decode_frame(AVCodecContext * avctx, AVFrame *frame,
     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
         return ret;
 
-    frame->palette_has_changed = ff_copy_palette(ctx->pal, avpkt, avctx);
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(ctx->pal, avpkt, avctx);
 
     header = bytestream2_get_byte(&ctx->g);
 
@@ -296,7 +296,7 @@ static int decode_frame(AVCodecContext * avctx, AVFrame *frame,
     }
 
     if (header & KMVC_PALETTE) {
-        frame->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
         // palette starts from index 1 and has 127 entries
         for (i = 1; i <= ctx->palsize; i++) {
             ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&ctx->g);
@@ -305,7 +305,7 @@ static int decode_frame(AVCodecContext * avctx, AVFrame *frame,
 
     if (ctx->setpal) {
         ctx->setpal = 0;
-        frame->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     }
 
     /* make the palette available on the way out */
diff --git a/libavcodec/mscc.c b/libavcodec/mscc.c
index e8406aa268..b70e43e4ad 100644
--- a/libavcodec/mscc.c
+++ b/libavcodec/mscc.c
@@ -150,7 +150,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
         const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size);
 
         if (pal && size == AVPALETTE_SIZE) {
-            frame->palette_has_changed = 1;
+            avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
             for (j = 0; j < 256; j++)
                 s->pal[j] = 0xFF000000 | AV_RL32(pal + j * 4);
         } else if (pal) {
diff --git a/libavcodec/msrle.c b/libavcodec/msrle.c
index b6fa7f7abb..803db81012 100644
--- a/libavcodec/msrle.c
+++ b/libavcodec/msrle.c
@@ -95,7 +95,7 @@ static int msrle_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
         return ret;
 
     if (avctx->bits_per_coded_sample > 1 && avctx->bits_per_coded_sample <= 8) {
-        s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(s->pal, avpkt, avctx);
 
         /* make the palette available */
         memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
diff --git a/libavcodec/mss1.c b/libavcodec/mss1.c
index 775852102a..ae2459cc00 100644
--- a/libavcodec/mss1.c
+++ b/libavcodec/mss1.c
@@ -178,7 +178,7 @@ static int mss1_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
     if (c->corrupted)
         return AVERROR_INVALIDDATA;
     memcpy(ctx->pic->data[1], c->pal, AVPALETTE_SIZE);
-    ctx->pic->palette_has_changed = pal_changed;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * pal_changed;
 
     if ((ret = av_frame_ref(rframe, ctx->pic)) < 0)
         return ret;
diff --git a/libavcodec/msvideo1.c b/libavcodec/msvideo1.c
index 9903ff36a7..b92fa40e8b 100644
--- a/libavcodec/msvideo1.c
+++ b/libavcodec/msvideo1.c
@@ -312,7 +312,7 @@ static int msvideo1_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
         return ret;
 
     if (s->mode_8bit) {
-        s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(s->pal, avpkt, avctx);
     }
 
     if (s->mode_8bit)
diff --git a/libavcodec/pafvideo.c b/libavcodec/pafvideo.c
index 458fe9ff47..3f0468e847 100644
--- a/libavcodec/pafvideo.c
+++ b/libavcodec/pafvideo.c
@@ -327,7 +327,7 @@ static int paf_video_decode(AVCodecContext *avctx, AVFrame *rframe,
             b = b << 2 | b >> 4;
             *out++ = (0xFFU << 24) | (r << 16) | (g << 8) | b;
         }
-        c->pic->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     }
 
     c->dirty[c->current_frame] = 1;
diff --git a/libavcodec/pictordec.c b/libavcodec/pictordec.c
index aef3d3de76..7b406a0347 100644
--- a/libavcodec/pictordec.c
+++ b/libavcodec/pictordec.c
@@ -191,7 +191,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
         return ret;
     memset(frame->data[0], 0, s->height * frame->linesize[0]);
     frame->pict_type           = AV_PICTURE_TYPE_I;
-    frame->palette_has_changed = 1;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
 
     pos_after_pal = bytestream2_tell(&s->g) + esize;
     palette = (uint32_t*)frame->data[1];
diff --git a/libavcodec/psd.c b/libavcodec/psd.c
index ee96bd1237..389363677c 100644
--- a/libavcodec/psd.c
+++ b/libavcodec/psd.c
@@ -532,7 +532,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture,
     }
 
     if (s->color_mode == PSD_INDEXED) {
-        picture->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
         memcpy(picture->data[1], s->palette, AVPALETTE_SIZE);
     }
 
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 74864e19c5..e1cb0109fb 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -324,6 +324,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
             return err;
     }
 
+    dst->event_flags |= src->event_flags;
+
     if (for_user) {
         if (codec->update_thread_context_for_user)
             err = codec->update_thread_context_for_user(dst, src);
diff --git a/libavcodec/qdrw.c b/libavcodec/qdrw.c
index e41451e9a7..277777e638 100644
--- a/libavcodec/qdrw.c
+++ b/libavcodec/qdrw.c
@@ -384,7 +384,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p,
             ret = parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors, flags & 0x8000);
             if (ret < 0)
                 return ret;
-            p->palette_has_changed = 1;
+            avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
 
             /* jump to image data */
             bytestream2_skip(&gbc, 18);
diff --git a/libavcodec/qpeg.c b/libavcodec/qpeg.c
index 5bca338acf..a3b821971d 100644
--- a/libavcodec/qpeg.c
+++ b/libavcodec/qpeg.c
@@ -297,7 +297,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p,
     }
 
     /* make the palette available on the way out */
-    p->palette_has_changed = ff_copy_palette(a->pal, avpkt, avctx);
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(a->pal, avpkt, avctx);
     memcpy(p->data[1], a->pal, AVPALETTE_SIZE);
 
     av_frame_unref(ref);
diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c
index 5cb18c86c2..1e2bf705ec 100644
--- a/libavcodec/qtrle.c
+++ b/libavcodec/qtrle.c
@@ -537,7 +537,7 @@ static int qtrle_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
     }
 
     if(has_palette) {
-        s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
+        s->avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(s->pal, avpkt, avctx);
 
         /* make the palette available on the way out */
         memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
diff --git a/libavcodec/rawdec.c b/libavcodec/rawdec.c
index c20c317fed..afd6a19514 100644
--- a/libavcodec/rawdec.c
+++ b/libavcodec/rawdec.c
@@ -372,7 +372,7 @@ static int raw_decode(AVCodecContext *avctx, AVFrame *frame,
         }
 
         if (ff_copy_palette(context->palette->data, avpkt, avctx)) {
-            frame->palette_has_changed = 1;
+            avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
         } else if (context->is_nut_pal8) {
             int vid_size = avctx->width * avctx->height;
             int pal_size = avpkt->size - vid_size;
@@ -380,7 +380,7 @@ static int raw_decode(AVCodecContext *avctx, AVFrame *frame,
             if (avpkt->size > vid_size && pal_size <= AVPALETTE_SIZE) {
                 const uint8_t *pal = avpkt->data + vid_size;
                 memcpy(context->palette->data, pal, pal_size);
-                frame->palette_has_changed = 1;
+                avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
             }
         }
     }
diff --git a/libavcodec/rscc.c b/libavcodec/rscc.c
index 61a25df382..68cf957990 100644
--- a/libavcodec/rscc.c
+++ b/libavcodec/rscc.c
@@ -346,7 +346,7 @@ static int rscc_decode_frame(AVCodecContext *avctx, AVFrame *frame,
 
     /* Palette handling */
     if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
-        frame->palette_has_changed = ff_copy_palette(ctx->palette, avpkt, avctx);
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(ctx->palette, avpkt, avctx);
         memcpy(frame->data[1], ctx->palette, AVPALETTE_SIZE);
     }
     // We only return a picture when enough of it is undamaged, this avoids copying nearly broken frames around
diff --git a/libavcodec/sga.c b/libavcodec/sga.c
index d3f4924298..7fceb34406 100644
--- a/libavcodec/sga.c
+++ b/libavcodec/sga.c
@@ -497,7 +497,7 @@ static int sga_decode_frame(AVCodecContext *avctx, AVFrame *frame,
     }
 
     memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
-    frame->palette_has_changed = 1;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     frame->pict_type = AV_PICTURE_TYPE_I;
     frame->key_frame = 1;
 
diff --git a/libavcodec/smacker.c b/libavcodec/smacker.c
index ecc27e9b67..c7c4d5ac15 100644
--- a/libavcodec/smacker.c
+++ b/libavcodec/smacker.c
@@ -392,7 +392,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
     pal = (uint32_t*)smk->pic->data[1];
     bytestream2_init(&gb2, avpkt->data, avpkt->size);
     flags = bytestream2_get_byteu(&gb2);
-    smk->pic->palette_has_changed = flags & 1;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * !!(flags & 1);
     smk->pic->key_frame = !!(flags & 2);
     if (smk->pic->key_frame)
         smk->pic->pict_type = AV_PICTURE_TYPE_I;
diff --git a/libavcodec/smc.c b/libavcodec/smc.c
index 2b10e74386..9f9b6570a3 100644
--- a/libavcodec/smc.c
+++ b/libavcodec/smc.c
@@ -437,7 +437,7 @@ static int smc_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
     if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
         return ret;
 
-    s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * ff_copy_palette(s->pal, avpkt, avctx);
 
     bytestream2_init(&gb, buf, buf_size);
     ret = smc_decode_stream(s, &gb);
diff --git a/libavcodec/targa.c b/libavcodec/targa.c
index 07005f2be6..f8286990a7 100644
--- a/libavcodec/targa.c
+++ b/libavcodec/targa.c
@@ -249,7 +249,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p,
                 }
                 break;
             }
-            p->palette_has_changed = 1;
+            avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
         }
     }
 
diff --git a/libavcodec/tiertexseqv.c b/libavcodec/tiertexseqv.c
index 19c0671bf6..d1998194e5 100644
--- a/libavcodec/tiertexseqv.c
+++ b/libavcodec/tiertexseqv.c
@@ -162,8 +162,9 @@ static const unsigned char *seq_decode_op3(SeqVideoContext *seq,
     return src;
 }
 
-static int seqvideo_decode(SeqVideoContext *seq, const unsigned char *data, int data_size)
+static int seqvideo_decode(AVCodecContext *avctx, const unsigned char *data, int data_size)
 {
+    SeqVideoContext *seq = avctx->priv_data;
     const unsigned char *data_end = data + data_size;
     GetBitContext gb;
     int flags, i, j, x, y, op;
@@ -182,7 +183,7 @@ static int seqvideo_decode(SeqVideoContext *seq, const unsigned char *data, int
                 c[j] = (*data << 2) | (*data >> 4);
             palette[i] = 0xFFU << 24 | AV_RB24(c);
         }
-        seq->frame->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     }
 
     if (flags & 2) {
@@ -242,7 +243,7 @@ static int seqvideo_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
     if ((ret = ff_reget_buffer(avctx, seq->frame, 0)) < 0)
         return ret;
 
-    if (seqvideo_decode(seq, buf, buf_size))
+    if (seqvideo_decode(avctx, buf, buf_size))
         return AVERROR_INVALIDDATA;
 
     if ((ret = av_frame_ref(rframe, seq->frame)) < 0)
diff --git a/libavcodec/tmv.c b/libavcodec/tmv.c
index cdb83452e5..97f007a3bd 100644
--- a/libavcodec/tmv.c
+++ b/libavcodec/tmv.c
@@ -60,7 +60,7 @@ static int tmv_decode_frame(AVCodecContext *avctx, AVFrame *frame,
     frame->key_frame = 1;
     dst              = frame->data[0];
 
-    frame->palette_has_changed = 1;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     memcpy(frame->data[1], ff_cga_palette, 16 * 4);
     memset(frame->data[1] + 16 * 4, 0, AVPALETTE_SIZE - 16 * 4);
 
diff --git a/libavcodec/tscc.c b/libavcodec/tscc.c
index 0ebe641ab1..639f2b53b2 100644
--- a/libavcodec/tscc.c
+++ b/libavcodec/tscc.c
@@ -106,7 +106,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
 
     /* make the palette available on the way out */
     if (c->avctx->pix_fmt == AV_PIX_FMT_PAL8) {
-        frame->palette_has_changed = palette_has_changed;
+        c->avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * palette_has_changed;
         memcpy(frame->data[1], c->pal, AVPALETTE_SIZE);
     }
 
diff --git a/libavcodec/vb.c b/libavcodec/vb.c
index 8b0e216473..42b048870a 100644
--- a/libavcodec/vb.c
+++ b/libavcodec/vb.c
@@ -230,7 +230,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
     }
 
     memcpy(frame->data[1], c->pal, AVPALETTE_SIZE);
-    frame->palette_has_changed = flags & VB_HAS_PALETTE;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED * !!(flags & VB_HAS_PALETTE);
 
     outptr = frame->data[0];
     srcptr = c->frame;
diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c
index 0573696d94..9a82106566 100644
--- a/libavcodec/vqavideo.c
+++ b/libavcodec/vqavideo.c
@@ -809,7 +809,7 @@ static int vqa_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
 
         /* make the palette available on the way out */
         memcpy(s->frame->data[1], s->palette, PALETTE_COUNT * 4);
-        s->frame->palette_has_changed = 1;
+        avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
     } else if (avctx->pix_fmt == AV_PIX_FMT_RGB555LE) {
         if ((res = vqa_decode_frame_hicolor(s, s->frame)) < 0)
             return res;
diff --git a/libavcodec/yop.c b/libavcodec/yop.c
index 14244c942a..51fb07bddc 100644
--- a/libavcodec/yop.c
+++ b/libavcodec/yop.c
@@ -232,7 +232,7 @@ static int yop_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
                                    (palette[i + firstcolor] >> 6) & 0x30303;
     }
 
-    frame->palette_has_changed = 1;
+    avctx->event_flags |= AVCTX_EVENT_FLAG_PALETTE_HAS_CHANGED;
 
     for (y = 0; y < avctx->height; y += 2) {
         for (x = 0; x < avctx->width; x += 2) {
