Commit b6267901 authored by Michael Niedermayer's avatar Michael Niedermayer

mp3demux: Rewrite xing TOC based seeking

The libav code depends on mp3 startcodes only occuring at the start of
frames. But there is nothing in mp3 that prevents them occuring elsewhere
by chance. Thus the code would fail randomly, the new code searches for 3
consecutive valid frames. If this turns out to be still insufficient the
number can be raised further, or additional checks added.
Signed-off-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parent 7696a392
...@@ -253,6 +253,21 @@ static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -253,6 +253,21 @@ static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt)
return ret; return ret;
} }
static int check(AVFormatContext *s, int64_t pos)
{
int64_t ret = avio_seek(s->pb, pos, SEEK_SET);
unsigned header;
MPADecodeHeader sd;
if (ret < 0)
return ret;
header = avio_rb32(s->pb);
if (ff_mpa_check_header(header) < 0)
return -1;
if (avpriv_mpegaudio_decode_header(&sd, header) == 1)
return -1;
return sd.frame_size;
}
static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
int flags) int flags)
{ {
...@@ -261,6 +276,7 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, ...@@ -261,6 +276,7 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
AVStream *st = s->streams[0]; AVStream *st = s->streams[0];
int64_t ret = av_index_search_timestamp(st, timestamp, flags); int64_t ret = av_index_search_timestamp(st, timestamp, flags);
uint32_t header = 0; uint32_t header = 0;
int i, j;
if (!mp3->xing_toc) { if (!mp3->xing_toc) {
st->skip_samples = timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0; st->skip_samples = timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0;
...@@ -276,19 +292,27 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, ...@@ -276,19 +292,27 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
if (ret < 0) if (ret < 0)
return ret; return ret;
while (!s->pb->eof_reached) { #define MIN_VALID 3
header = (header << 8) + avio_r8(s->pb); for(i=0; i<4096; i++) {
if (ff_mpa_check_header(header) >= 0) { int64_t pos = ie->pos + i;
ff_update_cur_dts(s, st, ie->timestamp); for(j=0; j<MIN_VALID; j++) {
ret = avio_seek(s->pb, -4, SEEK_CUR); ret = check(s, pos);
if(ret < 0)
st->skip_samples = ie->timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0; break;
pos += ret;
return (ret >= 0) ? 0 : ret;
} }
if(j==MIN_VALID)
break;
} }
if(j!=MIN_VALID)
i=0;
return AVERROR_EOF; ret = avio_seek(s->pb, ie->pos + i, SEEK_SET);
if (ret < 0)
return ret;
ff_update_cur_dts(s, st, ie->timestamp);
st->skip_samples = ie->timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0;
return 0;
} }
AVInputFormat ff_mp3_demuxer = { AVInputFormat ff_mp3_demuxer = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment