This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 6397b2b5b6493ed5cb61bd18fdac18a32ae27548 Author: Romain Beauxis <[email protected]> AuthorDate: Wed Sep 16 15:20:09 2026 -0500 Commit: James Almer <[email protected]> CommitDate: Sat Sep 19 13:40:52 2026 +0000 avformat/mp3enc: build the Xing frame header from the first audio frame Some hardware decoders reject files whose Xing frame header differs from the audio frames, e.g. joint stereo from libmp3lame. Fail when the first frame does not match the Xing frame layout. Fixes #24129. --- libavformat/mp3enc.c | 40 ++++++++++++++++++++++++---- tests/ref/fate/cover-art-mp3-id3v2-remux | 2 +- tests/ref/fate/gapless-mp3-remux | 2 +- tests/ref/fate/id3v2-priv-remux | 2 +- tests/ref/fate/id3v2-reenc-remux-keep | 2 +- tests/ref/fate/mpegaudiodecheader-libmp3lame | 3 +-- tests/ref/fate/mpegaudiodecheader-mp3-remux | 3 +-- 7 files changed, 41 insertions(+), 13 deletions(-) diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index 14e56c5738..4ea54f72c3 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -127,6 +127,8 @@ typedef struct MP3Context { int initial_bitrate; int has_variable_bitrate; MPADecodeHeader2 *hdr; + MPADecodeHeader2 *xing_header; + MPADecodeHeader2 *first_frame; int delay; int64_t padding; @@ -209,13 +211,13 @@ static int mp3_write_xing(AVFormatContext *s) return 0; header |= mask; - ret = avpriv_mpegaudio_decode_header2(&mp3->hdr, header); + ret = avpriv_mpegaudio_decode_header2(&mp3->xing_header, header); if (ret < 0) return ret; - mp3->xing_offset = xing_offtbl[mp3->hdr->lsf == 1][mp3->hdr->nb_channels == 1] + 4; + mp3->xing_offset = xing_offtbl[mp3->xing_header->lsf == 1][mp3->xing_header->nb_channels == 1] + 4; bytes_needed = mp3->xing_offset + XING_SIZE; - if (bytes_needed <= mp3->hdr->frame_size) + if (bytes_needed <= mp3->xing_header->frame_size) break; header &= ~mask; @@ -231,7 +233,7 @@ static int mp3_write_xing(AVFormatContext *s) ffio_wfourcc(dyn_ctx, "Xing"); avio_wb32(dyn_ctx, 0x01 | 0x02 | 0x04 | 0x08); // frames / size / TOC / vbr scale - mp3->size = mp3->hdr->frame_size; + mp3->size = mp3->xing_header->frame_size; mp3->want=1; mp3->seen=0; mp3->pos=0; @@ -276,7 +278,7 @@ static int mp3_write_xing(AVFormatContext *s) avio_wb16(dyn_ctx, 0); // music crc avio_wb16(dyn_ctx, 0); // tag crc - ffio_fill(dyn_ctx, 0, mp3->hdr->frame_size - bytes_needed); + ffio_fill(dyn_ctx, 0, mp3->xing_header->frame_size - bytes_needed); mp3->xing_frame_size = avio_close_dyn_buf(dyn_ctx, &mp3->xing_frame); mp3->xing_frame_offset = avio_tell(s->pb); @@ -332,6 +334,23 @@ static int mp3_write_audio_packet(AVFormatContext *s, AVPacket *pkt) mp3->initial_bitrate = mp3->hdr->bit_rate; if ((mp3->hdr->bit_rate == 0) || (mp3->initial_bitrate != mp3->hdr->bit_rate)) mp3->has_variable_bitrate = 1; + if (mp3->xing_offset && !mp3->first_frame) { + const MPADecodeHeader2 *xing = mp3->xing_header; + + if (mp3->hdr->layer != xing->layer || + mp3->hdr->sample_rate != xing->sample_rate || + mp3->hdr->nb_channels != xing->nb_channels) { + av_log(s, AV_LOG_ERROR, "First audio frame (layer %d, %d Hz, %d channels) " + "does not match the stream (layer %d, %d Hz, %d channels).\n", + mp3->hdr->layer, mp3->hdr->sample_rate, mp3->hdr->nb_channels, + xing->layer, xing->sample_rate, xing->nb_channels); + return AVERROR_INVALIDDATA; + } + + ret = avpriv_mpegaudio_decode_header2(&mp3->first_frame, h); + if (ret < 0) + return ret; + } } else if (ret == AVERROR(ENOMEM)) { return ret; } else { @@ -443,6 +462,15 @@ static void mp3_update_xing(AVFormatContext *s) if (!mp3->has_variable_bitrate) AV_WL32(mp3->xing_frame + mp3->xing_offset, MKTAG('I', 'n', 'f', 'o')); + if (mp3->first_frame) { + MPADecodeHeader2 *header = mp3->first_frame; + + header->error_protection = mp3->xing_header->error_protection; + header->bitrate_index = mp3->xing_header->bitrate_index; + header->padding = mp3->xing_header->padding; + AV_WB32(mp3->xing_frame, ff_mpa_encode_header(header)); + } + AV_WB32(mp3->xing_frame + mp3->xing_offset + 8, mp3->frames); AV_WB32(mp3->xing_frame + mp3->xing_offset + 12, mp3->size); @@ -694,6 +722,8 @@ static void mp3_deinit(struct AVFormatContext *s) ffio_free_dyn_buf(&mp3->id3_pb); av_freep(&mp3->xing_frame); av_freep(&mp3->hdr); + av_freep(&mp3->xing_header); + av_freep(&mp3->first_frame); } const FFOutputFormat ff_mp3_muxer = { diff --git a/tests/ref/fate/cover-art-mp3-id3v2-remux b/tests/ref/fate/cover-art-mp3-id3v2-remux index ddc47c4988..2be6836b76 100644 --- a/tests/ref/fate/cover-art-mp3-id3v2-remux +++ b/tests/ref/fate/cover-art-mp3-id3v2-remux @@ -1,4 +1,4 @@ -3a20f15563ed1d277f54562743f615de *tests/data/fate/cover-art-mp3-id3v2-remux.mp3 +eb486ac9092d44a280e4041ee354e53b *tests/data/fate/cover-art-mp3-id3v2-remux.mp3 346486 tests/data/fate/cover-art-mp3-id3v2-remux.mp3 #tb 0: 1/14112000 #media_type 0: audio diff --git a/tests/ref/fate/gapless-mp3-remux b/tests/ref/fate/gapless-mp3-remux index 0d3d625e33..6d56043a7f 100644 --- a/tests/ref/fate/gapless-mp3-remux +++ b/tests/ref/fate/gapless-mp3-remux @@ -1,3 +1,3 @@ -4458dffaa3fd294d708f05965e1a3186 *tests/data/fate/gapless-mp3-remux.mp3 +a490eb522f8fd2c772d1e27a1b5054a2 *tests/data/fate/gapless-mp3-remux.mp3 249138 tests/data/fate/gapless-mp3-remux.mp3 stream|start_pts=353600|duration_ts=218521600 diff --git a/tests/ref/fate/id3v2-priv-remux b/tests/ref/fate/id3v2-priv-remux index c732f36ae2..617bcf2437 100644 --- a/tests/ref/fate/id3v2-priv-remux +++ b/tests/ref/fate/id3v2-priv-remux @@ -1,4 +1,4 @@ -bb2816e3a05ce136e9ac14479c1ebe24 *tests/data/fate/id3v2-priv-remux.mp3 +a95cafeff7e82a72aaced6e713cc479a *tests/data/fate/id3v2-priv-remux.mp3 8542 tests/data/fate/id3v2-priv-remux.mp3 #tb 0: 1/14112000 #media_type 0: audio diff --git a/tests/ref/fate/id3v2-reenc-remux-keep b/tests/ref/fate/id3v2-reenc-remux-keep index 5139f6a408..5c2def69e8 100644 --- a/tests/ref/fate/id3v2-reenc-remux-keep +++ b/tests/ref/fate/id3v2-reenc-remux-keep @@ -1,4 +1,4 @@ -a1712e6e4f04a9066f221157b5a55a23 *tests/data/fate/id3v2-reenc-remux-keep.mp3 +4e886ae5b38188d171a61c19deabac0a *tests/data/fate/id3v2-reenc-remux-keep.mp3 192081 tests/data/fate/id3v2-reenc-remux-keep.mp3 [FORMAT] TAG:title=7rk diff --git a/tests/ref/fate/mpegaudiodecheader-libmp3lame b/tests/ref/fate/mpegaudiodecheader-libmp3lame index 3955a43426..ddf18712e5 100644 --- a/tests/ref/fate/mpegaudiodecheader-libmp3lame +++ b/tests/ref/fate/mpegaudiodecheader-libmp3lame @@ -1,3 +1,2 @@ -offset=20 frames=1 header=FFFB9000 layer=3 sample_rate=44100 bit_rate=128000 crc=0 mode=0 mode_ext=0 copyright=0 original=0 emphasis=0 private_bit=0 -offset=437 frames=231 header=FFFB9064 layer=3 sample_rate=44100 bit_rate=128000 crc=0 mode=1 mode_ext=2 copyright=0 original=1 emphasis=0 private_bit=0 +offset=20 frames=232 header=FFFB9064 layer=3 sample_rate=44100 bit_rate=128000 crc=0 mode=1 mode_ext=2 copyright=0 original=1 emphasis=0 private_bit=0 frames=232 diff --git a/tests/ref/fate/mpegaudiodecheader-mp3-remux b/tests/ref/fate/mpegaudiodecheader-mp3-remux index c5d4d5cdd7..4a7602dc83 100644 --- a/tests/ref/fate/mpegaudiodecheader-mp3-remux +++ b/tests/ref/fate/mpegaudiodecheader-mp3-remux @@ -1,3 +1,2 @@ -offset=301 frames=1 header=FFFB9000 layer=3 sample_rate=44100 bit_rate=128000 crc=0 mode=0 mode_ext=0 copyright=0 original=0 emphasis=0 private_bit=0 -offset=718 frames=21 header=FFFB9064 layer=3 sample_rate=44100 bit_rate=128000 crc=0 mode=1 mode_ext=2 copyright=0 original=1 emphasis=0 private_bit=0 +offset=301 frames=22 header=FFFB9064 layer=3 sample_rate=44100 bit_rate=128000 crc=0 mode=1 mode_ext=2 copyright=0 original=1 emphasis=0 private_bit=0 frames=22 -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
