diff options
author | wm4 <wm4@nowhere> | 2014-12-07 02:47:09 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-12-07 02:47:54 +0100 |
commit | 090f6cfc30a55c044b45dbd66cd46d8a66ce4b44 (patch) | |
tree | e0556ad41324eaf1a48bb368a3369abc59eaaee2 /player/playloop.c | |
parent | 6adaddbe63196ba0c75796ce157d2e041c390b71 (diff) | |
download | mpv-090f6cfc30a55c044b45dbd66cd46d8a66ce4b44.tar.bz2 mpv-090f6cfc30a55c044b45dbd66cd46d8a66ce4b44.tar.xz |
player: when seeking past EOF with --keep-open, seek to last frame
It feels strange that seeking past EOF with --keep-open actually leaves
the player at a random position. You can't even unpause, because the
demuxer is in the EOF state, and what you see on screen is just what was
around before the seek.
Improve this by attempting to seek to the last video frame if EOF
happens. We explicitly don't do this if EOF was reached normally to
increase robustness (if the VO got a frame since the last seek, it
obviously means we had normal playback before EOF).
If an error happens when trying to find the last frame (such as not
actually finding a last frame because e.g. the demuxer misbehaves), this
will probably turn your CPU into a heater. There is no logic to prevent
reinitiating the last-frame search if the last-frame search reached EOF.
(Pausing usually prevents that EOF is reached again after a successful
last-frame search.)
Fixes #819.
Diffstat (limited to 'player/playloop.c')
-rw-r--r-- | player/playloop.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/player/playloop.c b/player/playloop.c index e20e088e00..67e7f22001 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -151,6 +151,7 @@ void reset_playback_state(struct MPContext *mpctx) mpctx->hrseek_active = false; mpctx->hrseek_framedrop = false; + mpctx->hrseek_lastframe = false; mpctx->playback_pts = MP_NOPTS_VALUE; mpctx->last_seek_pts = MP_NOPTS_VALUE; mpctx->cache_wait_time = 0; @@ -780,6 +781,28 @@ static void handle_loop_file(struct MPContext *mpctx) } } +static void seek_to_last_frame(struct MPContext *mpctx) +{ + if (!mpctx->d_video) + return; + MP_VERBOSE(mpctx, "seeking to last frame...\n"); + // Approximately seek close to the end of the file. + // Usually, it will seek some seconds before end. + double end = get_play_end_pts(mpctx); + if (end == MP_NOPTS_VALUE) + end = get_time_length(mpctx); + mp_seek(mpctx, (struct seek_params){ + .type = MPSEEK_ABSOLUTE, + .amount = end, + .exact = 2, // "very exact", no framedrop + }, false); + // Make it exact: stop seek only if last frame was reached. + if (mpctx->hrseek_active) { + mpctx->hrseek_pts = 1e99; // "infinite" + mpctx->hrseek_lastframe = true; + } +} + static void handle_keep_open(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; @@ -787,8 +810,11 @@ static void handle_keep_open(struct MPContext *mpctx) !playlist_get_next(mpctx->playlist, 1) && opts->loop_times < 0) { mpctx->stop_play = KEEP_PLAYING; - if (mpctx->d_video) + if (mpctx->d_video) { + if (!vo_has_frame(mpctx->video_out)) // EOF not reached normally + seek_to_last_frame(mpctx); mpctx->playback_pts = mpctx->last_vo_pts; + } if (!mpctx->opts->pause) pause_player(mpctx); } |