summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2015-08-19 22:41:26 +0300
committerwm4 <wm4@nowhere>2015-08-21 00:01:01 +0200
commite05dc7bfb7c8a2d0c461cb1d60386f067bd01061 (patch)
tree6d9799398a092797a5ee43954fa68387070167c8
parent3245bfefc3803904f5aeade0b3e60cd504ccb16c (diff)
downloadmpv-e05dc7bfb7c8a2d0c461cb1d60386f067bd01061.tar.bz2
mpv-e05dc7bfb7c8a2d0c461cb1d60386f067bd01061.tar.xz
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.
-rw-r--r--video/out/vo_wayland.c30
-rw-r--r--video/out/wayland_common.c65
-rw-r--r--video/out/wayland_common.h7
3 files changed, 84 insertions, 18 deletions
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 */