diff --git a/demux/demux.c b/demux/demux.c index c099dbac19..51131dfd4c 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -760,6 +760,7 @@ static void demux_copy(struct demuxer *dst, struct demuxer *src) dst->seekable = src->seekable; dst->filetype = src->filetype; dst->ts_resets_possible = src->ts_resets_possible; + dst->rel_seeks = src->rel_seeks; dst->start_time = src->start_time; } if (src->events & DEMUX_EVENT_STREAMS) { diff --git a/demux/demux.h b/demux/demux.h index ca96d60732..b53a30c805 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -71,11 +71,12 @@ struct demux_ctrl_stream_ctrl { int res; }; -#define SEEK_ABSOLUTE (1 << 0) -#define SEEK_FACTOR (1 << 1) -#define SEEK_FORWARD (1 << 2) -#define SEEK_BACKWARD (1 << 3) -#define SEEK_SUBPREROLL (1 << 4) +#define SEEK_ABSOLUTE (1 << 0) // argument is a timestamp +#define SEEK_FACTOR (1 << 1) // argument is in range [0,1] +#define SEEK_FORWARD (1 << 2) // prefer later time if not exact +#define SEEK_BACKWARD (1 << 3) // prefer earlier time if not exact +#define SEEK_SUBPREROLL (1 << 4) // try to get more subtitle packets +#define SEEK_HR (1 << 5) // hr-seek (this is a weak hint only) // Strictness of the demuxer open format check. // demux.c will try by default: NORMAL, UNSAFE (in this order) @@ -188,6 +189,9 @@ typedef struct demuxer { double start_time; // File format allows PTS resets (even if the current file is without) bool ts_resets_possible; + // Send relative seek requests, instead of SEEK_ABSOLUTE or SEEK_FACTOR. + // This is only done if the user explicitly uses a relative seek. + bool rel_seeks; // Bitmask of DEMUX_EVENT_* int events; diff --git a/demux/demux_disc.c b/demux/demux_disc.c index 69643a0053..37b189861f 100644 --- a/demux/demux_disc.c +++ b/demux/demux_disc.c @@ -169,6 +169,7 @@ static void d_seek(demuxer_t *demuxer, double rel_seek_secs, int flags) double pts = p->seek_pts; if (flags & SEEK_ABSOLUTE) pts = 0.0f; + double base_pts = pts; // to what pts is relative if (flags & SEEK_FACTOR) { double tmp = 0; @@ -180,7 +181,8 @@ static void d_seek(demuxer_t *demuxer, double rel_seek_secs, int flags) MP_VERBOSE(demuxer, "seek to: %f\n", pts); - stream_control(demuxer->stream, STREAM_CTRL_SEEK_TO_TIME, &pts); + double seek_arg[] = {pts, base_pts, flags}; + stream_control(demuxer->stream, STREAM_CTRL_SEEK_TO_TIME, seek_arg); demux_control(p->slave, DEMUXER_CTRL_RESYNC, NULL); p->seek_pts = pts; @@ -312,6 +314,8 @@ static int d_open(demuxer_t *demuxer, enum demux_check check) // Can be seekable even if the stream isn't. demuxer->seekable = true; + demuxer->rel_seeks = true; + // With cache enabled, the stream can be seekable. This causes demux_lavf.c // (actually libavformat/mpegts.c) to seek sometimes when reading a packet. // It does this to seek back a bit in case the current file position points diff --git a/player/playloop.c b/player/playloop.c index cabdb4e441..bcec02e21a 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -204,7 +204,7 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek, } } int direction = 0; - if (seek.type == MPSEEK_RELATIVE) { + if (seek.type == MPSEEK_RELATIVE && (!mpctx->demuxer->rel_seeks || hr_seek)) { seek.type = MPSEEK_ABSOLUTE; direction = seek.amount > 0 ? 1 : -1; seek.amount += get_current_time(mpctx); @@ -233,10 +233,13 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek, demuxer_style |= SEEK_ABSOLUTE; break; } - if (hr_seek || direction < 0) + if (hr_seek || direction < 0) { demuxer_style |= SEEK_BACKWARD; - else if (direction > 0) + } else if (direction > 0) { demuxer_style |= SEEK_FORWARD; + } + if (hr_seek) + demuxer_style |= SEEK_HR; if (hr_seek || opts->mkv_subtitle_preroll) demuxer_style |= SEEK_SUBPREROLL;