Commit 202cde51ad for ffmpeg

commit 202cde51adef18e0f90cd3211165edf0e3e1bf7e
Author: Rainbaby <r@bgr.jp>
Date:   Fri Aug 28 16:18:06 2026 +0900

    avcodec/cavsdec: do not re-parse slice headers

    The scanner advanced only past the picture start code, so every slice
    header was parsed twice, the second time with a stale h->stc. The
    second parse is what produced the wrong "weighted prediction not yet
    supported" warning of trac ticket 3885; decoded output is unchanged.

    A start code that is not a slice now ends the picture's data and is
    left unread; decoding past it fails unless a pending skip run covers
    the remaining macroblocks.

    Fixes: https://trac.ffmpeg.org/ticket/3885
    Signed-off-by: Rainbaby <r@bgr.jp>

diff --git a/libavcodec/cavs.h b/libavcodec/cavs.h
index fc80bf5aa9..2172ac9ac0 100644
--- a/libavcodec/cavs.h
+++ b/libavcodec/cavs.h
@@ -192,6 +192,7 @@ typedef struct AVSContext {
     int mbx, mby, mbidx; ///< macroblock coordinates
     int flags;         ///< availability flags of neighbouring macroblocks
     int stc;           ///< last start code
+    int pic_data_end;  ///< a unit that is not a slice ended the picture's data
     uint8_t *cy, *cu, *cv; ///< current MB sample pointers
     int left_qp;
     uint8_t *top_qp;
diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c
index 953d2fc503..73212305c0 100644
--- a/libavcodec/cavsdec.c
+++ b/libavcodec/cavsdec.c
@@ -928,9 +928,6 @@ static int decode_mb_b(AVSContext *h, enum cavs_mb mb_type)

 static inline int decode_slice_header(AVSContext *h, GetBitContext *gb)
 {
-    if (h->stc > 0xAF)
-        av_log(h->avctx, AV_LOG_ERROR, "unexpected start code 0x%02x\n", h->stc);
-
     if (h->stc >= h->mb_height) {
         av_log(h->avctx, AV_LOG_ERROR, "stc 0x%02x is too large\n", h->stc);
         return AVERROR_INVALIDDATA;
@@ -967,10 +964,19 @@ static inline int check_for_slice(AVSContext *h)
     if (!align && (show_bits(gb, 8) == 0x80))
         align = 8;
     if ((show_bits_long(gb, 24 + align) & 0xFFFFFF) == 0x000001) {
-        skip_bits_long(gb, 24 + align);
-        h->stc = get_bits(gb, 8);
-        if (h->stc >= h->mb_height)
+        GetBitContext peek;
+        int stc;
+
+        peek = *gb;
+        skip_bits_long(&peek, 24 + align);
+        stc = get_bits(&peek, 8);
+        /* any other unit ends the picture's data; leave it to the caller */
+        if (stc > (SLICE_MAX_START_CODE & 0xFF)) {
+            h->pic_data_end = 1;
             return 0;
+        }
+        *gb    = peek;
+        h->stc = stc;
         decode_slice_header(h, gb);
         return 1;
     }
@@ -1098,17 +1104,36 @@ static int decode_pic(AVSContext *h)
     }

     ret = 0;
+    h->pic_data_end = 0;
     if (h->cur.f->pict_type == AV_PICTURE_TYPE_I) {
         do {
-            check_for_slice(h);
+            ret = check_for_slice(h);
+            if (ret < 0)
+                break;
+            if (h->pic_data_end) {
+                av_log(h->avctx, AV_LOG_ERROR,
+                       "picture data ended before MB %d\n", h->mbidx);
+                ret = AVERROR_INVALIDDATA;
+                break;
+            }
             ret = decode_mb_i(h, 0);
             if (ret < 0)
                 break;
         } while (ff_cavs_next_mb(h));
     } else if (h->cur.f->pict_type == AV_PICTURE_TYPE_P) {
         do {
-            if (check_for_slice(h))
+            ret = check_for_slice(h);
+            if (ret < 0)
+                break;
+            if (ret)
                 skip_count = -1;
+            /* past the picture's data, only a pending skip run can code MBs */
+            if (h->pic_data_end && !(h->skip_mode_flag && skip_count > 0)) {
+                av_log(h->avctx, AV_LOG_ERROR,
+                       "picture data ended before MB %d\n", h->mbidx);
+                ret = AVERROR_INVALIDDATA;
+                break;
+            }
             if (h->skip_mode_flag && (skip_count < 0)) {
                 if (get_bits_left(&h->gb) < 1) {
                     ret = AVERROR_INVALIDDATA;
@@ -1134,8 +1159,18 @@ static int decode_pic(AVSContext *h)
         } while (ff_cavs_next_mb(h));
     } else { /* AV_PICTURE_TYPE_B */
         do {
-            if (check_for_slice(h))
+            ret = check_for_slice(h);
+            if (ret < 0)
+                break;
+            if (ret)
                 skip_count = -1;
+            /* past the picture's data, only a pending skip run can code MBs */
+            if (h->pic_data_end && !(h->skip_mode_flag && skip_count > 0)) {
+                av_log(h->avctx, AV_LOG_ERROR,
+                       "picture data ended before MB %d\n", h->mbidx);
+                ret = AVERROR_INVALIDDATA;
+                break;
+            }
             if (h->skip_mode_flag && (skip_count < 0)) {
                 if (get_bits_left(&h->gb) < 1) {
                     ret = AVERROR_INVALIDDATA;
@@ -1314,9 +1349,7 @@ static int cavs_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
             //mpeg_decode_user_data(avctx, buf_ptr, input_size);
             break;
         default:
-            if (stc <= SLICE_MAX_START_CODE) {
-                decode_slice_header(h, &h->gb);
-            }
+            /* slice start codes are consumed by check_for_slice() */
             break;
         }
     }