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.
This commit is contained in:
Jari Vetoniemi authored and wm4 committed 2015-08-21 00:01:01 +02:00
1 parent 3245bfefc3
commit e05dc7bfb7
3 files changed
+84 -18

No files matched your search

+17 -13
View File
@@ -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)
+60 -5
View File
@@ -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;
}
+7
View File
@@ -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 */