On Tue, 1 Sept 2026, 04:48 michaelni via ffmpeg-devel, < [email protected]> wrote:
> PR #24342 opened by michaelni > URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24342 > Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24342.patch > > Decoding a 4690 frame 720x576 stream single threaded > runs each: > full decode: 2.973 +- 0.014 s > metadata only: 0.058 +- 0.007 s > > > >From 5f3b824fb389feaedf3b62c078634291a6c2c2f9 Mon Sep 17 00:00:00 2001 > From: Michael Niedermayer <[email protected]> > Date: Tue, 1 Sep 2026 02:04:15 +0200 > Subject: [PATCH 1/2] avcodec: add AVCodecContext.skip_pred > > Skipping prediction complements skip_idct and skip_loop_filter: with > both skip_pred and skip_idct discarding a frame, no pixel of that frame > is needed, so a decoder can drop all pixel operations and output the > frame with only its metadata valid. This allows callers to determine > timestamps, frame types and the reorder delay of a stream at a small > fraction of the cost of a full decode. > --- > doc/APIchanges | 3 +++ > doc/codecs.texi | 10 +++++++++- > libavcodec/avcodec.h | 11 +++++++++++ > libavcodec/options_table.h | 1 + > libavcodec/pthread_frame.c | 1 + > libavcodec/version.h | 2 +- > 6 files changed, 26 insertions(+), 2 deletions(-) > > diff --git a/doc/APIchanges b/doc/APIchanges > index 7d878a630c..9cf1f85702 100644 > --- a/doc/APIchanges > +++ b/doc/APIchanges > @@ -2,6 +2,9 @@ The last version increases of all libraries were on > 2026-06-23. > > API changes, most recent first: > > +2026-09-01 - xxxxxxxxxx - lavc 63.10.100 - avcodec.h > + Add AVCodecContext.skip_pred. > + > 2026-08-28 - xxxxxxxxxx - lavc 63.9.100 - avcodec.h > Add FF_BUG_H264_DP_NNZ. > > diff --git a/doc/codecs.texi b/doc/codecs.texi > index e905282f1e..136462e13c 100644 > --- a/doc/codecs.texi > +++ b/doc/codecs.texi > @@ -724,13 +724,21 @@ Set max macroblock lagrange factor (VBR). > > @item skip_loop_filter @var{integer} (@emph{decoding,video}) > @item skip_idct @var{integer} (@emph{decoding,video}) > +@item skip_pred @var{integer} (@emph{decoding,video}) > @item skip_frame @var{integer} (@emph{decoding,video}) > > Make decoder discard processing depending on the frame type selected > by the option value. > > @option{skip_loop_filter} skips frame loop filtering, @option{skip_idct} > -skips frame IDCT/dequantization, @option{skip_frame} skips decoding. > +skips frame IDCT/dequantization, @option{skip_pred} skips prediction > +(intra prediction and motion compensation), @option{skip_frame} skips > +decoding. > + > +@option{skip_pred} takes effect only together with @option{skip_idct}: > +with both set to @samp{all} the decoder (currently only h264) skips all > +pixel operations and outputs frames with uninitialized pixels whose > +metadata, such as timestamps and frame types, is valid. > > Possible values: > @table @samp > diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h > index cf2257f3c9..55ea151074 100644 > --- a/libavcodec/avcodec.h > +++ b/libavcodec/avcodec.h > @@ -1936,6 +1936,17 @@ typedef struct AVCodecContext { > * - decoding: Set by libavcodec > */ > enum AVAlphaMode alpha_mode; > + > + /** > + * Skip prediction (intra prediction and motion compensation) for > + * selected frames. Decoders honor this only when skip_pred and > + * skip_idct both discard a frame: all pixel operations of that frame > + * are then skipped and it is output with valid metadata and > + * uninitialized pixels. > + * - encoding: unused > + * - decoding: Set by user. > + */ > + enum AVDiscard skip_pred; > } AVCodecContext; > > /** > diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h > index 23fe7d3409..e18d0d4c46 100644 > --- a/libavcodec/options_table.h > +++ b/libavcodec/options_table.h > @@ -255,6 +255,7 @@ static const AVOption avcodec_options[] = { > {"mblmax", "maximum macroblock Lagrange factor (VBR)", OFFSET(mb_lmax), > AV_OPT_TYPE_INT, {.i64 = FF_QP2LAMBDA * 31 }, 1, FF_LAMBDA_MAX, V|E}, > {"skip_loop_filter", "skip loop filtering process for the selected > frames", OFFSET(skip_loop_filter), AV_OPT_TYPE_INT, {.i64 = > AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, .unit = "avdiscard"}, > {"skip_idct" , "skip IDCT/dequantization for the selected frames", > OFFSET(skip_idct), AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, > INT_MIN, INT_MAX, V|D, .unit = "avdiscard"}, > +{"skip_pred" , "skip prediction for the selected frames", > OFFSET(skip_pred), AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, > INT_MIN, INT_MAX, V|D, .unit = "avdiscard"}, > {"skip_frame" , "skip decoding for the selected frames", > OFFSET(skip_frame), AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, > INT_MIN, INT_MAX, V|D, .unit = "avdiscard"}, > {"none" , "discard no frame", 0, > AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONE }, INT_MIN, INT_MAX, V|D, > .unit = "avdiscard"}, > {"default" , "discard useless frames", 0, > AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, > .unit = "avdiscard"}, > diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c > index 1814ab2768..5ec9a8a974 100644 > --- a/libavcodec/pthread_frame.c > +++ b/libavcodec/pthread_frame.c > @@ -476,6 +476,7 @@ static int update_context_from_user(AVCodecContext > *dst, const AVCodecContext *s > > dst->skip_loop_filter = src->skip_loop_filter; > dst->skip_idct = src->skip_idct; > + dst->skip_pred = src->skip_pred; > dst->skip_frame = src->skip_frame; > > dst->frame_num = src->frame_num; > diff --git a/libavcodec/version.h b/libavcodec/version.h > index 230d5fa13e..80e2ae630d 100644 > --- a/libavcodec/version.h > +++ b/libavcodec/version.h > @@ -29,7 +29,7 @@ > > #include "version_major.h" > > -#define LIBAVCODEC_VERSION_MINOR 9 > +#define LIBAVCODEC_VERSION_MINOR 10 > #define LIBAVCODEC_VERSION_MICRO 100 > > #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ > -- > 2.52.0 > > > >From ebe403eb039e1859fccf1fc9b2fbde886bf8c11f Mon Sep 17 00:00:00 2001 > From: Michael Niedermayer <[email protected]> > Date: Tue, 1 Sep 2026 02:04:20 +0200 > Subject: [PATCH 2/2] avcodec/h264dec: decode only metadata when prediction > and > IDCT are discarded > > Decoding a 4690 frame 720x576 stream single threaded, 12 interleaved > runs each: > full decode: 2.973 +- 0.014 s > metadata only: 0.058 +- 0.007 s > 51x faster, p = 5e-37 (Welch) > --- > libavcodec/h264_slice.c | 8 +++++++- > libavcodec/h264dec.c | 3 ++- > libavcodec/h264dec.h | 7 +++++++ > 3 files changed, 16 insertions(+), 2 deletions(-) > > diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c > index 4f4cf3f66b..501e637dae 100644 > --- a/libavcodec/h264_slice.c > +++ b/libavcodec/h264_slice.c > @@ -525,6 +525,7 @@ static int h264_frame_start(H264Context *h) > pic->needs_fg = > h->sei.common.film_grain_characteristics && > h->sei.common.film_grain_characteristics->present && > + !ff_h264_skip_all_pixels(h->avctx) && > !h->avctx->hwaccel && > !(h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN); > > @@ -1578,7 +1579,7 @@ static int h264_field_start(H264Context *h, const > H264SliceContext *sl, > if (h->short_ref[0]->field_picture) > ff_thread_report_progress(&h->short_ref[0]->tf, > INT_MAX, 1); > } else if (!h->frame_recovered) { > - if (!h->avctx->hwaccel) > + if (!h->avctx->hwaccel && > !ff_h264_skip_all_pixels(h->avctx)) > color_frame(h->short_ref[0]->f, c); > h->short_ref[0]->gray = 1; > } > @@ -2886,6 +2887,11 @@ int ff_h264_execute_decode_slices(H264Context *h) > if (h->avctx->hwaccel || context_count < 1) > return 0; > > + if (ff_h264_skip_all_pixels(avctx)) { > + h->mb_y = h->mb_height; > + goto finish; > + } > + > av_assert0(context_count && h->slice_ctx[context_count - 1].mb_y < > h->mb_height); > > if (context_count == 1) { > diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c > index 0892850fe0..6b9b6981ee 100644 > --- a/libavcodec/h264dec.c > +++ b/libavcodec/h264dec.c > @@ -830,7 +830,8 @@ end: > * past end by one (callers fault) and resync_mb_y != 0 > * causes problems for the first MB line, too. > */ > - if (!FIELD_PICTURE(h) && h->current_slice && h->enable_er) { > + if (!FIELD_PICTURE(h) && h->current_slice && h->enable_er && > + !ff_h264_skip_all_pixels(h->avctx)) { > > H264SliceContext *sl = h->slice_ctx; > int use_last_pic = h->last_pic_for_ec.f->buf[0] && > !sl->ref_count[0]; > diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h > index 7bce897021..715b16d9c8 100644 > --- a/libavcodec/h264dec.h > +++ b/libavcodec/h264dec.h > @@ -683,6 +683,13 @@ static av_always_inline int get_chroma_qp(const PPS > *pps, int t, int qscale) > return pps->chroma_qp_table[t][qscale]; > } > > +static inline int ff_h264_skip_all_pixels(const AVCodecContext *avctx) > +{ > + return avctx->skip_pred >= AVDISCARD_ALL && > + avctx->skip_idct >= AVDISCARD_ALL && > + !(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS); > +} > + > int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup); > > int ff_h264_ref_picture(H264Picture *dst, const H264Picture *src); > -- > 2.52.0 > Why? > _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
