PR #25777 opened by Zhao Zhili (quink) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25777 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25777.patch
# Summary of changes - skip extension and user data after picture headers - support PFieldSkip in field-coded P pictures ```fate-samples cavs/avsplus-user-data.ts ``` >From 18c77e29cba024c9181830138f3c767ef3ec67cf Mon Sep 17 00:00:00 2001 From: Zhao Zhili <[email protected]> Date: Tue, 3 Nov 2026 16:15:03 +0800 Subject: [PATCH 1/3] avcodec/cavsdec: skip extension and user data after picture headers check_for_slice() ended the picture's data at any non-slice start code, so a picture with extension_and_user_data(1) before its first slice decoded no macroblock and produced no frame. --- libavcodec/cavsdec.c | 58 +++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c index efcd156d764..4138a57a670 100644 --- a/libavcodec/cavsdec.c +++ b/libavcodec/cavsdec.c @@ -1079,19 +1079,16 @@ static int is_start_code_offset(AVSContext *h, int offset) } /** - * Position the reader on the start code that ends an AEC slice: the first - * one at or after the slice's own payload. The reader position is not - * reliable: the arithmetic decoder's look ahead has run past it. + * Position the reader on the first start code prefix at or after @p offset, + * or near the end of the buffer when there is none. + * @return 1 if a start code prefix was found */ -static void aec_end_of_slice(AVSContext *h) +static int seek_to_start_code(AVSContext *h, int offset) { GetBitContext *gb = &h->gb; const uint8_t *buf = gb->buffer; int size = gb->size_in_bits >> 3; - int i = h->aec_start; - - /* release gb; check_for_slice() waits for this */ - h->aec.gb = NULL; + int i = offset; for (; i + 2 < size; i++) if (!buf[i] && !buf[i + 1] && buf[i + 2] == 1 && @@ -1099,6 +1096,20 @@ static void aec_end_of_slice(AVSContext *h) break; if (init_get_bits8(gb, buf, size) >= 0) skip_bits_long(gb, i * 8); + return i + 2 < size; +} + +/** + * Position the reader on the start code that ends an AEC slice: the first + * one at or after the slice's own payload. The reader position is not + * reliable: the arithmetic decoder's look ahead has run past it. + */ +static void aec_end_of_slice(AVSContext *h) +{ + /* release gb; check_for_slice() waits for this */ + h->aec.gb = NULL; + + seek_to_start_code(h, h->aec_start); } /** @@ -1715,23 +1726,37 @@ static inline int check_for_slice(AVSContext *h) /* an AEC slice ends with its stuffing bit, not at a start code (7.2.4) */ if (h->aec_enable && h->aec.gb) return 0; - align = (-get_bits_count(gb)) & 7; - /* check for stuffing byte */ - if (!align && (show_bits(gb, 8) == 0x80)) - align = 8; - if ((show_bits_long(gb, 24 + align) & 0xFFFFFF) == 0x000001) { + for (;;) { GetBitContext peek; int stc; + align = (-get_bits_count(gb)) & 7; + /* check for stuffing byte */ + if (!align && (show_bits(gb, 8) == 0x80)) + align = 8; + if ((show_bits_long(gb, 24 + align) & 0xFFFFFF) != 0x000001) + return 0; if (!is_start_code_offset(h, (get_bits_count(gb) + align) >> 3)) return 0; 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; + /* video_sequence() places extension_and_user_data(1) between + * the picture header and picture_data() (table 13) + */ + if (stc != (USER_START_CODE & 0xFF) && + stc != (EXT_START_CODE & 0xFF)) { + /* any other unit ends the picture's data; leave it to the + * caller */ + h->pic_data_end = 1; + return 0; + } + if (!seek_to_start_code(h, get_bits_count(&peek) >> 3)) { + h->pic_data_end = 1; + return 0; + } + continue; } *gb = peek; h->stc = stc; @@ -1747,7 +1772,6 @@ static inline int check_for_slice(AVSContext *h) } return 1; } - return 0; } /***************************************************************************** -- 2.54.0 >From 65211b6e9b37afad65e7cd6e7704cd6a5d68eedd Mon Sep 17 00:00:00 2001 From: Zhao Zhili <[email protected]> Date: Tue, 3 Nov 2026 18:25:21 +0800 Subject: [PATCH 2/3] avcodec/cavsdec: support PFieldSkip in field-coded P pictures Decoding such pictures failed with AVERROR_PATCHWELCOME. Skip macroblocks now predict from the same-parity field of the previous frame, and the zero-vector shortcut compares neighbours against the reference actually in use. --- libavcodec/cavs.c | 7 +++++-- libavcodec/cavs.h | 1 + libavcodec/cavsdec.c | 15 ++++++++------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/libavcodec/cavs.c b/libavcodec/cavs.c index 05117a098c0..72a3ce70edb 100644 --- a/libavcodec/cavs.c +++ b/libavcodec/cavs.c @@ -607,11 +607,14 @@ void ff_cavs_mv(AVSContext *h, enum cavs_mv_loc nP, enum cavs_mv_loc nC, mvP->ref_idx = 0; if (mvC->ref == NOT_AVAIL || (nP == MV_FWD_X3) || (nP == MV_BWD_X3 )) mvC = &h->mv[nP - 5]; // set to top-left (mvD) + /* the zero-vector cases of 9.9.1 a) 2) and 3), against this block's + * own reference + */ if (mode == MV_PRED_PSKIP && (mvA->ref == NOT_AVAIL || mvB->ref == NOT_AVAIL || - (mvA->x | mvA->y | mvA->ref) == 0 || - (mvB->x | mvB->y | mvB->ref) == 0)) { + ((mvA->x | mvA->y) == 0 && mvA->ref == ref) || + ((mvB->x | mvB->y) == 0 && mvB->ref == ref))) { mvP2 = &un_mv; /* if there is only one suitable candidate, take it */ } else if (mvA->ref >= 0 && mvB->ref < 0 && mvC->ref < 0) { diff --git a/libavcodec/cavs.h b/libavcodec/cavs.h index b51a5e6c19e..acc33b07934 100644 --- a/libavcodec/cavs.h +++ b/libavcodec/cavs.h @@ -204,6 +204,7 @@ typedef struct AVSContext { int pic_structure; int top_field_first; ///< first coded field is the top one, clause 7.2.3 int b_field_enhanced; ///< BFieldEnhanced of the picture, clause 9.9.1 b) + int p_field_skip; ///< PFieldSkip of the picture, clause 9.9.1 a) int field; ///< field of the current MB, 0 or 1, clause 3.24 int field_mby; ///< macroblock row of the current macroblock in it int skip_mode_flag; ///< select between skip_count or one skip_flag per MB diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c index 4138a57a670..ab168ba8ca5 100644 --- a/libavcodec/cavsdec.c +++ b/libavcodec/cavsdec.c @@ -1397,7 +1397,11 @@ static int decode_mb_p(AVSContext *h, enum cavs_mb mb_type) set_inter_mb_ctx(h, mb_type, mb_type == P_SKIP); switch (mb_type) { case P_SKIP: - MV(MV_FWD_X0, MV_FWD_C2, MV_PRED_PSKIP, BLK_16X16, h->ref_base[0]); + /* PFieldSkip predicts from the reference marked 1, the same + * parity field of the previous frame (9.9.1 a) 1)) + */ + MV(MV_FWD_X0, MV_FWD_C2, MV_PRED_PSKIP, BLK_16X16, + h->ref_base[0] + h->p_field_skip); break; case P_16X16: REF(ref[0], 0, MV_FWD_X0); @@ -1992,14 +1996,11 @@ static int decode_pic(AVSContext *h) } /* in a frame picture the field derivations reduce to the frame ones - * (9.9.1 b) 3)); PFieldSkip of 9.9.1 a) 1) is not implemented */ + * (9.9.1 b) 3)) */ h->b_field_enhanced = pb_field_enhanced_flag && !h->pic_structure && h->cur.f->pict_type == AV_PICTURE_TYPE_B; - if (pb_field_enhanced_flag && !h->pic_structure && - h->cur.f->pict_type == AV_PICTURE_TYPE_P) { - avpriv_request_sample(h->avctx, "Enhanced field coded P picture"); - return AVERROR_PATCHWELCOME; - } + h->p_field_skip = pb_field_enhanced_flag && !h->pic_structure && + h->cur.f->pict_type == AV_PICTURE_TYPE_P; if (!h->progressive) { h->cur.f->flags |= AV_FRAME_FLAG_INTERLACED; -- 2.54.0 >From a1f5e75df44d4a594bb159b84b59cb26f521f140 Mon Sep 17 00:00:00 2001 From: Zhao Zhili <[email protected]> Date: Wed, 4 Nov 2026 16:41:41 +0800 Subject: [PATCH 3/3] tests/fate/video: add an AVS+ test for user data and PFieldSkip The sample holds an I picture, an enhanced field-coded P picture and a B picture from a Broadcasting profile stream. The I picture has user data after its picture header. --- tests/fate/video.mak | 3 +++ tests/ref/fate/cavs-avsplus-user-data | 8 ++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/ref/fate/cavs-avsplus-user-data diff --git a/tests/fate/video.mak b/tests/fate/video.mak index caf45d2cfe6..e663b807a84 100644 --- a/tests/fate/video.mak +++ b/tests/fate/video.mak @@ -79,6 +79,9 @@ fate-cavs-bunny: CMD = framecrc -f cavsvideo -i $(TARGET_SAMPLES)/cavs/bunny.mp4 FATE_VIDEO-$(call FRAMECRC, MPEGTS, CAVS, CAVSVIDEO_PARSER) += fate-cavs-avsplus fate-cavs-avsplus: CMD = framecrc -i $(TARGET_SAMPLES)/cavs/avsplus-1080i-testcard.ts -an +FATE_VIDEO-$(call FRAMECRC, MPEGTS, CAVS, CAVSVIDEO_PARSER) += fate-cavs-avsplus-user-data +fate-cavs-avsplus-user-data: CMD = framecrc -i $(TARGET_SAMPLES)/cavs/avsplus-user-data.ts -an + FATE_VIDEO-$(call FRAMECRC, CDG, CDGRAPHICS, SCALE_FILTER) += fate-cdgraphics fate-cdgraphics: CMD = framecrc -i $(TARGET_SAMPLES)/cdgraphics/BrotherJohn.cdg -pix_fmt rgba -t 1 -vf scale diff --git a/tests/ref/fate/cavs-avsplus-user-data b/tests/ref/fate/cavs-avsplus-user-data new file mode 100644 index 00000000000..3ae5c7dc315 --- /dev/null +++ b/tests/ref/fate/cavs-avsplus-user-data @@ -0,0 +1,8 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 0/1 +0, 0, 0, 1, 3110400, 0x75e52781 +0, 1, 1, 1, 3110400, 0x27214479 +0, 2, 2, 1, 3110400, 0xd1df20d2 -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
