]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/mp3dec.c
avformat/mp3dec: make generic index mode the default
[ffmpeg] / libavformat / mp3dec.c
index 161f27d2caaec695ae4af7281132f6938cbc1c25..a2d3dfe737754b24f0210824d996f04acd667229 100644 (file)
@@ -106,11 +106,11 @@ static int mp3_read_probe(AVProbeData *p)
 //mpegps_mp3_unrecognized_format.mpg has max_frames=3
 }
 
-static void read_xing_toc(AVFormatContext *s, int64_t base, int64_t filesize, int64_t duration)
+static void read_xing_toc(AVFormatContext *s, int64_t filesize, int64_t duration)
 {
     int i;
     MP3DecContext *mp3 = s->priv_data;
-    int fill_index = mp3->usetoc && duration > 0;
+    int fill_index = mp3->usetoc == 1 && duration > 0;
 
     if (!filesize &&
         !(filesize = avio_size(s->pb))) {
@@ -122,7 +122,7 @@ static void read_xing_toc(AVFormatContext *s, int64_t base, int64_t filesize, in
         uint8_t b = avio_r8(s->pb);
         if (fill_index)
             av_add_index_entry(s->streams[0],
-                           av_rescale(b, filesize, 256) + base,
+                           av_rescale(b, filesize, 256),
                            av_rescale(i, duration, XING_TOC_COUNT),
                            0, 0, AVINDEX_KEYFRAME);
     }
@@ -130,7 +130,7 @@ static void read_xing_toc(AVFormatContext *s, int64_t base, int64_t filesize, in
         mp3->xing_toc = 1;
 }
 
-static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st, int64_t base,
+static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st,
                                MPADecodeHeader *c, uint32_t spf)
 {
 #define LAST_BITS(k, n) ((k) & ((1 << (n)) - 1))
@@ -172,7 +172,7 @@ static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st, int64_t base,
         }
     }
     if (v & XING_FLAG_TOC)
-        read_xing_toc(s, base, mp3->header_filesize, av_rescale_q(mp3->frames,
+        read_xing_toc(s, mp3->header_filesize, av_rescale_q(mp3->frames,
                                        (AVRational){spf, c->sample_rate},
                                        st->time_base));
     /* VBR quality */
@@ -228,13 +228,13 @@ static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st, int64_t base,
 
         mp3->start_pad = v>>12;
         mp3->  end_pad = v&4095;
-        st->skip_samples = mp3->start_pad + 528 + 1;
+        st->start_skip_samples = mp3->start_pad + 528 + 1;
         if (mp3->frames) {
             st->first_discard_sample = -mp3->end_pad + 528 + 1 + mp3->frames * (int64_t)spf;
             st->last_discard_sample = mp3->frames * (int64_t)spf;
         }
         if (!st->start_time)
-            st->start_time = av_rescale_q(st->skip_samples,
+            st->start_time = av_rescale_q(st->start_skip_samples,
                                             (AVRational){1, c->sample_rate},
                                             st->time_base);
         av_log(s, AV_LOG_DEBUG, "pad %d %d\n", mp3->start_pad, mp3->  end_pad);
@@ -310,7 +310,7 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
     mp3->frames = 0;
     mp3->header_filesize   = 0;
 
-    mp3_parse_info_tag(s, st, base, &c, spf);
+    mp3_parse_info_tag(s, st, &c, spf);
     mp3_parse_vbri_tag(s, st, base);
 
     if (!mp3->frames && !mp3->header_filesize)
@@ -334,6 +334,10 @@ static int mp3_read_header(AVFormatContext *s)
     AVStream *st;
     int64_t off;
     int ret;
+    int i;
+
+    if (mp3->usetoc < 0)
+        mp3->usetoc = 2;
 
     st = avformat_new_stream(s, NULL);
     if (!st)
@@ -363,6 +367,10 @@ static int mp3_read_header(AVFormatContext *s)
     if (ret < 0)
         return ret;
 
+    // the seek index is relative to the end of the xing vbr headers
+    for (i = 0; i < st->nb_index_entries; i++)
+        st->index_entries[i].pos += avio_tell(s->pb);
+
     /* the parameters will be extracted from the compressed bitstream */
     return 0;
 }
@@ -427,28 +435,24 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
     int64_t best_pos;
     int best_score;
 
+    if (mp3->usetoc == 2)
+        return -1; // generic index code
+
     if (   mp3->is_cbr
+        && (mp3->usetoc == 0 || !mp3->xing_toc)
         && st->duration > 0
         && mp3->header_filesize > s->internal->data_offset
         && mp3->frames) {
-        int64_t filesize = avio_size(s->pb);
-        int64_t duration;
-        if (filesize <= s->internal->data_offset)
-            filesize = mp3->header_filesize;
-        filesize -= s->internal->data_offset;
-        duration = av_rescale(st->duration, filesize, mp3->header_filesize - s->internal->data_offset);
         ie = &ie1;
-        timestamp = av_clip64(timestamp, 0, duration);
+        timestamp = av_clip64(timestamp, 0, st->duration);
         ie->timestamp = timestamp;
-        ie->pos       = av_rescale(timestamp, filesize, duration) + s->internal->data_offset;
+        ie->pos       = av_rescale(timestamp, mp3->header_filesize, st->duration) + s->internal->data_offset;
     } else if (mp3->xing_toc) {
         if (ret < 0)
             return ret;
 
         ie = &st->index_entries[ret];
     } else {
-        st->skip_samples = timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0;
-
         return -1;
     }
 
@@ -489,13 +493,18 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
     ret = avio_seek(s->pb, best_pos, SEEK_SET);
     if (ret < 0)
         return ret;
+
+    if (mp3->is_cbr && ie == &ie1) {
+        int frame_duration = av_rescale(st->duration, 1, mp3->frames);
+        ie1.timestamp = frame_duration * av_rescale(best_pos - s->internal->data_offset, mp3->frames, mp3->header_filesize);
+    }
+
     ff_update_cur_dts(s, st, ie->timestamp);
-    st->skip_samples = ie->timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0;
     return 0;
 }
 
 static const AVOption options[] = {
-    { "usetoc", "use table of contents", offsetof(MP3DecContext, usetoc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, AV_OPT_FLAG_DECODING_PARAM},
+    { "usetoc", "use table of contents", offsetof(MP3DecContext, usetoc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, AV_OPT_FLAG_DECODING_PARAM},
     { NULL },
 };