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

Reply via email to