On Sat, 11 Jul 2015 17:41:52 +0200 Luca Barbato <[email protected]> wrote:
> Try to parse up to 4 packets to find the closest packet. > > Reported-By: [email protected] > --- > libavformat/mp3dec.c | 78 > ++++++++++++++++++++++++++++++++++++++++++++-------- > 1 file changed, 67 insertions(+), 11 deletions(-) > > diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c > index cba6778..94a6633 100644 > --- a/libavformat/mp3dec.c > +++ b/libavformat/mp3dec.c > @@ -366,6 +366,69 @@ 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 +436,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 +444,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 = { You could just remove all this code, and use generic indexing. It's the only way to get exact seeking with mp3. _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
