mp3: Make the seek more robust
Try to parse up to 4 packets to find the closest packet. Reported-By: jan.schlueter@ofai.at
This commit is contained in:
parent
d80811c94e
commit
c1d647b15a
@ -366,6 +366,67 @@ static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
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 (ff_mpa_check_header(header) < 0 ||
|
||||
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);
|
||||
|
||||
avio_seek(s->pb, best_pos, SEEK_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
|
||||
int flags)
|
||||
{
|
||||
@ -373,7 +434,6 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
|
||||
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);
|
||||
@ -382,20 +442,14 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
|
||||
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 = {
|
||||
|
Loading…
Reference in New Issue
Block a user