From: George Kiagiadakis Date: Fri, 20 Jun 2014 11:47:57 +0000 (+0300) Subject: waylandsink: rework the mechanism for keeping buffers out of the pool until wl_buffer... X-Git-Tag: 1.19.3~507^2~10155 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9807d58b01cca8b71e5fe2908bafb0a3e80b7059;p=platform%2Fupstream%2Fgstreamer.git waylandsink: rework the mechanism for keeping buffers out of the pool until wl_buffer::release This also removes the GstWlMeta and adds a wrapper class for wl_buffer which is saved in the GstBuffer qdata instead of being a GstMeta. The motivation behind this is mainly to allow attaching wl_buffers on GstBuffers that have not been allocated inside the GstWaylandBufferPool, so that if for example an upstream element is sending us a buffer from a different pool, which however does not need to be copied to a buffer from our pool because it may be a hardware buffer (hello dmabuf!), we can create a wl_buffer directly from it and first, attach it on it so that we don't have to re-create a wl_buffer every time the same GstBuffer arrives and second, force the whole mechanism for keeping the buffer out of the pool until there is a wl_buffer::release on that foreign GstBuffer. --- diff --git a/ext/wayland/Makefile.am b/ext/wayland/Makefile.am index 58c1e99..73aae2c 100644 --- a/ext/wayland/Makefile.am +++ b/ext/wayland/Makefile.am @@ -3,6 +3,7 @@ plugin_LTLIBRARIES = libgstwaylandsink.la libgstwaylandsink_la_SOURCES = \ gstwaylandsink.c \ waylandpool.c \ + wlbuffer.c \ wldisplay.c \ wlwindow.c \ wlvideoformat.c \ @@ -21,6 +22,7 @@ libgstwaylandsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) noinst_HEADERS = \ gstwaylandsink.h \ waylandpool.h \ + wlbuffer.h \ wldisplay.h \ wlwindow.h \ wlvideoformat.h \ @@ -39,6 +41,8 @@ gstwaylandsink.c: scaler-client-protocol.h waylandpool.c: scaler-client-protocol.h +wlbuffer.c: scaler-client-protocol.h + wldisplay.c: scaler-client-protocol.h wlwindow.c: scaler-client-protocol.h diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c index d029d83..1e2c11d 100644 --- a/ext/wayland/gstwaylandsink.c +++ b/ext/wayland/gstwaylandsink.c @@ -44,6 +44,7 @@ #include "gstwaylandsink.h" #include "wlvideoformat.h" #include "waylandpool.h" +#include "wlbuffer.h" #include #include @@ -212,11 +213,9 @@ gst_wayland_sink_finalize (GObject * object) if (sink->last_buffer) gst_buffer_unref (sink->last_buffer); if (sink->display) { - /* see comment about this call in gst_wayland_sink_change_state() */ - if (sink->pool) { - gst_wayland_compositor_release_all_buffers (GST_WAYLAND_BUFFER_POOL - (sink->pool)); - } + /* the display must be stopped before droping our reference to it + * - see the comment on wlbuffer.c for details */ + gst_wl_display_stop (sink->display); g_object_unref (sink->display); } if (sink->window) @@ -359,23 +358,9 @@ gst_wayland_sink_change_state (GstElement * element, GstStateChange transition) * restarted (GstVideoOverlay behaves like that in other sinks) */ if (sink->display && !sink->window) { /* -> the window was toplevel */ - /* Force all buffers to return to the pool, regardless of - * whether the compositor has released them or not. We are - * going to kill the display, so we need to return all buffers - * to be destroyed before this happens. - * Note that this is done here instead of the pool destructor - * because the buffers hold a reference to the pool. Also, - * the buffers can only be unref'ed from the display's event loop - * and the pool holds a reference to the display. If we drop - * our references here, when the compositor releases the buffers, - * they will be unref'ed from the event loop thread, which will - * unref the pool and therefore the display, which will try to - * stop the thread from within itself and cause a deadlock. - */ - if (sink->pool) { - gst_wayland_compositor_release_all_buffers (GST_WAYLAND_BUFFER_POOL - (sink->pool)); - } + /* the display must be stopped before droping our reference to it + * - see the comment on wlbuffer.c for details */ + gst_wl_display_stop (sink->display); g_clear_object (&sink->display); g_clear_object (&sink->pool); } @@ -637,24 +622,18 @@ static const struct wl_callback_listener frame_callback_listener = { static void render_last_buffer (GstWaylandSink * sink) { - GstWlMeta *meta; + GstWlBuffer *wlbuffer; struct wl_surface *surface; struct wl_callback *callback; - meta = gst_buffer_get_wl_meta (sink->last_buffer); + wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer); surface = gst_wl_window_get_wl_surface (sink->window); g_atomic_int_set (&sink->redraw_pending, TRUE); callback = wl_surface_frame (surface); wl_callback_add_listener (callback, &frame_callback_listener, sink); - /* Here we essentially add a reference to the buffer. This represents - * the fact that the compositor is using the buffer and it should - * not return back to the pool and be reused until the compositor - * releases it. The release is handled internally in the pool */ - gst_wayland_compositor_acquire_buffer (meta->pool, sink->last_buffer); - - wl_surface_attach (surface, meta->wbuffer, 0, 0); + gst_wl_buffer_attach (wlbuffer, sink->window); wl_surface_damage (surface, 0, 0, sink->window->surface_width, sink->window->surface_height); @@ -667,7 +646,7 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) { GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); GstBuffer *to_render; - GstWlMeta *meta; + GstWlBuffer *wlbuffer; GstFlowReturn ret = GST_FLOW_OK; g_mutex_lock (&sink->render_lock); @@ -710,9 +689,9 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) sink->window->surface_height == 0)) goto no_window_size; - meta = gst_buffer_get_wl_meta (buffer); + wlbuffer = gst_buffer_get_wl_buffer (buffer); - if (meta && meta->pool->display == sink->display) { + if (wlbuffer && wlbuffer->display == sink->display) { GST_LOG_OBJECT (sink, "buffer %p from our pool, writing directly", buffer); to_render = buffer; } else { diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c index de20602..94758c8 100644 --- a/ext/wayland/waylandpool.c +++ b/ext/wayland/waylandpool.c @@ -26,6 +26,7 @@ #include "waylandpool.h" #include "wldisplay.h" #include "wlvideoformat.h" +#include "wlbuffer.h" #include #include @@ -38,44 +39,6 @@ GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); #define GST_CAT_DEFAULT gstwayland_debug -/* wl metadata */ -GType -gst_wl_meta_api_get_type (void) -{ - static volatile GType type; - static const gchar *tags[] = - { "memory", "size", "colorspace", "orientation", NULL }; - - if (g_once_init_enter (&type)) { - GType _type = gst_meta_api_type_register ("GstWlMetaAPI", tags); - g_once_init_leave (&type, _type); - } - return type; -} - -static void -gst_wl_meta_free (GstWlMeta * meta, GstBuffer * buffer) -{ - GST_DEBUG ("destroying wl_buffer %p", meta->wbuffer); - wl_buffer_destroy (meta->wbuffer); -} - -const GstMetaInfo * -gst_wl_meta_get_info (void) -{ - static const GstMetaInfo *wl_meta_info = NULL; - - if (g_once_init_enter (&wl_meta_info)) { - const GstMetaInfo *meta = - gst_meta_register (GST_WL_META_API_TYPE, "GstWlMeta", - sizeof (GstWlMeta), (GstMetaInitFunction) NULL, - (GstMetaFreeFunction) gst_wl_meta_free, - (GstMetaTransformFunction) NULL); - g_once_init_leave (&wl_meta_info, meta); - } - return wl_meta_info; -} - /* bufferpool */ static void gst_wayland_buffer_pool_finalize (GObject * object); static gboolean gst_wayland_buffer_pool_set_config (GstBufferPool * pool, @@ -107,8 +70,6 @@ static void gst_wayland_buffer_pool_init (GstWaylandBufferPool * self) { gst_video_info_init (&self->info); - g_mutex_init (&self->buffers_map_mutex); - self->buffers_map = g_hash_table_new (g_direct_hash, g_direct_equal); } static void @@ -119,86 +80,11 @@ gst_wayland_buffer_pool_finalize (GObject * object) if (pool->wl_pool) gst_wayland_buffer_pool_stop (GST_BUFFER_POOL (pool)); - g_mutex_clear (&pool->buffers_map_mutex); - g_hash_table_unref (pool->buffers_map); - g_object_unref (pool->display); G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object); } -static void -buffer_release (void *data, struct wl_buffer *wl_buffer) -{ - GstWaylandBufferPool *self = data; - GstBuffer *buffer; - GstWlMeta *meta; - - g_mutex_lock (&self->buffers_map_mutex); - buffer = g_hash_table_lookup (self->buffers_map, wl_buffer); - - GST_LOG_OBJECT (self, "wl_buffer::release (GstBuffer: %p)", buffer); - - if (buffer) { - meta = gst_buffer_get_wl_meta (buffer); - if (meta->used_by_compositor) { - meta->used_by_compositor = FALSE; - /* unlock before unref because stop() may be called from here */ - g_mutex_unlock (&self->buffers_map_mutex); - gst_buffer_unref (buffer); - return; - } - } - g_mutex_unlock (&self->buffers_map_mutex); -} - -static const struct wl_buffer_listener buffer_listener = { - buffer_release -}; - -void -gst_wayland_compositor_acquire_buffer (GstWaylandBufferPool * self, - GstBuffer * buffer) -{ - GstWlMeta *meta; - - meta = gst_buffer_get_wl_meta (buffer); - g_return_if_fail (meta != NULL); - g_return_if_fail (meta->pool == self); - g_return_if_fail (meta->used_by_compositor == FALSE); - - meta->used_by_compositor = TRUE; - gst_buffer_ref (buffer); -} - -static void -unref_used_buffers (gpointer key, gpointer value, gpointer data) -{ - GstBuffer *buffer = value; - GstWlMeta *meta = gst_buffer_get_wl_meta (buffer); - GList **to_unref = data; - - if (meta->used_by_compositor) { - meta->used_by_compositor = FALSE; - *to_unref = g_list_prepend (*to_unref, buffer); - } -} - -void -gst_wayland_compositor_release_all_buffers (GstWaylandBufferPool * self) -{ - GList *to_unref = NULL; - - g_mutex_lock (&self->buffers_map_mutex); - g_hash_table_foreach (self->buffers_map, unref_used_buffers, &to_unref); - g_mutex_unlock (&self->buffers_map_mutex); - - /* unref without the lock because stop() may be called from here */ - if (to_unref) { - g_list_free_full (to_unref, (GDestroyNotify) gst_buffer_unref); - } -} - static gboolean gst_wayland_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) { @@ -302,12 +188,6 @@ gst_wayland_buffer_pool_stop (GstBufferPool * pool) self->size = 0; self->used = 0; - /* all buffers are about to be destroyed; - * we should no longer do anything with them */ - g_mutex_lock (&self->buffers_map_mutex); - g_hash_table_remove_all (self->buffers_map); - g_mutex_unlock (&self->buffers_map_mutex); - return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool); } @@ -321,7 +201,7 @@ gst_wayland_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, enum wl_shm_format format; gint offset; void *data; - GstWlMeta *meta; + struct wl_buffer *wbuffer; width = GST_VIDEO_INFO_WIDTH (&self->info); height = GST_VIDEO_INFO_HEIGHT (&self->info); @@ -342,26 +222,18 @@ gst_wayland_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, self->used += size; data = ((gchar *) self->data) + offset; - /* create buffer and its metadata object */ *buffer = gst_buffer_new (); - meta = (GstWlMeta *) gst_buffer_add_meta (*buffer, GST_WL_META_INFO, NULL); - meta->pool = self; - meta->wbuffer = wl_shm_pool_create_buffer (self->wl_pool, offset, - width, height, stride, format); - meta->used_by_compositor = FALSE; - - /* configure listening to wl_buffer.release */ - g_mutex_lock (&self->buffers_map_mutex); - g_hash_table_insert (self->buffers_map, meta->wbuffer, *buffer); - g_mutex_unlock (&self->buffers_map_mutex); - - wl_buffer_add_listener (meta->wbuffer, &buffer_listener, self); /* add the allocated memory on the GstBuffer */ gst_buffer_append_memory (*buffer, gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data, size, 0, size, NULL, NULL)); + /* create wl_buffer and attach it on the GstBuffer via GstWlBuffer */ + wbuffer = wl_shm_pool_create_buffer (self->wl_pool, offset, width, height, + stride, format); + gst_buffer_add_wl_buffer (*buffer, wbuffer, self->display); + return GST_FLOW_OK; /* ERROR */ diff --git a/ext/wayland/waylandpool.h b/ext/wayland/waylandpool.h index ad5020b..e0944d0 100644 --- a/ext/wayland/waylandpool.h +++ b/ext/wayland/waylandpool.h @@ -23,7 +23,6 @@ #define __GST_WAYLAND_BUFFER_POOL_H__ #include -#include #include "wldisplay.h" @@ -37,25 +36,6 @@ G_BEGIN_DECLS typedef struct _GstWaylandBufferPool GstWaylandBufferPool; typedef struct _GstWaylandBufferPoolClass GstWaylandBufferPoolClass; -/* buffer meta */ -typedef struct _GstWlMeta GstWlMeta; - -GType gst_wl_meta_api_get_type (void); -#define GST_WL_META_API_TYPE (gst_wl_meta_api_get_type()) - -const GstMetaInfo * gst_wl_meta_get_info (void); -#define GST_WL_META_INFO (gst_wl_meta_get_info()) - -#define gst_buffer_get_wl_meta(b) ((GstWlMeta*)gst_buffer_get_meta((b),GST_WL_META_API_TYPE)) - -struct _GstWlMeta { - GstMeta meta; - - GstWaylandBufferPool *pool; - struct wl_buffer *wbuffer; - gboolean used_by_compositor; -}; - /* buffer pool */ struct _GstWaylandBufferPool { @@ -70,9 +50,6 @@ struct _GstWaylandBufferPool size_t size; size_t used; void *data; - - GMutex buffers_map_mutex; - GHashTable *buffers_map; }; struct _GstWaylandBufferPoolClass @@ -84,11 +61,6 @@ GType gst_wayland_buffer_pool_get_type (void); GstBufferPool *gst_wayland_buffer_pool_new (GstWlDisplay * display); - -void gst_wayland_compositor_acquire_buffer (GstWaylandBufferPool * self, - GstBuffer * buffer); -void gst_wayland_compositor_release_all_buffers (GstWaylandBufferPool * self); - G_END_DECLS #endif /*__GST_WAYLAND_BUFFER_POOL_H__*/ diff --git a/ext/wayland/wlbuffer.c b/ext/wayland/wlbuffer.c new file mode 100644 index 0000000..1806b17 --- /dev/null +++ b/ext/wayland/wlbuffer.c @@ -0,0 +1,192 @@ +/* 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. + */ + +/* GstWlBuffer wraps wl_buffer and provides a mechanism for preventing + * buffers from being re-used while the compositor is using them. This + * is achieved by adding a reference to the GstBuffer as soon as its + * associated wl_buffer is sent to the compositor and by removing this + * reference as soon as the compositor sends a wl_buffer::release message. + * + * This mechanism is a bit complicated, though, because it adds cyclic + * references that can be dangerous. The reference cycles looks like: + * + * ---------------- + * | GstWlDisplay | ----------------------------------> + * ---------------- | + * ^ | + * | V + * ------------------------ ------------- --------------- + * | GstWaylandBufferPool | --> | GstBuffer | ==> | GstWlBuffer | + * | | <-- | | <-- | | + * ------------------------ ------------- --------------- + * + * A GstBufferPool normally holds references to its GstBuffers and each buffer + * holds a reference to a GstWlBuffer (saved in the GstMiniObject qdata). + * When a GstBuffer is in use, it holds a reference back to the pool and the + * pool doesn't hold a reference to the GstBuffer. When the GstBuffer is unrefed + * externally, it returns back to the pool and the pool holds again a reference + * to the buffer. + * + * Now when the compositor is using a buffer, the GstWlBuffer also holds a ref + * to the GstBuffer, which prevents it from returning to the pool. When the + * last GstWlBuffer receives a release event and unrefs the last GstBuffer, + * the GstBufferPool will be able to stop and if no-one is holding a strong + * ref to it, it will be destroyed. This will destroy that last GstBuffer and + * also the GstWlBuffer. This will all happen in the same context of the + * gst_buffer_unref, which will be called from the buffer_release() callback. + * + * The big problem here lies in the fact that buffer_release() will be called + * from the event loop thread of GstWlDisplay and the second big problem is + * that the GstWaylandBufferPool holds a strong ref to the GstWlDisplay. + * Therefore, if the buffer_release() causes the pool to be destroyed, it may + * also cause the GstWlDisplay to be destroyed and that will happen in the + * context of the event loop thread that GstWlDisplay runs. Destroying the + * GstWlDisplay will need to join the thread (from inside the thread!) and boom. + * + * Normally, this will never happen, even if we don't take special care for it, + * because the compositor releases buffers almost immediately and when + * waylandsink stops, they are already released. + * + * However, we want to be absolutely certain, so a solution is introduced + * by explicitly releasing all the buffer references and destroying the + * GstWlBuffers as soon as we know that we are not going to use them again. + * All the GstWlBuffers are registered in a hash set inside GstWlDisplay + * and there is gst_wl_display_stop(), which stops the event loop thread + * and releases all the buffers explicitly. This gets called from GstWaylandSink + * right before dropping its own reference to the GstWlDisplay, leaving + * a possible last (but safe now!) reference to the pool, which may be + * referenced by an upstream element. + */ + +#include "wlbuffer.h" + +GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); +#define GST_CAT_DEFAULT gstwayland_debug + +G_DEFINE_TYPE (GstWlBuffer, gst_wl_buffer, G_TYPE_OBJECT); + +static G_DEFINE_QUARK (GstWlBufferQDataQuark, gst_wl_buffer_qdata); + +static void +gst_wl_buffer_finalize (GObject * gobject) +{ + GstWlBuffer *self = GST_WL_BUFFER (gobject); + + if (self->display) + gst_wl_display_unregister_buffer (self->display, self); + wl_buffer_destroy (self->wlbuffer); + + G_OBJECT_CLASS (gst_wl_buffer_parent_class)->finalize (gobject); +} + +static void +gst_wl_buffer_class_init (GstWlBufferClass * klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + object_class->finalize = gst_wl_buffer_finalize; +} + +static void +gst_wl_buffer_init (GstWlBuffer * self) +{ +} + +static void +buffer_release (void *data, struct wl_buffer *wl_buffer) +{ + GstWlBuffer *self = data; + + GST_LOG_OBJECT (self, "wl_buffer::release (GstBuffer: %p)", self->gstbuffer); + + self->used_by_compositor = FALSE; + + /* unref should be last, because it may end up destroying the GstWlBuffer */ + gst_buffer_unref (self->gstbuffer); +} + +static const struct wl_buffer_listener buffer_listener = { + buffer_release +}; + +void +gst_buffer_add_wl_buffer (GstBuffer * gstbuffer, struct wl_buffer *wlbuffer, + GstWlDisplay * display) +{ + GstWlBuffer *self; + + self = g_object_new (GST_TYPE_WL_BUFFER, NULL); + self->gstbuffer = gstbuffer; + self->wlbuffer = wlbuffer; + self->display = display; + + gst_wl_display_register_buffer (self->display, self); + + wl_buffer_add_listener (self->wlbuffer, &buffer_listener, self); + + gst_mini_object_set_qdata ((GstMiniObject *) gstbuffer, + gst_wl_buffer_qdata_quark (), self, g_object_unref); +} + +GstWlBuffer * +gst_buffer_get_wl_buffer (GstBuffer * gstbuffer) +{ + return gst_mini_object_get_qdata ((GstMiniObject *) gstbuffer, + gst_wl_buffer_qdata_quark ()); +} + +void +gst_wl_buffer_force_release_and_unref (GstWlBuffer * self) +{ + /* detach from the GstBuffer */ + (void) gst_mini_object_steal_qdata ((GstMiniObject *) self->gstbuffer, + gst_wl_buffer_qdata_quark ()); + + /* force a buffer release + * at this point, the GstWlDisplay has killed its event loop, + * so we don't need to worry about buffer_release() being called + * at the same time from the event loop thread */ + if (self->used_by_compositor) { + GST_DEBUG_OBJECT (self, "forcing wl_buffer::release (GstBuffer: %p)", + self->gstbuffer); + gst_buffer_unref (self->gstbuffer); + self->used_by_compositor = FALSE; + } + + /* avoid unregistering from the display in finalize() because this + * function is being called from a hash table foreach function, + * which would be modified in gst_wl_display_unregister_buffer() */ + self->display = NULL; + g_object_unref (self); +} + +void +gst_wl_buffer_attach (GstWlBuffer * self, GstWlWindow * target) +{ + g_return_if_fail (self->used_by_compositor == FALSE); + + wl_surface_attach (target->surface, self->wlbuffer, 0, 0); + + /* Add a reference to the buffer. This represents the fact that + * the compositor is using the buffer and it should not return + * back to the pool and be re-used until the compositor releases it. */ + gst_buffer_ref (self->gstbuffer); + self->used_by_compositor = TRUE; +} diff --git a/ext/wayland/wlbuffer.h b/ext/wayland/wlbuffer.h new file mode 100644 index 0000000..b434df4 --- /dev/null +++ b/ext/wayland/wlbuffer.h @@ -0,0 +1,67 @@ +/* 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_BUFFER_H__ +#define __GST_WL_BUFFER_H__ + +#include "wlwindow.h" + +G_BEGIN_DECLS + +#define GST_TYPE_WL_BUFFER (gst_wl_buffer_get_type ()) +#define GST_WL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_BUFFER, GstWlBuffer)) +#define GST_IS_WL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_BUFFER)) +#define GST_WL_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_BUFFER, GstWlBufferClass)) +#define GST_IS_WL_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_BUFFER)) +#define GST_WL_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_BUFFER, GstWlBufferClass)) + +typedef struct _GstWlBuffer GstWlBuffer; +typedef struct _GstWlBufferClass GstWlBufferClass; + +struct _GstWlBuffer +{ + GObject parent_instance; + + struct wl_buffer * wlbuffer; + GstBuffer *gstbuffer; + + GstWlDisplay *display; + + gboolean used_by_compositor; +}; + +struct _GstWlBufferClass +{ + GObjectClass parent_class; +}; + +GType gst_wl_buffer_get_type (void); + +void gst_buffer_add_wl_buffer (GstBuffer * gstbuffer, + struct wl_buffer * wlbuffer, GstWlDisplay * display); +GstWlBuffer * gst_buffer_get_wl_buffer (GstBuffer * gstbuffer); + +void gst_wl_buffer_force_release_and_unref (GstWlBuffer * self); + +void gst_wl_buffer_attach (GstWlBuffer * self, GstWlWindow * target); + +G_END_DECLS + +#endif /* __GST_WL_BUFFER_H__ */ diff --git a/ext/wayland/wldisplay.c b/ext/wayland/wldisplay.c index 46efab9..17bfa8c 100644 --- a/ext/wayland/wldisplay.c +++ b/ext/wayland/wldisplay.c @@ -23,6 +23,7 @@ #endif #include "wldisplay.h" +#include "wlbuffer.h" #include @@ -45,6 +46,7 @@ gst_wl_display_init (GstWlDisplay * self) { self->formats = g_array_new (FALSE, FALSE, sizeof (uint32_t)); self->wl_fd_poll = gst_poll_new (TRUE); + self->buffers = g_hash_table_new (g_direct_hash, g_direct_equal); } static void @@ -52,13 +54,9 @@ 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); - g_array_unref (self->formats); gst_poll_free (self->wl_fd_poll); + g_hash_table_unref (self->buffers); if (self->shm) wl_shm_destroy (self->shm); @@ -266,3 +264,26 @@ gst_wl_display_new_existing (struct wl_display * display, return self; } + +void +gst_wl_display_stop (GstWlDisplay * self) +{ + gst_poll_set_flushing (self->wl_fd_poll, TRUE); + g_thread_join (self->thread); + + g_hash_table_foreach (self->buffers, + (GHFunc) gst_wl_buffer_force_release_and_unref, NULL); + g_hash_table_remove_all (self->buffers); +} + +void +gst_wl_display_register_buffer (GstWlDisplay * self, gpointer buf) +{ + g_hash_table_add (self->buffers, buf); +} + +void +gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer buf) +{ + g_hash_table_remove (self->buffers, buf); +} diff --git a/ext/wayland/wldisplay.h b/ext/wayland/wldisplay.h index 0224406..ac1df84 100644 --- a/ext/wayland/wldisplay.h +++ b/ext/wayland/wldisplay.h @@ -58,6 +58,8 @@ struct _GstWlDisplay gboolean own_display; GThread *thread; GstPoll *wl_fd_poll; + + GHashTable *buffers; }; struct _GstWlDisplayClass @@ -71,6 +73,11 @@ 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); +/* see wlbuffer.c for explanation */ +void gst_wl_display_stop (GstWlDisplay * self); +void gst_wl_display_register_buffer (GstWlDisplay * self, gpointer buf); +void gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer buf); + G_END_DECLS #endif /* __GST_WL_DISPLAY_H__ */