From: Nil Fons Miret via ffmpeg-devel <ffmpeg-devel@ffmpeg.org> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org> Cc: Nil Fons Miret <nilf@netflix.com>, Kyle Swanson <kswanson@netflix.com> Subject: [FFmpeg-devel] [PATCH] avformat/demux: avoid unconditional ID3v2 tag consumption Date: Tue, 8 Jul 2025 18:07:35 -0400 Message-ID: <mailman.5729.1752012474.1384.ffmpeg-devel@ffmpeg.org> (raw) [-- Attachment #1: Type: message/rfc822, Size: 9887 bytes --] [-- Attachment #1.1.1: Type: text/plain, Size: 1478 bytes --] I have found a few instances of rawvideo files that coincidentally start with a header matching the ID3v2 header format, and ffmpeg consumes the header before demuxing, causing a decoding error. This happens even if "-f rawvideo" is specified. This patch limits the formats for which this automatic consuming of ID3v2 headers is done. Note: I am not an expert in ID3v2 by any means, and I'm happy to accept suggestions, both on the scope and mechanism of the solution. To reproduce, you can easily generate an example as follows: ``` ( echo "49 44 33 2B 98 3A 49 44 33 2B 98 3A 6A 44 54 2B" | xxd -r -p dd if=/dev/zero bs=1 count=115184 2>/dev/null ) > id3v2_320x240_yuv420p.yuv ffmpeg -f rawvideo -s 320x240 -pix_fmt yuv420p -i id3v2_320x240_yuv420p.yuv -f null - ``` This generates a 320x240 yuv420p file with a 16-byte header that matches the ID3v2 header format (this was copied from a real case I saw) and completed with zeroes for a total of 115200 bytes, the right size for this resolution and pixel format. On the master branch, I see: ``` [...] ID3v2.43 tag skipped, cannot handle version [...] [out#0/null @ 0x15700a6e0] Output file is empty, nothing was encoded(check -ss / -t / -frames parameters if used) frame= 0 fps=0.0 q=0.0 Lsize=N/A time=N/A bitrate=N/A speed=N/A ``` After the changes: it decodes as expected. ``` [...] frame= 1 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=16.5x elapsed=0:00:00.00 ``` Thanks in advance, Nil [-- Attachment #1.1.2: 0001-avformat-demux-avoid-unconditional-ID3v2-tag-consumpti.eml --] [-- Type: message/rfc822, Size: 5071 bytes --] From: nilfm <nil.fons@gmail.com> To: ffmpeg-devel@ffmpeg.org Subject: [PATCH] avformat/demux: avoid unconditional ID3v2 tag consumption Date: Wed, 2 Jul 2025 14:37:24 -0400 ID3v2 headers are now only parsed for formats that explicitly support them, avoiding premature data consumption that broke demuxing in other formats. Introduces AVFMT_FLAG_ID3V2_AUTO and applies it to mp3, aac, tta, and wav. Signed-off-by: nilfm <nil.fons@gmail.com> --- libavformat/aacdec.c | 2 +- libavformat/avformat.h | 1 + libavformat/demux.c | 9 ++++++--- libavformat/mp3dec.c | 2 +- libavformat/tta.c | 1 + libavformat/wavdec.c | 2 +- 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c index 0b4bd69dd2..21d63ce189 100644 --- a/libavformat/aacdec.c +++ b/libavformat/aacdec.c @@ -208,7 +208,7 @@ retry: const FFInputFormat ff_aac_demuxer = { .p.name = "aac", .p.long_name = NULL_IF_CONFIG_SMALL("raw ADTS AAC (Advanced Audio Coding)"), - .p.flags = AVFMT_GENERIC_INDEX, + .p.flags = AVFMT_GENERIC_INDEX | AVFMT_FLAG_ID3V2_AUTO, .p.extensions = "aac", .p.mime_type = "audio/aac,audio/aacp,audio/x-aac", .read_probe = adts_aac_probe, diff --git a/libavformat/avformat.h b/libavformat/avformat.h index b6c63e2237..6fe4559a6f 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1435,6 +1435,7 @@ typedef struct AVFormatContext { #define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) #define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats #define AVFMT_FLAG_AUTO_BSF 0x200000 ///< Add bitstream filters as requested by the muxer +#define AVFMT_FLAG_ID3V2_AUTO 0x400000 ///< Automatically parse ID3v2 metadata /** * Maximum number of bytes read from input in order to determine stream diff --git a/libavformat/demux.c b/libavformat/demux.c index 3749ab67a3..dfc146d9c4 100644 --- a/libavformat/demux.c +++ b/libavformat/demux.c @@ -214,6 +214,10 @@ static int update_stream_avctx(AVFormatContext *s) return 0; } +static av_always_inline int is_id3v2_format(const AVInputFormat *fmt) { + return fmt->flags & AVFMT_FLAG_ID3V2_AUTO; +} + int avformat_open_input(AVFormatContext **ps, const char *filename, const AVInputFormat *fmt, AVDictionary **options) { @@ -302,7 +306,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, } /* e.g. AVFMT_NOFILE formats will not have an AVIOContext */ - if (s->pb) + if (s->pb && is_id3v2_format(s->iformat)) ff_id3v2_read_dict(s->pb, &si->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); if (ffifmt(s->iformat)->read_header) @@ -321,8 +325,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, } if (id3v2_extra_meta) { - if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") || - !strcmp(s->iformat->name, "tta") || !strcmp(s->iformat->name, "wav")) { + if (is_id3v2_format(s->iformat)) { if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0) goto close; if ((ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0) diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c index 31eeb68ebb..9cfc711493 100644 --- a/libavformat/mp3dec.c +++ b/libavformat/mp3dec.c @@ -618,7 +618,7 @@ static const AVClass demuxer_class = { const FFInputFormat ff_mp3_demuxer = { .p.name = "mp3", .p.long_name = NULL_IF_CONFIG_SMALL("MP2/3 (MPEG audio layer 2/3)"), - .p.flags = AVFMT_GENERIC_INDEX, + .p.flags = AVFMT_GENERIC_INDEX | AVFMT_FLAG_ID3V2_AUTO, .p.extensions = "mp2,mp3,m2a,mpa", /* XXX: use probe */ .p.priv_class = &demuxer_class, .p.mime_type = "audio/mpeg", diff --git a/libavformat/tta.c b/libavformat/tta.c index fdc18216c8..26335202c7 100644 --- a/libavformat/tta.c +++ b/libavformat/tta.c @@ -191,6 +191,7 @@ static int tta_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp const FFInputFormat ff_tta_demuxer = { .p.name = "tta", .p.long_name = NULL_IF_CONFIG_SMALL("TTA (True Audio)"), + .p.flags = AVFMT_FLAG_ID3V2_AUTO, .p.extensions = "tta", .priv_data_size = sizeof(TTAContext), .read_probe = tta_probe, diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c index c65e0a2723..4c47a5f05c 100644 --- a/libavformat/wavdec.c +++ b/libavformat/wavdec.c @@ -1011,7 +1011,7 @@ static const AVClass w64_demuxer_class = { const FFInputFormat ff_w64_demuxer = { .p.name = "w64", .p.long_name = NULL_IF_CONFIG_SMALL("Sony Wave64"), - .p.flags = AVFMT_GENERIC_INDEX, + .p.flags = AVFMT_GENERIC_INDEX | AVFMT_FLAG_ID3V2_AUTO, .p.codec_tag = ff_wav_codec_tags_list, .p.priv_class = &w64_demuxer_class, .priv_data_size = sizeof(WAVDemuxContext), -- 2.47.1 [-- Attachment #2: Type: text/plain, Size: 251 bytes --] _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
reply other threads:[~2025-07-08 22:07 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=mailman.5729.1752012474.1384.ffmpeg-devel@ffmpeg.org \ --to=ffmpeg-devel@ffmpeg.org \ --cc=kswanson@netflix.com \ --cc=nilf@netflix.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
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