summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-04-07 18:33:25 +0200
committerwm4 <wm4@nowhere>2014-04-17 22:58:47 +0200
commitb991c072f69e2fa4b842060ed5a7a8b1ece09f52 (patch)
tree1bc0cf349f91055ebe40fb9be93a46822a074043
parent3c2777994b6d45ec4503b088231bd2dac4861d9e (diff)
downloadmpv-b991c072f69e2fa4b842060ed5a7a8b1ece09f52.tar.bz2
mpv-b991c072f69e2fa4b842060ed5a7a8b1ece09f52.tar.xz
vo_vdpau: simplify time management and make it more robust
vo_vdpau used a somewhat complicated and fragile mechanism to convert the vdpau time to internal mpv time. This was fragile as in it couldn't deal well with Mesa's (apparently) random timestamps, which can change the base offset in multiple situations. It can happen when moving the mpv window to a different screen, and somehow it also happens when pausing the player. It seems this mechanism to synchronize the vdpau time is not actually needed. There are only 2 places where sync_vdptime() is used (i.e. returning the current vdpau time interpolated by system time). The first call is for determining the PTS used to queue a frame. This also uses convert_to_vdptime(). It's easily replaced by querying the time directly, and adding the wait time to it (rel_pts_ns in the patch). The second call is pretty odd: it updates the vdpau time a second time in the same function. From what I can see, this can matter only if update_presentation_queue_status() is very slow. I'm not sure what to make out of this, because the call merely queries the presentation queue. Just assume it isn't slow, and that we don't have to update the time. Another potential issue with this is that we call VdpPresentationQueueGetTime() every frame now, instead of every 5 seconds and interpolating the other calls via system time. More over, this is per video frame (which can be portantially dropped, and not per actually displayed frame. Assume this doesn't matter. This simplifies the code, and should make it more robust on Mesa. But note that what Mesa does is obviously insane - this is one situation where you really need a stable time source. There are still plenty of race condition windows where things can go wrong, although this commit should drastically reduce the possibility of this. In my tests, everything worked well. But I have no access to a Mesa system with vdpau, so it needs testing by others. See github issues #520, #694, #695.
-rw-r--r--video/out/vo_vdpau.c79
1 files changed, 11 insertions, 68 deletions
diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c
index 1b99a3fe86..58ac6b971f 100644
--- a/video/out/vo_vdpau.c
+++ b/video/out/vo_vdpau.c
@@ -76,8 +76,6 @@ struct vdpctx {
VdpPresentationQueueTarget flip_target;
VdpPresentationQueue flip_queue;
- uint64_t last_vdp_time;
- uint64_t last_sync_update;
VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES];
VdpOutputSurface screenshot_surface;
@@ -160,53 +158,6 @@ struct vdpctx {
static bool status_ok(struct vo *vo);
-static int change_vdptime_sync(struct vo *vo, int64_t *t)
-{
- struct vdpctx *vc = vo->priv;
- struct vdp_functions *vdp = vc->vdp;
- VdpStatus vdp_st;
- VdpTime vdp_time;
- vdp_st = vdp->presentation_queue_get_time(vc->flip_queue, &vdp_time);
- CHECK_VDP_ERROR(vo, "Error when calling vdp_presentation_queue_get_time");
- uint64_t t1 = *t;
- uint64_t t2 = mp_time_us();
- uint64_t old = vc->last_vdp_time + (t1 - vc->last_sync_update) * 1000ULL;
- if (vdp_time > old) {
- if (vdp_time > old + (t2 - t1) * 1000ULL)
- vdp_time -= (t2 - t1) * 1000ULL;
- else
- vdp_time = old;
- } else if (!vdp_time) {
- /* Some drivers do not return timestamps. */
- vdp_time = old;
- }
- MP_DBG(vo, "adjusting VdpTime offset by %f µs\n",
- (int64_t)(vdp_time - old) / 1000.);
- vc->last_vdp_time = vdp_time;
- vc->last_sync_update = t1;
- *t = t2;
- return 0;
-}
-
-static uint64_t sync_vdptime(struct vo *vo)
-{
- struct vdpctx *vc = vo->priv;
-
- uint64_t t = mp_time_us();
- if (t - vc->last_sync_update > 5000000)
- change_vdptime_sync(vo, &t);
- uint64_t now = (t - vc->last_sync_update) * 1000ULL + vc->last_vdp_time;
- // Make sure nanosecond inaccuracies don't make things inconsistent
- now = FFMAX(now, vc->recent_vsync_time);
- return now;
-}
-
-static uint64_t convert_to_vdptime(struct vo *vo, uint64_t t)
-{
- struct vdpctx *vc = vo->priv;
- return (t - vc->last_sync_update) * 1000LL + vc->last_vdp_time;
-}
-
static int render_video_to_output_surface(struct vo *vo,
VdpOutputSurface output_surface,
VdpRect *output_rect,
@@ -485,12 +436,6 @@ static int win_x11_init_vdpau_flip_queue(struct vo *vo)
CHECK_VDP_WARNING(vo, "Error setting colorkey");
}
- VdpTime vdp_time;
- vdp_st = vdp->presentation_queue_get_time(vc->flip_queue, &vdp_time);
- CHECK_VDP_ERROR(vo, "Error when calling vdp_presentation_queue_get_time");
- vc->last_vdp_time = vdp_time;
- vc->last_sync_update = mp_time_us();
-
vc->vsync_interval = 1;
if (vc->composite_detect && vo_x11_screen_is_composited(vo)) {
MP_INFO(vo, "Compositing window manager detected. Assuming timing info "
@@ -1076,12 +1021,16 @@ static void flip_page_timed(struct vo *vo, int64_t pts_us, int duration)
if (vc->vsync_interval == 1)
duration = -1; // Make sure drop logic is disabled
- /* If the presentation time may not be before our last timestamp sync. */
- if (pts_us && pts_us < vc->last_sync_update)
- pts_us = vc->last_sync_update;
+ VdpTime vdp_time = 0;
+ vdp_st = vdp->presentation_queue_get_time(vc->flip_queue, &vdp_time);
+ CHECK_VDP_WARNING(vo, "Error when calling vdp_presentation_queue_get_time");
+
+ int64_t rel_pts_ns = (pts_us - mp_time_us()) * 1000;
+ if (!pts_us || rel_pts_ns < 0)
+ rel_pts_ns = 0;
- uint64_t now = sync_vdptime(vo);
- uint64_t pts = pts_us ? convert_to_vdptime(vo, pts_us) : now;
+ uint64_t now = vdp_time;
+ uint64_t pts = now + rel_pts_ns;
uint64_t ideal_pts = pts;
uint64_t npts = duration >= 0 ? pts + duration : UINT64_MAX;
@@ -1131,7 +1080,6 @@ static void flip_page_timed(struct vo *vo, int64_t pts_us, int duration)
int num_flips = update_presentation_queue_status(vo);
vsync = vc->recent_vsync_time + num_flips * vc->vsync_interval;
- now = sync_vdptime(vo);
pts = FFMAX(pts, now);
pts = FFMAX(pts, vsync + (vsync_interval >> 2));
vsync = PREV_VSYNC(pts);
@@ -1143,13 +1091,8 @@ static void flip_page_timed(struct vo *vo, int64_t pts_us, int duration)
vo->dwidth, vo->dheight, pts);
CHECK_VDP_WARNING(vo, "Error when calling vdp_presentation_queue_display");
- if (mp_msg_test(vo->log, MSGL_TRACE)) {
- VdpTime vdp_time;
- vdp_st = vdp->presentation_queue_get_time(vc->flip_queue, &vdp_time);
- CHECK_VDP_WARNING(vo, "Error when calling vdp_presentation_queue_display");
- MP_TRACE(vo, "Queue new surface %d: current=%"PRIu64" int=%"PRIu64
- " pts=%"PRIu64"\n", (int)frame, (uint64_t)vdp_time, now, pts);
- }
+ MP_TRACE(vo, "Queue new surface %d: Vdpau time: %"PRIu64" "
+ "pts: %"PRIu64"\n", (int)frame, now, pts);
vc->last_queue_time = pts;
vc->queue_time[vc->surface_num] = pts;