0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 12:02:23 +02:00

player: make repeated hr-seeks past EOF trigger EOF as expected

If you have a normal file with audio and video, and keep "spamming"
forward hr-seeks, the player just kept showing the last video frame
instead of exiting or playing the next file. This started happening
since commit 6bcda94cb. Although not a bug per se, it was odd, and very
user-noticable.

The main problem was that the pending seek command was processed before
the EOF was "noticed". Processing the command reset everything, so the
player did not terminate playback, but repeated the seek.

This commit restores the old behavior.

For one, it makes video return the correct status (video.c). The
parameter is a bit ugly, but better than duplicating the logic or having
another MPContext field. (As a minor detail, setting r=VD_EOF makes sure
have_new_frame() returns true, rather than going through another
iteration or whatever the hell will happen instead, which would clobber
logical_eof.)

Another thing is making the seek logic actually wait until the seek
outcome has been determined if audio is also active. Audio needs to wait
for video in order to get the video seek target position. (Which in turn
is because hr-seek still "snaps" to video frames. You can't seek in
between two frames, so audio can't just use the seek target, but always
has to wait on the timestamp of the video frame. This has other
disadvantages and is a misdesign, but not something I'll fix today.)

In theory, this might make hr-seeks less responsive, because it needs to
fully decode/filter the audio too, but in practice most time is spent on
video, which had to be fully decoded before this change. (In general,
hr-seek could probably just show a random frame when a queued hr-seek
overrides the current hr-seek, which would probably lead to a better
user experience, but that's out of scope.)

Fixes: #7206
This commit is contained in:
wm4 2019-12-14 14:17:16 +01:00
parent 23c5965d47
commit 57fbc9cd76
2 changed files with 16 additions and 3 deletions

View File

@ -477,6 +477,12 @@ void execute_queued_seek(struct MPContext *mpctx)
// Wait until a video frame is available and has been shown.
if (mpctx->video_status < STATUS_PLAYING)
return;
// On A/V hr-seeks, always wait for the full result, to avoid corner
// cases when seeking past EOF (we want it to determine that EOF
// actually happened, instead of overwriting it with the new seek).
if (mpctx->hrseek_active && queued_hr_seek && mpctx->vo_chain &&
mpctx->ao_chain && !mpctx->restart_complete)
return;
}
mp_seek(mpctx, mpctx->seek);
mpctx->seek = (struct seek_params){0};
@ -1124,6 +1130,7 @@ static void handle_playback_restart(struct MPContext *mpctx)
// actually play the audio, but resume seeking immediately.
if (mpctx->seek.type && mpctx->video_status == STATUS_PLAYING) {
handle_playback_time(mpctx);
mpctx->seek.flags &= ~MPSEEK_FLAG_DELAY; // immediately
execute_queued_seek(mpctx);
return;
}

View File

@ -452,7 +452,7 @@ static bool have_new_frame(struct MPContext *mpctx, bool eof)
// Fill mpctx->next_frames[] with a newly filtered or decoded image.
// returns VD_* code
static int video_output_image(struct MPContext *mpctx)
static int video_output_image(struct MPContext *mpctx, bool *logical_eof)
{
struct vo_chain *vo_c = mpctx->vo_chain;
bool hrseek = false;
@ -532,7 +532,8 @@ static int video_output_image(struct MPContext *mpctx)
if (r <= 0 && hrseek && mpctx->saved_frame && r == VD_EOF) {
add_new_frame(mpctx, mpctx->saved_frame);
mpctx->saved_frame = NULL;
r = VD_PROGRESS;
r = VD_EOF;
*logical_eof = true;
}
return have_new_frame(mpctx, r <= 0) ? VD_NEW_FRAME : r;
@ -1003,7 +1004,8 @@ void write_video(struct MPContext *mpctx)
if (mpctx->paused && mpctx->video_status >= STATUS_READY)
return;
int r = video_output_image(mpctx);
bool logical_eof = false;
int r = video_output_image(mpctx, &logical_eof);
MP_TRACE(mpctx, "video_output_image: %d\n", r);
if (r < 0)
@ -1199,6 +1201,10 @@ void write_video(struct MPContext *mpctx)
mpctx->video_status = STATUS_EOF;
}
// hr-seek past EOF -> returns last frame, but terminates playback.
if (logical_eof)
mpctx->video_status = STATUS_EOF;
if (mpctx->video_status != STATUS_EOF) {
if (mpctx->step_frames > 0) {
mpctx->step_frames--;