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:
1 parent
3245bfefc3
commit
e05dc7bfb7
3 files changed
+84
-18
No files matched your search
+17
-13
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
Reference in new issue
Block a user