From fca3f95fff993fb11ee3cd3ba09da7139177d8f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Sun, 8 Sep 2013 09:43:53 +0200 Subject: [PATCH] avformat/vobsub: fix seeking. --- libavformat/mpeg.c | 16 ++++++++++++++++ libavformat/subtitles.c | 16 ++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c index 63b35ef..0b4fc23 100644 --- a/libavformat/mpeg.c +++ b/libavformat/mpeg.c @@ -701,6 +701,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; @@ -865,6 +866,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); } diff --git a/libavformat/subtitles.c b/libavformat/subtitles.c index 21d68a9..99f6f34 100644 --- a/libavformat/subtitles.c +++ b/libavformat/subtitles.c @@ -111,7 +111,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; } @@ -121,7 +122,8 @@ 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; @@ -129,6 +131,16 @@ int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int st break; } q->current_sub_idx = idx; + + /* 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 (q->current_sub_idx > 0 && + q->subs[q->current_sub_idx - 1].pts == q->subs[q->current_sub_idx].pts) + q->current_sub_idx--; } return 0; } -- 1.8.4