From: George Kiagiadakis Date: Wed, 12 Feb 2014 10:28:40 +0000 (+0100) Subject: waylandsink: process display events in a separate thread X-Git-Tag: 1.19.3~507^2~10869 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e600a323b72898a33f5b06c76ae4c4909eac1910;p=platform%2Fupstream%2Fgstreamer.git waylandsink: process display events in a separate thread This also moves the display-related code into a new GstWlDisplay class, which takes care of the new thread --- diff --git a/ext/wayland/Makefile.am b/ext/wayland/Makefile.am index e8edf73..80b3614 100644 --- a/ext/wayland/Makefile.am +++ b/ext/wayland/Makefile.am @@ -1,6 +1,6 @@ plugin_LTLIBRARIES = libgstwaylandsink.la -libgstwaylandsink_la_SOURCES = gstwaylandsink.c waylandpool.c +libgstwaylandsink_la_SOURCES = gstwaylandsink.c waylandpool.c wldisplay.c libgstwaylandsink_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ $(WAYLAND_CFLAGS) libgstwaylandsink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ @@ -9,4 +9,4 @@ libgstwaylandsink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ libgstwaylandsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstwaylandsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) -noinst_HEADERS = gstwaylandsink.h waylandpool.h +noinst_HEADERS = gstwaylandsink.h waylandpool.h wldisplay.h diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c index e286f32..50c3d52 100644 --- a/ext/wayland/gstwaylandsink.c +++ b/ext/wayland/gstwaylandsink.c @@ -91,12 +91,9 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query); static gboolean gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer); -static struct display *create_display (void); -static void registry_handle_global (void *data, struct wl_registry *registry, - uint32_t id, const char *interface, uint32_t version); static void frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time); -static void create_window (GstWaylandSink * sink, struct display *display, +static void create_window (GstWaylandSink * sink, GstWlDisplay * display, int width, int height); static void shm_pool_destroy (struct shm_pool *pool); @@ -225,23 +222,6 @@ gst_wayland_sink_set_property (GObject * object, } static void -destroy_display (struct display *display) -{ - if (display->shm) - wl_shm_destroy (display->shm); - - if (display->shell) - wl_shell_destroy (display->shell); - - if (display->compositor) - wl_compositor_destroy (display->compositor); - - wl_display_flush (display->display); - wl_display_disconnect (display->display); - free (display); -} - -static void destroy_window (struct window *window) { if (window->callback) @@ -277,7 +257,7 @@ gst_wayland_sink_finalize (GObject * object) if (sink->window) destroy_window (sink->window); if (sink->display) - destroy_display (sink->display); + g_object_unref (sink->display); if (sink->shm_pool) shm_pool_destroy (sink->shm_pool); @@ -306,68 +286,6 @@ gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) return caps; } -static void -shm_format (void *data, struct wl_shm *wl_shm, uint32_t format) -{ - struct display *d = data; - - d->formats |= (1 << format); -} - -struct wl_shm_listener shm_listenter = { - shm_format -}; - -static void -registry_handle_global (void *data, struct wl_registry *registry, - uint32_t id, const char *interface, uint32_t version) -{ - struct display *d = data; - - if (strcmp (interface, "wl_compositor") == 0) { - d->compositor = - wl_registry_bind (registry, id, &wl_compositor_interface, 1); - } else if (strcmp (interface, "wl_shell") == 0) { - d->shell = wl_registry_bind (registry, id, &wl_shell_interface, 1); - } else if (strcmp (interface, "wl_shm") == 0) { - d->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1); - wl_shm_add_listener (d->shm, &shm_listenter, d); - } -} - -static const struct wl_registry_listener registry_listener = { - registry_handle_global -}; - -static struct display * -create_display (void) -{ - struct display *display; - - display = malloc (sizeof *display); - display->display = wl_display_connect (NULL); - - if (display->display == NULL) { - free (display); - return NULL; - } - - display->registry = wl_display_get_registry (display->display); - wl_registry_add_listener (display->registry, ®istry_listener, display); - - wl_display_roundtrip (display->display); - if (display->shm == NULL) { - GST_ERROR ("No wl_shm global.."); - return NULL; - } - - wl_display_roundtrip (display->display); - - wl_display_get_fd (display->display); - - return display; -} - static gboolean gst_wayland_sink_format_from_caps (uint32_t * wl_format, GstCaps * caps) { @@ -473,7 +391,7 @@ static const struct wl_shell_surface_listener shell_surface_listener = { }; static void -create_window (GstWaylandSink * sink, struct display *display, int width, +create_window (GstWaylandSink * sink, GstWlDisplay * display, int width, int height) { struct window *window; @@ -484,7 +402,6 @@ create_window (GstWaylandSink * sink, struct display *display, int width, g_mutex_lock (&sink->wayland_lock); window = malloc (sizeof *window); - window->display = display; window->width = width; window->height = height; window->redraw_pending = FALSE; @@ -511,16 +428,17 @@ gst_wayland_sink_start (GstBaseSink * bsink) { GstWaylandSink *sink = (GstWaylandSink *) bsink; gboolean result = TRUE; + GError *error = NULL; GST_DEBUG_OBJECT (sink, "start"); if (!sink->display) - sink->display = create_display (); + sink->display = gst_wl_display_new (NULL, &error); if (sink->display == NULL) { - GST_ELEMENT_ERROR (bsink, RESOURCE, OPEN_READ_WRITE, + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ_WRITE, ("Could not initialise Wayland output"), - ("Could not create Wayland display")); + ("Failed to create GstWlDisplay: '%s'", error->message)); return FALSE; } @@ -617,6 +535,7 @@ frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time) { struct window *window = (struct window *) data; window->redraw_pending = FALSE; + GST_LOG ("frame_redraw_cb"); wl_callback_destroy (callback); } @@ -633,21 +552,15 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) GstWlMeta *meta; GstFlowReturn ret; struct window *window; - struct display *display; GST_LOG_OBJECT (sink, "render buffer %p", buffer); if (!sink->window) create_window (sink, sink->display, sink->video_width, sink->video_height); window = sink->window; - display = sink->display; meta = gst_buffer_get_wl_meta (buffer); - if (window->redraw_pending) { - wl_display_dispatch (display->display); - } - if (meta && meta->sink == sink) { GST_LOG_OBJECT (sink, "buffer %p from our pool, writing directly", buffer); to_render = buffer; @@ -685,7 +598,7 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) window->callback = wl_surface_frame (window->surface); wl_callback_add_listener (window->callback, &frame_callback_listener, window); wl_surface_commit (window->surface); - wl_display_dispatch (display->display); + wl_display_flush (sink->display->display); if (buffer != to_render) gst_buffer_unref (to_render); diff --git a/ext/wayland/gstwaylandsink.h b/ext/wayland/gstwaylandsink.h index 9e9b011..617e51f 100644 --- a/ext/wayland/gstwaylandsink.h +++ b/ext/wayland/gstwaylandsink.h @@ -42,6 +42,8 @@ #include +#include "wldisplay.h" + G_BEGIN_DECLS #define GST_TYPE_WAYLAND_SINK \ @@ -57,19 +59,8 @@ G_BEGIN_DECLS #define GST_WAYLAND_SINK_GET_CLASS(inst) \ (G_TYPE_INSTANCE_GET_CLASS ((inst), GST_TYPE_WAYLAND_SINK, GstWaylandSinkClass)) -struct display -{ - struct wl_display *display; - struct wl_registry *registry; - struct wl_compositor *compositor; - struct wl_shell *shell; - struct wl_shm *shm; - uint32_t formats; -}; - struct window { - struct display *display; int width, height; struct wl_surface *surface; struct wl_shell_surface *shell_surface; @@ -97,7 +88,7 @@ struct _GstWaylandSink { GstVideoSink parent; - struct display *display; + GstWlDisplay *display; struct window *window; struct shm_pool *shm_pool; diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c index 9eb028a..9ab993c 100644 --- a/ext/wayland/waylandpool.c +++ b/ext/wayland/waylandpool.c @@ -24,6 +24,7 @@ /* Object header */ #include "gstwaylandsink.h" +#include "wldisplay.h" /* Debugging category */ #include @@ -127,7 +128,7 @@ wrong_caps: } static struct wl_shm_pool * -make_shm_pool (struct display *display, int size, void **data) +make_shm_pool (GstWlDisplay * display, int size, void **data) { struct wl_shm_pool *pool; int fd; @@ -162,7 +163,7 @@ make_shm_pool (struct display *display, int size, void **data) } static struct shm_pool * -shm_pool_create (struct display *display, size_t size) +shm_pool_create (GstWlDisplay * display, size_t size) { struct shm_pool *pool = malloc (sizeof *pool); diff --git a/ext/wayland/wldisplay.c b/ext/wayland/wldisplay.c new file mode 100644 index 0000000..5f142fb --- /dev/null +++ b/ext/wayland/wldisplay.c @@ -0,0 +1,233 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include "wldisplay.h" + +#include + +G_DEFINE_TYPE (GstWlDisplay, gst_wl_display, G_TYPE_OBJECT); + +static void gst_wl_display_finalize (GObject * gobject); + +static void +gst_wl_display_class_init (GstWlDisplayClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = gst_wl_display_finalize; +} + +static void +gst_wl_display_init (GstWlDisplay * self) +{ + self->wl_fd_poll = gst_poll_new (TRUE); +} + +static void +gst_wl_display_finalize (GObject * gobject) +{ + GstWlDisplay *self = GST_WL_DISPLAY (gobject); + + gst_poll_set_flushing (self->wl_fd_poll, TRUE); + + if (self->thread) + g_thread_join (self->thread); + + gst_poll_free (self->wl_fd_poll); + + if (self->shm) + wl_shm_destroy (self->shm); + + if (self->shell) + wl_shell_destroy (self->shell); + + if (self->compositor) + wl_compositor_destroy (self->compositor); + + if (self->registry) + wl_registry_destroy (self->registry); + + if (self->queue) + wl_event_queue_destroy (self->queue); + + if (self->own_display) { + wl_display_flush (self->display); + wl_display_disconnect (self->display); + } + + G_OBJECT_CLASS (gst_wl_display_parent_class)->finalize (gobject); +} + +static void +sync_callback (void *data, struct wl_callback *callback, uint32_t serial) +{ + gboolean *done = data; + *done = TRUE; +} + +static const struct wl_callback_listener sync_listener = { + sync_callback +}; + +static gint +gst_wl_display_roundtrip (GstWlDisplay * self) +{ + struct wl_callback *callback; + gint ret = 0; + gboolean done = FALSE; + + g_return_val_if_fail (self != NULL, -1); + + /* We don't own the display, process only our queue */ + callback = wl_display_sync (self->display); + wl_callback_add_listener (callback, &sync_listener, &done); + wl_proxy_set_queue ((struct wl_proxy *) callback, self->queue); + while (ret != -1 && !done) + ret = wl_display_dispatch_queue (self->display, self->queue); + wl_callback_destroy (callback); + + return ret; +} + +static void +shm_format (void *data, struct wl_shm *wl_shm, uint32_t format) +{ + GstWlDisplay *self = data; + + self->formats |= (1 << format); +} + +static const struct wl_shm_listener shm_listener = { + shm_format +}; + +static void +registry_handle_global (void *data, struct wl_registry *registry, + uint32_t id, const char *interface, uint32_t version) +{ + GstWlDisplay *self = data; + + if (g_strcmp0 (interface, "wl_compositor") == 0) { + self->compositor = + wl_registry_bind (registry, id, &wl_compositor_interface, 1); + } else if (g_strcmp0 (interface, "wl_shell") == 0) { + self->shell = wl_registry_bind (registry, id, &wl_shell_interface, 1); + } else if (g_strcmp0 (interface, "wl_shm") == 0) { + self->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1); + wl_shm_add_listener (self->shm, &shm_listener, self); + } +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global +}; + +static gpointer +gst_wl_display_thread_run (gpointer data) +{ + GstWlDisplay *self = data; + GstPollFD pollfd = GST_POLL_FD_INIT; + + pollfd.fd = wl_display_get_fd (self->display); + gst_poll_add_fd (self->wl_fd_poll, &pollfd); + gst_poll_fd_ctl_read (self->wl_fd_poll, &pollfd, TRUE); + + /* main loop */ + while (1) { + while (wl_display_prepare_read_queue (self->display, self->queue) != 0) + wl_display_dispatch_queue_pending (self->display, self->queue); + wl_display_flush (self->display); + + if (gst_poll_wait (self->wl_fd_poll, GST_CLOCK_TIME_NONE) < 0) { + gboolean normal = (errno == EBUSY); + wl_display_cancel_read (self->display); + if (normal) + break; + else + goto error; + } else { + wl_display_read_events (self->display); + wl_display_dispatch_queue_pending (self->display, self->queue); + } + } + + return NULL; + +error: + GST_ERROR ("Error communicating with the wayland server"); + return NULL; +} + +GstWlDisplay * +gst_wl_display_new (const gchar * name, GError ** error) +{ + struct wl_display *display; + + display = wl_display_connect (name); + + if (!display) { + *error = g_error_new (g_quark_from_static_string ("GstWlDisplay"), 0, + "Failed to connect to the wayland display '%s'", + name ? name : "(default)"); + return NULL; + } else { + return gst_wl_display_new_existing (display, TRUE, error); + } +} + +GstWlDisplay * +gst_wl_display_new_existing (struct wl_display * display, + gboolean take_ownership, GError ** error) +{ + GstWlDisplay *self; + GError *err = NULL; + gint i; + + g_return_val_if_fail (display != NULL, NULL); + + self = g_object_new (GST_TYPE_WL_DISPLAY, NULL); + self->display = display; + self->own_display = take_ownership; + + self->queue = wl_display_create_queue (self->display); + self->registry = wl_display_get_registry (self->display); + wl_proxy_set_queue ((struct wl_proxy *) self->registry, self->queue); + wl_registry_add_listener (self->registry, ®istry_listener, self); + + /* we need exactly 2 roundtrips to discover global objects and their state */ + for (i = 0; i < 2; i++) { + if (gst_wl_display_roundtrip (self) < 0) { + *error = g_error_new (g_quark_from_static_string ("GstWlDisplay"), 0, + "Error communicating with the wayland display"); + g_object_unref (self); + return NULL; + } + } + + self->thread = g_thread_try_new ("GstWlDisplay", gst_wl_display_thread_run, + self, &err); + if (err) { + g_propagate_prefixed_error (error, err, + "Failed to start thread for the display's events"); + g_object_unref (self); + return NULL; + } + + return self; +} diff --git a/ext/wayland/wldisplay.h b/ext/wayland/wldisplay.h new file mode 100644 index 0000000..149b921 --- /dev/null +++ b/ext/wayland/wldisplay.h @@ -0,0 +1,69 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __GST_WL_DISPLAY_H__ +#define __GST_WL_DISPLAY_H__ + +#include +#include + +#define GST_TYPE_WL_DISPLAY (gst_wl_display_get_type ()) +#define GST_WL_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_DISPLAY, GstWlDisplay)) +#define GST_IS_WL_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_DISPLAY)) +#define GST_WL_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_DISPLAY, GstWlDisplayClass)) +#define GST_IS_WL_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_DISPLAY)) +#define GST_WL_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_DISPLAY, GstWlDisplayClass)) + +typedef struct _GstWlDisplay GstWlDisplay; +typedef struct _GstWlDisplayClass GstWlDisplayClass; + +struct _GstWlDisplay +{ + GObject parent_instance; + + /* public objects */ + struct wl_display *display; + struct wl_event_queue *queue; + + /* globals */ + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_shell *shell; + struct wl_shm *shm; + guint32 formats; + + /* private */ + gboolean own_display; + GThread *thread; + GstPoll *wl_fd_poll; +}; + +struct _GstWlDisplayClass +{ + GObjectClass parent_class; +}; + +GType gst_wl_display_get_type (void); + +GstWlDisplay *gst_wl_display_new (const gchar * name, GError ** error); +GstWlDisplay *gst_wl_display_new_existing (struct wl_display * display, + gboolean take_ownership, GError ** error); + +#endif /* __GST_WL_DISPLAY_H__ */