Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PR] avformat/demux: prevent the loss of packet side data when using an parser (PR #21388)
@ 2026-01-06  3:07 James Almer via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: James Almer via ffmpeg-devel @ 2026-01-06  3:07 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: James Almer

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 <jamrial@gmail.com>
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 <jamrial@gmail.com>
---
 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 <jamrial@gmail.com>
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 <jamrial@gmail.com>
---
 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 -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-01-06  3:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-06  3:07 [FFmpeg-devel] [PR] avformat/demux: prevent the loss of packet side data when using an parser (PR #21388) James Almer via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git