avformat/vobsub: fix seeking.
authorClément Bœsch <u@pkh.me>
Sun, 8 Sep 2013 07:43:53 +0000 (09:43 +0200)
committerClément Bœsch <u@pkh.me>
Tue, 10 Sep 2013 19:32:52 +0000 (21:32 +0200)
(cherry picked from commit f8678dcef3c5b0ea82e898e1f419863409fa135f)

libavformat/mpeg.c
libavformat/subtitles.c

index 5d5b09f..ca54f71 100644 (file)
@@ -725,6 +725,7 @@ static int vobsub_read_header(AVFormatContext *s)
             st->id = stream_id;
             st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
             st->codec->codec_id   = AV_CODEC_ID_DVD_SUBTITLE;
+            avpriv_set_pts_info(st, 64, 1, 1000);
             av_dict_set(&st->metadata, "language", id, 0);
             av_log(s, AV_LOG_DEBUG, "IDX stream[%d] id=%s\n", stream_id, id);
             header_parsed = 1;
@@ -889,6 +890,21 @@ static int vobsub_read_seek(AVFormatContext *s, int stream_index,
                             int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
 {
     MpegDemuxContext *vobsub = s->priv_data;
+
+    /* Rescale requested timestamps based on the first stream (timebase is the
+     * same for all subtitles stream within a .idx/.sub). Rescaling is done just
+     * like in avformat_seek_file(). */
+    if (stream_index == -1 && s->nb_streams != 1) {
+        AVRational time_base = s->streams[0]->time_base;
+        ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
+        min_ts = av_rescale_rnd(min_ts, time_base.den,
+                                time_base.num * (int64_t)AV_TIME_BASE,
+                                AV_ROUND_UP   | AV_ROUND_PASS_MINMAX);
+        max_ts = av_rescale_rnd(max_ts, time_base.den,
+                                time_base.num * (int64_t)AV_TIME_BASE,
+                                AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
+    }
+
     return ff_subtitles_queue_seek(&vobsub->q, s, stream_index,
                                    min_ts, ts, max_ts, flags);
 }
index 2af0450..11cf1a1 100644 (file)
@@ -109,7 +109,8 @@ int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int st
         for (i = 0; i < q->nb_subs; i++) {
             int64_t pts = q->subs[i].pts;
             uint64_t ts_diff = FFABS(pts - ts);
-            if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) {
+            if ((stream_index == -1 || q->subs[i].stream_index == stream_index) &&
+                pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) {
                 min_ts_diff = ts_diff;
                 idx = i;
             }
@@ -119,13 +120,24 @@ int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int st
         /* look back in the latest subtitles for overlapping subtitles */
         ts_selected = q->subs[idx].pts;
         for (i = idx - 1; i >= 0; i--) {
-            if (q->subs[i].duration <= 0)
+            if (q->subs[i].duration <= 0 ||
+                (stream_index != -1 && q->subs[i].stream_index != stream_index))
                 continue;
             if (q->subs[i].pts > ts_selected - q->subs[i].duration)
                 idx = i;
             else
                 break;
         }
+
+        /* If the queue is used to store multiple subtitles streams (like with
+         * VobSub) and the stream index is not specified, we need to make sure
+         * to focus on the smallest file position offset for a same timestamp;
+         * queue is ordered by pts and then filepos, so we can take the first
+         * entry for a given timestamp. */
+        if (stream_index == -1)
+            while (idx > 0 && q->subs[idx - 1].pts == q->subs[idx].pts)
+                idx--;
+
         q->current_sub_idx = idx;
     }
     return 0;