From ea05fe1278738591e4f2f0cea3882d8dce72a1d8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 3 Mar 2011 16:48:23 +0100 Subject: [PATCH] ximage: rewrite the buffer pool in ximagesink Rewrite the pooling in ximagesink to extend from the bufferpool base class in core. Move some code to a comon place and refactor. --- sys/ximage/Makefile.am | 4 +- sys/ximage/ximage.c | 3 + sys/ximage/ximagepool.c | 529 +++++++++++++++++++++++++++++++++ sys/ximage/ximagepool.h | 116 ++++++++ sys/ximage/ximagesink.c | 630 ++++++---------------------------------- sys/ximage/ximagesink.h | 46 +-- 6 files changed, 748 insertions(+), 580 deletions(-) create mode 100644 sys/ximage/ximagepool.c create mode 100644 sys/ximage/ximagepool.h diff --git a/sys/ximage/Makefile.am b/sys/ximage/Makefile.am index 69f9bbca9b..df14448b80 100644 --- a/sys/ximage/Makefile.am +++ b/sys/ximage/Makefile.am @@ -1,6 +1,6 @@ plugin_LTLIBRARIES = libgstximagesink.la -libgstximagesink_la_SOURCES = ximagesink.c ximage.c +libgstximagesink_la_SOURCES = ximagesink.c ximage.c ximagepool.c libgstximagesink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS) libgstximagesink_la_LIBADD = \ $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \ @@ -11,4 +11,4 @@ libgstximagesink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstximagesink_la_DEPENDENCIES = $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la libgstximagesink_la_LIBTOOLFLAGS = --tag=disable-static -noinst_HEADERS = ximagesink.h +noinst_HEADERS = ximagesink.h ximagepool.h diff --git a/sys/ximage/ximage.c b/sys/ximage/ximage.c index 24b7bf2847..6e541fd4ca 100644 --- a/sys/ximage/ximage.c +++ b/sys/ximage/ximage.c @@ -25,6 +25,7 @@ #include "ximagesink.h" +GST_DEBUG_CATEGORY (gst_debug_ximagepool); GST_DEBUG_CATEGORY (gst_debug_ximagesink); static gboolean @@ -36,6 +37,8 @@ plugin_init (GstPlugin * plugin) GST_DEBUG_CATEGORY_INIT (gst_debug_ximagesink, "ximagesink", 0, "ximagesink element"); + GST_DEBUG_CATEGORY_INIT (gst_debug_ximagepool, "ximagepool", 0, + "ximagepool object"); return TRUE; } diff --git a/sys/ximage/ximagepool.c b/sys/ximage/ximagepool.c new file mode 100644 index 0000000000..e31ed884b1 --- /dev/null +++ b/sys/ximage/ximagepool.c @@ -0,0 +1,529 @@ +/* GStreamer + * Copyright (C) <2005> Julien Moutte + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Object header */ +#include "ximagesink.h" + +/* Debugging category */ +#include + +GST_DEBUG_CATEGORY_EXTERN (gst_debug_ximagepool); +#define GST_CAT_DEFAULT gst_debug_ximagepool + +static void gst_meta_ximage_free (GstMetaXImage * meta, GstBuffer * buffer); + +/* ximage buffers */ +const GstMetaInfo * +gst_meta_ximage_get_info (void) +{ + static const GstMetaInfo *meta_ximage_info = NULL; + + if (meta_ximage_info == NULL) { + meta_ximage_info = gst_meta_register ("GstMetaXImage", "GstMetaXImage", + sizeof (GstMetaXImage), + (GstMetaInitFunction) NULL, + (GstMetaFreeFunction) gst_meta_ximage_free, + (GstMetaCopyFunction) NULL, + (GstMetaSubFunction) NULL, + (GstMetaSerializeFunction) NULL, (GstMetaDeserializeFunction) NULL); + } + return meta_ximage_info; +} + +/* X11 stuff */ +static gboolean error_caught; + +static int +gst_ximagesink_handle_xerror (Display * display, XErrorEvent * xevent) +{ + char error_msg[1024]; + + XGetErrorText (display, xevent->error_code, error_msg, 1024); + GST_DEBUG ("ximagesink triggered an XError. error: %s", error_msg); + error_caught = TRUE; + return 0; +} + +GstBuffer * +gst_ximage_buffer_new (GstXImageSink * ximagesink, gint width, gint height) +{ + GstBuffer *ximage; + int (*handler) (Display *, XErrorEvent *); + gboolean success = FALSE; + GstXContext *xcontext; + GstMetaXImage *meta; + + xcontext = ximagesink->xcontext; + + ximage = gst_buffer_new (); + meta = GST_META_XIMAGE_ADD (ximage); +#ifdef HAVE_XSHM + meta->SHMInfo.shmaddr = ((void *) -1); + meta->SHMInfo.shmid = -1; +#endif + meta->width = width; + meta->height = height; + meta->sink = gst_object_ref (ximagesink); + + GST_DEBUG_OBJECT (ximagesink, "creating image %p (%dx%d)", ximage, + meta->width, meta->height); + + g_mutex_lock (ximagesink->x_lock); + + /* Setting an error handler to catch failure */ + error_caught = FALSE; + handler = XSetErrorHandler (gst_ximagesink_handle_xerror); + +#ifdef HAVE_XSHM + if (xcontext->use_xshm) { + meta->ximage = XShmCreateImage (xcontext->disp, + xcontext->visual, + xcontext->depth, + ZPixmap, NULL, &meta->SHMInfo, meta->width, meta->height); + if (!meta->ximage || error_caught) + goto create_failed; + + /* we have to use the returned bytes_per_line for our shm size */ + meta->size = meta->ximage->bytes_per_line * meta->ximage->height; + GST_LOG_OBJECT (ximagesink, + "XShm image size is %" G_GSIZE_FORMAT ", width %d, stride %d", + meta->size, meta->width, meta->ximage->bytes_per_line); + + /* get shared memory */ + meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size, IPC_CREAT | 0777); + if (meta->SHMInfo.shmid == -1) + goto shmget_failed; + + /* attach */ + meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, NULL, 0); + if (meta->SHMInfo.shmaddr == ((void *) -1)) + goto shmat_failed; + + /* now we can set up the image data */ + meta->ximage->data = meta->SHMInfo.shmaddr; + meta->SHMInfo.readOnly = FALSE; + + if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0) + goto xattach_failed; + + XSync (xcontext->disp, FALSE); + + /* Now that everyone has attached, we can delete the shared memory segment. + * This way, it will be deleted as soon as we detach later, and not + * leaked if we crash. */ + shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL); + } else +#endif /* HAVE_XSHM */ + { + guint allocsize; + + meta->ximage = XCreateImage (xcontext->disp, + xcontext->visual, + xcontext->depth, + ZPixmap, 0, NULL, meta->width, meta->height, xcontext->bpp, 0); + if (!meta->ximage || error_caught) + goto create_failed; + + /* upstream will assume that rowstrides are multiples of 4, but this + * doesn't always seem to be the case with XCreateImage() */ + if ((meta->ximage->bytes_per_line % 4) != 0) { + GST_WARNING_OBJECT (ximagesink, "returned stride not a multiple of 4 as " + "usually assumed"); + } + + /* we have to use the returned bytes_per_line for our image size */ + meta->size = meta->ximage->bytes_per_line * meta->ximage->height; + + /* alloc a bit more for unexpected strides to avoid crashes upstream. + * FIXME: if we get an unrounded stride, the image will be displayed + * distorted, since all upstream elements assume a rounded stride */ + allocsize = + GST_ROUND_UP_4 (meta->ximage->bytes_per_line) * meta->ximage->height; + + meta->ximage->data = g_malloc (allocsize); + GST_LOG_OBJECT (ximagesink, + "non-XShm image size is %" G_GSIZE_FORMAT " (alloced: %u), width %d, " + "stride %d", meta->size, allocsize, meta->width, + meta->ximage->bytes_per_line); + + XSync (xcontext->disp, FALSE); + } + + /* Reset error handler */ + error_caught = FALSE; + XSetErrorHandler (handler); + + GST_BUFFER_DATA (ximage) = (guchar *) meta->ximage->data; + GST_BUFFER_SIZE (ximage) = meta->size; + + g_mutex_unlock (ximagesink->x_lock); + + success = TRUE; + +beach: + if (!success) { + gst_buffer_unref (GST_BUFFER_CAST (ximage)); + ximage = NULL; + } + return ximage; + + /* ERRORS */ +create_failed: + { + g_mutex_unlock (ximagesink->x_lock); + /* Reset error handler */ + error_caught = FALSE; + XSetErrorHandler (handler); + /* Push an error */ + GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, + ("Failed to create output image buffer of %dx%d pixels", + meta->width, meta->height), + ("could not XShmCreateImage a %dx%d image", meta->width, meta->height)); + goto beach; + } +shmget_failed: + { + g_mutex_unlock (ximagesink->x_lock); + GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, + ("Failed to create output image buffer of %dx%d pixels", + meta->width, meta->height), + ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", + meta->size)); + goto beach; + } +shmat_failed: + { + g_mutex_unlock (ximagesink->x_lock); + GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, + ("Failed to create output image buffer of %dx%d pixels", + meta->width, meta->height), + ("Failed to shmat: %s", g_strerror (errno))); + /* Clean up the shared memory segment */ + shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL); + goto beach; + } +xattach_failed: + { + /* Clean up shm seg */ + shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL); + g_mutex_unlock (ximagesink->x_lock); + + GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, + ("Failed to create output image buffer of %dx%d pixels", + meta->width, meta->height), ("Failed to XShmAttach")); + goto beach; + } +} + +static void +gst_meta_ximage_free (GstMetaXImage * meta, GstBuffer * buffer) +{ + GstXImageSink *ximagesink; + + ximagesink = meta->sink; + + GST_DEBUG_OBJECT (ximagesink, "free meta on buffer %p", buffer); + + /* Hold the object lock to ensure the XContext doesn't disappear */ + GST_OBJECT_LOCK (ximagesink); + /* We might have some buffers destroyed after changing state to NULL */ + if (!ximagesink->xcontext) { + GST_DEBUG_OBJECT (ximagesink, "Destroying XImage after XContext"); +#ifdef HAVE_XSHM + if (meta->SHMInfo.shmaddr != ((void *) -1)) { + shmdt (meta->SHMInfo.shmaddr); + } +#endif + goto beach; + } + + g_mutex_lock (ximagesink->x_lock); + +#ifdef HAVE_XSHM + if (ximagesink->xcontext->use_xshm) { + if (meta->SHMInfo.shmaddr != ((void *) -1)) { + XShmDetach (ximagesink->xcontext->disp, &meta->SHMInfo); + XSync (ximagesink->xcontext->disp, 0); + shmdt (meta->SHMInfo.shmaddr); + meta->SHMInfo.shmaddr = (void *) -1; + } + if (meta->ximage) + XDestroyImage (meta->ximage); + + } else +#endif /* HAVE_XSHM */ + { + if (meta->ximage) { + XDestroyImage (meta->ximage); + } + } + + XSync (ximagesink->xcontext->disp, FALSE); + + g_mutex_unlock (ximagesink->x_lock); + +beach: + GST_OBJECT_UNLOCK (ximagesink); +} + +#ifdef HAVE_XSHM /* Check that XShm calls actually work */ +gboolean +gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink, + GstXContext * xcontext) +{ + XImage *ximage; + XShmSegmentInfo SHMInfo; + size_t size; + int (*handler) (Display *, XErrorEvent *); + gboolean result = FALSE; + gboolean did_attach = FALSE; + + g_return_val_if_fail (xcontext != NULL, FALSE); + + /* Sync to ensure any older errors are already processed */ + XSync (xcontext->disp, FALSE); + + /* Set defaults so we don't free these later unnecessarily */ + SHMInfo.shmaddr = ((void *) -1); + SHMInfo.shmid = -1; + + /* Setting an error handler to catch failure */ + error_caught = FALSE; + handler = XSetErrorHandler (gst_ximagesink_handle_xerror); + + /* Trying to create a 1x1 ximage */ + GST_DEBUG ("XShmCreateImage of 1x1"); + + ximage = XShmCreateImage (xcontext->disp, xcontext->visual, + xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1); + + /* Might cause an error, sync to ensure it is noticed */ + XSync (xcontext->disp, FALSE); + if (!ximage || error_caught) { + GST_WARNING ("could not XShmCreateImage a 1x1 image"); + goto beach; + } + size = ximage->height * ximage->bytes_per_line; + + SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); + if (SHMInfo.shmid == -1) { + GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", + size); + goto beach; + } + + SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0); + if (SHMInfo.shmaddr == ((void *) -1)) { + GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); + /* Clean up shm seg */ + shmctl (SHMInfo.shmid, IPC_RMID, NULL); + goto beach; + } + + ximage->data = SHMInfo.shmaddr; + SHMInfo.readOnly = FALSE; + + if (XShmAttach (xcontext->disp, &SHMInfo) == 0) { + GST_WARNING ("Failed to XShmAttach"); + /* Clean up shm seg */ + shmctl (SHMInfo.shmid, IPC_RMID, NULL); + goto beach; + } + + /* Sync to ensure we see any errors we caused */ + XSync (xcontext->disp, FALSE); + + /* Delete the shared memory segment as soon as everyone is attached. + * This way, it will be deleted as soon as we detach later, and not + * leaked if we crash. */ + shmctl (SHMInfo.shmid, IPC_RMID, NULL); + + if (!error_caught) { + did_attach = TRUE; + /* store whether we succeeded in result */ + result = TRUE; + } + +beach: + /* Sync to ensure we swallow any errors we caused and reset error_caught */ + XSync (xcontext->disp, FALSE); + error_caught = FALSE; + XSetErrorHandler (handler); + + if (did_attach) { + XShmDetach (xcontext->disp, &SHMInfo); + XSync (xcontext->disp, FALSE); + } + if (SHMInfo.shmaddr != ((void *) -1)) + shmdt (SHMInfo.shmaddr); + if (ximage) + XDestroyImage (ximage); + return result; +} +#endif /* HAVE_XSHM */ + +/* bufferpool */ +static void gst_ximage_buffer_pool_finalize (GObject * object); + +#define GST_XIMAGE_BUFFER_POOL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_XIMAGE_BUFFER_POOL, GstXImageBufferPoolPrivate)) + +struct _GstXImageBufferPoolPrivate +{ + GstCaps *caps; + gint width, height; +}; + +G_DEFINE_TYPE (GstXImageBufferPool, gst_ximage_buffer_pool, + GST_TYPE_BUFFER_POOL); + +static gboolean +ximage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) +{ + GstXImageBufferPool *xpool = GST_XIMAGE_BUFFER_POOL_CAST (pool); + GstXImageBufferPoolPrivate *priv = xpool->priv; + GstStructure *structure; + gint width, height; + const GstCaps *caps; + + if (!gst_buffer_pool_config_get (config, &caps, NULL, NULL, NULL, NULL, + NULL, NULL)) + goto wrong_config; + + if (caps == NULL) + goto no_caps; + + /* now parse the caps from the config */ + structure = gst_caps_get_structure (caps, 0); + + if (!gst_structure_get_int (structure, "width", &width) || + !gst_structure_get_int (structure, "height", &height)) + goto wrong_caps; + + /* keep track of the width and height and caps */ + if (priv->caps) + gst_caps_unref (priv->caps); + priv->caps = gst_caps_copy (caps); + priv->width = width; + priv->height = height; + + return TRUE; + + /* ERRORS */ +wrong_config: + { + GST_WARNING_OBJECT (pool, "invalid config"); + return FALSE; + } +no_caps: + { + GST_WARNING_OBJECT (pool, "no caps in config"); + return FALSE; + } +wrong_caps: + { + GST_WARNING_OBJECT (pool, + "failed getting geometry from caps %" GST_PTR_FORMAT, caps); + return FALSE; + } +} + +/* This function handles GstXImageBuffer creation depending on XShm availability */ +static GstFlowReturn +ximage_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, + GstBufferPoolParams * params) +{ + GstXImageBufferPool *xpool = GST_XIMAGE_BUFFER_POOL_CAST (pool); + GstXImageBufferPoolPrivate *priv = xpool->priv; + GstBuffer *ximage; + + ximage = gst_ximage_buffer_new (xpool->sink, priv->width, priv->height); + if (ximage == NULL) + goto no_buffer; + + *buffer = ximage; + + return GST_FLOW_OK; + + /* ERROR */ +no_buffer: + { + GST_WARNING_OBJECT (pool, "can't create image"); + return GST_FLOW_ERROR; + } +} + +static void +ximage_buffer_pool_free (GstBufferPool * pool, GstBuffer * buffer) +{ + gst_buffer_unref (buffer); +} + +GstBufferPool * +gst_ximage_buffer_pool_new (GstXImageSink * ximagesink) +{ + GstXImageBufferPool *pool; + + g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); + + pool = g_object_new (GST_TYPE_XIMAGE_BUFFER_POOL, NULL); + pool->sink = gst_object_ref (ximagesink); + + return GST_BUFFER_POOL_CAST (pool); +} + +static void +gst_ximage_buffer_pool_class_init (GstXImageBufferPoolClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass; + + g_type_class_add_private (klass, sizeof (GstXImageBufferPoolPrivate)); + + gobject_class->finalize = gst_ximage_buffer_pool_finalize; + + gstbufferpool_class->set_config = ximage_buffer_pool_set_config; + gstbufferpool_class->alloc_buffer = ximage_buffer_pool_alloc; + gstbufferpool_class->free_buffer = ximage_buffer_pool_free; +} + +static void +gst_ximage_buffer_pool_init (GstXImageBufferPool * pool) +{ + pool->priv = GST_XIMAGE_BUFFER_POOL_GET_PRIVATE (pool); +} + +static void +gst_ximage_buffer_pool_finalize (GObject * object) +{ + GstXImageBufferPool *pool = GST_XIMAGE_BUFFER_POOL_CAST (object); + GstXImageBufferPoolPrivate *priv = pool->priv; + + GST_LOG_OBJECT (pool->sink, "finalize XImage buffer pool"); + + if (priv->caps) + gst_caps_unref (priv->caps); + gst_object_unref (pool->sink); + + G_OBJECT_CLASS (gst_ximage_buffer_pool_parent_class)->finalize (object); +} diff --git a/sys/ximage/ximagepool.h b/sys/ximage/ximagepool.h new file mode 100644 index 0000000000..691ffb8406 --- /dev/null +++ b/sys/ximage/ximagepool.h @@ -0,0 +1,116 @@ +/* GStreamer + * Copyright (C) <2005> Julien Moutte + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_XIMAGEPOOL_H__ +#define __GST_XIMAGEPOOL_H__ + +#ifdef HAVE_XSHM +#include +#include +#include +#endif /* HAVE_XSHM */ + +#include +#include + +#ifdef HAVE_XSHM +#include +#endif /* HAVE_XSHM */ + +#include +#include + + +G_BEGIN_DECLS + +typedef struct _GstMetaXImage GstMetaXImage; + +typedef struct _GstXImageBufferPool GstXImageBufferPool; +typedef struct _GstXImageBufferPoolClass GstXImageBufferPoolClass; +typedef struct _GstXImageBufferPoolPrivate GstXImageBufferPoolPrivate; + +#include "ximagesink.h" + +const GstMetaInfo * gst_meta_ximage_get_info (void); +#define GST_META_INFO_XIMAGE (gst_meta_ximage_get_info()) + +#define GST_META_GET(b,t,i) ((t *)gst_buffer_get_meta((b),(i))) +#define GST_META_ADD(b,t,i,p) ((t *)gst_buffer_add_meta((b),(i),(p))) + +#define GST_META_XIMAGE_GET(b) GST_META_GET(b,GstMetaXImage,GST_META_INFO_XIMAGE) +#define GST_META_XIMAGE_ADD(b) GST_META_ADD(b,GstMetaXImage,GST_META_INFO_XIMAGE,NULL) + +/** + * GstMetaXImage: + * @simagesink: a reference to the our #GstXImageSink + * @ximage: the XImage of this buffer + * @width: the width in pixels of XImage @ximage + * @height: the height in pixels of XImage @ximage + * @size: the size in bytes of XImage @ximage + * + * Subclass of #GstBuffer containing additional information about an XImage. + */ +struct _GstMetaXImage +{ + GstMeta meta; + + GstXImageSink *sink; + + XImage *ximage; + +#ifdef HAVE_XSHM + XShmSegmentInfo SHMInfo; +#endif /* HAVE_XSHM */ + + gint width, height; + size_t size; +}; + +GstBuffer * gst_ximage_buffer_new (GstXImageSink *ximagesink, gint width, gint height); + +/* buffer pool functions */ +#define GST_TYPE_XIMAGE_BUFFER_POOL (gst_ximage_buffer_pool_get_type()) +#define GST_IS_XIMAGE_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XIMAGE_BUFFER_POOL)) +#define GST_XIMAGE_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XIMAGE_BUFFER_POOL, GstXImageBufferPool)) +#define GST_XIMAGE_BUFFER_POOL_CAST(obj) ((GstXImageBufferPool*)(obj)) + +struct _GstXImageBufferPool +{ + GstBufferPool bufferpool; + + GstXImageSink *sink; + + GstXImageBufferPoolPrivate *priv; +}; + +struct _GstXImageBufferPoolClass +{ + GstBufferPoolClass parent_class; +}; + +GType gst_ximage_buffer_pool_get_type (void); + +GstBufferPool * gst_ximage_buffer_pool_new (GstXImageSink * ximagesink); + +gboolean gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink, + GstXContext * xcontext); + +G_END_DECLS + +#endif /* __GST_XIMAGEPOOL_H__ */ diff --git a/sys/ximage/ximagesink.c b/sys/ximage/ximagesink.c index 06f97a5d24..47383e0f4e 100644 --- a/sys/ximage/ximagesink.c +++ b/sys/ximage/ximagesink.c @@ -129,8 +129,6 @@ MotifWmHints, MwmHints; #define MWM_HINTS_DECORATIONS (1L << 1) static void gst_ximagesink_reset (GstXImageSink * ximagesink); -static void gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink, - GstBuffer * ximage); static void gst_ximagesink_xwindow_update_geometry (GstXImageSink * ximagesink); static void gst_ximagesink_expose (GstXOverlay * overlay); @@ -164,446 +162,8 @@ static GstVideoSinkClass *parent_class = NULL; /* */ /* ============================================================= */ -/* ximage buffers */ -const GstMetaInfo * -gst_meta_ximage_get_info (void) -{ - static const GstMetaInfo *meta_ximage_info = NULL; - - if (meta_ximage_info == NULL) { - meta_ximage_info = gst_meta_register ("GstMetaXImage", "GstMetaXImage", - sizeof (GstMetaXImage), - (GstMetaInitFunction) NULL, - (GstMetaFreeFunction) NULL, - (GstMetaCopyFunction) NULL, - (GstMetaSubFunction) NULL, - (GstMetaSerializeFunction) NULL, (GstMetaDeserializeFunction) NULL); - } - return meta_ximage_info; -} - -static void -gst_ximage_buffer_dispose (GstBuffer * ximage) -{ - GstMetaXImage *meta = NULL; - GstXImageSink *ximagesink = NULL; - gboolean recycled = FALSE; - gboolean running; - - meta = GST_META_XIMAGE_GET (ximage); - g_return_if_fail (meta != NULL); - - ximagesink = meta->ximagesink; - if (G_UNLIKELY (ximagesink == NULL)) - goto no_sink; - - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - GST_OBJECT_LOCK (ximagesink); - running = ximagesink->running; - GST_OBJECT_UNLOCK (ximagesink); - - if (running == FALSE) { - /* If the sink is shutting down, need to clear the image */ - GST_DEBUG_OBJECT (ximagesink, - "destroy image %p because the sink is shutting down", ximage); - gst_ximagesink_ximage_destroy (ximagesink, ximage); - } else if ((meta->width != GST_VIDEO_SINK_WIDTH (ximagesink)) || - (meta->height != GST_VIDEO_SINK_HEIGHT (ximagesink))) { - /* If our geometry changed we can't reuse that image. */ - GST_DEBUG_OBJECT (ximagesink, - "destroy image %p as its size changed %dx%d vs current %dx%d", - ximage, meta->width, meta->height, - GST_VIDEO_SINK_WIDTH (ximagesink), GST_VIDEO_SINK_HEIGHT (ximagesink)); - gst_ximagesink_ximage_destroy (ximagesink, ximage); - } else { - /* In that case we can reuse the image and add it to our image pool. */ - GST_LOG_OBJECT (ximagesink, "recycling image %p in pool", ximage); - /* need to increment the refcount again to recycle */ - gst_buffer_ref (ximage); - g_mutex_lock (ximagesink->pool_lock); - ximagesink->buffer_pool = g_slist_prepend (ximagesink->buffer_pool, ximage); - g_mutex_unlock (ximagesink->pool_lock); - recycled = TRUE; - } - return; - -no_sink: - { - GST_WARNING ("no sink found"); - return; - } -} - -static void -gst_ximage_buffer_free (GstBuffer * ximage) -{ - GstMetaXImage *meta = GST_META_XIMAGE_GET (ximage); - g_return_if_fail (meta != NULL); - - /* make sure it is not recycled */ - meta->width = -1; - meta->height = -1; - gst_buffer_unref (ximage); -} - /* X11 stuff */ -static gboolean error_caught = FALSE; - -static int -gst_ximagesink_handle_xerror (Display * display, XErrorEvent * xevent) -{ - char error_msg[1024]; - - XGetErrorText (display, xevent->error_code, error_msg, 1024); - GST_DEBUG ("ximagesink triggered an XError. error: %s", error_msg); - error_caught = TRUE; - return 0; -} - -#ifdef HAVE_XSHM /* Check that XShm calls actually work */ - -static gboolean -gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink, - GstXContext * xcontext) -{ - XImage *ximage; - XShmSegmentInfo SHMInfo; - size_t size; - int (*handler) (Display *, XErrorEvent *); - gboolean result = FALSE; - gboolean did_attach = FALSE; - - g_return_val_if_fail (xcontext != NULL, FALSE); - - /* Sync to ensure any older errors are already processed */ - XSync (xcontext->disp, FALSE); - - /* Set defaults so we don't free these later unnecessarily */ - SHMInfo.shmaddr = ((void *) -1); - SHMInfo.shmid = -1; - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_ximagesink_handle_xerror); - - /* Trying to create a 1x1 ximage */ - GST_DEBUG ("XShmCreateImage of 1x1"); - - ximage = XShmCreateImage (xcontext->disp, xcontext->visual, - xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1); - - /* Might cause an error, sync to ensure it is noticed */ - XSync (xcontext->disp, FALSE); - if (!ximage || error_caught) { - GST_WARNING ("could not XShmCreateImage a 1x1 image"); - goto beach; - } - size = ximage->height * ximage->bytes_per_line; - - SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); - if (SHMInfo.shmid == -1) { - GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", - size); - goto beach; - } - - SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0); - if (SHMInfo.shmaddr == ((void *) -1)) { - GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); - /* Clean up shm seg */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - ximage->data = SHMInfo.shmaddr; - SHMInfo.readOnly = FALSE; - - if (XShmAttach (xcontext->disp, &SHMInfo) == 0) { - GST_WARNING ("Failed to XShmAttach"); - /* Clean up shm seg */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - /* Sync to ensure we see any errors we caused */ - XSync (xcontext->disp, FALSE); - - /* Delete the shared memory segment as soon as everyone is attached. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - - if (!error_caught) { - did_attach = TRUE; - /* store whether we succeeded in result */ - result = TRUE; - } - -beach: - /* Sync to ensure we swallow any errors we caused and reset error_caught */ - XSync (xcontext->disp, FALSE); - error_caught = FALSE; - XSetErrorHandler (handler); - - if (did_attach) { - XShmDetach (xcontext->disp, &SHMInfo); - XSync (xcontext->disp, FALSE); - } - if (SHMInfo.shmaddr != ((void *) -1)) - shmdt (SHMInfo.shmaddr); - if (ximage) - XDestroyImage (ximage); - return result; -} -#endif /* HAVE_XSHM */ - -/* This function handles GstXImageBuffer creation depending on XShm availability */ -static GstBuffer * -gst_ximagesink_ximage_new (GstXImageSink * ximagesink, GstCaps * caps) -{ - GstBuffer *buffer = NULL; - GstMetaXImage *meta = NULL; - GstStructure *structure = NULL; - gboolean succeeded = FALSE; - int (*handler) (Display *, XErrorEvent *); - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); - - - buffer = gst_buffer_new (); - GST_MINI_OBJECT_CAST (buffer)->dispose = - (GstMiniObjectDisposeFunction) gst_ximage_buffer_dispose; - meta = GST_META_XIMAGE_ADD (buffer); -#ifdef HAVE_XSHM - meta->SHMInfo.shmaddr = ((void *) -1); - meta->SHMInfo.shmid = -1; -#endif - - structure = gst_caps_get_structure (caps, 0); - - if (!gst_structure_get_int (structure, "width", &meta->width) || - !gst_structure_get_int (structure, "height", &meta->height)) { - GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps); - } - - GST_DEBUG_OBJECT (ximagesink, "creating image %p (%dx%d)", buffer, - meta->width, meta->height); - - g_mutex_lock (ximagesink->x_lock); - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_ximagesink_handle_xerror); - -#ifdef HAVE_XSHM - if (ximagesink->xcontext->use_xshm) { - meta->ximage = XShmCreateImage (ximagesink->xcontext->disp, - ximagesink->xcontext->visual, - ximagesink->xcontext->depth, - ZPixmap, NULL, &meta->SHMInfo, meta->width, meta->height); - if (!meta->ximage || error_caught) { - g_mutex_unlock (ximagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - meta->width, meta->height), - ("could not XShmCreateImage a %dx%d image", - meta->width, meta->height)); - goto beach; - } - - /* we have to use the returned bytes_per_line for our shm size */ - meta->size = meta->ximage->bytes_per_line * meta->ximage->height; - GST_LOG_OBJECT (ximagesink, - "XShm image size is %" G_GSIZE_FORMAT ", width %d, stride %d", - meta->size, meta->width, meta->ximage->bytes_per_line); - - meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size, IPC_CREAT | 0777); - if (meta->SHMInfo.shmid == -1) { - g_mutex_unlock (ximagesink->x_lock); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - meta->width, meta->height), - ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", - meta->size)); - goto beach; - } - - meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, NULL, 0); - if (meta->SHMInfo.shmaddr == ((void *) -1)) { - g_mutex_unlock (ximagesink->x_lock); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - meta->width, meta->height), - ("Failed to shmat: %s", g_strerror (errno))); - /* Clean up the shared memory segment */ - shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - meta->ximage->data = meta->SHMInfo.shmaddr; - meta->SHMInfo.readOnly = FALSE; - - if (XShmAttach (ximagesink->xcontext->disp, &meta->SHMInfo) == 0) { - /* Clean up shm seg */ - shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL); - - g_mutex_unlock (ximagesink->x_lock); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - meta->width, meta->height), ("Failed to XShmAttach")); - goto beach; - } - - XSync (ximagesink->xcontext->disp, FALSE); - - /* Now that everyone has attached, we can delete the shared memory segment. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL); - - } else -#endif /* HAVE_XSHM */ - { - guint allocsize; - - meta->ximage = XCreateImage (ximagesink->xcontext->disp, - ximagesink->xcontext->visual, - ximagesink->xcontext->depth, - ZPixmap, 0, NULL, - meta->width, meta->height, ximagesink->xcontext->bpp, 0); - if (!meta->ximage || error_caught) { - g_mutex_unlock (ximagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - meta->width, meta->height), - ("could not XCreateImage a %dx%d image", meta->width, meta->height)); - goto beach; - } - - /* upstream will assume that rowstrides are multiples of 4, but this - * doesn't always seem to be the case with XCreateImage() */ - if ((meta->ximage->bytes_per_line % 4) != 0) { - GST_WARNING_OBJECT (ximagesink, "returned stride not a multiple of 4 as " - "usually assumed"); - } - - /* we have to use the returned bytes_per_line for our image size */ - meta->size = meta->ximage->bytes_per_line * meta->ximage->height; - - /* alloc a bit more for unexpected strides to avoid crashes upstream. - * FIXME: if we get an unrounded stride, the image will be displayed - * distorted, since all upstream elements assume a rounded stride */ - allocsize = - GST_ROUND_UP_4 (meta->ximage->bytes_per_line) * meta->ximage->height; - meta->ximage->data = g_malloc (allocsize); - GST_LOG_OBJECT (ximagesink, - "non-XShm image size is %" G_GSIZE_FORMAT " (alloced: %u), width %d, " - "stride %d", meta->size, allocsize, meta->width, - meta->ximage->bytes_per_line); - - XSync (ximagesink->xcontext->disp, FALSE); - } - - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - - succeeded = TRUE; - - /* Keep a ref to our sink */ - meta->ximagesink = gst_object_ref (ximagesink); - - GST_BUFFER_DATA (buffer) = (guchar *) meta->ximage->data; - GST_BUFFER_SIZE (buffer) = meta->size; - - g_mutex_unlock (ximagesink->x_lock); - -beach: - if (!succeeded) { - gst_ximage_buffer_free (buffer); - buffer = NULL; - } - - return buffer; -} - -/* This function destroys a GstBuffer with GstXImageData handling XShm availability */ -static void -gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink, GstBuffer * ximage) -{ - GstMetaXImage *meta; - - g_return_if_fail (ximage != NULL); - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - meta = GST_META_XIMAGE_GET (ximage); - g_return_if_fail (meta != NULL); - - /* Hold the object lock to ensure the XContext doesn't disappear */ - GST_OBJECT_LOCK (ximagesink); - - /* If the destroyed image is the current one we destroy our reference too */ - if (ximagesink->cur_image == ximage) { - ximagesink->cur_image = NULL; - } - - /* We might have some buffers destroyed after changing state to NULL */ - if (!ximagesink->xcontext) { - GST_DEBUG_OBJECT (ximagesink, "Destroying XImage after XContext"); -#ifdef HAVE_XSHM - if (meta->SHMInfo.shmaddr != ((void *) -1)) { - shmdt (meta->SHMInfo.shmaddr); - } -#endif - goto beach; - } - - g_mutex_lock (ximagesink->x_lock); - -#ifdef HAVE_XSHM - if (ximagesink->xcontext->use_xshm) { - if (meta->SHMInfo.shmaddr != ((void *) -1)) { - XShmDetach (ximagesink->xcontext->disp, &meta->SHMInfo); - XSync (ximagesink->xcontext->disp, 0); - shmdt (meta->SHMInfo.shmaddr); - } - if (meta->ximage) - XDestroyImage (meta->ximage); - - } else -#endif /* HAVE_XSHM */ - { - if (meta->ximage) { - XDestroyImage (meta->ximage); - } - } - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - -beach: - GST_OBJECT_UNLOCK (ximagesink); - - if (meta->ximagesink) { - /* Release the ref to our sink */ - meta->ximagesink = NULL; - gst_object_unref (ximagesink); - } - - return; -} - /* We are called with the x_lock taken */ static void gst_ximagesink_xwindow_draw_borders (GstXImageSink * ximagesink, @@ -1384,22 +944,6 @@ gst_ximagesink_xcontext_clear (GstXImageSink * ximagesink) g_free (xcontext); } -static void -gst_ximagesink_bufferpool_clear (GstXImageSink * ximagesink) -{ - g_mutex_lock (ximagesink->pool_lock); - - while (ximagesink->buffer_pool) { - GstBuffer *ximage = ximagesink->buffer_pool->data; - - ximagesink->buffer_pool = g_slist_delete_link (ximagesink->buffer_pool, - ximagesink->buffer_pool); - gst_ximage_buffer_free (ximage); - } - - g_mutex_unlock (ximagesink->pool_lock); -} - /* Element stuff */ static GstCaps * @@ -1440,6 +984,7 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) GstXImageSink *ximagesink; gboolean ret = TRUE; GstStructure *structure; + GstBufferPool *newpool, *oldpool; const GValue *par; gint new_width, new_height; const GValue *fps; @@ -1497,11 +1042,8 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) /* Creating our window and our image */ if (GST_VIDEO_SINK_WIDTH (ximagesink) <= 0 || - GST_VIDEO_SINK_HEIGHT (ximagesink) <= 0) { - GST_ELEMENT_ERROR (ximagesink, CORE, NEGOTIATION, (NULL), - ("Invalid image size.")); - return FALSE; - } + GST_VIDEO_SINK_HEIGHT (ximagesink) <= 0) + goto invalid_size; g_mutex_lock (ximagesink->flow_lock); if (!ximagesink->xwindow) { @@ -1512,20 +1054,26 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) ximagesink->draw_border = TRUE; g_mutex_unlock (ximagesink->flow_lock); - /* If our ximage has changed we destroy it, next chain iteration will create - a new one */ - if ((ximagesink->ximage)) { - GstMetaXImage *meta = GST_META_XIMAGE_GET (ximagesink->ximage); + /* create a new pool for the new configuration */ + newpool = gst_ximage_buffer_pool_new (ximagesink); - if (((GST_VIDEO_SINK_WIDTH (ximagesink) != meta->width) || - (GST_VIDEO_SINK_HEIGHT (ximagesink) != meta->height))) { - GST_DEBUG_OBJECT (ximagesink, "our image is not usable anymore, unref %p", - ximagesink->ximage); - gst_buffer_unref (ximagesink->ximage); - ximagesink->ximage = NULL; - } + structure = gst_buffer_pool_get_config (newpool); + gst_buffer_pool_config_set (structure, caps, 0, 0, 0, 0, 0, 16); + if (!gst_buffer_pool_set_config (newpool, structure)) + goto config_failed; + + if (!gst_buffer_pool_set_active (newpool, TRUE)) + goto activate_failed; + + oldpool = ximagesink->pool; + ximagesink->pool = newpool; + + /* unref the old sink */ + if (oldpool) { + /* deactivate */ + gst_buffer_pool_set_active (oldpool, FALSE); + gst_object_unref (oldpool); } - return TRUE; /* ERRORS */ @@ -1539,6 +1087,22 @@ wrong_aspect: GST_INFO_OBJECT (ximagesink, "pixel aspect ratio does not match"); return FALSE; } +invalid_size: + { + GST_ELEMENT_ERROR (ximagesink, CORE, NEGOTIATION, (NULL), + ("Invalid image size.")); + return FALSE; + } +config_failed: + { + GST_ERROR_OBJECT (ximagesink, "failed to set config."); + return FALSE; + } +activate_failed: + { + GST_ERROR_OBJECT (ximagesink, "failed to activate bufferpool."); + return FALSE; + } } static GstStateChangeReturn @@ -1633,6 +1197,7 @@ gst_ximagesink_get_times (GstBaseSink * bsink, GstBuffer * buf, static GstFlowReturn gst_ximagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) { + GstFlowReturn res; GstXImageSink *ximagesink; GstMetaXImage *meta; @@ -1651,46 +1216,56 @@ gst_ximagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) /* If this buffer has been allocated using our buffer management we simply put the ximage which is in the PRIVATE pointer */ GST_LOG_OBJECT (ximagesink, "buffer from our pool, writing directly"); - if (!gst_ximagesink_ximage_put (ximagesink, buf)) - goto no_window; + res = GST_FLOW_OK; } else { + GstBuffer *temp; + /* Else we have to copy the data into our private image, */ /* if we have one... */ - GST_LOG_OBJECT (ximagesink, "normal buffer, copying from it"); - if (!ximagesink->ximage) { - GST_DEBUG_OBJECT (ximagesink, "creating our ximage"); - ximagesink->ximage = gst_ximagesink_ximage_new (ximagesink, - GST_BUFFER_CAPS (buf)); - if (!ximagesink->ximage) - /* The create method should have posted an informative error */ - goto no_ximage; + GST_LOG_OBJECT (ximagesink, "buffer not from our pool, copying"); - if (GST_BUFFER_SIZE (ximagesink->ximage) < GST_BUFFER_SIZE (buf)) { - meta = GST_META_XIMAGE_GET (ximagesink->ximage); + /* we should have a pool, configured in setcaps */ + if (ximagesink->pool == NULL) + goto no_pool; - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - meta->width, meta->height), - ("XServer allocated buffer size did not match input buffer")); + /* take a buffer form our pool */ + res = gst_buffer_pool_acquire_buffer (ximagesink->pool, &temp, NULL); + if (res != GST_FLOW_OK) + goto no_buffer; - gst_ximagesink_ximage_destroy (ximagesink, ximagesink->ximage); - ximagesink->ximage = NULL; - goto no_ximage; - } - } - memcpy (GST_BUFFER_DATA (ximagesink->ximage), GST_BUFFER_DATA (buf), - MIN (GST_BUFFER_SIZE (buf), GST_BUFFER_SIZE (ximagesink->ximage))); - if (!gst_ximagesink_ximage_put (ximagesink, ximagesink->ximage)) - goto no_window; + if (GST_BUFFER_SIZE (temp) < GST_BUFFER_SIZE (buf)) + goto wrong_size; + + memcpy (GST_BUFFER_DATA (temp), GST_BUFFER_DATA (buf), + MIN (GST_BUFFER_SIZE (temp), GST_BUFFER_SIZE (buf))); + + buf = temp; } - return GST_FLOW_OK; + if (!gst_ximagesink_ximage_put (ximagesink, buf)) + goto no_window; + + return res; /* ERRORS */ -no_ximage: +no_pool: + { + GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, + ("Internal error: can't allocate images"), + ("We don't have a bufferpool negotiated")); + return GST_FLOW_ERROR; + } +no_buffer: { /* No image available. That's very bad ! */ GST_WARNING_OBJECT (ximagesink, "could not create image"); + return res; + } +wrong_size: + { + GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, + ("Failed to create output image buffer"), + ("XServer allocated buffer size did not match input buffer")); return GST_FLOW_ERROR; } no_window: @@ -1701,7 +1276,6 @@ no_window: } } - static gboolean gst_ximagesink_event (GstBaseSink * sink, GstEvent * event) { @@ -1748,7 +1322,6 @@ gst_ximagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf) { GstXImageSink *ximagesink; - GstMetaXImage *meta = NULL; GstBuffer *ximage = NULL; GstStructure *structure = NULL; GstFlowReturn ret = GST_FLOW_OK; @@ -1877,34 +1450,21 @@ gst_ximagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, } alloc: - /* Inspect our buffer pool */ - g_mutex_lock (ximagesink->pool_lock); - while (ximagesink->buffer_pool) { - ximage = ximagesink->buffer_pool->data; - if (ximage) { - meta = GST_META_XIMAGE_GET (ximage); - - /* Removing from the pool */ - ximagesink->buffer_pool = g_slist_delete_link (ximagesink->buffer_pool, - ximagesink->buffer_pool); - - /* If the ximage is invalid for our need, destroy */ - if ((meta->width != width) || (meta->height != height)) { - gst_ximage_buffer_free (ximage); - ximage = NULL; - } else { - /* We found a suitable ximage */ - break; - } + if (gst_caps_is_equal (GST_PAD_CAPS (bsink->sinkpad), alloc_caps)) { + /* we negotiated this format before, use the pool */ + if (ximagesink->pool) { + GST_LOG_OBJECT (ximagesink, "retrieving buffer from pool"); + ret = gst_buffer_pool_acquire_buffer (ximagesink->pool, &ximage, NULL); } } - g_mutex_unlock (ximagesink->pool_lock); - /* We haven't found anything, creating a new one */ - if (!ximage) { - ximage = gst_ximagesink_ximage_new (ximagesink, alloc_caps); + if (ximage == NULL) { + /* Something new make a new image a new one */ + GST_LOG_OBJECT (ximagesink, "allocating new image"); + ximage = gst_ximage_buffer_new (ximagesink, width, height); } + /* Now we should have a ximage, set appropriate caps on it */ if (ximage) { /* Make sure the buffer is cleared of any previously used flags */ @@ -2247,16 +1807,13 @@ gst_ximagesink_reset (GstXImageSink * ximagesink) if (thread) g_thread_join (thread); - if (ximagesink->ximage) { - gst_buffer_unref (GST_BUFFER_CAST (ximagesink->ximage)); - ximagesink->ximage = NULL; - } if (ximagesink->cur_image) { gst_buffer_unref (GST_BUFFER_CAST (ximagesink->cur_image)); ximagesink->cur_image = NULL; } - +#if 0 gst_ximagesink_bufferpool_clear (ximagesink); +#endif g_mutex_lock (ximagesink->flow_lock); if (ximagesink->xwindow) { @@ -2294,10 +1851,6 @@ gst_ximagesink_finalize (GObject * object) g_mutex_free (ximagesink->flow_lock); ximagesink->flow_lock = NULL; } - if (ximagesink->pool_lock) { - g_mutex_free (ximagesink->pool_lock); - ximagesink->pool_lock = NULL; - } g_free (ximagesink->media_title); @@ -2310,7 +1863,6 @@ gst_ximagesink_init (GstXImageSink * ximagesink) ximagesink->display_name = NULL; ximagesink->xcontext = NULL; ximagesink->xwindow = NULL; - ximagesink->ximage = NULL; ximagesink->cur_image = NULL; ximagesink->event_thread = NULL; @@ -2324,8 +1876,7 @@ gst_ximagesink_init (GstXImageSink * ximagesink) ximagesink->par = NULL; - ximagesink->pool_lock = g_mutex_new (); - ximagesink->buffer_pool = NULL; + ximagesink->pool = NULL; ximagesink->synchronous = FALSE; ximagesink->keep_aspect = FALSE; @@ -2473,6 +2024,11 @@ gst_ximagesink_get_type (void) &navigation_info); g_type_add_interface_static (ximagesink_type, GST_TYPE_X_OVERLAY, &overlay_info); + + /* register type and create class in a more safe place instead of at + * runtime since the type registration and class creation is not + * threadsafe. */ + g_type_class_ref (gst_ximage_buffer_pool_get_type ()); } return ximagesink_type; diff --git a/sys/ximage/ximagesink.h b/sys/ximage/ximagesink.h index 314d1a9a3b..b4ccfb41a8 100644 --- a/sys/ximage/ximagesink.h +++ b/sys/ximage/ximagesink.h @@ -49,14 +49,15 @@ G_BEGIN_DECLS (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XIMAGESINK)) #define GST_IS_XIMAGESINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XIMAGESINK)) + typedef struct _GstXContext GstXContext; typedef struct _GstXWindow GstXWindow; -typedef struct _GstMetaXImage GstMetaXImage; - typedef struct _GstXImageSink GstXImageSink; typedef struct _GstXImageSinkClass GstXImageSinkClass; +#include "ximagepool.h" + /* * GstXContext: * @disp: the X11 Display of this context @@ -129,42 +130,6 @@ struct _GstXWindow }; -/** - * GstMetaXImage: - * @ximagesink: a reference to our #GstXImageSink - * @ximage: the XImage of this buffer - * @width: the width in pixels of XImage @ximage - * @height: the height in pixels of XImage @ximage - * @size: the size in bytes of XImage @ximage - * - * Structure with additional information about an XImage. - */ -struct _GstMetaXImage -{ - GstMeta meta; - - /* Reference to the ximagesink we belong to */ - GstXImageSink *ximagesink; - - XImage *ximage; - -#ifdef HAVE_XSHM - XShmSegmentInfo SHMInfo; -#endif /* HAVE_XSHM */ - - gint width, height; - size_t size; -}; - -const GstMetaInfo * gst_meta_ximage_get_info (void); -#define GST_META_INFO_XIMAGE (gst_meta_ximage_get_info()) - -#define GST_META_GET(b,t,i) ((t *)gst_buffer_get_meta((b),(i))) -#define GST_META_ADD(b,t,i,p) ((t *)gst_buffer_add_meta((b),(i),(p))) - -#define GST_META_XIMAGE_GET(b) GST_META_GET(b,GstMetaXImage,GST_META_INFO_XIMAGE) -#define GST_META_XIMAGE_ADD(b) GST_META_ADD(b,GstMetaXImage,GST_META_INFO_XIMAGE,NULL) - /** * GstXImageSink: * @display_name: the name of the Display we want to render to @@ -203,7 +168,6 @@ struct _GstXImageSink GstXContext *xcontext; GstXWindow *xwindow; - GstBuffer *ximage; GstBuffer *cur_image; GThread *event_thread; @@ -219,8 +183,8 @@ struct _GstXImageSink /* object-set pixel aspect ratio */ GValue *par; - GMutex *pool_lock; - GSList *buffer_pool; + /* the buffer pool */ + GstBufferPool *pool; gboolean synchronous; gboolean keep_aspect;