diff --git a/Frameworks/FFMPEG/ffmpeg-minimal/libavformat/mp3dec.c b/Frameworks/FFMPEG/ffmpeg-minimal/libavformat/mp3dec.c index 900544e67..95435712b 100644 --- a/Frameworks/FFMPEG/ffmpeg-minimal/libavformat/mp3dec.c +++ b/Frameworks/FFMPEG/ffmpeg-minimal/libavformat/mp3dec.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" #include "libavutil/opt.h" #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" @@ -28,8 +29,11 @@ #include "internal.h" #include "id3v2.h" #include "id3v1.h" +#include "apetag.h" #include "libavcodec/mpegaudiodecheader.h" +#define MP3_RESYNC_TOLERANCE_BYTES 65536 + #define XING_FLAG_FRAMES 0x01 #define XING_FLAG_SIZE 0x02 #define XING_FLAG_TOC 0x04 @@ -130,6 +134,8 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) MPADecodeHeader c; int vbrtag_size = 0; int is_cbr; + AVDictionaryEntry *de; + uint64_t duration = 0; v = avio_rb32(s->pb); if(ff_mpa_check_header(v) < 0) @@ -139,7 +145,10 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) vbrtag_size = c.frame_size; if(c.layer != 3) return -1; - + + mp3->start_pad = 0; + mp3->end_pad = 0; + spf = c.lsf ? 576 : 1152; /* Samples per frame, layer 3 */ /* Check for Xing / Info tag */ @@ -164,7 +173,12 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) v= avio_rb24(s->pb); mp3->start_pad = v>>12; mp3-> end_pad = v&4095; - st->skip_samples = mp3->start_pad + 528 + 1; + if (mp3->end_pad >= 528 + 1) { + mp3->end_pad = mp3->end_pad - (528 + 1); + st->skip_samples = mp3->start_pad + 528 + 1; + } else { + st->skip_samples = mp3->start_pad; + } if (!st->start_time) st->start_time = av_rescale_q(st->skip_samples, (AVRational){1, c.sample_rate}, @@ -185,18 +199,58 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) frames = avio_rb32(s->pb); } } + + if (!frames) + vbrtag_size = 0; - if(!frames && !size) + if (s->metadata && (de = av_dict_get(s->metadata, "iTunSMPB", NULL, 0))) { + uint32_t zero, start_pad, end_pad; + uint64_t last_eight_frames_offset; + if (sscanf(de->value, "%x %x %x %llx %x %llx", &zero, &start_pad, &end_pad, &duration, &zero, &last_eight_frames_offset) < 6) { + duration = 0; + } + else { + mp3->start_pad = start_pad; + mp3->end_pad = end_pad; + if (end_pad >= 528 + 1) + mp3->end_pad = end_pad - (528 + 1); + st->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) { + int i; + size = last_eight_frames_offset; + avio_seek(s->pb, base + vbrtag_size + last_eight_frames_offset, SEEK_SET); + for (i = 0; i < 8; ++i) { + v = avio_rb32(s->pb); + if (ff_mpa_check_header(v) < 0) + return -1; + if (avpriv_mpegaudio_decode_header(&c, v) != 0) + break; + size += c.frame_size; + avio_skip(s->pb, c.frame_size - 4); + } + } + } + } + + if(!frames && !size && !duration) return -1; /* Skip the vbr tag frame */ avio_seek(s->pb, base + vbrtag_size, SEEK_SET); - if(frames) + if (duration) + st->duration = av_rescale_q(duration, (AVRational){1, c.sample_rate}, st->time_base); + else if(frames) st->duration = av_rescale_q(frames, (AVRational){spf, c.sample_rate}, - st->time_base); - if (size && frames && !is_cbr) - st->codec->bit_rate = av_rescale(size, 8 * c.sample_rate, frames * (int64_t)spf); + st->time_base) - av_rescale_q(mp3->end_pad, (AVRational){1, c.sample_rate}, st->time_base); + + if (size) { + if (duration) + st->codec->bit_rate = av_rescale(size, 8 * c.sample_rate, duration); + else if (frames) + st->codec->bit_rate = av_rescale(size, 8 * c.sample_rate, frames * (int64_t)spf); + } mp3->is_cbr = is_cbr; mp3->header_filesize = size; @@ -231,8 +285,60 @@ static int mp3_read_header(AVFormatContext *s) if(s->pb->seekable) mp3->filesize = avio_size(s->pb); - if (mp3_parse_vbr_tags(s, st, off) < 0) + if (mp3_parse_vbr_tags(s, st, off) < 0 && s->pb->seekable) + { + uint64_t duration = 0; + uint8_t buf[8]; + int sample_rate = 0; + int retry_count; + /* Time for a full parse! */ + avio_seek(s->pb, mp3->filesize - 128, SEEK_SET); + avio_read(s->pb, buf, 3); + if (buf[0] == 'T' && buf[1] == 'A' && buf[2] == 'G') + mp3->filesize -= 128; + avio_seek(s->pb, mp3->filesize - APE_TAG_FOOTER_BYTES, SEEK_SET); + avio_read(s->pb, buf, 8); + if (memcmp(buf, APE_TAG_PREAMBLE, 8) == 0) + { + avio_seek(s->pb, 4, SEEK_CUR); + mp3->filesize -= avio_rl32(s->pb) + APE_TAG_FOOTER_BYTES; + } avio_seek(s->pb, off, SEEK_SET); + retry_count = MP3_RESYNC_TOLERANCE_BYTES; + while (avio_tell(s->pb) < mp3->filesize) + { + MPADecodeHeader c; + uint32_t v, spf; + + v = avio_rb32(s->pb); + + if(ff_mpa_check_header(v) < 0) + { + if (--retry_count) + { + avio_seek(s->pb, -3, SEEK_CUR); + continue; + } + else break; + } + + retry_count = MP3_RESYNC_TOLERANCE_BYTES; + + if (avpriv_mpegaudio_decode_header(&c, v) != 0) + break; + + if (!sample_rate) + sample_rate = c.sample_rate; + + spf = c.lsf ? 576 : 1152; /* Samples per frame, layer 3 */ + + duration += spf; + + avio_skip(s->pb, c.frame_size - 4); + } + avio_seek(s->pb, off, SEEK_SET); + st->duration = duration && sample_rate ? av_rescale_q(duration, (AVRational){1, sample_rate}, st->time_base) : 0; + } /* the parameters will be extracted from the compressed bitstream */ return 0; @@ -362,7 +468,7 @@ static const AVClass demuxer_class = { AVInputFormat ff_mp3_demuxer = { .name = "mp3", - .long_name = "MP2/3 (MPEG audio layer 2/3)", + .long_name = NULL_IF_CONFIG_SMALL("MP2/3 (MPEG audio layer 2/3)"), .read_probe = mp3_read_probe, .read_header = mp3_read_header, .read_packet = mp3_read_packet, diff --git a/Plugins/FFMPEG/FFMPEGDecoder.m b/Plugins/FFMPEG/FFMPEGDecoder.m index beb7f3a80..1d8215884 100644 --- a/Plugins/FFMPEG/FFMPEGDecoder.m +++ b/Plugins/FFMPEG/FFMPEGDecoder.m @@ -179,6 +179,9 @@ int lockmgr_callback(void ** mutex, enum AVLockOp op) - (int)readAudio:(void *)buf frames:(UInt32)frames { + if ( framesRead >= totalFrames ) + return 0; + int frameSize = channels * (bitsPerSample / 8); int gotFrame = 0; int dataSize = 0;