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;
}
}