From e05dc7bfb7c8a2d0c461cb1d60386f067bd01061 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Wed, 19 Aug 2015 22:41:26 +0300 Subject: vo_wayland: Wait for frame callbacks Privdes small api for vo_wayland where one can request frame callback and then wait for it. This will make vo_wayland play video smoothly. --- video/out/vo_wayland.c | 30 +++++++++++---------- video/out/wayland_common.c | 65 ++++++++++++++++++++++++++++++++++++++++++---- video/out/wayland_common.h | 7 +++++ 3 files changed, 84 insertions(+), 18 deletions(-) (limited to 'video/out') diff --git a/video/out/vo_wayland.c b/video/out/vo_wayland.c index 3367e46fe6..5d3c77e2bf 100644 --- a/video/out/vo_wayland.c +++ b/video/out/vo_wayland.c @@ -389,14 +389,12 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) p->original_image = mpi; } - if (!p->wl->frame.pending) - return; + if (!vo_wayland_wait_frame(vo)) + MP_DBG(p->wl, "discarding frame callback\n"); shm_buffer_t *buf = buffer_pool_get_back(&p->video_bufpool); if (!buf) { - // TODO: use similar handling of busy buffers as the osd buffers - // if the need arises MP_VERBOSE(p->wl, "can't draw, back buffer is busy\n"); return; } @@ -504,25 +502,31 @@ static void draw_osd(struct vo *vo) osd_draw(vo->osd, p->osd, pts, 0, osd_formats, draw_osd_cb, p); } -static void flip_page(struct vo *vo) +static void redraw(void *data, uint32_t time) { - struct priv *p = vo->priv; - - if (!p->wl->frame.pending) - return; - - buffer_pool_swap(&p->video_bufpool); + struct priv *p = data; shm_buffer_t *buf = buffer_pool_get_front(&p->video_bufpool); wl_surface_attach(p->wl->window.video_surface, buf->buffer, p->x, p->y); wl_surface_damage(p->wl->window.video_surface, 0, 0, p->dst_w, p->dst_h); - wl_surface_commit(p->wl->window.video_surface); buffer_finalise_front(buf); p->x = 0; p->y = 0; p->recent_flip_time = mp_time_us(); - p->wl->frame.pending = false; +} + +static void flip_page(struct vo *vo) +{ + struct priv *p = vo->priv; + + buffer_pool_swap(&p->video_bufpool); + + if (!p->wl->frame.callback) + vo_wayland_request_frame(vo, p, redraw); + + if (!vo_wayland_wait_frame(vo)) + MP_DBG(p->wl, "discarding frame callback\n"); } static int query_format(struct vo *vo, int format) diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index aff3d7c2ee..198b167d79 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -812,6 +812,9 @@ static void frame_callback(void *data, { struct vo_wayland_state *wl = data; + if (wl->frame.function) + wl->frame.function(wl->frame.data, time); + if (callback) wl_callback_destroy(callback); @@ -823,7 +826,11 @@ static void frame_callback(void *data, } wl_callback_add_listener(wl->frame.callback, &frame_listener, wl); + wl_surface_commit(wl->window.video_surface); + + wl->frame.last_us = mp_time_us(); wl->frame.pending = true; + wl->frame.dropping = false; } static const struct wl_callback_listener frame_listener = { @@ -913,7 +920,6 @@ static bool create_window (struct vo_wayland_state *wl) wl_shell_surface_set_class(wl->window.shell_surface, "mpv"); } - frame_callback(wl, NULL, 0); return true; } @@ -1083,7 +1089,7 @@ static void vo_wayland_fullscreen (struct vo *vo) } } -static int vo_wayland_check_events (struct vo *vo) +static int vo_wayland_poll (struct vo *vo, int timeout_msecs) { struct vo_wayland_state *wl = vo->wayland; struct wl_display *dp = wl->display.display; @@ -1102,7 +1108,8 @@ static int vo_wayland_check_events (struct vo *vo) * * when pausing no input events get queued so we have to check if there * are events to read from the file descriptor through poll */ - if (poll(&fd, 1, 0) > 0) { + int polled; + if ((polled = poll(&fd, 1, timeout_msecs)) > 0) { if (fd.revents & POLLERR || fd.revents & POLLHUP) { MP_FATAL(wl, "error occurred on the display fd: " "closing file descriptor\n"); @@ -1115,13 +1122,25 @@ static int vo_wayland_check_events (struct vo *vo) wl_display_flush(dp); } + return polled; +} + +static int vo_wayland_check_events (struct vo *vo) +{ + struct vo_wayland_state *wl = vo->wayland; + + vo_wayland_poll(vo, 0); + /* If drag & drop was ended poll the file descriptor from the offer if * there is data to read. * We only accept the mime type text/uri-list. */ if (wl->input.dnd_fd != -1) { - fd.fd = wl->input.dnd_fd; - fd.events = POLLIN | POLLHUP | POLLERR; + struct pollfd fd = { + wl->input.dnd_fd, + POLLIN | POLLERR | POLLHUP, + 0 + }; if (poll(&fd, 1, 0) > 0) { if (fd.revents & POLLERR) { @@ -1297,3 +1316,39 @@ bool vo_wayland_config (struct vo *vo, uint32_t flags) return true; } + +void vo_wayland_request_frame(struct vo *vo, void *data, vo_wayland_frame_cb cb) +{ + struct vo_wayland_state *wl = vo->wayland; + wl->frame.data = data; + wl->frame.function = cb; + MP_DBG(wl, "restart frame callback\n"); + frame_callback(wl, NULL, 0); +} + +bool vo_wayland_wait_frame(struct vo *vo) +{ + struct vo_wayland_state *wl = vo->wayland; + + if (!wl->frame.callback || wl->frame.dropping) + return false; + + // If mpv isn't receiving frame callbacks (for 100ms), this usually means that + // mpv window is not visible and compositor tells kindly to not draw anything. + while (!wl->frame.pending) { + int64_t timeout = wl->frame.last_us + (100 * 1000) - mp_time_us(); + + if (timeout <= 0) + break; + + if (vo_wayland_poll(vo, timeout) <= 0) + break; + } + + wl->frame.dropping = !wl->frame.pending; + wl->frame.pending = false; + + // Return false if the frame callback was not received + // Handler should act accordingly. + return !wl->frame.dropping; +} diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h index d7c505290a..6f3ac72e94 100644 --- a/video/out/wayland_common.h +++ b/video/out/wayland_common.h @@ -47,14 +47,19 @@ struct vo_wayland_output { struct wl_list link; }; +typedef void (*vo_wayland_frame_cb)(void *data, uint32_t time); struct vo_wayland_state { struct vo *vo; struct mp_log* log; struct { + void *data; + vo_wayland_frame_cb function; struct wl_callback *callback; + uint64_t last_us; bool pending; + bool dropping; } frame; #if HAVE_GL_WAYLAND @@ -144,6 +149,8 @@ int vo_wayland_init(struct vo *vo); void vo_wayland_uninit(struct vo *vo); bool vo_wayland_config(struct vo *vo, uint32_t flags); int vo_wayland_control(struct vo *vo, int *events, int request, void *arg); +void vo_wayland_request_frame(struct vo *vo, void *data, vo_wayland_frame_cb cb); +bool vo_wayland_wait_frame(struct vo *vo); #endif /* MPLAYER_WAYLAND_COMMON_H */ -- cgit v1.2.3