PR #25126 opened by Baptiste Coudurier (bcoudurier) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25126 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25126.patch
With complete frames, the parser stopped at the first slice and reported a field picture as a single field even when the packet holds both fields of the frame, as in MXF. This halved the avg_frame_rate estimated by avformat_find_stream_info() (25/2 for 1080i25 XAVC Long GOP), so stream copy to MXF failed with "Unsupported frame rate 25/2". The parser now looks for the first slice of the opposite parity field and, if found, adds it to repeat_pict, sets field_order from the first field and picture_structure to frame, as the MPEG-2 parser does for field pairs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) From 96211bc708a4ec5cbf786aafb5f7d91c2ecfda67 Mon Sep 17 00:00:00 2001 From: Baptiste Coudurier <[email protected]> Date: Fri, 16 Oct 2026 12:08:09 -0700 Subject: [PATCH] avcodec/h264_parser: count both fields of a field pair in complete frames With complete frames, the parser stopped at the first slice and reported a field picture as a single field even when the packet holds both fields of the frame, as in MXF. This halved the avg_frame_rate estimated by avformat_find_stream_info(). Co-Authored-By: Claude Opus 5.5 <[email protected]> --- libavcodec/h264_parser.c | 52 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c index 1bd0be38a5..751892692d 100644 --- a/libavcodec/h264_parser.c +++ b/libavcodec/h264_parser.c @@ -251,6 +251,30 @@ static int scan_mmco_reset(AVCodecParserContext *s, GetBitContext *gb, return 0; } +/** + * Check whether a slice is the first slice of the field of opposite + * parity to the field picture already parsed. + */ +static int is_second_field(const H264ParseContext *p, GetBitContext *gb) +{ + const SPS *sps; + unsigned int pps_id; + + if (get_ue_golomb_long(gb)) // first_mb_in_slice + return 0; + get_ue_golomb_31(gb); // slice_type + pps_id = get_ue_golomb(gb); + if (pps_id >= MAX_PPS_COUNT || !p->ps.pps_list[pps_id]) + return 0; + sps = p->ps.pps_list[pps_id]->sps; + if (sps->residual_color_transform_flag) + skip_bits(gb, 2); // colour_plane_id + skip_bits(gb, sps->log2_max_frame_num); // frame_num + if (sps->frame_mbs_only_flag || !get_bits1(gb)) // field_pic_flag + return 0; + return PICT_TOP_FIELD + get_bits1(gb) != p->picture_structure; // bottom_field_flag +} + /** * Parse NAL units of found picture and decode some basic information. * @@ -270,6 +294,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, unsigned int pps_id; unsigned int slice_type; int state = -1, got_reset = 0; + int first_field = 0; int q264 = buf_size >=4 && !memcmp("Q264", buf, 4); int field_poc[2]; int ret; @@ -341,6 +366,23 @@ static inline int parse_nal_units(AVCodecParserContext *s, nal.ref_idc = get_bits(&nal.gb, 2); nal.type = get_bits(&nal.gb, 5); + if (first_field) { + /* The packet also holds the second field of the pair. */ + if ((nal.type == H264_NAL_SLICE || + nal.type == H264_NAL_IDR_SLICE || + nal.type == H264_NAL_DPA) && + is_second_field(p, &nal.gb)) { + s->repeat_pict++; + s->field_order = s->picture_structure == AV_PICTURE_STRUCTURE_TOP_FIELD ? + AV_FIELD_TT : AV_FIELD_BB; + s->picture_structure = AV_PICTURE_STRUCTURE_FRAME; + break; + } + /* Keep the parameter sets the second field may refer to. */ + if (nal.type != H264_NAL_SPS && nal.type != H264_NAL_PPS) + continue; + } + switch (nal.type) { case H264_NAL_SPS: ff_h264_decode_seq_parameter_set(&nal.gb, avctx, &p->ps, 0); @@ -577,11 +619,19 @@ static inline int parse_nal_units(AVCodecParserContext *s, sps->num_units_in_tick * 2, den, 1 << 30); } + /* A complete frame starting with a field picture may hold + * both fields of the pair, look for the second one. */ + if ((s->flags & PARSER_FLAG_COMPLETE_FRAMES) && + p->picture_structure != PICT_FRAME) { + first_field = 1; + break; + } + av_freep(&rbsp.rbsp_buffer); return 0; /* no need to evaluate the rest */ } } - if (q264) { + if (first_field || q264) { av_freep(&rbsp.rbsp_buffer); return 0; } -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
