PR #21388 opened by James Almer (jamrial) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21388 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21388.patch
Many parsers will request data until they find what will be the start of the next assembled packet in order to decide where to cut the current one. If this happens, the loop in demux.c will, in case the demuxer exports already fully assembled packets as is sometimes the case for MPEG-TS, discard the already handled first input packet before it tries to move its side data to the output. The affected FATE tests reflect this change by no longer dropping the side data from the first input packet, nor exporting every other side data in the wrong output packet. >From 54490f8ea42b47fee3364fa99c2b9e72831b8070 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Mon, 5 Jan 2026 23:50:41 -0300 Subject: [PATCH 1/2] avformat/demux: use a stream specific temporary packet for the parser This will be useful for the next commit. Signed-off-by: James Almer <[email protected]> --- libavformat/avformat.c | 2 ++ libavformat/demux.c | 2 +- libavformat/internal.h | 15 +++++++++++++++ libavformat/options.c | 4 ++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/libavformat/avformat.c b/libavformat/avformat.c index 18ca4643ee..ee3f7ee1b2 100644 --- a/libavformat/avformat.c +++ b/libavformat/avformat.c @@ -59,6 +59,8 @@ void ff_free_stream(AVStream **pst) av_freep(&sti->index_entries); av_freep(&sti->probe_data.buf); + av_packet_free(&sti->parse_pkt); + av_bsf_free(&sti->extract_extradata.bsf); if (sti->info) { diff --git a/libavformat/demux.c b/libavformat/demux.c index b40739dc3a..89b947730b 100644 --- a/libavformat/demux.c +++ b/libavformat/demux.c @@ -1175,9 +1175,9 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, { FormatContextInternal *const fci = ff_fc_internal(s); FFFormatContext *const si = &fci->fc; - AVPacket *out_pkt = si->parse_pkt; AVStream *st = s->streams[stream_index]; FFStream *const sti = ffstream(st); + AVPacket *out_pkt = sti->parse_pkt; const AVPacketSideData *sd = NULL; const uint8_t *data = pkt->data; uint8_t *extradata = sti->avctx->extradata; diff --git a/libavformat/internal.h b/libavformat/internal.h index 245f6eeb86..64452cce6e 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -314,6 +314,21 @@ typedef struct FFStream { enum AVStreamParseType need_parsing; struct AVCodecParserContext *parser; + /** + * The generic code uses this as a temporary packet + * to parse packets or for muxing, especially flushing. + * For demuxers, it may also be used for other means + * for short periods that are guaranteed not to overlap + * with calls to av_read_frame() (or ff_read_packet()) + * or with each other. + * It may be used by demuxers as a replacement for + * stack packets (unless they call one of the aforementioned + * functions with their own AVFormatContext). + * Every user has to ensure that this packet is blank + * after using it. + */ + AVPacket *parse_pkt; + /** * Number of frames that have been demuxed during avformat_find_stream_info() */ diff --git a/libavformat/options.c b/libavformat/options.c index 7e4130b405..28aa2da942 100644 --- a/libavformat/options.c +++ b/libavformat/options.c @@ -270,6 +270,10 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) sti->fmtctx = s; + sti->parse_pkt = av_packet_alloc(); + if (!sti->parse_pkt) + goto fail; + if (s->iformat) { sti->avctx = avcodec_alloc_context3(NULL); if (!sti->avctx) -- 2.49.1 >From 097a757f5f7a2b1349b583e8561e66fa554c3993 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Mon, 5 Jan 2026 23:52:04 -0300 Subject: [PATCH 2/2] avformat/demux: prevent the loss of packet side data when using an parser Many parsers will request data until they find what will be the start of the next assembled packet in order to decide where to cut the current one. If this happens, the loop in demux.c will, in case the demuxer exports already fully assembled packets as is sometimes the case for MPEG-TS, discard the already handled first input packet before it tries to move its side data to the output. The affected FATE tests reflect this change by no longer dropping the side data from the first input packet, nor exporting every other side data in the wrong output packet. Signed-off-by: James Almer <[email protected]> --- libavformat/demux.c | 14 +++++++------- tests/ref/fate/concat-demuxer-simple2-lavf-ts | 6 +++--- tests/ref/fate/segment-mp4-to-ts | 2 +- tests/ref/fate/ts-demux | 2 +- tests/ref/fate/ts-small-demux | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/libavformat/demux.c b/libavformat/demux.c index 89b947730b..72d23c3aa6 100644 --- a/libavformat/demux.c +++ b/libavformat/demux.c @@ -1226,6 +1226,13 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, got_output = !!out_pkt->size; + if (pkt->side_data && !out_pkt->side_data) { + out_pkt->side_data = pkt->side_data; + out_pkt->side_data_elems = pkt->side_data_elems; + pkt->side_data = NULL; + pkt->side_data_elems = 0; + } + if (!out_pkt->size) continue; @@ -1245,13 +1252,6 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, goto fail; } - if (pkt->side_data) { - out_pkt->side_data = pkt->side_data; - out_pkt->side_data_elems = pkt->side_data_elems; - pkt->side_data = NULL; - pkt->side_data_elems = 0; - } - /* set the duration */ out_pkt->duration = (sti->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) ? pkt->duration : 0; if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { diff --git a/tests/ref/fate/concat-demuxer-simple2-lavf-ts b/tests/ref/fate/concat-demuxer-simple2-lavf-ts index 620f1944ba..ab29edea88 100644 --- a/tests/ref/fate/concat-demuxer-simple2-lavf-ts +++ b/tests/ref/fate/concat-demuxer-simple2-lavf-ts @@ -61,7 +61,7 @@ audio|0|84637|0.940411|84637|0.940411|2351|0.026122|209|N/A|K__ audio|0|86988|0.966533|86988|0.966533|2351|0.026122|209|N/A|K__ audio|0|89339|0.992656|89339|0.992656|2351|0.026122|209|N/A|K__ video|1|83782|0.930911|80182|0.890911|3600|0.040000|12678|347800|___|MPEGTS Stream ID|224 -video|1|87382|0.970911|83782|0.930911|3600|0.040000|24711|361336|K__ +video|1|87382|0.970911|83782|0.930911|3600|0.040000|24711|361336|K__|MPEGTS Stream ID|224 video|1|91964|1.021822|88364|0.981822|3600|0.040000|24801|564|K__|MPEGTS Stream ID|224 video|1|95564|1.061822|91964|1.021822|3600|0.040000|16429|25944|___|MPEGTS Stream ID|224 video|1|99164|1.101822|95564|1.061822|3600|0.040000|14508|42864|___|MPEGTS Stream ID|224 @@ -125,7 +125,7 @@ audio|0|175619|1.951322|175619|1.951322|2351|0.026122|209|N/A|K__ audio|0|177970|1.977444|177970|1.977444|2351|0.026122|209|N/A|K__ audio|0|180321|2.003567|180321|2.003567|2351|0.026122|209|N/A|K__ video|1|174764|1.941822|171164|1.901822|3600|0.040000|12678|347800|___|MPEGTS Stream ID|224 -video|1|178364|1.981822|174764|1.941822|3600|0.040000|24711|361336|K__ +video|1|178364|1.981822|174764|1.941822|3600|0.040000|24711|361336|K__|MPEGTS Stream ID|224 video|1|139582|1.550911|135982|1.510911|3600|0.040000|12692|311516|___|MPEGTS Stream ID|224 video|1|143182|1.590911|139582|1.550911|3600|0.040000|10824|325052|___|MPEGTS Stream ID|224 video|1|146782|1.630911|143182|1.590911|3600|0.040000|11286|336144|___|MPEGTS Stream ID|224 @@ -141,7 +141,7 @@ audio|0|151237|1.680411|151237|1.680411|2351|0.026122|209|N/A|K__ audio|0|153588|1.706533|153588|1.706533|2351|0.026122|209|N/A|K__ audio|0|155939|1.732656|155939|1.732656|2351|0.026122|209|N/A|K__ video|1|150382|1.670911|146782|1.630911|3600|0.040000|12678|347800|___|MPEGTS Stream ID|224 -video|1|153982|1.710911|150382|1.670911|3600|0.040000|24711|361336|K__ +video|1|153982|1.710911|150382|1.670911|3600|0.040000|24711|361336|K__|MPEGTS Stream ID|224 video|1|161182|1.790911|157582|1.750911|3600|0.040000|12135|155852|___|MPEGTS Stream ID|224 video|1|164782|1.830911|161182|1.790911|3600|0.040000|12282|168448|___|MPEGTS Stream ID|224 video|1|168382|1.870911|164782|1.830911|3600|0.040000|24786|181420|K__|MPEGTS Stream ID|224 diff --git a/tests/ref/fate/segment-mp4-to-ts b/tests/ref/fate/segment-mp4-to-ts index 642d2a9fc9..9f3bdf4e1d 100644 --- a/tests/ref/fate/segment-mp4-to-ts +++ b/tests/ref/fate/segment-mp4-to-ts @@ -129,4 +129,4 @@ 0, 432000, 439200, 3600, 330, 0x150d9b60, F=0x0, S=1, MPEGTS Stream ID, 1, 0x00e000e0 0, 435600, 446400, 3600, 324, 0x558194ee, F=0x0, S=1, MPEGTS Stream ID, 1, 0x00e000e0 0, 439200, 442800, 3600, 191, 0x108e54d1, F=0x0, S=1, MPEGTS Stream ID, 1, 0x00e000e0 -0, 442800, 450000, 3600, 233, 0xac5b6486, F=0x0 +0, 442800, 450000, 3600, 233, 0xac5b6486, F=0x0, S=1, MPEGTS Stream ID, 1, 0x00e000e0 diff --git a/tests/ref/fate/ts-demux b/tests/ref/fate/ts-demux index 0a76d6cdc0..5c4d6bca3d 100644 --- a/tests/ref/fate/ts-demux +++ b/tests/ref/fate/ts-demux @@ -20,7 +20,7 @@ packet|codec_type=video|stream_index=0|pts=3912687864|pts_time=43474.309600|dts= packet|codec_type=video|stream_index=0|pts=3912684861|pts_time=43474.276233|dts=3912684861|dts_time=43474.276233|duration=1501|duration_time=0.016678|size=16296|pos=489176|flags=___|data_hash=CRC32:911b1649|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224 packet|codec_type=audio|stream_index=1|pts=3912641945|pts_time=43473.799389|dts=3912641945|dts_time=43473.799389|duration=2880|duration_time=0.032000|size=1536|pos=N/A|flags=K_C|data_hash=CRC32:d2f2012f|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189 packet|codec_type=audio|stream_index=2|pts=3912642700|pts_time=43473.807778|dts=3912642700|dts_time=43473.807778|duration=2880|duration_time=0.032000|size=768|pos=N/A|flags=K_C|data_hash=CRC32:3dad674a|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189 -packet|codec_type=video|stream_index=0|pts=3912686363|pts_time=43474.292922|dts=3912686363|dts_time=43474.292922|duration=1501|duration_time=0.016678|size=4944|pos=506660|flags=___|data_hash=CRC32:54a86cbb +packet|codec_type=video|stream_index=0|pts=3912686363|pts_time=43474.292922|dts=3912686363|dts_time=43474.292922|duration=1501|duration_time=0.016678|size=4944|pos=506660|flags=___|data_hash=CRC32:54a86cbb|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224 packet|codec_type=audio|stream_index=1|pts=3912644825|pts_time=43473.831389|dts=3912644825|dts_time=43473.831389|duration=2880|duration_time=0.032000|size=906|pos=474888|flags=K__|data_hash=CRC32:0893d398 packet|codec_type=audio|stream_index=2|pts=3912645580|pts_time=43473.839778|dts=3912645580|dts_time=43473.839778|duration=2880|duration_time=0.032000|size=354|pos=491808|flags=K__|data_hash=CRC32:f5963fa6 stream|index=0|codec_name=mpeg2video|profile=4|codec_type=video|codec_tag_string=[2][0][0][0]|codec_tag=0x0002|width=1280|height=720|coded_width=0|coded_height=0|has_b_frames=1|sample_aspect_ratio=1:1|display_aspect_ratio=16:9|pix_fmt=yuv420p|level=4|color_range=tv|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|ts_id=32776|ts_packetsize=188|id=0x31|r_frame_rate=60000/1001|avg_frame_rate=60000/1001|time_base=1/90000|start_pts=3912669846|start_time=43474.109400|duration_ts=19519|duration=0.216878|bit_rate=15000000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=15|extradata_size=150|extradata_hash=CRC32:53134fa8|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0| disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|side_datum/cpb_properties:side_data_type=CPB properties|side_datum/cpb_properties:max_bitrate=15000000|side_datum/cpb_properties:min_bitrate=0|side_datum/cpb_properties:avg_bitrate=0|side_datum/cpb_properties:buffer_size=9781248|side_datum/cpb_properties:vbv_delay=-1 diff --git a/tests/ref/fate/ts-small-demux b/tests/ref/fate/ts-small-demux index 7b4e54322d..596d3cb5c4 100644 --- a/tests/ref/fate/ts-small-demux +++ b/tests/ref/fate/ts-small-demux @@ -71,6 +71,6 @@ packet|codec_type=video|stream_index=0|pts=540000|pts_time=6.000000|dts=540000|d packet|codec_type=video|stream_index=0|pts=546000|pts_time=6.066667|dts=546000|dts_time=6.066667|duration=6000|duration_time=0.066667|size=15|pos=15416|flags=___|data_hash=CRC32:391aa740|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224 packet|codec_type=video|stream_index=0|pts=552000|pts_time=6.133333|dts=552000|dts_time=6.133333|duration=6000|duration_time=0.066667|size=16|pos=15604|flags=___|data_hash=CRC32:cca62b67|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224 packet|codec_type=video|stream_index=0|pts=558000|pts_time=6.200000|dts=558000|dts_time=6.200000|duration=6000|duration_time=0.066667|size=16|pos=15792|flags=___|data_hash=CRC32:27b943ef|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224 -packet|codec_type=video|stream_index=0|pts=564000|pts_time=6.266667|dts=564000|dts_time=6.266667|duration=6000|duration_time=0.066667|size=16|pos=16356|flags=___|data_hash=CRC32:f7116111 +packet|codec_type=video|stream_index=0|pts=564000|pts_time=6.266667|dts=564000|dts_time=6.266667|duration=6000|duration_time=0.066667|size=16|pos=16356|flags=___|data_hash=CRC32:f7116111|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224 stream|index=0|codec_name=h264|profile=578|codec_type=video|codec_tag_string=[27][0][0][0]|codec_tag=0x001b|mime_codec_string=avc1.42c00a|width=82|height=144|coded_width=82|coded_height=144|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=41:72|pix_fmt=yuv420p|level=10|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|is_avc=false|nal_length_size=0|ts_id=1|ts_packetsize=188|id=0x100|r_frame_rate=15/1|avg_frame_rate=15/1|time_base=1/90000|start_pts=126000|start_time=1.400000|duration_ts=444000|duration=4.933333|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=74|extradata_size=35|extradata_hash=CRC32:e62cae27|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_e ffects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0 format|filename=h264small.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=1.400000|duration=4.933333|size=16544|bit_rate=26828|probe_score=50 -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
