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.
This commit is contained in:
George Kiagiadakis 2014-06-20 14:47:57 +03:00
parent b8927d848c
commit 9807d58b01
8 changed files with 316 additions and 202 deletions

View file

@ -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

View file

@ -44,6 +44,7 @@
#include "gstwaylandsink.h"
#include "wlvideoformat.h"
#include "waylandpool.h"
#include "wlbuffer.h"
#include <gst/wayland/wayland.h>
#include <gst/video/videooverlay.h>
@ -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 {

View file

@ -26,6 +26,7 @@
#include "waylandpool.h"
#include "wldisplay.h"
#include "wlvideoformat.h"
#include "wlbuffer.h"
#include <stdio.h>
#include <stdlib.h>
@ -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 */

View file

@ -23,7 +23,6 @@
#define __GST_WAYLAND_BUFFER_POOL_H__
#include <gst/video/video.h>
#include <gst/video/gstvideometa.h>
#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__*/

192
ext/wayland/wlbuffer.c Normal file
View file

@ -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;
}

67
ext/wayland/wlbuffer.h Normal file
View file

@ -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__ */

View file

@ -23,6 +23,7 @@
#endif
#include "wldisplay.h"
#include "wlbuffer.h"
#include <errno.h>
@ -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);
}

View file

@ -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__ */