From 57fbc9cd76f7a78f1034c42dd3c453ff35123264 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 14 Dec 2019 14:17:16 +0100 Subject: [PATCH] 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 --- player/playloop.c | 7 +++++++ player/video.c | 12 +++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/player/playloop.c b/player/playloop.c index a8d784ae93..20580a95ab 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -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; } diff --git a/player/video.c b/player/video.c index 9dbe19cae4..af795c316f 100644 --- a/player/video.c +++ b/player/video.c @@ -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--;