summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demux/demux.c62
-rw-r--r--demux/demux.h1
-rw-r--r--player/playloop.c17
3 files changed, 52 insertions, 28 deletions
diff --git a/demux/demux.c b/demux/demux.c
index a52ca0fbfd..4ea8cce595 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -2240,17 +2240,16 @@ static struct demux_packet *find_seek_target(struct demux_queue *queue,
}
// must be called locked
-static bool try_seek_cache(struct demux_internal *in, double pts, int flags)
+static struct demux_cached_range *find_cache_seek_target(struct demux_internal *in,
+ double pts, int flags)
{
- if ((flags & SEEK_FACTOR) || !in->seekable_cache)
- return false;
-
// Note about queued low level seeks: in->seeking can be true here, and it
// might come from a previous resume seek to the current range. If we end
// up seeking into the current range (i.e. just changing time offset), the
// seek needs to continue. Otherwise, we override the queued seek anyway.
+ if ((flags & SEEK_FACTOR) || !in->seekable_cache)
+ return NULL;
- struct demux_cached_range *range = NULL;
for (int n = 0; n < in->num_ranges; n++) {
struct demux_cached_range *r = in->ranges[n];
if (r->seek_start != MP_NOPTS_VALUE) {
@@ -2259,15 +2258,21 @@ static bool try_seek_cache(struct demux_internal *in, double pts, int flags)
if (pts >= r->seek_start && pts <= r->seek_end) {
MP_VERBOSE(in, "...using this range for in-cache seek.\n");
- range = r;
- break;
+ return r;
}
}
}
- if (!range)
- return false;
+ return NULL;
+}
+// must be called locked
+// range must be non-NULL and from find_cache_seek_target() using the same pts
+// and flags, before any other changes to the cached state
+static void execute_cache_seek(struct demux_internal *in,
+ struct demux_cached_range *range,
+ double pts, int flags)
+{
// Adjust the seek target to the found video key frames. Otherwise the
// video will undershoot the seek target, while audio will be closer to it.
// The player frontend will play the additional video without audio, so
@@ -2341,8 +2346,6 @@ static bool try_seek_cache(struct demux_internal *in, double pts, int flags)
MP_VERBOSE(in, "resuming demuxer to end of cached range\n");
}
-
- return true;
}
// Create a new blank ache range, and backup the old one. If the seekable
@@ -2369,16 +2372,12 @@ int demux_seek(demuxer_t *demuxer, double seek_pts, int flags)
{
struct demux_internal *in = demuxer->in;
assert(demuxer == in->d_user);
+ int res = 0;
- if (!demuxer->seekable) {
- MP_WARN(demuxer, "Cannot seek in this file.\n");
- return 0;
- }
+ pthread_mutex_lock(&in->lock);
if (seek_pts == MP_NOPTS_VALUE)
- return 0;
-
- pthread_mutex_lock(&in->lock);
+ goto done;
MP_VERBOSE(in, "queuing seek to %f%s\n", seek_pts,
in->seeking ? " (cascade)" : "");
@@ -2386,6 +2385,23 @@ int demux_seek(demuxer_t *demuxer, double seek_pts, int flags)
if (!(flags & SEEK_FACTOR))
seek_pts = MP_ADD_PTS(seek_pts, -in->ts_offset);
+ bool require_cache = flags & SEEK_CACHED;
+ flags &= ~(unsigned)SEEK_CACHED;
+
+ struct demux_cached_range *cache_target =
+ find_cache_seek_target(in, seek_pts, flags);
+
+ if (!cache_target) {
+ if (require_cache) {
+ MP_VERBOSE(demuxer, "Cached seek not possible.\n");
+ goto done;
+ }
+ if (!demuxer->seekable) {
+ MP_WARN(demuxer, "Cannot seek in this file.\n");
+ goto done;
+ }
+ }
+
clear_reader_state(in);
in->eof = false;
@@ -2393,7 +2409,9 @@ int demux_seek(demuxer_t *demuxer, double seek_pts, int flags)
in->idle = true;
in->reading = false;
- if (!try_seek_cache(in, seek_pts, flags)) {
+ if (cache_target) {
+ execute_cache_seek(in, cache_target, seek_pts, flags);
+ } else {
switch_to_fresh_cache_range(in);
in->seeking = true;
@@ -2404,10 +2422,12 @@ int demux_seek(demuxer_t *demuxer, double seek_pts, int flags)
if (!in->threading && in->seeking)
execute_seek(in);
+ res = 1;
+
+done:
pthread_cond_signal(&in->wakeup);
pthread_mutex_unlock(&in->lock);
-
- return 1;
+ return res;
}
struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d,
diff --git a/demux/demux.h b/demux/demux.h
index aeabd36e99..ab8edb7aa0 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -68,6 +68,7 @@ struct demux_ctrl_stream_ctrl {
#define SEEK_FACTOR (1 << 1) // argument is in range [0,1]
#define SEEK_FORWARD (1 << 2) // prefer later time if not exact
// (if unset, prefer earlier time)
+#define SEEK_CACHED (1 << 3) // allow packet cache seeks only
#define SEEK_HR (1 << 5) // hr-seek (this is a weak hint only)
// Strictness of the demuxer open format check.
diff --git a/player/playloop.c b/player/playloop.c
index bf1de03db5..245b49217e 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -253,12 +253,6 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
if (!mpctx->demuxer || seek.type == MPSEEK_NONE || seek.amount == MP_NOPTS_VALUE)
return;
- if (!mpctx->demuxer->seekable) {
- MP_ERR(mpctx, "Cannot seek in this file.\n");
- MP_ERR(mpctx, "You can forcibly enable it with '--force-seekable=yes'.\n");
- return;
- }
-
bool hr_seek_very_exact = seek.exact == MPSEEK_VERY_EXACT;
double current_time = get_current_time(mpctx);
if (current_time == MP_NOPTS_VALUE && seek.type == MPSEEK_RELATIVE)
@@ -325,7 +319,16 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
demux_flags = (demux_flags | SEEK_HR) & ~SEEK_FORWARD;
}
- demux_seek(mpctx->demuxer, demux_pts, demux_flags);
+ if (!mpctx->demuxer->seekable)
+ demux_flags |= SEEK_CACHED;
+
+ if (!demux_seek(mpctx->demuxer, demux_pts, demux_flags)) {
+ if (!mpctx->demuxer->seekable) {
+ MP_ERR(mpctx, "Cannot seek in this file.\n");
+ MP_ERR(mpctx, "You can force it with '--force-seekable=yes'.\n");
+ }
+ return;
+ }
// Seek external, extra files too:
for (int t = 0; t < mpctx->num_tracks; t++) {