[FFmpeg-devel] [PATCH] avformat: parse iTunes gapless information

Christopher Snowhill kode54 at gmail.com
Sun Jan 29 02:09:20 EET 2017


Disregard those two, they were mistaken transcodes. These two are supposed to be gapless, however. Same signal, just not transcoded and downsampled first.
On 1/27/2017 1:26:24 PM, Christopher Snowhill <kode54 at gmail.com> wrote:
Combined with the ID3v2.2 COM frame fix I just submitted, these MP3 files will decode to a continuous signal.
On 1/27/2017 4:10:54 AM, wm4 <nfxjfg at googlemail.com> wrote:
On Thu, 26 Jan 2017 16:47:12 -0800
Christopher Snowhill wrote:

> Signed-off-by: Christopher Snowhill
> ---
> libavformat/mp3dec.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 76 insertions(+), 1 deletion(-)
>
> diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c
> index 099ca57..b895e37 100644
> --- a/libavformat/mp3dec.c
> +++ b/libavformat/mp3dec.c
> @@ -295,6 +295,66 @@ static void mp3_parse_vbri_tag(AVFormatContext *s, AVStream *st, int64_t base)
> }
> }
>
> +static void mp3_parse_itunes_tag(AVFormatContext *s, AVStream *st, MPADecodeHeader *c, int64_t base, int vbrtag_size, unsigned int *size, uint64_t *duration)
> +{
> + uint32_t v;
> + AVDictionaryEntry *de;
> + MP3DecContext *mp3 = s->priv_data;
> + size_t length;
> + uint32_t zero, start_pad, end_pad;
> + uint64_t last_eight_frames_offset;
> + int64_t temp_duration, file_size;
> + int i;
> +
> + if (!s->metadata || !(de = av_dict_get(s->metadata, "iTunSMPB", NULL, 0)))
> + return;
> +
> + length = strlen(de->value);
> +
> + /* Minimum length is one digit per field plus the whitespace, maximum length should depend on field type
> + * There are four fields we need in the first six, the rest are currently zero padding */
> + if (length (10 * 8 + 2 * 16 + 11))
> + return;
> +
> + file_size = avio_size(s->pb);
> + if (file_size
> + file_size = 0;
> +
> + if (sscanf(de->value, "%"PRIx32" %"PRIx32" %"PRIx32" %"PRIx64" %"PRIx32" %"PRIx64, &zero, &start_pad, &end_pad, &temp_duration, &zero, &last_eight_frames_offset)
> + temp_duration
> + start_pad > (576 * 2 * 32) ||
> + end_pad > (576 * 2 * 64) ||
> + (file_size && (last_eight_frames_offset >= (file_size - base - vbrtag_size)))) {
> + *duration = 0;
> + return;
> + }
> +
> + *duration = temp_duration;
> +
> + mp3->start_pad = start_pad;
> + mp3->end_pad = end_pad;
> + if (end_pad >= 528 + 1)
> + mp3->end_pad = end_pad - (528 + 1);
> + st->start_skip_samples = mp3->start_pad + 528 + 1;
> + av_log(s, AV_LOG_DEBUG, "pad %d %d\n", mp3->start_pad, mp3->end_pad);
> + if (!s->pb->seekable)
> + return;
> +
> + *size = (unsigned int) last_eight_frames_offset;
> + if (avio_seek(s->pb, base + vbrtag_size + last_eight_frames_offset, SEEK_SET)
> + return;
> +
> + for (i = 0; i
> + v = avio_rb32(s->pb);
> + if (ff_mpa_check_header(v)
> + return;
> + if (avpriv_mpegaudio_decode_header(c, v) != 0)
> + break;
> + *size += c->frame_size;
> + avio_skip(s->pb, c->frame_size - 4);
> + }
> +}
> +
> /**
> * Try to find Xing/Info/VBRI tags and compute duration from info therein
> */
> @@ -303,8 +363,10 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
> uint32_t v, spf;
> MPADecodeHeader c;
> int vbrtag_size = 0;
> + unsigned int size = 0;
> MP3DecContext *mp3 = s->priv_data;
> int ret;
> + uint64_t duration = 0;
>
> ffio_init_checksum(s->pb, ff_crcA001_update, 0);
>
> @@ -327,16 +389,29 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
> mp3_parse_vbri_tag(s, st, base);
>
> if (!mp3->frames && !mp3->header_filesize)
> + vbrtag_size = 0;
> +
> + mp3_parse_itunes_tag(s, st, &c, base, vbrtag_size, &size, &duration);
> +
> + if (!mp3->frames && !size && !duration)
> return -1;
>
> /* Skip the vbr tag frame */
> avio_seek(s->pb, base + vbrtag_size, SEEK_SET);
>
> - if (mp3->frames)
> + if (duration)
> + st->duration = av_rescale_q(duration, (AVRational){1, c.sample_rate}, st->time_base);
> + else if (mp3->frames)
> st->duration = av_rescale_q(mp3->frames, (AVRational){spf, c.sample_rate},
> st->time_base);
> if (mp3->header_filesize && mp3->frames && !mp3->is_cbr)
> st->codecpar->bit_rate = av_rescale(mp3->header_filesize, 8 * c.sample_rate, mp3->frames * (int64_t)spf);
> + if (size) {
> + if (duration)
> + st->codecpar->bit_rate = av_rescale(size, 8 * c.sample_rate, duration);
> + else if (mp3->frames)
> + st->codecpar->bit_rate = av_rescale(size, 8 * c.sample_rate, mp3->frames * (int64_t)spf);
> + }
>
> return 0;
> }

If we add this, can we add a fate sample as well? The test should be
similar to the other gapless tests.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel at ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: m1.mp3
Type: audio/mpeg
Size: 347622 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20170128/8664023d/attachment.mp3>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: m2.mp3
Type: audio/mpeg
Size: 353474 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20170128/8664023d/attachment-0001.mp3>


More information about the ffmpeg-devel mailing list