[PR] avformat & h264: avoid-decode-for-parse (PR #24320)
michaelni via ffmpeg-devel <[email protected]>
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <[email protected]> |
PR #24320 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24320 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24320.patch Previously av_find_stream_info() did decode a h264 frame to obtain all needed info, this patchset attempts to extract that information without fully decoding frame(s) this depends on all SPS matching as without a frame we cannot know which is correct otherwise >From 54635d2abf4b792cedf4b53588d0d658fe95436b Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sat, 29 Aug 2026 19:45:07 +0200 Subject: [PATCH 1/3] h264: factor the software pixel format choice out of get_pixel_format() --- libavcodec/h264_slice.c | 64 +++++------------------------------------ libavcodec/h264dec.h | 30 +++++++++++++++++++ 2 files changed, 37 insertions(+), 57 deletions(-) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 9b5ed8f77e..95911cfdef 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -799,15 +799,6 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) switch (h->ps.sps->bit_depth_luma) { case 9: - if (CHROMA444(h)) { - if (h->avctx->colorspace == AVCOL_SPC_RGB) { - *fmt++ = AV_PIX_FMT_GBRP9; - } else - *fmt++ = AV_PIX_FMT_YUV444P9; - } else if (CHROMA422(h)) - *fmt++ = AV_PIX_FMT_YUV422P9; - else - *fmt++ = AV_PIX_FMT_YUV420P9; break; case 10: #if CONFIG_H264_VIDEOTOOLBOX_HWACCEL @@ -823,47 +814,20 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) #if CONFIG_H264_NVDEC_CUARRAY_HWACCEL *fmt++ = AV_PIX_FMT_CUARRAY; #endif - if (CHROMA444(h)) { - if (h->avctx->colorspace == AVCOL_SPC_RGB) { - *fmt++ = AV_PIX_FMT_GBRP10; - } else - *fmt++ = AV_PIX_FMT_YUV444P10; - } else if (CHROMA422(h)) - *fmt++ = AV_PIX_FMT_YUV422P10; - else { #if CONFIG_H264_VAAPI_HWACCEL - // Just add as candidate. Whether VAProfileH264High10 usable or - // not is decided by vaapi_decode_make_config() defined in FFmpeg - // and vaQueryCodingProfile() defined in libva. + // Just add as candidate. Whether VAProfileH264High10 usable or + // not is decided by vaapi_decode_make_config() defined in FFmpeg + // and vaQueryCodingProfile() defined in libva. + if (!CHROMA444(h) && !CHROMA422(h)) *fmt++ = AV_PIX_FMT_VAAPI; #endif - *fmt++ = AV_PIX_FMT_YUV420P10; - } break; case 12: #if CONFIG_H264_VULKAN_HWACCEL *fmt++ = AV_PIX_FMT_VULKAN; #endif - if (CHROMA444(h)) { - if (h->avctx->colorspace == AVCOL_SPC_RGB) { - *fmt++ = AV_PIX_FMT_GBRP12; - } else - *fmt++ = AV_PIX_FMT_YUV444P12; - } else if (CHROMA422(h)) - *fmt++ = AV_PIX_FMT_YUV422P12; - else - *fmt++ = AV_PIX_FMT_YUV420P12; break; case 14: - if (CHROMA444(h)) { - if (h->avctx->colorspace == AVCOL_SPC_RGB) { - *fmt++ = AV_PIX_FMT_GBRP14; - } else - *fmt++ = AV_PIX_FMT_YUV444P14; - } else if (CHROMA422(h)) - *fmt++ = AV_PIX_FMT_YUV422P14; - else - *fmt++ = AV_PIX_FMT_YUV420P14; break; case 8: #if CONFIG_H264_VDPAU_HWACCEL @@ -882,19 +846,7 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) if (h->avctx->colorspace != AVCOL_SPC_RGB) *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX; #endif - if (CHROMA444(h)) { - if (h->avctx->colorspace == AVCOL_SPC_RGB) - *fmt++ = AV_PIX_FMT_GBRP; - else if (h->avctx->color_range == AVCOL_RANGE_JPEG) - *fmt++ = AV_PIX_FMT_YUVJ444P; - else - *fmt++ = AV_PIX_FMT_YUV444P; - } else if (CHROMA422(h)) { - if (h->avctx->color_range == AVCOL_RANGE_JPEG) - *fmt++ = AV_PIX_FMT_YUVJ422P; - else - *fmt++ = AV_PIX_FMT_YUV422P; - } else { + if (!CHROMA444(h) && !CHROMA422(h)) { #if CONFIG_H264_DXVA2_HWACCEL *fmt++ = AV_PIX_FMT_DXVA2_VLD; #endif @@ -908,10 +860,6 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) #if CONFIG_H264_VAAPI_HWACCEL *fmt++ = AV_PIX_FMT_VAAPI; #endif - if (h->avctx->color_range == AVCOL_RANGE_JPEG) - *fmt++ = AV_PIX_FMT_YUVJ420P; - else - *fmt++ = AV_PIX_FMT_YUV420P; } break; default: @@ -920,6 +868,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) return AVERROR_INVALIDDATA; } + *fmt++ = h264_sw_pix_fmt(h->ps.sps, h->avctx); + *fmt = AV_PIX_FMT_NONE; for (int i = 0; pix_fmts[i] != AV_PIX_FMT_NONE; i++) diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 74fd09dfaa..5817f5381f 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -703,4 +703,34 @@ void ff_h264_free_tables(H264Context *h); void ff_h264_set_erpic(ERPicture *dst, const H264Picture *src); +static inline enum AVPixelFormat h264_sw_pix_fmt(const SPS *sps, + const AVCodecContext *avctx) +{ + const int chroma444 = sps->chroma_format_idc == 3; + const int chroma422 = sps->chroma_format_idc == 2; + const int rgb = avctx->colorspace == AVCOL_SPC_RGB; + const int jpeg = avctx->color_range == AVCOL_RANGE_JPEG; + + switch (sps->bit_depth_luma) { + case 9: + return chroma444 ? (rgb ? AV_PIX_FMT_GBRP9 : AV_PIX_FMT_YUV444P9) : + chroma422 ? AV_PIX_FMT_YUV422P9 : AV_PIX_FMT_YUV420P9; + case 10: + return chroma444 ? (rgb ? AV_PIX_FMT_GBRP10 : AV_PIX_FMT_YUV444P10) : + chroma422 ? AV_PIX_FMT_YUV422P10 : AV_PIX_FMT_YUV420P10; + case 12: + return chroma444 ? (rgb ? AV_PIX_FMT_GBRP12 : AV_PIX_FMT_YUV444P12) : + chroma422 ? AV_PIX_FMT_YUV422P12 : AV_PIX_FMT_YUV420P12; + case 14: + return chroma444 ? (rgb ? AV_PIX_FMT_GBRP14 : AV_PIX_FMT_YUV444P14) : + chroma422 ? AV_PIX_FMT_YUV422P14 : AV_PIX_FMT_YUV420P14; + case 8: + return chroma444 ? (rgb ? AV_PIX_FMT_GBRP : + jpeg ? AV_PIX_FMT_YUVJ444P : AV_PIX_FMT_YUV444P) : + chroma422 ? (jpeg ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV422P) : + (jpeg ? AV_PIX_FMT_YUVJ420P : AV_PIX_FMT_YUV420P); + } + return AV_PIX_FMT_NONE; +} + #endif /* AVCODEC_H264DEC_H */ -- 2.52.0 >From 6e79ab0fb1c99a1a75bf63daaaa17452a4e36108 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sat, 29 Aug 2026 15:13:52 +0200 Subject: [PATCH 2/3] h264dec: export stream parameters from the extradata at init avformat_find_stream_info() then sees the complete parameter set without decoding a frame. --- libavcodec/h264dec.c | 70 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index b78b7989ea..09d1153b2f 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -59,6 +59,71 @@ const uint16_t ff_h264_mb_sizes[4] = { 256, 384, 512, 768 }; +static const SPS *h264_effective_sps(const H264ParamSets *ps) +{ + const SPS *sps = ps->sps; + + if (sps) + return sps; + + for (int i = 0; i < MAX_SPS_COUNT; i++) { + const SPS *s = ps->sps_list[i]; + if (!s) + continue; + if (!sps) { + sps = s; + continue; + } + if (s->chroma_format_idc != sps->chroma_format_idc || + s->bit_depth_luma != sps->bit_depth_luma || + s->level_idc != sps->level_idc || + ff_h264_get_profile(s) != ff_h264_get_profile(sps) || + s->bitstream_restriction_flag != sps->bitstream_restriction_flag || + s->num_reorder_frames != sps->num_reorder_frames || + s->vui.sar.num != sps->vui.sar.num || + s->vui.sar.den != sps->vui.sar.den || + s->vui.video_signal_type_present_flag != sps->vui.video_signal_type_present_flag || + s->vui.video_full_range_flag != sps->vui.video_full_range_flag || + s->vui.colour_description_present_flag != sps->vui.colour_description_present_flag || + s->vui.colour_primaries != sps->vui.colour_primaries || + s->vui.transfer_characteristics != sps->vui.transfer_characteristics || + s->vui.matrix_coeffs != sps->vui.matrix_coeffs || + s->vui.chroma_location != sps->vui.chroma_location) + return NULL; + } + return sps; +} + +static void h264_export_extradata_params(AVCodecContext *avctx, const H264Context *h) +{ + const SPS *sps = h264_effective_sps(&h->ps); + + if (!sps) + return; + + avctx->profile = ff_h264_get_profile(sps); + avctx->level = sps->level_idc; + if (sps->vui.video_signal_type_present_flag) { + avctx->color_range = sps->vui.video_full_range_flag > 0 ? AVCOL_RANGE_JPEG + : AVCOL_RANGE_MPEG; + if (sps->vui.colour_description_present_flag) { + avctx->color_primaries = sps->vui.colour_primaries; + avctx->color_trc = sps->vui.transfer_characteristics; + avctx->colorspace = sps->vui.matrix_coeffs; + } + } + avctx->chroma_sample_location = sps->vui.chroma_location; + avctx->bits_per_raw_sample = sps->bit_depth_luma; + if (!avctx->sample_aspect_ratio.num && sps->vui.sar.num > 0) + avctx->sample_aspect_ratio = sps->vui.sar; + if (sps->bitstream_restriction_flag && + avctx->has_b_frames < sps->num_reorder_frames) + avctx->has_b_frames = sps->num_reorder_frames; + if (avctx->pix_fmt == AV_PIX_FMT_NONE && + avctx->get_format == avcodec_default_get_format) + avctx->pix_fmt = h264_sw_pix_fmt(sps, avctx); +} + int avpriv_h264_has_num_reorder_frames(AVCodecContext *avctx) { H264Context *h = avctx->priv_data; @@ -413,10 +478,7 @@ static av_cold int h264_decode_init(AVCodecContext *avctx) } } - if (h->ps.sps && h->ps.sps->bitstream_restriction_flag && - h->avctx->has_b_frames < h->ps.sps->num_reorder_frames) { - h->avctx->has_b_frames = h->ps.sps->num_reorder_frames; - } + h264_export_extradata_params(avctx, h); ff_h264_flush_change(h); -- 2.52.0 >From 36a1338569eb3a7fd98ad5a6c051432e6a890335 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sat, 29 Aug 2026 15:13:52 +0200 Subject: [PATCH 3/3] avformat/demux: settle the h264 reorder-delay guess without decoding --- libavcodec/h264dec.c | 4 +++- libavformat/demux.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index 09d1153b2f..8c2878e03f 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -127,7 +127,9 @@ static void h264_export_extradata_params(AVCodecContext *avctx, const H264Contex int avpriv_h264_has_num_reorder_frames(AVCodecContext *avctx) { H264Context *h = avctx->priv_data; - return h && h->ps.sps ? h->ps.sps->num_reorder_frames : 0; + const SPS *sps = h ? h264_effective_sps(&h->ps) : NULL; + + return sps ? sps->num_reorder_frames : 0; } static void h264_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type, diff --git a/libavformat/demux.c b/libavformat/demux.c index da0f5853cc..c789a06bdf 100644 --- a/libavformat/demux.c +++ b/libavformat/demux.c @@ -764,7 +764,7 @@ static int has_decode_delay_been_guessed(AVStream *st) return 1; av_assert0(sti->avctx->codec_id == AV_CODEC_ID_H264 || (sti->avctx->codec_id == AV_CODEC_ID_NONE && !avcodec_is_open(sti->avctx))); #if CONFIG_H264_DECODER - if (sti->avctx->has_b_frames && avcodec_is_open(sti->avctx) && + if (avcodec_is_open(sti->avctx) && avpriv_h264_has_num_reorder_frames(sti->avctx) == sti->avctx->has_b_frames) return 1; #endif -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]