summaryrefslogtreecommitdiffstats
path: root/mpvcore/player/playloop.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-12-10 19:33:11 +0100
committerwm4 <wm4@nowhere>2013-12-10 20:07:39 +0100
commit227d087db601a02d4d71ea914f61e4d69fd34e6c (patch)
treeccedfff3c3123b7764a6c24a9e8b124bcf0dc403 /mpvcore/player/playloop.c
parent5135e93d0cec05047aeced889bbf740a7d091012 (diff)
downloadmpv-227d087db601a02d4d71ea914f61e4d69fd34e6c.tar.bz2
mpv-227d087db601a02d4d71ea914f61e4d69fd34e6c.tar.xz
video: display last frame, drain frames on video reconfig
Until now, the player didn't care to drain frames on video reconfig. Instead, the VO was reconfigured (i.e. resized) before the queued frames finished displaying. This can for example be observed by passing multiple images with different size as mf:// filename. Then the window would resize one frame before image with the new size is displayed. With --vo=vdpau, the effect is worse, because this VO queues more than 1 frame internally. Fix this by explicitly draining buffered frames before video reconfig. Raise the display time of the last frame. Otherwise, the last frame would be shown for a very short time only. This usually doesn't matter, but helps when playing image files. This is a byproduct of frame draining, because normally, video timing is based on the frames queued to the VO, and we can't do that with frames of different size or format. So we pretend that the frame before the change is the last frame in order to time it. This code is incorrect though: it tries to use the framerate, which often doesn't make sense. But it's good enough to test this code with mf://.
Diffstat (limited to 'mpvcore/player/playloop.c')
-rw-r--r--mpvcore/player/playloop.c46
1 files changed, 42 insertions, 4 deletions
diff --git a/mpvcore/player/playloop.c b/mpvcore/player/playloop.c
index b87231c709..359e38058e 100644
--- a/mpvcore/player/playloop.c
+++ b/mpvcore/player/playloop.c
@@ -184,6 +184,8 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao)
mpctx->video_pts = MP_NOPTS_VALUE;
mpctx->video_next_pts = MP_NOPTS_VALUE;
+ mpctx->playing_last_frame = false;
+ mpctx->last_frame_duration = 0;
mpctx->delay = 0;
mpctx->time_frame = 0;
mpctx->restart_playback = true;
@@ -990,9 +992,31 @@ void run_playloop(struct MPContext *mpctx)
struct vo *vo = mpctx->video_out;
update_fps(mpctx);
- video_left = vo->hasframe || vo->frame_loaded;
+ video_left = vo->hasframe || vo->frame_loaded || mpctx->playing_last_frame;
if (!vo->frame_loaded && (!mpctx->paused || mpctx->restart_playback)) {
+
double frame_time = update_video(mpctx, endpts);
+ if (frame_time < 0) {
+ if (!mpctx->playing_last_frame && mpctx->last_frame_duration > 0) {
+ mpctx->time_frame += mpctx->last_frame_duration;
+ mpctx->last_frame_duration = 0;
+ mpctx->playing_last_frame = true;
+ }
+ if (mpctx->playing_last_frame) {
+ frame_time = 0; // don't stop playback yet
+ } else if (mpctx->d_video->waiting_decoded_mpi) {
+ // Format changes behave like EOF, and this call "unstucks"
+ // the EOF condition (after waiting for the previous frame
+ // to finish displaying).
+ video_execute_format_change(mpctx);
+ frame_time = update_video(mpctx, endpts);
+ // We just displayed the previous frame, so display the
+ // new frame immediately.
+ if (frame_time > 0)
+ frame_time = 0;
+ }
+ }
+
mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "*** ftime=%5.3f ***\n", frame_time);
if (mpctx->d_video->vfilter && mpctx->d_video->vfilter->initialized < 0)
{
@@ -1027,7 +1051,7 @@ void run_playloop(struct MPContext *mpctx)
if (!video_left || (mpctx->paused && !mpctx->restart_playback))
break;
- if (!vo->frame_loaded) {
+ if (!vo->frame_loaded && !mpctx->playing_last_frame) {
sleeptime = 0;
break;
}
@@ -1071,6 +1095,11 @@ void run_playloop(struct MPContext *mpctx)
break;
}
sleeptime = 0;
+ mpctx->playing_last_frame = false;
+
+ // last frame case (don't set video_left - consider format changes)
+ if (!vo->frame_loaded)
+ break;
//=================== FLIP PAGE (VIDEO BLT): ======================
@@ -1096,8 +1125,14 @@ void run_playloop(struct MPContext *mpctx)
int64_t pts_us = mpctx->last_time + time_frame * 1e6;
int duration = -1;
double pts2 = vo->next_pts2;
- if (pts2 != MP_NOPTS_VALUE && opts->correct_pts &&
- !mpctx->restart_playback) {
+ if (mpctx->video_pts != MP_NOPTS_VALUE && pts2 == MP_NOPTS_VALUE) {
+ // Make up a frame duration. Using the frame rate is not a good
+ // choice, since the frame rate could be unset/broken/random.
+ float fps = mpctx->d_video->fps;
+ double frame_time = fps > 0 ? 1.0 / fps : 0;
+ pts2 = mpctx->video_pts + frame_time;
+ }
+ if (pts2 != MP_NOPTS_VALUE) {
// expected A/V sync correction is ignored
double diff = (pts2 - mpctx->video_pts);
diff /= opts->playback_speed;
@@ -1108,7 +1143,10 @@ void run_playloop(struct MPContext *mpctx)
if (diff > 10)
diff = 10;
duration = diff * 1e6;
+ mpctx->last_frame_duration = diff;
}
+ if (mpctx->restart_playback)
+ duration = -1;
vo_flip_page(vo, pts_us | 1, duration);
mpctx->last_vo_flip_duration = (mp_time_us() - t2) * 0.000001;