static int mp3_read_probe(AVProbeData *p)
{
int max_frames, first_frames = 0;
- int fsize, frames, sample_rate;
+ int frames, ret;
uint32_t header;
uint8_t *buf, *buf0, *buf2, *end;
- AVCodecContext *avctx = avcodec_alloc_context3(NULL);
-
- if (!avctx)
- return AVERROR(ENOMEM);
buf0 = p->buf;
end = p->buf + p->buf_size - sizeof(uint32_t);
buf2 = buf;
for(frames = 0; buf2 < end; frames++) {
+ MPADecodeHeader h;
+
header = AV_RB32(buf2);
- fsize = avpriv_mpa_decode_header(avctx, header, &sample_rate,
- &sample_rate, &sample_rate,
- &sample_rate);
- if(fsize < 0)
+ ret = avpriv_mpegaudio_decode_header(&h, header);
+ if (ret != 0)
break;
- buf2 += fsize;
+ buf2 += h.frame_size;
}
max_frames = FFMAX(max_frames, frames);
if(buf == buf0)
first_frames= frames;
}
- avcodec_free_context(&avctx);
// keep this in sync with ac3 probe, both need to avoid
// issues with MPEG-files!
if (first_frames >= 10)
#define MIDDLE_BITS(k, m, n) LAST_BITS((k) >> (m), ((n) - (m)))
uint16_t crc;
- uint32_t v;
+ uint32_t v, delays;
char version[10];
int32_t r_gain = INT32_MIN, a_gain = INT32_MIN;
MP3DecContext *mp3 = s->priv_data;
- const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}};
+ static const int64_t xing_offtbl[2][2] = { { 32, 17 }, { 17, 9 } };
/* Check for Xing / Info tag */
avio_skip(s->pb, xing_offtbl[c->lsf == 1][c->nb_channels == 1]);
avio_r8(s->pb);
/* Encoder delays */
- avio_rb24(s->pb);
+ delays = avio_rb24(s->pb);
+ st->codecpar->initial_padding = delays >> 12;
+ st->codecpar->trailing_padding = delays & ((1 << 12) - 1);
/* Misc */
avio_r8(s->pb);
MPADecodeHeader c;
int vbrtag_size = 0;
MP3DecContext *mp3 = s->priv_data;
+ int ret;
ffio_init_checksum(s->pb, ff_crcA001_update, 0);
v = avio_rb32(s->pb);
- if(ff_mpa_check_header(v) < 0)
- return -1;
- if (avpriv_mpegaudio_decode_header(&c, v) == 0)
+ ret = avpriv_mpegaudio_decode_header(&c, v);
+ if (ret < 0)
+ return ret;
+ else if (ret == 0)
vbrtag_size = c.frame_size;
if(c.layer != 3)
return -1;
st->duration = av_rescale_q(mp3->frames, (AVRational){spf, c.sample_rate},
st->time_base);
if (mp3->size && mp3->frames && !mp3->is_cbr)
- st->codec->bit_rate = av_rescale(mp3->size, 8 * c.sample_rate, mp3->frames * (int64_t)spf);
+ st->codecpar->bit_rate = av_rescale(mp3->size, 8 * c.sample_rate, mp3->frames * (int64_t)spf);
return 0;
}
if (!st)
return AVERROR(ENOMEM);
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->codec_id = AV_CODEC_ID_MP3;
+ st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codecpar->codec_id = AV_CODEC_ID_MP3;
st->need_parsing = AVSTREAM_PARSE_FULL;
st->start_time = 0;
return ret;
}
+#define SEEK_PACKETS 4
+#define SEEK_WINDOW (SEEK_PACKETS * MP3_PACKET_SIZE)
+
+/* The toc entry can position to the wrong byte offset, try to pick
+ * the closest frame by probing the data in a window of 4 packets.
+ */
+
+static int check(AVIOContext *pb, int64_t pos, int64_t *out_pos)
+{
+ MPADecodeHeader mh = { 0 };
+ int i;
+ uint32_t header;
+ int64_t off = 0;
+
+
+ for (i = 0; i < SEEK_PACKETS; i++) {
+ off = avio_seek(pb, pos + mh.frame_size, SEEK_SET);
+ if (off < 0)
+ break;
+
+ header = avio_rb32(pb);
+
+
+ if (avpriv_mpegaudio_decode_header(&mh, header))
+ break;
+ out_pos[i] = off;
+ }
+
+ return i;
+}
+
+static int reposition(AVFormatContext *s, int64_t pos)
+{
+ int ret, best_valid = -1;
+ int64_t p, best_pos = -1;
+
+ for (p = FFMAX(pos - SEEK_WINDOW / 2, 0); p < pos + SEEK_WINDOW / 2; p++) {
+ int64_t out_pos[SEEK_PACKETS];
+ ret = check(s->pb, p, out_pos);
+
+ if (best_valid < ret) {
+ int i;
+ for (i = 0; i < ret; i++) {
+ if (llabs(best_pos - pos) > llabs(out_pos[i] - pos)) {
+ best_pos = out_pos[i];
+ best_valid = ret;
+ }
+ }
+ if (best_pos == pos && best_valid == SEEK_PACKETS)
+ break;
+ }
+ }
+
+ if (best_valid <= 0)
+ return AVERROR(ENOSYS);
+
+ p = avio_seek(s->pb, best_pos, SEEK_SET);
+ if (p < 0)
+ return p;
+
+ return 0;
+}
+
static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
int flags)
{
AVIndexEntry *ie;
AVStream *st = s->streams[0];
int64_t ret = av_index_search_timestamp(st, timestamp, flags);
- uint32_t header = 0;
if (!mp3->xing_toc)
return AVERROR(ENOSYS);
return ret;
ie = &st->index_entries[ret];
- ret = avio_seek(s->pb, ie->pos, SEEK_SET);
+
+ ret = reposition(s, ie->pos);
if (ret < 0)
return ret;
- while (!s->pb->eof_reached) {
- header = (header << 8) + avio_r8(s->pb);
- if (ff_mpa_check_header(header) >= 0) {
- ff_update_cur_dts(s, st, ie->timestamp);
- ret = avio_seek(s->pb, -4, SEEK_CUR);
- return (ret >= 0) ? 0 : ret;
- }
- }
+ ff_update_cur_dts(s, st, ie->timestamp);
- return AVERROR_EOF;
+ return 0;
}
AVInputFormat ff_mp3_demuxer = {