mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-25 16:48:11 +00:00
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.
This commit is contained in:
parent
6aa22111a1
commit
ea05fe1278
6 changed files with 748 additions and 580 deletions
|
@ -1,6 +1,6 @@
|
||||||
plugin_LTLIBRARIES = libgstximagesink.la
|
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_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS)
|
||||||
libgstximagesink_la_LIBADD = \
|
libgstximagesink_la_LIBADD = \
|
||||||
$(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \
|
$(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_DEPENDENCIES = $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la
|
||||||
libgstximagesink_la_LIBTOOLFLAGS = --tag=disable-static
|
libgstximagesink_la_LIBTOOLFLAGS = --tag=disable-static
|
||||||
|
|
||||||
noinst_HEADERS = ximagesink.h
|
noinst_HEADERS = ximagesink.h ximagepool.h
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "ximagesink.h"
|
#include "ximagesink.h"
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY (gst_debug_ximagepool);
|
||||||
GST_DEBUG_CATEGORY (gst_debug_ximagesink);
|
GST_DEBUG_CATEGORY (gst_debug_ximagesink);
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -36,6 +37,8 @@ plugin_init (GstPlugin * plugin)
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_debug_ximagesink, "ximagesink", 0,
|
GST_DEBUG_CATEGORY_INIT (gst_debug_ximagesink, "ximagesink", 0,
|
||||||
"ximagesink element");
|
"ximagesink element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_debug_ximagepool, "ximagepool", 0,
|
||||||
|
"ximagepool object");
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
529
sys/ximage/ximagepool.c
Normal file
529
sys/ximage/ximagepool.c
Normal file
|
@ -0,0 +1,529 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) <2005> Julien Moutte <julien@moutte.net>
|
||||||
|
*
|
||||||
|
* 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/gstinfo.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
116
sys/ximage/ximagepool.h
Normal file
116
sys/ximage/ximagepool.h
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) <2005> Julien Moutte <julien@moutte.net>
|
||||||
|
*
|
||||||
|
* 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 <sys/types.h>
|
||||||
|
#include <sys/ipc.h>
|
||||||
|
#include <sys/shm.h>
|
||||||
|
#endif /* HAVE_XSHM */
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_XSHM
|
||||||
|
#include <X11/extensions/XShm.h>
|
||||||
|
#endif /* HAVE_XSHM */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
|
||||||
|
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__ */
|
|
@ -129,8 +129,6 @@ MotifWmHints, MwmHints;
|
||||||
#define MWM_HINTS_DECORATIONS (1L << 1)
|
#define MWM_HINTS_DECORATIONS (1L << 1)
|
||||||
|
|
||||||
static void gst_ximagesink_reset (GstXImageSink * ximagesink);
|
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_xwindow_update_geometry (GstXImageSink * ximagesink);
|
||||||
static void gst_ximagesink_expose (GstXOverlay * overlay);
|
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 */
|
/* 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 */
|
/* We are called with the x_lock taken */
|
||||||
static void
|
static void
|
||||||
gst_ximagesink_xwindow_draw_borders (GstXImageSink * ximagesink,
|
gst_ximagesink_xwindow_draw_borders (GstXImageSink * ximagesink,
|
||||||
|
@ -1384,22 +944,6 @@ gst_ximagesink_xcontext_clear (GstXImageSink * ximagesink)
|
||||||
g_free (xcontext);
|
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 */
|
/* Element stuff */
|
||||||
|
|
||||||
static GstCaps *
|
static GstCaps *
|
||||||
|
@ -1440,6 +984,7 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
GstXImageSink *ximagesink;
|
GstXImageSink *ximagesink;
|
||||||
gboolean ret = TRUE;
|
gboolean ret = TRUE;
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
|
GstBufferPool *newpool, *oldpool;
|
||||||
const GValue *par;
|
const GValue *par;
|
||||||
gint new_width, new_height;
|
gint new_width, new_height;
|
||||||
const GValue *fps;
|
const GValue *fps;
|
||||||
|
@ -1497,11 +1042,8 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
|
|
||||||
/* Creating our window and our image */
|
/* Creating our window and our image */
|
||||||
if (GST_VIDEO_SINK_WIDTH (ximagesink) <= 0 ||
|
if (GST_VIDEO_SINK_WIDTH (ximagesink) <= 0 ||
|
||||||
GST_VIDEO_SINK_HEIGHT (ximagesink) <= 0) {
|
GST_VIDEO_SINK_HEIGHT (ximagesink) <= 0)
|
||||||
GST_ELEMENT_ERROR (ximagesink, CORE, NEGOTIATION, (NULL),
|
goto invalid_size;
|
||||||
("Invalid image size."));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_mutex_lock (ximagesink->flow_lock);
|
g_mutex_lock (ximagesink->flow_lock);
|
||||||
if (!ximagesink->xwindow) {
|
if (!ximagesink->xwindow) {
|
||||||
|
@ -1512,20 +1054,26 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
ximagesink->draw_border = TRUE;
|
ximagesink->draw_border = TRUE;
|
||||||
g_mutex_unlock (ximagesink->flow_lock);
|
g_mutex_unlock (ximagesink->flow_lock);
|
||||||
|
|
||||||
/* If our ximage has changed we destroy it, next chain iteration will create
|
/* create a new pool for the new configuration */
|
||||||
a new one */
|
newpool = gst_ximage_buffer_pool_new (ximagesink);
|
||||||
if ((ximagesink->ximage)) {
|
|
||||||
GstMetaXImage *meta = GST_META_XIMAGE_GET (ximagesink->ximage);
|
|
||||||
|
|
||||||
if (((GST_VIDEO_SINK_WIDTH (ximagesink) != meta->width) ||
|
structure = gst_buffer_pool_get_config (newpool);
|
||||||
(GST_VIDEO_SINK_HEIGHT (ximagesink) != meta->height))) {
|
gst_buffer_pool_config_set (structure, caps, 0, 0, 0, 0, 0, 16);
|
||||||
GST_DEBUG_OBJECT (ximagesink, "our image is not usable anymore, unref %p",
|
if (!gst_buffer_pool_set_config (newpool, structure))
|
||||||
ximagesink->ximage);
|
goto config_failed;
|
||||||
gst_buffer_unref (ximagesink->ximage);
|
|
||||||
ximagesink->ximage = NULL;
|
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;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -1539,6 +1087,22 @@ wrong_aspect:
|
||||||
GST_INFO_OBJECT (ximagesink, "pixel aspect ratio does not match");
|
GST_INFO_OBJECT (ximagesink, "pixel aspect ratio does not match");
|
||||||
return FALSE;
|
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
|
static GstStateChangeReturn
|
||||||
|
@ -1633,6 +1197,7 @@ gst_ximagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_ximagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
gst_ximagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
GstFlowReturn res;
|
||||||
GstXImageSink *ximagesink;
|
GstXImageSink *ximagesink;
|
||||||
GstMetaXImage *meta;
|
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
|
/* If this buffer has been allocated using our buffer management we simply
|
||||||
put the ximage which is in the PRIVATE pointer */
|
put the ximage which is in the PRIVATE pointer */
|
||||||
GST_LOG_OBJECT (ximagesink, "buffer from our pool, writing directly");
|
GST_LOG_OBJECT (ximagesink, "buffer from our pool, writing directly");
|
||||||
if (!gst_ximagesink_ximage_put (ximagesink, buf))
|
res = GST_FLOW_OK;
|
||||||
goto no_window;
|
|
||||||
} else {
|
} else {
|
||||||
|
GstBuffer *temp;
|
||||||
|
|
||||||
/* Else we have to copy the data into our private image, */
|
/* Else we have to copy the data into our private image, */
|
||||||
/* if we have one... */
|
/* if we have one... */
|
||||||
GST_LOG_OBJECT (ximagesink, "normal buffer, copying from it");
|
GST_LOG_OBJECT (ximagesink, "buffer not from our pool, copying");
|
||||||
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;
|
|
||||||
|
|
||||||
if (GST_BUFFER_SIZE (ximagesink->ximage) < GST_BUFFER_SIZE (buf)) {
|
/* we should have a pool, configured in setcaps */
|
||||||
meta = GST_META_XIMAGE_GET (ximagesink->ximage);
|
if (ximagesink->pool == NULL)
|
||||||
|
goto no_pool;
|
||||||
|
|
||||||
GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
|
/* take a buffer form our pool */
|
||||||
("Failed to create output image buffer of %dx%d pixels",
|
res = gst_buffer_pool_acquire_buffer (ximagesink->pool, &temp, NULL);
|
||||||
meta->width, meta->height),
|
if (res != GST_FLOW_OK)
|
||||||
("XServer allocated buffer size did not match input buffer"));
|
goto no_buffer;
|
||||||
|
|
||||||
gst_ximagesink_ximage_destroy (ximagesink, ximagesink->ximage);
|
if (GST_BUFFER_SIZE (temp) < GST_BUFFER_SIZE (buf))
|
||||||
ximagesink->ximage = NULL;
|
goto wrong_size;
|
||||||
goto no_ximage;
|
|
||||||
}
|
memcpy (GST_BUFFER_DATA (temp), GST_BUFFER_DATA (buf),
|
||||||
}
|
MIN (GST_BUFFER_SIZE (temp), GST_BUFFER_SIZE (buf)));
|
||||||
memcpy (GST_BUFFER_DATA (ximagesink->ximage), GST_BUFFER_DATA (buf),
|
|
||||||
MIN (GST_BUFFER_SIZE (buf), GST_BUFFER_SIZE (ximagesink->ximage)));
|
buf = temp;
|
||||||
if (!gst_ximagesink_ximage_put (ximagesink, ximagesink->ximage))
|
|
||||||
goto no_window;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
if (!gst_ximagesink_ximage_put (ximagesink, buf))
|
||||||
|
goto no_window;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
/* ERRORS */
|
/* 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 ! */
|
/* No image available. That's very bad ! */
|
||||||
GST_WARNING_OBJECT (ximagesink, "could not create image");
|
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;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
no_window:
|
no_window:
|
||||||
|
@ -1701,7 +1276,6 @@ no_window:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_ximagesink_event (GstBaseSink * sink, GstEvent * event)
|
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)
|
GstCaps * caps, GstBuffer ** buf)
|
||||||
{
|
{
|
||||||
GstXImageSink *ximagesink;
|
GstXImageSink *ximagesink;
|
||||||
GstMetaXImage *meta = NULL;
|
|
||||||
GstBuffer *ximage = NULL;
|
GstBuffer *ximage = NULL;
|
||||||
GstStructure *structure = NULL;
|
GstStructure *structure = NULL;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
@ -1877,34 +1450,21 @@ gst_ximagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc:
|
alloc:
|
||||||
/* Inspect our buffer pool */
|
|
||||||
g_mutex_lock (ximagesink->pool_lock);
|
|
||||||
while (ximagesink->buffer_pool) {
|
|
||||||
ximage = ximagesink->buffer_pool->data;
|
|
||||||
|
|
||||||
if (ximage) {
|
if (gst_caps_is_equal (GST_PAD_CAPS (bsink->sinkpad), alloc_caps)) {
|
||||||
meta = GST_META_XIMAGE_GET (ximage);
|
/* we negotiated this format before, use the pool */
|
||||||
|
if (ximagesink->pool) {
|
||||||
/* Removing from the pool */
|
GST_LOG_OBJECT (ximagesink, "retrieving buffer from pool");
|
||||||
ximagesink->buffer_pool = g_slist_delete_link (ximagesink->buffer_pool,
|
ret = gst_buffer_pool_acquire_buffer (ximagesink->pool, &ximage, NULL);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_mutex_unlock (ximagesink->pool_lock);
|
|
||||||
|
|
||||||
/* We haven't found anything, creating a new one */
|
if (ximage == NULL) {
|
||||||
if (!ximage) {
|
/* Something new make a new image a new one */
|
||||||
ximage = gst_ximagesink_ximage_new (ximagesink, alloc_caps);
|
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 */
|
/* Now we should have a ximage, set appropriate caps on it */
|
||||||
if (ximage) {
|
if (ximage) {
|
||||||
/* Make sure the buffer is cleared of any previously used flags */
|
/* Make sure the buffer is cleared of any previously used flags */
|
||||||
|
@ -2247,16 +1807,13 @@ gst_ximagesink_reset (GstXImageSink * ximagesink)
|
||||||
if (thread)
|
if (thread)
|
||||||
g_thread_join (thread);
|
g_thread_join (thread);
|
||||||
|
|
||||||
if (ximagesink->ximage) {
|
|
||||||
gst_buffer_unref (GST_BUFFER_CAST (ximagesink->ximage));
|
|
||||||
ximagesink->ximage = NULL;
|
|
||||||
}
|
|
||||||
if (ximagesink->cur_image) {
|
if (ximagesink->cur_image) {
|
||||||
gst_buffer_unref (GST_BUFFER_CAST (ximagesink->cur_image));
|
gst_buffer_unref (GST_BUFFER_CAST (ximagesink->cur_image));
|
||||||
ximagesink->cur_image = NULL;
|
ximagesink->cur_image = NULL;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
gst_ximagesink_bufferpool_clear (ximagesink);
|
gst_ximagesink_bufferpool_clear (ximagesink);
|
||||||
|
#endif
|
||||||
|
|
||||||
g_mutex_lock (ximagesink->flow_lock);
|
g_mutex_lock (ximagesink->flow_lock);
|
||||||
if (ximagesink->xwindow) {
|
if (ximagesink->xwindow) {
|
||||||
|
@ -2294,10 +1851,6 @@ gst_ximagesink_finalize (GObject * object)
|
||||||
g_mutex_free (ximagesink->flow_lock);
|
g_mutex_free (ximagesink->flow_lock);
|
||||||
ximagesink->flow_lock = NULL;
|
ximagesink->flow_lock = NULL;
|
||||||
}
|
}
|
||||||
if (ximagesink->pool_lock) {
|
|
||||||
g_mutex_free (ximagesink->pool_lock);
|
|
||||||
ximagesink->pool_lock = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (ximagesink->media_title);
|
g_free (ximagesink->media_title);
|
||||||
|
|
||||||
|
@ -2310,7 +1863,6 @@ gst_ximagesink_init (GstXImageSink * ximagesink)
|
||||||
ximagesink->display_name = NULL;
|
ximagesink->display_name = NULL;
|
||||||
ximagesink->xcontext = NULL;
|
ximagesink->xcontext = NULL;
|
||||||
ximagesink->xwindow = NULL;
|
ximagesink->xwindow = NULL;
|
||||||
ximagesink->ximage = NULL;
|
|
||||||
ximagesink->cur_image = NULL;
|
ximagesink->cur_image = NULL;
|
||||||
|
|
||||||
ximagesink->event_thread = NULL;
|
ximagesink->event_thread = NULL;
|
||||||
|
@ -2324,8 +1876,7 @@ gst_ximagesink_init (GstXImageSink * ximagesink)
|
||||||
|
|
||||||
ximagesink->par = NULL;
|
ximagesink->par = NULL;
|
||||||
|
|
||||||
ximagesink->pool_lock = g_mutex_new ();
|
ximagesink->pool = NULL;
|
||||||
ximagesink->buffer_pool = NULL;
|
|
||||||
|
|
||||||
ximagesink->synchronous = FALSE;
|
ximagesink->synchronous = FALSE;
|
||||||
ximagesink->keep_aspect = FALSE;
|
ximagesink->keep_aspect = FALSE;
|
||||||
|
@ -2473,6 +2024,11 @@ gst_ximagesink_get_type (void)
|
||||||
&navigation_info);
|
&navigation_info);
|
||||||
g_type_add_interface_static (ximagesink_type, GST_TYPE_X_OVERLAY,
|
g_type_add_interface_static (ximagesink_type, GST_TYPE_X_OVERLAY,
|
||||||
&overlay_info);
|
&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;
|
return ximagesink_type;
|
||||||
|
|
|
@ -49,14 +49,15 @@ G_BEGIN_DECLS
|
||||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XIMAGESINK))
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XIMAGESINK))
|
||||||
#define GST_IS_XIMAGESINK_CLASS(klass) \
|
#define GST_IS_XIMAGESINK_CLASS(klass) \
|
||||||
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XIMAGESINK))
|
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XIMAGESINK))
|
||||||
|
|
||||||
typedef struct _GstXContext GstXContext;
|
typedef struct _GstXContext GstXContext;
|
||||||
typedef struct _GstXWindow GstXWindow;
|
typedef struct _GstXWindow GstXWindow;
|
||||||
|
|
||||||
typedef struct _GstMetaXImage GstMetaXImage;
|
|
||||||
|
|
||||||
typedef struct _GstXImageSink GstXImageSink;
|
typedef struct _GstXImageSink GstXImageSink;
|
||||||
typedef struct _GstXImageSinkClass GstXImageSinkClass;
|
typedef struct _GstXImageSinkClass GstXImageSinkClass;
|
||||||
|
|
||||||
|
#include "ximagepool.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GstXContext:
|
* GstXContext:
|
||||||
* @disp: the X11 Display of this context
|
* @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:
|
* GstXImageSink:
|
||||||
* @display_name: the name of the Display we want to render to
|
* @display_name: the name of the Display we want to render to
|
||||||
|
@ -203,7 +168,6 @@ struct _GstXImageSink
|
||||||
|
|
||||||
GstXContext *xcontext;
|
GstXContext *xcontext;
|
||||||
GstXWindow *xwindow;
|
GstXWindow *xwindow;
|
||||||
GstBuffer *ximage;
|
|
||||||
GstBuffer *cur_image;
|
GstBuffer *cur_image;
|
||||||
|
|
||||||
GThread *event_thread;
|
GThread *event_thread;
|
||||||
|
@ -219,8 +183,8 @@ struct _GstXImageSink
|
||||||
/* object-set pixel aspect ratio */
|
/* object-set pixel aspect ratio */
|
||||||
GValue *par;
|
GValue *par;
|
||||||
|
|
||||||
GMutex *pool_lock;
|
/* the buffer pool */
|
||||||
GSList *buffer_pool;
|
GstBufferPool *pool;
|
||||||
|
|
||||||
gboolean synchronous;
|
gboolean synchronous;
|
||||||
gboolean keep_aspect;
|
gboolean keep_aspect;
|
||||||
|
|
Loading…
Reference in a new issue