diff options
-rw-r--r-- | demux/demux.c | 62 | ||||
-rw-r--r-- | demux/demux.h | 1 | ||||
-rw-r--r-- | player/playloop.c | 17 |
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++) { |