summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2012-12-08 13:12:46 +0100
committerwm4 <wm4@nowhere>2012-12-11 00:36:42 +0100
commitb3fb7c2cade9d70a4ca05821c87f68e941da6237 (patch)
tree192974248bd908e6b807d5fbf070174e48470d30
parent7288834a4c2945729f5a261cba2c007683754b7b (diff)
downloadmpv-b3fb7c2cade9d70a4ca05821c87f68e941da6237.tar.bz2
mpv-b3fb7c2cade9d70a4ca05821c87f68e941da6237.tar.xz
core: improve seeking in external files
This affects streams loaded with -subfile and -audiofile. They could get out of sync when they were deselected, and the main file was seeked. Add code to seek external files when they are selected (see init_demux_stream()). Use avformat_seek_file() under certain circumstances. Both av_seek_frame() ("old" API) and avformat_seek_file() ("new" API) seem to be broken with some formats. At least the vobsub demuxer doesn't implement the old API (and the old API doesn't fallback to the new API), while the fallback from new API to old API gives bad results. For example, seeking forward with small step sizes seems to fail with the new API (tested with Matroska by trying to seek 1 second forward relative to priv->last_pts). Since only subtitle demuxers implement the new API anyway, checking whether iformat->read_seek2 is set to test whether the old API is not supported gives best results. This is a hack at best, but makes things work. Remove backwards seeking on seek failure. This was annoying, and only was there to compensate for obscure corner cases (see 1ad332). In particular, files with completely broken seeking that used to skip back to the start on every seek request may now terminate playback.
-rw-r--r--core/mplayer.c38
-rw-r--r--demux/demux.c4
-rw-r--r--demux/demux_lavf.c12
3 files changed, 41 insertions, 13 deletions
diff --git a/core/mplayer.c b/core/mplayer.c
index 4eb4ff0e23..81302f284f 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -439,6 +439,23 @@ static void print_file_properties(struct MPContext *mpctx, const char *filename)
/// step size of mixer changes
int volstep = 3;
+// Time used to seek external tracks to.
+static double get_main_demux_pts(struct MPContext *mpctx)
+{
+ double main_new_pos = MP_NOPTS_VALUE;
+ if (mpctx->demuxer) {
+ for (int type = 0; type < STREAM_TYPE_COUNT; type++) {
+ struct demux_stream *ds = mpctx->demuxer->ds[type];
+ if (ds->sh && main_new_pos == MP_NOPTS_VALUE) {
+ demux_fill_buffer(mpctx->demuxer, ds);
+ if (ds->first)
+ main_new_pos = ds->first->pts;
+ }
+ }
+ }
+ return main_new_pos;
+}
+
static void set_demux_field(struct MPContext *mpctx, enum stream_type type,
struct sh_stream *s)
{
@@ -456,8 +473,13 @@ static void init_demux_stream(struct MPContext *mpctx, enum stream_type type)
struct track *track = mpctx->current_track[type];
set_demux_field(mpctx, type, track ? track->stream : NULL);
struct sh_stream *stream = mpctx->sh[type];
- if (stream)
+ if (stream) {
demuxer_switch_track(stream->demuxer, type, stream);
+ if (track->is_external) {
+ double pts = get_main_demux_pts(mpctx);
+ demux_seek(stream->demuxer, pts, audio_delay, SEEK_ABSOLUTE);
+ }
+ }
}
static void cleanup_demux_stream(struct MPContext *mpctx, enum stream_type type)
@@ -2863,18 +2885,12 @@ static int seek(MPContext *mpctx, struct seek_params seek,
have_external_tracks |= track && track->is_external && track->demuxer;
}
if (have_external_tracks) {
- double main_new_pos = MP_NOPTS_VALUE;
- if (seek.type == MPSEEK_ABSOLUTE)
+ double main_new_pos;
+ if (seek.type == MPSEEK_ABSOLUTE) {
main_new_pos = seek.amount - mpctx->video_offset;
- for (int type = 0; type < STREAM_TYPE_COUNT; type++) {
- struct demux_stream *ds = mpctx->demuxer->ds[type];
- if (ds->sh && main_new_pos == MP_NOPTS_VALUE) {
- demux_fill_buffer(mpctx->demuxer, ds);
- if (ds->first)
- main_new_pos = ds->first->pts;
- }
+ } else {
+ main_new_pos = get_main_demux_pts(mpctx);
}
- assert(main_new_pos != MP_NOPTS_VALUE);
for (int type = 0; type < STREAM_TYPE_COUNT; type++) {
struct track *track = mpctx->current_track[type];
if (track && track->is_external && track->demuxer)
diff --git a/demux/demux.c b/demux/demux.c
index 82159057d8..f765b2ae87 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -1077,6 +1077,10 @@ int demux_seek(demuxer_t *demuxer, float rel_seek_secs, float audio_delay,
mp_tmsg(MSGT_SEEK, MSGL_WARN, "Cannot seek in this file.\n");
return 0;
}
+
+ if (rel_seek_secs == MP_NOPTS_VALUE && (flags & SEEK_ABSOLUTE))
+ return 0;
+
// clear demux buffers:
demux_flush(demuxer);
demuxer->video->eof = 0;
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index c1c15f345a..42b687dc20 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -886,9 +886,17 @@ static void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs,
priv->last_pts += rel_seek_secs * priv->avfc->duration;
} else
priv->last_pts += rel_seek_secs * AV_TIME_BASE;
- if (av_seek_frame(priv->avfc, -1, priv->last_pts, avsflags) < 0) {
- avsflags ^= AVSEEK_FLAG_BACKWARD;
+
+ if (!priv->avfc->iformat->read_seek2) {
+ // Normal seeking.
av_seek_frame(priv->avfc, -1, priv->last_pts, avsflags);
+ } else {
+ // av_seek_frame() won't work. Use "new" seeking API. We don't use this
+ // API by default, because there are some major issues.
+ // Set max_ts==ts, so that demuxing starts from an earlier position in
+ // the worst case.
+ avformat_seek_file(priv->avfc, -1, INT64_MIN,
+ priv->last_pts, priv->last_pts, avsflags);
}
}