player: set playback_pts in hr-seek past EOF case

Hr-seek past the last frame instantly enters EOF, which means
handle_playback_time() will not set playback_pts to the video PTS (as
all video frames are skipped), which leads to the playback time being
taken from the last seek target. This results in confusing behavior,
especially since the seek time will be clipped to the file duration for
display, but not for further relative seeks.

Obviously, the time should be set to the last video frame, so use the
last video frame as fallback if both audio and video have ended. Also,
since the same problem exists with audio-only playback, add a fallback
for audio PTS too. We don't know which was the "last" fragment of media
played (to decide whether to use the audio or video PTS as the
fallback), but it doesn't matter since the maximum works.

This could lead to some undesired effects. In particular the audio PTS
is basically a bad guess, and is for example not clipped against --end.
(But the ridiculous way audio syncing and clamping currently works, I'm
not going to touch that shit unless I rewrite it completely.) The cover
art case is slightly broken: using --keep-open with keyframe seeks will
result in 0 as playback PTS (the video PTS). OK, who cares, it got late.

Also casually get rid of last_vo_pts, since that barely made any sense
at all.

Fixes: #7487
This commit is contained in:
wm4 2020-02-28 01:37:41 +01:00
parent 009d1ffda6
commit efe43d768f
5 changed files with 11 additions and 7 deletions

View File

@ -6211,7 +6211,7 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, int flags,
struct mp_decoder_wrapper *dec = track ? track->dec : NULL;
if (dec) {
mp_decoder_wrapper_control(dec, VDCTRL_REINIT, NULL);
double last_pts = mpctx->last_vo_pts;
double last_pts = mpctx->video_pts;
if (last_pts != MP_NOPTS_VALUE)
queue_seek(mpctx, MPSEEK_ABSOLUTE, last_pts, MPSEEK_EXACT, 0);
}

View File

@ -369,10 +369,8 @@ typedef struct MPContext {
/* timestamp of video frame currently visible on screen
* (or at least queued to be flipped by VO) */
double video_pts;
// Last seek target.
double last_seek_pts;
// As video_pts, but is not reset when seeking away. (For the very short
// period of time until a new frame is decoded and shown.)
double last_vo_pts;
// Frame duration field from demuxer. Only used for duration of the last
// video frame.
double last_frame_duration;

View File

@ -1390,7 +1390,6 @@ static void play_current_file(struct MPContext *mpctx)
mpctx->filename = NULL;
mpctx->shown_aframes = 0;
mpctx->shown_vframes = 0;
mpctx->last_vo_pts = MP_NOPTS_VALUE;
mpctx->last_chapter_seek = -2;
mpctx->last_chapter_pts = MP_NOPTS_VALUE;
mpctx->last_chapter = -2;

View File

@ -947,7 +947,6 @@ static void handle_keep_open(struct MPContext *mpctx)
if (mpctx->vo_chain) {
if (!vo_has_frame(mpctx->video_out)) // EOF not reached normally
seek_to_last_frame(mpctx);
mpctx->playback_pts = mpctx->last_vo_pts;
}
if (opts->keep_open_pause) {
if (mpctx->ao)
@ -1075,6 +1074,15 @@ static void handle_playback_time(struct MPContext *mpctx)
mpctx->audio_status < STATUS_EOF)
{
mpctx->playback_pts = playing_audio_pts(mpctx);
} else if (mpctx->video_status == STATUS_EOF &&
mpctx->audio_status == STATUS_EOF)
{
double apts =
mpctx->ao_chain ? mpctx->ao_chain->last_out_pts : MP_NOPTS_VALUE;
double vpts = mpctx->video_pts;
double mpts = MP_PTS_MAX(apts, vpts);
if (mpts != MP_NOPTS_VALUE)
mpctx->playback_pts = mpts;
}
}

View File

@ -1169,7 +1169,6 @@ void write_video(struct MPContext *mpctx)
}
mpctx->video_pts = mpctx->next_frames[0]->pts;
mpctx->last_vo_pts = mpctx->video_pts;
mpctx->last_frame_duration =
mpctx->next_frames[0]->pkt_duration / mpctx->video_speed;