xvimagesink: use bufferpool
authorbenjamin gaignard <benjamin.gaignard@linaro.org>
Wed, 6 Apr 2011 10:26:47 +0000 (12:26 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Wed, 6 Apr 2011 10:28:46 +0000 (12:28 +0200)
Improve bufferpool handling in ximagesink.
Implement bufferpool handling on xvimagesink.

Based on patches from benjamin gaignard <benjamin.gaignard@linaro.org>

sys/ximage/ximage.c
sys/ximage/ximagepool.c
sys/ximage/ximagepool.h
sys/ximage/ximagesink.c
sys/ximage/ximagesink.h
sys/xvimage/Makefile.am
sys/xvimage/xvimage.c [new file with mode: 0644]
sys/xvimage/xvimagepool.c [new file with mode: 0644]
sys/xvimage/xvimagepool.h [new file with mode: 0644]
sys/xvimage/xvimagesink.c
sys/xvimage/xvimagesink.h

index 6e541fd..24a9e61 100644 (file)
@@ -17,8 +17,6 @@
  * Boston, MA 02111-1307, USA.
  */
 
-
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -27,6 +25,7 @@
 
 GST_DEBUG_CATEGORY (gst_debug_ximagepool);
 GST_DEBUG_CATEGORY (gst_debug_ximagesink);
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
 
 static gboolean
 plugin_init (GstPlugin * plugin)
@@ -40,6 +39,8 @@ plugin_init (GstPlugin * plugin)
   GST_DEBUG_CATEGORY_INIT (gst_debug_ximagepool, "ximagepool", 0,
       "ximagepool object");
 
+  GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
+
   return TRUE;
 }
 
index 365324b..0041348 100644 (file)
@@ -32,7 +32,7 @@ GST_DEBUG_CATEGORY_EXTERN (gst_debug_ximagepool);
 
 static void gst_meta_ximage_free (GstMetaXImage * meta, GstBuffer * buffer);
 
-/* ximage buffers */
+/* ximage metadata */
 const GstMetaInfo *
 gst_meta_ximage_get_info (void)
 {
@@ -51,7 +51,7 @@ gst_meta_ximage_get_info (void)
 }
 
 /* X11 stuff */
-static gboolean error_caught;
+static gboolean error_caught = FALSE;
 
 static int
 gst_ximagesink_handle_xerror (Display * display, XErrorEvent * xevent)
@@ -133,6 +133,9 @@ gst_buffer_add_meta_ximage (GstBuffer * buffer, GstXImageSink * ximagesink,
      * 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);
+
+    GST_DEBUG_OBJECT (ximagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
+        meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
   } else
 #endif /* HAVE_XSHM */
   {
@@ -225,7 +228,7 @@ shmat_failed:
   }
 xattach_failed:
   {
-    /* Clean up shm seg */
+    /* Clean up the shared memory segment */
     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
     g_mutex_unlock (ximagesink->x_lock);
 
@@ -248,9 +251,11 @@ gst_meta_ximage_free (GstMetaXImage * meta, GstBuffer * 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) {
+  if (ximagesink->xcontext == NULL) {
     GST_DEBUG_OBJECT (ximagesink, "Destroying XImage after XContext");
 #ifdef HAVE_XSHM
+    /* Need to free the shared memory segment even if the x context
+     * was already cleaned up */
     if (meta->SHMInfo.shmaddr != ((void *) -1)) {
       shmdt (meta->SHMInfo.shmaddr);
     }
@@ -263,14 +268,15 @@ gst_meta_ximage_free (GstMetaXImage * meta, GstBuffer * buffer)
 #ifdef HAVE_XSHM
   if (ximagesink->xcontext->use_xshm) {
     if (meta->SHMInfo.shmaddr != ((void *) -1)) {
+      GST_DEBUG_OBJECT (ximagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
+          meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
       XShmDetach (ximagesink->xcontext->disp, &meta->SHMInfo);
-      XSync (ximagesink->xcontext->disp, 0);
+      XSync (ximagesink->xcontext->disp, FALSE);
       shmdt (meta->SHMInfo.shmaddr);
       meta->SHMInfo.shmaddr = (void *) -1;
     }
     if (meta->ximage)
       XDestroyImage (meta->ximage);
-
   } else
 #endif /* HAVE_XSHM */
   {
@@ -302,7 +308,9 @@ gst_ximage_buffer_new (GstXImageSink * ximagesink, gint width, gint height)
   return buffer;
 }
 
-#ifdef HAVE_XSHM                /* Check that XShm calls actually work */
+#ifdef HAVE_XSHM
+/* This function checks that it is actually really possible to create an image
+   using XShm */
 gboolean
 gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink,
     GstXContext * xcontext)
@@ -351,7 +359,7 @@ gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink,
   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 */
+    /* Clean up the shared memory segment */
     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
     goto beach;
   }
@@ -361,7 +369,7 @@ gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink,
 
   if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
     GST_WARNING ("Failed to XShmAttach");
-    /* Clean up shm seg */
+    /* Clean up the shared memory segment */
     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
     goto beach;
   }
@@ -369,24 +377,33 @@ gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink,
   /* Sync to ensure we see any errors we caused */
   XSync (xcontext->disp, FALSE);
 
-  /* Delete the shared memory segment as soon as everyone is attached. 
+  /* 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) {
+    GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
+        SHMInfo.shmseg);
+
     did_attach = TRUE;
     /* store whether we succeeded in result */
     result = TRUE;
+  } else {
+    GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
+        "Not using shared memory.");
   }
 
 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) {
+    GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
+        SHMInfo.shmid, SHMInfo.shmseg);
     XShmDetach (xcontext->disp, &SHMInfo);
     XSync (xcontext->disp, FALSE);
   }
index 273ed66..7f12bdc 100644 (file)
@@ -62,12 +62,13 @@ GstMetaXImage * gst_buffer_add_meta_ximage   (GstBuffer *buffer, GstXImageSink *
  * @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.
+ * Subclass of #GstMeta containing additional information about an XImage.
  */
 struct _GstMetaXImage
 {
   GstMeta meta;
 
+  /* Reference to the ximagesink we belong to */
   GstXImageSink *sink;
 
   XImage *ximage;
index 6e60fcf..54b2634 100644 (file)
@@ -208,8 +208,6 @@ gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstBuffer * ximage)
   GstVideoRectangle src, dst, result;
   gboolean draw_border = FALSE;
 
-  g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), FALSE);
-
   /* We take the flow_lock. If expose is in there we don't want to run
      concurrently from the data flow thread */
   g_mutex_lock (ximagesink->flow_lock);
@@ -229,7 +227,7 @@ gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstBuffer * ximage)
   if (ximage && ximagesink->cur_image != ximage) {
     if (ximagesink->cur_image) {
       GST_LOG_OBJECT (ximagesink, "unreffing %p", ximagesink->cur_image);
-      gst_buffer_unref (GST_BUFFER_CAST (ximagesink->cur_image));
+      gst_buffer_unref (ximagesink->cur_image);
     }
     GST_LOG_OBJECT (ximagesink, "reffing %p as our current image", ximage);
     ximagesink->cur_image = gst_buffer_ref (ximage);
@@ -247,6 +245,7 @@ gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstBuffer * ximage)
   }
 
   meta = gst_buffer_get_meta_ximage (ximage);
+
   src.w = meta->width;
   src.h = meta->height;
   dst.w = ximagesink->xwindow->width;
@@ -303,7 +302,8 @@ gst_ximagesink_xwindow_decorate (GstXImageSink * ximagesink,
 
   g_mutex_lock (ximagesink->x_lock);
 
-  hints_atom = XInternAtom (ximagesink->xcontext->disp, "_MOTIF_WM_HINTS", 1);
+  hints_atom = XInternAtom (ximagesink->xcontext->disp, "_MOTIF_WM_HINTS",
+      True);
   if (hints_atom == None) {
     g_mutex_unlock (ximagesink->x_lock);
     return FALSE;
@@ -586,7 +586,6 @@ gst_ximagesink_handle_xevents (GstXImageSink * ximagesink)
           g_mutex_unlock (ximagesink->x_lock);
           gst_navigation_send_key_event (GST_NAVIGATION (ximagesink),
               e.type == KeyPress ? "key-press" : "key-release", key_str);
-
         } else {
           gst_navigation_send_key_event (GST_NAVIGATION (ximagesink),
               e.type == KeyPress ? "key-press" : "key-release", "unknown");
@@ -600,6 +599,7 @@ gst_ximagesink_handle_xevents (GstXImageSink * ximagesink)
     g_mutex_lock (ximagesink->x_lock);
   }
 
+  /* Handle Expose */
   while (XCheckWindowEvent (ximagesink->xcontext->disp,
           ximagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
     switch (e.type) {
@@ -830,7 +830,7 @@ gst_ximagesink_xcontext_get (GstXImageSink * ximagesink)
     g_mutex_unlock (ximagesink->x_lock);
     g_free (xcontext->par);
     g_free (xcontext);
-    GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
+    GST_ELEMENT_ERROR (ximagesink, RESOURCE, SETTINGS,
         ("Could not get supported pixmap formats"), (NULL));
     return NULL;
   }
@@ -854,7 +854,7 @@ gst_ximagesink_xcontext_get (GstXImageSink * ximagesink)
     xcontext->use_xshm = TRUE;
     GST_DEBUG ("ximagesink is using XShm extension");
   } else
-#endif
+#endif /* HAVE_XSHM */
   {
     xcontext->use_xshm = FALSE;
     GST_DEBUG ("ximagesink is not using XShm extension");
@@ -982,9 +982,9 @@ static gboolean
 gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
 {
   GstXImageSink *ximagesink;
-  gboolean ret = TRUE;
   GstStructure *structure;
   GstBufferPool *newpool, *oldpool;
+  gboolean ret = TRUE;
   const GValue *par;
   gint new_width, new_height;
   const GValue *fps;
@@ -1008,6 +1008,7 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
   ret &= gst_structure_get_int (structure, "height", &new_height);
   fps = gst_structure_get_value (structure, "framerate");
   ret &= (fps != NULL);
+
   if (!ret)
     return FALSE;
 
@@ -1052,7 +1053,6 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
   }
   /* Remember to draw borders for next frame */
   ximagesink->draw_border = TRUE;
-  g_mutex_unlock (ximagesink->flow_lock);
 
   /* create a new pool for the new configuration */
   newpool = gst_ximage_buffer_pool_new (ximagesink);
@@ -1074,6 +1074,8 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
     gst_buffer_pool_set_active (oldpool, FALSE);
     gst_object_unref (oldpool);
   }
+  g_mutex_unlock (ximagesink->flow_lock);
+
   return TRUE;
 
   /* ERRORS */
@@ -1096,11 +1098,13 @@ invalid_size:
 config_failed:
   {
     GST_ERROR_OBJECT (ximagesink, "failed to set config.");
+    g_mutex_unlock (ximagesink->flow_lock);
     return FALSE;
   }
 activate_failed:
   {
     GST_ERROR_OBJECT (ximagesink, "failed to activate bufferpool.");
+    g_mutex_unlock (ximagesink->flow_lock);
     return FALSE;
   }
 }
@@ -1108,15 +1112,14 @@ activate_failed:
 static GstStateChangeReturn
 gst_ximagesink_change_state (GstElement * element, GstStateChange transition)
 {
-  GstXImageSink *ximagesink;
   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstXImageSink *ximagesink;
   GstXContext *xcontext = NULL;
 
   ximagesink = GST_XIMAGESINK (element);
 
   switch (transition) {
     case GST_STATE_CHANGE_NULL_TO_READY:
-
       /* Initializing the XContext */
       if (ximagesink->xcontext == NULL) {
         xcontext = gst_ximagesink_xcontext_get (ximagesink);
@@ -1160,6 +1163,9 @@ gst_ximagesink_change_state (GstElement * element, GstStateChange transition)
       ximagesink->fps_d = 1;
       GST_VIDEO_SINK_WIDTH (ximagesink) = 0;
       GST_VIDEO_SINK_HEIGHT (ximagesink) = 0;
+      g_mutex_lock (ximagesink->flow_lock);
+      gst_buffer_pool_set_active (ximagesink->pool, FALSE);
+      g_mutex_unlock (ximagesink->flow_lock);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
       gst_ximagesink_reset (ximagesink);
@@ -1201,15 +1207,8 @@ gst_ximagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
   GstXImageSink *ximagesink;
   GstMetaXImage *meta;
 
-  g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
-
   ximagesink = GST_XIMAGESINK (vsink);
 
-  /* This shouldn't really happen because state changes will fail
-   * if the xcontext can't be allocated */
-  if (!ximagesink->xcontext)
-    return GST_FLOW_ERROR;
-
   meta = gst_buffer_get_meta_ximage (buf);
 
   if (meta) {
@@ -1811,16 +1810,17 @@ gst_ximagesink_reset (GstXImageSink * ximagesink)
     g_thread_join (thread);
 
   if (ximagesink->cur_image) {
-    gst_buffer_unref (GST_BUFFER_CAST (ximagesink->cur_image));
+    gst_buffer_unref (ximagesink->cur_image);
     ximagesink->cur_image = NULL;
   }
 
+  g_mutex_lock (ximagesink->flow_lock);
+
   if (ximagesink->pool) {
     gst_object_unref (ximagesink->pool);
     ximagesink->pool = NULL;
   }
 
-  g_mutex_lock (ximagesink->flow_lock);
   if (ximagesink->xwindow) {
     gst_ximagesink_xwindow_clear (ximagesink, ximagesink->xwindow);
     gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow);
index b4ccfb4..b47dcde 100644 (file)
@@ -129,7 +129,6 @@ struct _GstXWindow
   GC gc;
 };
 
-
 /**
  * GstXImageSink:
  * @display_name: the name of the Display we want to render to
index fbff4d8..9669e72 100644 (file)
@@ -1,6 +1,6 @@
 plugin_LTLIBRARIES = libgstxvimagesink.la
 
-libgstxvimagesink_la_SOURCES =  xvimagesink.c 
+libgstxvimagesink_la_SOURCES =  xvimagesink.c xvimage.c xvimagepool.c 
 libgstxvimagesink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS)
 libgstxvimagesink_la_LIBADD = \
        $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \
@@ -12,4 +12,4 @@ libgstxvimagesink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 libgstxvimagesink_la_DEPENDENCIES = $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la
 libgstxvimagesink_la_LIBTOOLFLAGS = --tag=disable-static
 
-noinst_HEADERS = xvimagesink.h 
+noinst_HEADERS = xvimagesink.h xvimagepool.h
diff --git a/sys/xvimage/xvimage.c b/sys/xvimage/xvimage.c
new file mode 100644 (file)
index 0000000..5e2d619
--- /dev/null
@@ -0,0 +1,51 @@
+/* GStreamer
+ * Copyright (C) <2003> 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
+
+#include "xvimagesink.h"
+
+GST_DEBUG_CATEGORY (gst_debug_xvimagepool);
+GST_DEBUG_CATEGORY (gst_debug_xvimagesink);
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_element_register (plugin, "xvimagesink",
+          GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
+    return FALSE;
+
+  GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
+      "xvimagesink element");
+  GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagepool, "xvimagepool", 0,
+      "xvimagepool object");
+
+  GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    "xvimagesink",
+    "XFree86 video output plugin using Xv extension",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/xvimage/xvimagepool.c b/sys/xvimage/xvimagepool.c
new file mode 100644 (file)
index 0000000..0c37761
--- /dev/null
@@ -0,0 +1,642 @@
+/* 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 "xvimagesink.h"
+
+/* Debugging category */
+#include <gst/gstinfo.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvimagepool);
+#define GST_CAT_DEFAULT gst_debug_xvimagepool
+
+static void gst_meta_xvimage_free (GstMetaXvImage * meta, GstBuffer * buffer);
+
+/* xvimage metadata */
+const GstMetaInfo *
+gst_meta_xvimage_get_info (void)
+{
+  static const GstMetaInfo *meta_xvimage_info = NULL;
+
+  if (meta_xvimage_info == NULL) {
+    meta_xvimage_info = gst_meta_register ("GstMetaXvImage", "GstMetaXvImage",
+        sizeof (GstMetaXvImage),
+        (GstMetaInitFunction) NULL,
+        (GstMetaFreeFunction) gst_meta_xvimage_free,
+        (GstMetaCopyFunction) NULL,
+        (GstMetaTransformFunction) NULL,
+        (GstMetaSerializeFunction) NULL, (GstMetaDeserializeFunction) NULL);
+  }
+  return meta_xvimage_info;
+}
+
+/* X11 stuff */
+static gboolean error_caught = FALSE;
+
+static int
+gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
+{
+  char error_msg[1024];
+
+  XGetErrorText (display, xevent->error_code, error_msg, 1024);
+  GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
+  error_caught = TRUE;
+  return 0;
+}
+
+GstMetaXvImage *
+gst_buffer_add_meta_xvimage (GstBuffer * buffer, GstXvImageSink * xvimagesink,
+    gint width, gint height, gint im_format)
+{
+  int (*handler) (Display *, XErrorEvent *);
+  gboolean success = FALSE;
+  GstXContext *xcontext;
+  GstMetaXvImage *meta;
+
+  xcontext = xvimagesink->xcontext;
+
+  meta =
+      (GstMetaXvImage *) gst_buffer_add_meta (buffer, GST_META_INFO_XVIMAGE,
+      NULL);
+#ifdef HAVE_XSHM
+  meta->SHMInfo.shmaddr = ((void *) -1);
+  meta->SHMInfo.shmid = -1;
+#endif
+  meta->width = width;
+  meta->height = height;
+  meta->sink = gst_object_ref (xvimagesink);
+  meta->im_format = im_format;
+
+  GST_DEBUG_OBJECT (xvimagesink, "creating image %p (%dx%d)", buffer,
+      meta->width, meta->height);
+
+  g_mutex_lock (xvimagesink->x_lock);
+
+  /* Setting an error handler to catch failure */
+  error_caught = FALSE;
+  handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
+
+#ifdef HAVE_XSHM
+  if (xcontext->use_xshm) {
+    int expected_size;
+
+    meta->xvimage = XvShmCreateImage (xcontext->disp,
+        xcontext->xv_port_id,
+        meta->im_format, NULL, meta->width, meta->height, &meta->SHMInfo);
+    if (!meta->xvimage || error_caught)
+      goto create_failed;
+
+    /* we have to use the returned data_size for our shm size */
+    meta->size = meta->xvimage->data_size;
+    GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
+        meta->size);
+
+    /* calculate the expected size.  This is only for sanity checking the
+     * number we get from X. */
+    switch (meta->im_format) {
+      case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+      case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
+      {
+        gint pitches[3];
+        gint offsets[3];
+        guint plane;
+
+        offsets[0] = 0;
+        pitches[0] = GST_ROUND_UP_4 (meta->width);
+        offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (meta->height);
+        pitches[1] = GST_ROUND_UP_8 (meta->width) / 2;
+        offsets[2] =
+            offsets[1] + pitches[1] * GST_ROUND_UP_2 (meta->height) / 2;
+        pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
+
+        expected_size =
+            offsets[2] + pitches[2] * GST_ROUND_UP_2 (meta->height) / 2;
+
+        for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
+          GST_DEBUG_OBJECT (xvimagesink,
+              "Plane %u has a expected pitch of %d bytes, " "offset of %d",
+              plane, pitches[plane], offsets[plane]);
+        }
+        break;
+      }
+      case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
+      case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
+        expected_size = meta->height * GST_ROUND_UP_4 (meta->width * 2);
+        break;
+      default:
+        expected_size = 0;
+        break;
+    }
+    if (expected_size != 0 && meta->size != expected_size) {
+      GST_WARNING_OBJECT (xvimagesink,
+          "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
+          meta->size, expected_size);
+    }
+
+    /* Be verbose about our XvImage stride */
+    {
+      guint plane;
+
+      for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
+        GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
+            "offset of %d", plane, meta->xvimage->pitches[plane],
+            meta->xvimage->offsets[plane]);
+      }
+    }
+
+    /* 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->xvimage->data = meta->SHMInfo.shmaddr;
+    meta->SHMInfo.readOnly = FALSE;
+
+    if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
+      goto xattach_failed;
+
+    XSync (xcontext->disp, FALSE);
+
+    /* Delete the shared memory segment as soon as we everyone is attached.
+     * 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);
+
+    GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
+        meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
+  } else
+#endif /* HAVE_XSHM */
+  {
+    meta->xvimage = XvCreateImage (xcontext->disp,
+        xcontext->xv_port_id, meta->im_format, NULL, meta->width, meta->height);
+    if (!meta->xvimage || error_caught)
+      goto create_failed;
+
+    /* we have to use the returned data_size for our image size */
+    meta->size = meta->xvimage->data_size;
+    meta->xvimage->data = g_malloc (meta->size);
+
+    XSync (xcontext->disp, FALSE);
+  }
+
+  /* Reset error handler */
+  error_caught = FALSE;
+  XSetErrorHandler (handler);
+
+  gst_buffer_take_memory (buffer,
+      gst_memory_new_wrapped (0, meta->xvimage->data, NULL,
+          meta->size, 0, meta->size));
+
+  g_mutex_unlock (xvimagesink->x_lock);
+
+  success = TRUE;
+
+beach:
+  if (!success)
+    meta = NULL;
+
+  return meta;
+
+  /* ERRORS */
+create_failed:
+  {
+    g_mutex_unlock (xvimagesink->x_lock);
+    /* Reset error handler */
+    error_caught = FALSE;
+    XSetErrorHandler (handler);
+    /* Push an error */
+    GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
+        ("Failed to create output image buffer of %dx%d pixels",
+            meta->width, meta->height),
+        ("could not XvShmCreateImage a %dx%d image", meta->width,
+            meta->height));
+    goto beach;
+  }
+shmget_failed:
+  {
+    g_mutex_unlock (xvimagesink->x_lock);
+    GST_ELEMENT_ERROR (xvimagesink, 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 (xvimagesink->x_lock);
+    GST_ELEMENT_ERROR (xvimagesink, 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 the shared memory segment */
+    shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
+    g_mutex_unlock (xvimagesink->x_lock);
+
+    GST_ELEMENT_ERROR (xvimagesink, 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_xvimage_free (GstMetaXvImage * meta, GstBuffer * buffer)
+{
+  GstXvImageSink *xvimagesink;
+
+  xvimagesink = meta->sink;
+
+  GST_DEBUG_OBJECT (xvimagesink, "free meta on buffer %p", buffer);
+
+  /* Hold the object lock to ensure the XContext doesn't disappear */
+  GST_OBJECT_LOCK (xvimagesink);
+  /* We might have some buffers destroyed after changing state to NULL */
+  if (xvimagesink->xcontext == NULL) {
+    GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
+#ifdef HAVE_XSHM
+    /* Need to free the shared memory segment even if the x context
+     * was already cleaned up */
+    if (meta->SHMInfo.shmaddr != ((void *) -1)) {
+      shmdt (meta->SHMInfo.shmaddr);
+    }
+#endif
+    goto beach;
+  }
+
+  g_mutex_lock (xvimagesink->x_lock);
+
+#ifdef HAVE_XSHM
+  if (xvimagesink->xcontext->use_xshm) {
+    if (meta->SHMInfo.shmaddr != ((void *) -1)) {
+      GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
+          meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
+      XShmDetach (xvimagesink->xcontext->disp, &meta->SHMInfo);
+      XSync (xvimagesink->xcontext->disp, FALSE);
+      shmdt (meta->SHMInfo.shmaddr);
+      meta->SHMInfo.shmaddr = (void *) -1;
+    }
+    if (meta->xvimage)
+      XFree (meta->xvimage);
+  } else
+#endif /* HAVE_XSHM */
+  {
+    if (meta->xvimage) {
+      g_free (meta->xvimage->data);
+      XFree (meta->xvimage);
+    }
+  }
+
+  XSync (xvimagesink->xcontext->disp, FALSE);
+
+  g_mutex_unlock (xvimagesink->x_lock);
+
+beach:
+  GST_OBJECT_UNLOCK (xvimagesink);
+}
+
+GstBuffer *
+gst_xvimage_buffer_new (GstXvImageSink * xvimagesink, gint width, gint height,
+    gint im_format)
+{
+  GstBuffer *buffer;
+  GstMetaXvImage *meta;
+
+  buffer = gst_buffer_new ();
+  meta =
+      gst_buffer_add_meta_xvimage (buffer, xvimagesink, width, height,
+      im_format);
+  if (meta == NULL) {
+    gst_buffer_unref (buffer);
+    buffer = NULL;
+  }
+  return buffer;
+}
+
+#ifdef HAVE_XSHM
+/* This function checks that it is actually really possible to create an image
+   using XShm */
+gboolean
+gst_xvimagesink_check_xshm_calls (GstXvImageSink * xvimagesink,
+    GstXContext * xcontext)
+{
+  XvImage *xvimage;
+  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_xvimagesink_handle_xerror);
+
+  /* Trying to create a 1x1 picture */
+  GST_DEBUG ("XvShmCreateImage of 1x1");
+  xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
+      xcontext->im_format, NULL, 1, 1, &SHMInfo);
+
+  /* Might cause an error, sync to ensure it is noticed */
+  XSync (xcontext->disp, FALSE);
+  if (!xvimage || error_caught) {
+    GST_WARNING ("could not XvShmCreateImage a 1x1 image");
+    goto beach;
+  }
+  size = xvimage->data_size;
+
+  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 the shared memory segment */
+    shmctl (SHMInfo.shmid, IPC_RMID, NULL);
+    goto beach;
+  }
+
+  xvimage->data = SHMInfo.shmaddr;
+  SHMInfo.readOnly = FALSE;
+
+  if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
+    GST_WARNING ("Failed to XShmAttach");
+    /* Clean up the shared memory segment */
+    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) {
+    GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
+        SHMInfo.shmseg);
+
+    did_attach = TRUE;
+    /* store whether we succeeded in result */
+    result = TRUE;
+  } else {
+    GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
+        "Not using shared memory.");
+  }
+
+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) {
+    GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
+        SHMInfo.shmid, SHMInfo.shmseg);
+    XShmDetach (xcontext->disp, &SHMInfo);
+    XSync (xcontext->disp, FALSE);
+  }
+  if (SHMInfo.shmaddr != ((void *) -1))
+    shmdt (SHMInfo.shmaddr);
+  if (xvimage)
+    XFree (xvimage);
+  return result;
+}
+#endif /* HAVE_XSHM */
+
+/* bufferpool */
+static void gst_xvimage_buffer_pool_finalize (GObject * object);
+
+#define GST_XVIMAGE_BUFFER_POOL_GET_PRIVATE(obj)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_XVIMAGE_BUFFER_POOL, GstXvImageBufferPoolPrivate))
+
+struct _GstXvImageBufferPoolPrivate
+{
+  GstCaps *caps;
+  gint width, height;
+  gint im_format;
+};
+
+G_DEFINE_TYPE (GstXvImageBufferPool, gst_xvimage_buffer_pool,
+    GST_TYPE_BUFFER_POOL);
+
+static gboolean
+xvimage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
+{
+  GstXvImageBufferPool *xvpool = GST_XVIMAGE_BUFFER_POOL_CAST (pool);
+  GstXvImageBufferPoolPrivate *priv = xvpool->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;
+
+  GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, width, height, 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;
+  priv->im_format =
+      gst_xvimagesink_get_format_from_caps (xvpool->sink, (GstCaps *) caps);
+
+  if (priv->im_format == -1) {
+    GST_WARNING_OBJECT (xvpool->sink, "failed to get format from caps %"
+        GST_PTR_FORMAT, caps);
+    GST_ELEMENT_ERROR (xvpool->sink, RESOURCE, WRITE,
+        ("Failed to create output image buffer of %dx%d pixels",
+            priv->width, priv->height), ("Invalid input caps"));
+    goto wrong_config;
+  }
+
+  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
+xvimage_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
+    GstBufferPoolParams * params)
+{
+  GstXvImageBufferPool *xvpool = GST_XVIMAGE_BUFFER_POOL_CAST (pool);
+  GstXvImageBufferPoolPrivate *priv = xvpool->priv;
+  GstBuffer *xvimage;
+
+  xvimage =
+      gst_xvimage_buffer_new (xvpool->sink, priv->width, priv->height,
+      priv->im_format);
+  if (xvimage == NULL)
+    goto no_buffer;
+
+  *buffer = xvimage;
+
+  return GST_FLOW_OK;
+
+  /* ERROR */
+no_buffer:
+  {
+    GST_WARNING_OBJECT (pool, "can't create image");
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+xvimage_buffer_pool_free (GstBufferPool * pool, GstBuffer * buffer)
+{
+  gst_buffer_unref (buffer);
+}
+
+GstBufferPool *
+gst_xvimage_buffer_pool_new (GstXvImageSink * xvimagesink)
+{
+  GstXvImageBufferPool *pool;
+
+  g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
+
+  pool = g_object_new (GST_TYPE_XVIMAGE_BUFFER_POOL, NULL);
+  pool->sink = gst_object_ref (xvimagesink);
+
+  GST_LOG_OBJECT (pool, "new XvImage buffer pool %p", pool);
+
+  return GST_BUFFER_POOL_CAST (pool);
+}
+
+static void
+gst_xvimage_buffer_pool_class_init (GstXvImageBufferPoolClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
+
+  g_type_class_add_private (klass, sizeof (GstXvImageBufferPoolPrivate));
+
+  gobject_class->finalize = gst_xvimage_buffer_pool_finalize;
+
+  gstbufferpool_class->set_config = xvimage_buffer_pool_set_config;
+  gstbufferpool_class->alloc_buffer = xvimage_buffer_pool_alloc;
+  gstbufferpool_class->free_buffer = xvimage_buffer_pool_free;
+}
+
+static void
+gst_xvimage_buffer_pool_init (GstXvImageBufferPool * pool)
+{
+  pool->priv = GST_XVIMAGE_BUFFER_POOL_GET_PRIVATE (pool);
+}
+
+static void
+gst_xvimage_buffer_pool_finalize (GObject * object)
+{
+  GstXvImageBufferPool *pool = GST_XVIMAGE_BUFFER_POOL_CAST (object);
+  GstXvImageBufferPoolPrivate *priv = pool->priv;
+
+  GST_LOG_OBJECT (pool, "finalize XvImage buffer pool %p", pool);
+
+  if (priv->caps)
+    gst_caps_unref (priv->caps);
+  gst_object_unref (pool->sink);
+
+  G_OBJECT_CLASS (gst_xvimage_buffer_pool_parent_class)->finalize (object);
+}
+
+/* This function tries to get a format matching with a given caps in the
+   supported list of formats we generated in gst_xvimagesink_get_xv_support */
+gint
+gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
+    GstCaps * caps)
+{
+  GList *list = NULL;
+
+  g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
+
+  list = xvimagesink->xcontext->formats_list;
+
+  while (list) {
+    GstXvImageFormat *format = list->data;
+
+    if (format) {
+      if (gst_caps_can_intersect (caps, format->caps)) {
+        return format->format;
+      }
+    }
+    list = g_list_next (list);
+  }
+
+  return -1;
+}
diff --git a/sys/xvimage/xvimagepool.h b/sys/xvimage/xvimagepool.h
new file mode 100644 (file)
index 0000000..d927251
--- /dev/null
@@ -0,0 +1,120 @@
+/* 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_XVIMAGEPOOL_H__
+#define __GST_XVIMAGEPOOL_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 _GstMetaXvImage GstMetaXvImage;
+
+typedef struct _GstXvImageBufferPool GstXvImageBufferPool;
+typedef struct _GstXvImageBufferPoolClass GstXvImageBufferPoolClass;
+typedef struct _GstXvImageBufferPoolPrivate GstXvImageBufferPoolPrivate;
+
+#include "xvimagesink.h"
+
+const GstMetaInfo * gst_meta_xvimage_get_info (void);
+#define GST_META_INFO_XVIMAGE  (gst_meta_xvimage_get_info())
+
+#define gst_buffer_get_meta_xvimage(b) ((GstMetaXvImage*)gst_buffer_get_meta((b),GST_META_INFO_XVIMAGE))
+GstMetaXvImage * gst_buffer_add_meta_xvimage   (GstBuffer *buffer, GstXvImageSink * xvimagesink,
+                                                gint width, gint height, gint im_format);
+
+/**
+ * GstMetaXvImage:
+ * @sink: a reference to the our #GstXvImageSink
+ * @xvimage: the XvImage of this buffer
+ * @width: the width in pixels of XvImage @xvimage
+ * @height: the height in pixels of XvImage @xvimage
+ * @im_format: the format of XvImage @xvimage
+ * @size: the size in bytes of XvImage @xvimage
+ *
+ * Subclass of #GstMeta containing additional information about an XvImage.
+ */
+struct _GstMetaXvImage
+{
+  GstMeta meta;
+
+  /* Reference to the xvimagesink we belong to */
+  GstXvImageSink *sink;
+
+  XvImage *xvimage;
+
+#ifdef HAVE_XSHM
+  XShmSegmentInfo SHMInfo;
+#endif                          /* HAVE_XSHM */
+
+  gint width, height, im_format;
+  size_t size;
+};
+
+GstBuffer *gst_xvimage_buffer_new (GstXvImageSink *xvimagesink, gint width, gint height,
+    gint in_format);
+
+/* buffer pool functions */
+#define GST_TYPE_XVIMAGE_BUFFER_POOL      (gst_xvimage_buffer_pool_get_type())
+#define GST_IS_XVIMAGE_BUFFER_POOL(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER_POOL))
+#define GST_XVIMAGE_BUFFER_POOL(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER_POOL, GstXvImageBufferPool))
+#define GST_XVIMAGE_BUFFER_POOL_CAST(obj) ((GstXvImageBufferPool*)(obj))
+
+struct _GstXvImageBufferPool
+{
+  GstBufferPool bufferpool;
+
+  GstXvImageSink *sink;
+
+  GstXvImageBufferPoolPrivate *priv;
+};
+
+struct _GstXvImageBufferPoolClass
+{
+  GstBufferPoolClass parent_class;
+};
+
+GType gst_xvimage_buffer_pool_get_type (void);
+
+GstBufferPool *gst_xvimage_buffer_pool_new (GstXvImageSink * xvimagesink);
+
+gboolean gst_xvimagesink_check_xshm_calls (GstXvImageSink * xvimagesink,
+      GstXContext * xcontext);
+
+gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
+    GstCaps * caps);
+
+G_END_DECLS
+
+#endif /*__GST_XVIMAGEPOOL_H__*/
index de21d5c..a7d34d7 100644 (file)
 
 /* Debugging category */
 #include <gst/gstinfo.h>
-GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink);
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvimagesink);
+GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
 #define GST_CAT_DEFAULT gst_debug_xvimagesink
-GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
 
 typedef struct
 {
@@ -143,12 +144,8 @@ MotifWmHints, MwmHints;
 #define MWM_HINTS_DECORATIONS   (1L << 1)
 
 static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
-static void gst_xvimagesink_xvimage_destroy (GstXvImageSink * xvimagesink,
-    GstBuffer * xvimage);
 static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
     xvimagesink);
-static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
-    GstCaps * caps);
 static void gst_xvimagesink_expose (GstXOverlay * overlay);
 
 /* Default template - initiated with class struct to allow gst-register to work
@@ -197,501 +194,6 @@ static GstVideoSinkClass *parent_class = NULL;
 /*                                                               */
 /* ============================================================= */
 
-/* xvimage buffers */
-const GstMetaInfo *
-gst_meta_xvimage_get_info (void)
-{
-  static const GstMetaInfo *meta_xvimage_info = NULL;
-
-  if (meta_xvimage_info == NULL) {
-    meta_xvimage_info = gst_meta_register ("GstMetaXvImage", "GstMetaXvImage",
-        sizeof (GstMetaXvImage),
-        (GstMetaInitFunction) NULL,
-        (GstMetaFreeFunction) NULL,
-        (GstMetaCopyFunction) NULL,
-        (GstMetaTransformFunction) NULL,
-        (GstMetaSerializeFunction) NULL, (GstMetaDeserializeFunction) NULL);
-  }
-  return meta_xvimage_info;
-}
-
-static void
-gst_xvimage_buffer_dispose (GstBuffer * xvimage)
-{
-  GstMetaXvImage *data = NULL;
-  GstXvImageSink *xvimagesink;
-  gboolean running;
-
-  data = GST_META_XVIMAGE_GET (xvimage);
-  g_return_if_fail (data != NULL);
-
-  xvimagesink = data->xvimagesink;
-  if (G_UNLIKELY (xvimagesink == NULL))
-    goto no_sink;
-
-  g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
-
-  GST_OBJECT_LOCK (xvimagesink);
-  running = xvimagesink->running;
-  GST_OBJECT_UNLOCK (xvimagesink);
-
-  if (running == FALSE) {
-    GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down");
-    gst_xvimagesink_xvimage_destroy (xvimagesink, xvimage);
-  } else if ((data->width != xvimagesink->video_width) ||
-      (data->height != xvimagesink->video_height)) {
-    /* If our geometry changed we can't reuse that image. */
-    GST_LOG_OBJECT (xvimage,
-        "destroy image as its size changed %dx%d vs current %dx%d",
-        data->width, data->height,
-        xvimagesink->video_width, xvimagesink->video_height);
-    gst_xvimagesink_xvimage_destroy (xvimagesink, xvimage);
-  } else {
-    /* In that case we can reuse the image and add it to our image pool. */
-    GST_LOG_OBJECT (xvimage, "recycling image in pool");
-    /* need to increment the refcount again to recycle */
-    gst_buffer_ref (xvimage);
-    g_mutex_lock (xvimagesink->pool_lock);
-    xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
-        xvimage);
-    g_mutex_unlock (xvimagesink->pool_lock);
-  }
-  return;
-
-no_sink:
-  {
-    GST_WARNING ("no sink found");
-    return;
-  }
-}
-
-static void
-gst_xvimage_buffer_free (GstBuffer * xvimage)
-{
-  GstMetaXvImage *data = GST_META_XVIMAGE_GET (xvimage);
-
-  g_return_if_fail (data != NULL);
-
-  /* make sure it is not recycled */
-  data->width = -1;
-  data->height = -1;
-  gst_buffer_unref (xvimage);
-}
-
-/* X11 stuff */
-
-static gboolean error_caught = FALSE;
-
-static int
-gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
-{
-  char error_msg[1024];
-
-  XGetErrorText (display, xevent->error_code, error_msg, 1024);
-  GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
-  error_caught = TRUE;
-  return 0;
-}
-
-#ifdef HAVE_XSHM
-/* This function checks that it is actually really possible to create an image
-   using XShm */
-static gboolean
-gst_xvimagesink_check_xshm_calls (GstXContext * xcontext)
-{
-  XvImage *xvimage;
-  XShmSegmentInfo SHMInfo;
-  gint 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_xvimagesink_handle_xerror);
-
-  /* Trying to create a 1x1 picture */
-  GST_DEBUG ("XvShmCreateImage of 1x1");
-  xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
-      xcontext->im_format, NULL, 1, 1, &SHMInfo);
-
-  /* Might cause an error, sync to ensure it is noticed */
-  XSync (xcontext->disp, FALSE);
-  if (!xvimage || error_caught) {
-    GST_WARNING ("could not XvShmCreateImage a 1x1 image");
-    goto beach;
-  }
-  size = xvimage->data_size;
-
-  SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
-  if (SHMInfo.shmid == -1) {
-    GST_WARNING ("could not get shared memory of %d 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 the shared memory segment */
-    shmctl (SHMInfo.shmid, IPC_RMID, NULL);
-    goto beach;
-  }
-
-  xvimage->data = SHMInfo.shmaddr;
-  SHMInfo.readOnly = FALSE;
-
-  if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
-    GST_WARNING ("Failed to XShmAttach");
-    /* Clean up the shared memory segment */
-    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) {
-    GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
-        SHMInfo.shmseg);
-
-    did_attach = TRUE;
-    /* store whether we succeeded in result */
-    result = TRUE;
-  } else {
-    GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
-        "Not using shared memory.");
-  }
-
-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) {
-    GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
-        SHMInfo.shmid, SHMInfo.shmseg);
-    XShmDetach (xcontext->disp, &SHMInfo);
-    XSync (xcontext->disp, FALSE);
-  }
-  if (SHMInfo.shmaddr != ((void *) -1))
-    shmdt (SHMInfo.shmaddr);
-  if (xvimage)
-    XFree (xvimage);
-  return result;
-}
-#endif /* HAVE_XSHM */
-
-/* This function handles GstXvImage creation depending on XShm availability */
-static GstBuffer *
-gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
-{
-  GstBuffer *buffer = NULL;
-  GstMetaXvImage *meta = NULL;
-  GstStructure *structure = NULL;
-  gboolean succeeded = FALSE;
-  int (*handler) (Display *, XErrorEvent *);
-
-  g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
-
-  if (caps == NULL)
-    return NULL;
-
-  buffer = gst_buffer_new ();
-  GST_DEBUG_OBJECT (xvimagesink, "Creating new XvImageBuffer");
-  GST_MINI_OBJECT_CAST (buffer)->dispose =
-      (GstMiniObjectDisposeFunction) gst_xvimage_buffer_dispose;
-
-  meta = GST_META_XVIMAGE_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_LOG_OBJECT (xvimagesink, "creating %dx%d", meta->width, meta->height);
-
-  meta->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
-  if (meta->im_format == -1) {
-    GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
-        GST_PTR_FORMAT, caps);
-    GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
-        ("Failed to create output image buffer of %dx%d pixels",
-            meta->width, meta->height), ("Invalid input caps"));
-    goto beach_unlocked;
-  }
-  meta->xvimagesink = gst_object_ref (xvimagesink);
-
-  g_mutex_lock (xvimagesink->x_lock);
-
-  /* Setting an error handler to catch failure */
-  error_caught = FALSE;
-  handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
-
-#ifdef HAVE_XSHM
-  if (xvimagesink->xcontext->use_xshm) {
-    int expected_size;
-
-    meta->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
-        xvimagesink->xcontext->xv_port_id,
-        meta->im_format, NULL, meta->width, meta->height, &meta->SHMInfo);
-    if (!meta->xvimage || error_caught) {
-      g_mutex_unlock (xvimagesink->x_lock);
-      /* Reset error handler */
-      error_caught = FALSE;
-      XSetErrorHandler (handler);
-      /* Push an error */
-      GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
-          ("Failed to create output image buffer of %dx%d pixels",
-              meta->width, meta->height),
-          ("could not XvShmCreateImage a %dx%d image",
-              meta->width, meta->height));
-      goto beach_unlocked;
-    }
-
-    /* we have to use the returned data_size for our shm size */
-    meta->size = meta->xvimage->data_size;
-    GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
-        meta->size);
-
-    /* calculate the expected size.  This is only for sanity checking the
-     * number we get from X. */
-    switch (meta->im_format) {
-      case GST_MAKE_FOURCC ('I', '4', '2', '0'):
-      case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
-      {
-        gint pitches[3];
-        gint offsets[3];
-        guint plane;
-
-        offsets[0] = 0;
-        pitches[0] = GST_ROUND_UP_4 (meta->width);
-        offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (meta->height);
-        pitches[1] = GST_ROUND_UP_8 (meta->width) / 2;
-        offsets[2] =
-            offsets[1] + pitches[1] * GST_ROUND_UP_2 (meta->height) / 2;
-        pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
-
-        expected_size =
-            offsets[2] + pitches[2] * GST_ROUND_UP_2 (meta->height) / 2;
-
-        for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
-          GST_DEBUG_OBJECT (xvimagesink,
-              "Plane %u has a expected pitch of %d bytes, " "offset of %d",
-              plane, pitches[plane], offsets[plane]);
-        }
-        break;
-      }
-      case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
-      case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
-        expected_size = meta->height * GST_ROUND_UP_4 (meta->width * 2);
-        break;
-      default:
-        expected_size = 0;
-        break;
-    }
-    if (expected_size != 0 && meta->size != expected_size) {
-      GST_WARNING_OBJECT (xvimagesink,
-          "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
-          meta->size, expected_size);
-    }
-
-    /* Be verbose about our XvImage stride */
-    {
-      guint plane;
-
-      for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
-        GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
-            "offset of %d", plane, meta->xvimage->pitches[plane],
-            meta->xvimage->offsets[plane]);
-      }
-    }
-
-    meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size, IPC_CREAT | 0777);
-    if (meta->SHMInfo.shmid == -1) {
-      g_mutex_unlock (xvimagesink->x_lock);
-      GST_ELEMENT_ERROR (xvimagesink, 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_unlocked;
-    }
-
-    meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, NULL, 0);
-    if (meta->SHMInfo.shmaddr == ((void *) -1)) {
-      g_mutex_unlock (xvimagesink->x_lock);
-      GST_ELEMENT_ERROR (xvimagesink, 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_unlocked;
-    }
-
-    meta->xvimage->data = meta->SHMInfo.shmaddr;
-    meta->SHMInfo.readOnly = FALSE;
-
-    if (XShmAttach (xvimagesink->xcontext->disp, &meta->SHMInfo) == 0) {
-      /* Clean up the shared memory segment */
-      shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
-
-      g_mutex_unlock (xvimagesink->x_lock);
-      GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
-          ("Failed to create output image buffer of %dx%d pixels",
-              meta->width, meta->height), ("Failed to XShmAttach"));
-      goto beach_unlocked;
-    }
-
-    XSync (xvimagesink->xcontext->disp, FALSE);
-
-    /* Delete the shared memory segment as soon as we everyone is attached.
-     * 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);
-
-    GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
-        meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
-  } else
-#endif /* HAVE_XSHM */
-  {
-    meta->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
-        xvimagesink->xcontext->xv_port_id,
-        meta->im_format, NULL, meta->width, meta->height);
-    if (!meta->xvimage || error_caught) {
-      g_mutex_unlock (xvimagesink->x_lock);
-      /* Reset error handler */
-      error_caught = FALSE;
-      XSetErrorHandler (handler);
-      /* Push an error */
-      GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
-          ("Failed to create outputimage buffer of %dx%d pixels",
-              meta->width, meta->height),
-          ("could not XvCreateImage a %dx%d image", meta->width, meta->height));
-      goto beach_unlocked;
-    }
-
-    /* we have to use the returned data_size for our image size */
-    meta->size = meta->xvimage->data_size;
-    meta->xvimage->data = g_malloc (meta->size);
-
-    XSync (xvimagesink->xcontext->disp, FALSE);
-  }
-
-  /* Reset error handler */
-  error_caught = FALSE;
-  XSetErrorHandler (handler);
-
-  succeeded = TRUE;
-
-  gst_buffer_take_memory (buffer,
-      gst_memory_new_wrapped (0, meta->xvimage->data, NULL,
-          meta->size, 0, meta->size));
-
-  g_mutex_unlock (xvimagesink->x_lock);
-
-beach_unlocked:
-  if (!succeeded) {
-    gst_xvimage_buffer_free (buffer);
-    buffer = NULL;
-  }
-
-  return buffer;
-}
-
-/* This function destroys a GstXvImage handling XShm availability */
-static void
-gst_xvimagesink_xvimage_destroy (GstXvImageSink * xvimagesink,
-    GstBuffer * xvimage)
-{
-  GstMetaXvImage *data = NULL;
-
-  GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
-
-  g_return_if_fail (xvimage != NULL);
-  g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
-
-  data = GST_META_XVIMAGE_GET (xvimage);
-  g_return_if_fail (data != NULL);
-
-  GST_OBJECT_LOCK (xvimagesink);
-
-  /* If the destroyed image is the current one we destroy our reference too */
-  if (xvimagesink->cur_image == xvimage)
-    xvimagesink->cur_image = NULL;
-
-  /* We might have some buffers destroyed after changing state to NULL */
-  if (xvimagesink->xcontext == NULL) {
-    GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
-#ifdef HAVE_XSHM
-    /* Need to free the shared memory segment even if the x context
-     * was already cleaned up */
-    if (data->SHMInfo.shmaddr != ((void *) -1)) {
-      shmdt (data->SHMInfo.shmaddr);
-    }
-#endif
-    goto beach;
-  }
-
-  g_mutex_lock (xvimagesink->x_lock);
-
-#ifdef HAVE_XSHM
-  if (xvimagesink->xcontext->use_xshm) {
-    if (data->SHMInfo.shmaddr != ((void *) -1)) {
-      GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
-          data->SHMInfo.shmid, data->SHMInfo.shmseg);
-      XShmDetach (xvimagesink->xcontext->disp, &data->SHMInfo);
-      XSync (xvimagesink->xcontext->disp, FALSE);
-
-      shmdt (data->SHMInfo.shmaddr);
-    }
-    if (data->xvimage)
-      XFree (data->xvimage);
-  } else
-#endif /* HAVE_XSHM */
-  {
-    if (data->xvimage) {
-      if (data->xvimage->data) {
-        g_free (data->xvimage->data);
-      }
-      XFree (data->xvimage);
-    }
-  }
-
-  XSync (xvimagesink->xcontext->disp, FALSE);
-
-  g_mutex_unlock (xvimagesink->x_lock);
-
-beach:
-  GST_OBJECT_UNLOCK (xvimagesink);
-
-  data->xvimagesink = NULL;
-  gst_object_unref (xvimagesink);
-
-  return;
-}
 
 /* We are called with the x_lock taken */
 static void
@@ -742,7 +244,7 @@ gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink,
 static gboolean
 gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage)
 {
-  GstMetaXvImage *data;
+  GstMetaXvImage *meta;
   GstVideoRectangle result;
   gboolean draw_border = FALSE;
 
@@ -782,6 +284,8 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage)
     }
   }
 
+  meta = gst_buffer_get_meta_xvimage (xvimage);
+
   if (xvimagesink->keep_aspect) {
     GstVideoRectangle src, dst;
 
@@ -806,23 +310,18 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage)
         result);
     xvimagesink->redraw_border = FALSE;
   }
-
-  data = GST_META_XVIMAGE_GET (xvimage);
-  g_assert (data != NULL);
-
-  /* We scale to the window's geometry */
 #ifdef HAVE_XSHM
   if (xvimagesink->xcontext->use_xshm) {
     GST_LOG_OBJECT (xvimagesink,
         "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
         GST_PTR_FORMAT,
-        data->width, data->height,
+        meta->width, meta->height,
         xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
 
     XvShmPutImage (xvimagesink->xcontext->disp,
         xvimagesink->xcontext->xv_port_id,
         xvimagesink->xwindow->win,
-        xvimagesink->xwindow->gc, data->xvimage,
+        xvimagesink->xwindow->gc, meta->xvimage,
         xvimagesink->disp_x, xvimagesink->disp_y,
         xvimagesink->disp_width, xvimagesink->disp_height,
         result.x, result.y, result.w, result.h, FALSE);
@@ -832,7 +331,7 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage)
     XvPutImage (xvimagesink->xcontext->disp,
         xvimagesink->xcontext->xv_port_id,
         xvimagesink->xwindow->win,
-        xvimagesink->xwindow->gc, data->xvimage,
+        xvimagesink->xwindow->gc, meta->xvimage,
         xvimagesink->disp_x, xvimagesink->disp_y,
         xvimagesink->disp_width, xvimagesink->disp_height,
         result.x, result.y, result.w, result.h);
@@ -1176,6 +675,7 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
     g_mutex_lock (xvimagesink->flow_lock);
     g_mutex_lock (xvimagesink->x_lock);
   }
+
   if (pointer_moved) {
     g_mutex_unlock (xvimagesink->x_lock);
     g_mutex_unlock (xvimagesink->flow_lock);
@@ -1241,7 +741,8 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
         }
         break;
       default:
-        GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type);
+        GST_DEBUG_OBJECT (xvimagesink, "xvimagesink unhandled X event (%d)",
+            e.type);
     }
     g_mutex_lock (xvimagesink->flow_lock);
     g_mutex_lock (xvimagesink->x_lock);
@@ -1824,18 +1325,10 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
 
   xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
 
-  if (!xcontext->caps) {
-    XCloseDisplay (xcontext->disp);
-    g_mutex_unlock (xvimagesink->x_lock);
-    g_free (xcontext->par);
-    g_free (xcontext);
-    /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
-    return NULL;
-  }
-#ifdef HAVE_XSHM
   /* Search for XShm extension support */
+#ifdef HAVE_XSHM
   if (XShmQueryExtension (xcontext->disp) &&
-      gst_xvimagesink_check_xshm_calls (xcontext)) {
+      gst_xvimagesink_check_xshm_calls (xvimagesink, xcontext)) {
     xcontext->use_xshm = TRUE;
     GST_DEBUG ("xvimagesink is using XShm extension");
   } else
@@ -1845,6 +1338,15 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
     GST_DEBUG ("xvimagesink is not using XShm extension");
   }
 
+  if (!xcontext->caps) {
+    XCloseDisplay (xcontext->disp);
+    g_mutex_unlock (xvimagesink->x_lock);
+    g_free (xcontext->par);
+    g_free (xcontext);
+    /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
+    return NULL;
+  }
+
   xv_attr = XvQueryPortAttributes (xcontext->disp,
       xcontext->xv_port_id, &N_attr);
 
@@ -1981,50 +1483,8 @@ gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
   g_free (xcontext);
 }
 
-static void
-gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
-{
-  g_mutex_lock (xvimagesink->pool_lock);
-
-  while (xvimagesink->image_pool) {
-    GstBuffer *xvimage = xvimagesink->image_pool->data;
-
-    xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
-        xvimagesink->image_pool);
-    gst_xvimage_buffer_free (xvimage);
-  }
-
-  g_mutex_unlock (xvimagesink->pool_lock);
-}
-
 /* Element stuff */
 
-/* This function tries to get a format matching with a given caps in the
-   supported list of formats we generated in gst_xvimagesink_get_xv_support */
-static gint
-gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
-    GstCaps * caps)
-{
-  GList *list = NULL;
-
-  g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
-
-  list = xvimagesink->xcontext->formats_list;
-
-  while (list) {
-    GstXvImageFormat *format = list->data;
-
-    if (format) {
-      if (gst_caps_can_intersect (caps, format->caps)) {
-        return format->format;
-      }
-    }
-    list = g_list_next (list);
-  }
-
-  return -1;
-}
-
 static GstCaps *
 gst_xvimagesink_getcaps (GstBaseSink * bsink)
 {
@@ -2045,8 +1505,9 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
 {
   GstXvImageSink *xvimagesink;
   GstStructure *structure;
-  guint32 im_format = 0;
+  GstBufferPool *newpool, *oldpool;
   gboolean ret;
+  guint32 im_format = 0;
   gint video_width, video_height;
   gint disp_x, disp_y;
   gint disp_width, disp_height;
@@ -2184,22 +1645,26 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
    * doesn't cover the same area */
   xvimagesink->redraw_border = TRUE;
 
-  /* We renew our xvimage only if size or format changed;
-   * the xvimage is the same size as the video pixel size */
-  if ((xvimagesink->xvimage)) {
-    GstMetaXvImage *data = GST_META_XVIMAGE_GET (xvimagesink->xvimage);
+  /* create a new pool for the new configuration */
+  newpool = gst_xvimage_buffer_pool_new (xvimagesink);
 
-    if (((im_format != data->im_format) ||
-            (video_width != data->width) || (video_height != data->height))) {
-      GST_DEBUG_OBJECT (xvimagesink,
-          "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
-          GST_FOURCC_ARGS (data->im_format), GST_FOURCC_ARGS (im_format));
-      GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
-      gst_buffer_unref (xvimagesink->xvimage);
-      xvimagesink->xvimage = 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 = xvimagesink->pool;
+  xvimagesink->pool = newpool;
 
+  /* unref the old sink */
+  if (oldpool) {
+    /* deactivate */
+    gst_buffer_pool_set_active (oldpool, FALSE);
+    gst_object_unref (oldpool);
+  }
   g_mutex_unlock (xvimagesink->flow_lock);
 
   return TRUE;
@@ -2234,6 +1699,18 @@ no_display_size:
         ("Error calculating the output display ratio of the video."));
     return FALSE;
   }
+config_failed:
+  {
+    GST_ERROR_OBJECT (xvimagesink, "failed to set config.");
+    g_mutex_unlock (xvimagesink->flow_lock);
+    return FALSE;
+  }
+activate_failed:
+  {
+    GST_ERROR_OBJECT (xvimagesink, "failed to activate bufferpool.");
+    g_mutex_unlock (xvimagesink->flow_lock);
+    return FALSE;
+  }
 }
 
 static GstStateChangeReturn
@@ -2272,16 +1749,10 @@ gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
       gst_xvimagesink_manage_event_thread (xvimagesink);
       break;
     case GST_STATE_CHANGE_READY_TO_PAUSED:
-      g_mutex_lock (xvimagesink->pool_lock);
-      xvimagesink->pool_invalid = FALSE;
-      g_mutex_unlock (xvimagesink->pool_lock);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
-      g_mutex_lock (xvimagesink->pool_lock);
-      xvimagesink->pool_invalid = TRUE;
-      g_mutex_unlock (xvimagesink->pool_lock);
       break;
     default:
       break;
@@ -2297,6 +1768,9 @@ gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
       xvimagesink->fps_d = 1;
       GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
       GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
+      g_mutex_lock (xvimagesink->flow_lock);
+      gst_buffer_pool_set_active (xvimagesink->pool, FALSE);
+      g_mutex_lock (xvimagesink->flow_lock);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
       gst_xvimagesink_reset (xvimagesink);
@@ -2333,20 +1807,21 @@ gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
 static GstFlowReturn
 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
 {
+  GstFlowReturn res;
   GstXvImageSink *xvimagesink;
   GstMetaXvImage *meta;
 
   xvimagesink = GST_XVIMAGESINK (vsink);
 
-  meta = GST_META_XVIMAGE_GET (buf);
+  meta = gst_buffer_get_meta_xvimage (buf);
 
   if (meta) {
     /* If this buffer has been allocated using our buffer management we simply
        put the ximage which is in the PRIVATE pointer */
-    GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
-    if (!gst_xvimagesink_xvimage_put (xvimagesink, buf))
-      goto no_window;
+    GST_LOG_OBJECT (xvimagesink, "buffer from our pool, writing directly");
+    res = GST_FLOW_OK;
   } else {
+    GstBuffer *temp;
     guint8 *data;
     gsize size;
 
@@ -2354,36 +1829,51 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
         "slow copy into bufferpool buffer %p", buf);
     /* Else we have to copy the data into our private image, */
     /* if we have one... */
-    if (!xvimagesink->xvimage) {
-      GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
+    GST_LOG_OBJECT (xvimagesink, "buffer not from our pool, copying");
 
-      xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
-          GST_BUFFER_CAPS (buf));
+    /* we should have a pool, configured in setcaps */
+    if (xvimagesink->pool == NULL)
+      goto no_pool;
 
-      if (!xvimagesink->xvimage)
-        /* The create method should have posted an informative error */
-        goto no_image;
+    /* take a buffer form our pool */
+    res = gst_buffer_pool_acquire_buffer (xvimagesink->pool, &temp, NULL);
+    if (res != GST_FLOW_OK)
+      goto no_buffer;
 
-      if (gst_buffer_get_size (xvimagesink->xvimage) <
-          gst_buffer_get_size (buf))
-        goto wrong_size;
-    }
+    if (gst_buffer_get_size (temp) < gst_buffer_get_size (buf))
+      goto wrong_size;
 
-    data = gst_buffer_map (xvimagesink->xvimage, &size, NULL, GST_MAP_WRITE);
+    data = gst_buffer_map (temp, &size, NULL, GST_MAP_WRITE);
     gst_buffer_extract (buf, 0, data, size);
-    gst_buffer_unmap (xvimagesink->xvimage, data, size);
+    gst_buffer_unmap (temp, data, size);
 
-    if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
-      goto no_window;
+    buf = temp;
   }
 
-  return GST_FLOW_OK;
+  if (!gst_xvimagesink_xvimage_put (xvimagesink, buf))
+    goto no_window;
+
+  return res;
 
   /* ERRORS */
-no_image:
+no_pool:
+  {
+    GST_ELEMENT_ERROR (xvimagesink, 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 (xvimagesink, "could not create image");
+    return res;
+  }
+wrong_size:
+  {
+    GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
+        ("Failed to create output image buffer"),
+        ("XServer allocated buffer size did not match input buffer"));
     return GST_FLOW_ERROR;
   }
 no_window:
@@ -2392,19 +1882,6 @@ no_window:
     GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
     return GST_FLOW_ERROR;
   }
-wrong_size:
-  {
-    meta = GST_META_XVIMAGE_GET (xvimagesink->xvimage);
-
-    GST_ELEMENT_ERROR (xvimagesink, 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"));
-
-    gst_xvimagesink_xvimage_destroy (xvimagesink, xvimagesink->xvimage);
-    xvimagesink->xvimage = NULL;
-    goto no_image;
-  }
 }
 
 static gboolean
@@ -2491,20 +1968,15 @@ static GstFlowReturn
 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
     GstCaps * caps, GstBuffer ** buf)
 {
-  GstFlowReturn ret = GST_FLOW_OK;
   GstXvImageSink *xvimagesink;
   GstBuffer *xvimage = NULL;
-  GstMetaXvImage *meta = NULL;
-  GstCaps *intersection = NULL;
   GstStructure *structure = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstCaps *intersection = NULL;
   gint width, height, image_format;
 
   xvimagesink = GST_XVIMAGESINK (bsink);
 
-  g_mutex_lock (xvimagesink->pool_lock);
-  if (G_UNLIKELY (xvimagesink->pool_invalid))
-    goto invalid;
-
   if (G_LIKELY (xvimagesink->xcontext->last_caps &&
           gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
     GST_LOG_OBJECT (xvimagesink,
@@ -2622,38 +2094,22 @@ gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
 
 reuse_last_caps:
 
-  /* Walking through the pool cleaning unusable images and searching for a
-     suitable one */
-  while (xvimagesink->image_pool) {
-    xvimage = xvimagesink->image_pool->data;
-
-    if (xvimage) {
-      meta = GST_META_XVIMAGE_GET (xvimage);
-
-      /* Removing from the pool */
-      xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
-          xvimagesink->image_pool);
+  if (gst_caps_is_equal (GST_PAD_CAPS (bsink->sinkpad), caps)) {
+    /* we negotiated this format before, use the pool */
+    if (xvimagesink->pool) {
+      GstBuffer *tmp;
 
-      /* We check for geometry or image format changes */
-      if ((meta->width != width) ||
-          (meta->height != height) || (meta->im_format != image_format)) {
-        /* This image is unusable. Destroying... */
-        gst_xvimage_buffer_free (xvimage);
-        xvimage = NULL;
-      } else {
-        /* We found a suitable image */
-        GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
-        break;
-      }
+      GST_LOG_OBJECT (xvimagesink, "retrieving buffer from pool");
+      ret = gst_buffer_pool_acquire_buffer (xvimagesink->pool, &tmp, NULL);
+      xvimage = tmp;
     }
   }
 
-  if (!xvimage) {
-    /* We found no suitable image in the pool. Creating... */
-    GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
-    xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
+  if (xvimage == NULL) {
+    /* Something new make a new image a new one */
+    GST_LOG_OBJECT (xvimagesink, "allocating new image");
+    xvimage = gst_xvimage_buffer_new (xvimagesink, width, height, image_format);
   }
-  g_mutex_unlock (xvimagesink->pool_lock);
 
   if (xvimage) {
     /* Make sure the buffer is cleared of any previously used flags */
@@ -2675,7 +2131,6 @@ invalid:
   {
     GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
     ret = GST_FLOW_WRONG_STATE;
-    g_mutex_unlock (xvimagesink->pool_lock);
     goto beach;
   }
 incompatible:
@@ -2685,7 +2140,6 @@ incompatible:
         " are completely incompatible with those caps", caps,
         xvimagesink->xcontext->caps);
     ret = GST_FLOW_NOT_NEGOTIATED;
-    g_mutex_unlock (xvimagesink->pool_lock);
     goto beach;
   }
 invalid_caps:
@@ -2693,7 +2147,6 @@ invalid_caps:
     GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
         GST_PTR_FORMAT, intersection);
     ret = GST_FLOW_NOT_NEGOTIATED;
-    g_mutex_unlock (xvimagesink->pool_lock);
     goto beach;
   }
 }
@@ -2810,15 +2263,6 @@ gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
 
   gst_xvimagesink_update_colorbalance (xvimagesink);
 
-  /* Clear image pool as the images are unusable anyway */
-  gst_xvimagesink_imagepool_clear (xvimagesink);
-
-  /* Clear the xvimage */
-  if (xvimagesink->xvimage) {
-    gst_xvimage_buffer_free (xvimagesink->xvimage);
-    xvimagesink->xvimage = NULL;
-  }
-
   /* If a window is there already we destroy it */
   if (xvimagesink->xwindow) {
     gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
@@ -3382,32 +2826,28 @@ gst_xvimagesink_reset (GstXvImageSink * xvimagesink)
   xvimagesink->event_thread = NULL;
   GST_OBJECT_UNLOCK (xvimagesink);
 
-  /* invalidate the pool, current allocations continue, new buffer_alloc fails
-   * with wrong_state */
-  g_mutex_lock (xvimagesink->pool_lock);
-  xvimagesink->pool_invalid = TRUE;
-  g_mutex_unlock (xvimagesink->pool_lock);
-
   /* Wait for our event thread to finish before we clean up our stuff. */
   if (thread)
     g_thread_join (thread);
 
   if (xvimagesink->cur_image) {
-    gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
+    gst_buffer_unref (xvimagesink->cur_image);
     xvimagesink->cur_image = NULL;
   }
-  if (xvimagesink->xvimage) {
-    gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
-    xvimagesink->xvimage = NULL;
-  }
 
-  gst_xvimagesink_imagepool_clear (xvimagesink);
+  g_mutex_lock (xvimagesink->flow_lock);
+
+  if (xvimagesink->pool) {
+    gst_object_unref (xvimagesink->pool);
+    xvimagesink->pool = NULL;
+  }
 
   if (xvimagesink->xwindow) {
     gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
     gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
     xvimagesink->xwindow = NULL;
   }
+  g_mutex_unlock (xvimagesink->flow_lock);
 
   xvimagesink->render_rect.x = xvimagesink->render_rect.y =
       xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
@@ -3445,10 +2885,6 @@ gst_xvimagesink_finalize (GObject * object)
     g_mutex_free (xvimagesink->flow_lock);
     xvimagesink->flow_lock = NULL;
   }
-  if (xvimagesink->pool_lock) {
-    g_mutex_free (xvimagesink->pool_lock);
-    xvimagesink->pool_lock = NULL;
-  }
 
   g_free (xvimagesink->media_title);
 
@@ -3462,7 +2898,6 @@ gst_xvimagesink_init (GstXvImageSink * xvimagesink)
   xvimagesink->adaptor_no = 0;
   xvimagesink->xcontext = NULL;
   xvimagesink->xwindow = NULL;
-  xvimagesink->xvimage = NULL;
   xvimagesink->cur_image = NULL;
 
   xvimagesink->hue = xvimagesink->saturation = 0;
@@ -3477,8 +2912,7 @@ gst_xvimagesink_init (GstXvImageSink * xvimagesink)
   xvimagesink->x_lock = g_mutex_new ();
   xvimagesink->flow_lock = g_mutex_new ();
 
-  xvimagesink->image_pool = NULL;
-  xvimagesink->pool_lock = g_mutex_new ();
+  xvimagesink->pool = NULL;
 
   xvimagesink->synchronous = FALSE;
   xvimagesink->double_buffer = TRUE;
@@ -3737,27 +3171,11 @@ gst_xvimagesink_get_type (void)
         &colorbalance_info);
     g_type_add_interface_static (xvimagesink_type, GST_TYPE_PROPERTY_PROBE,
         &propertyprobe_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_xvimage_buffer_pool_get_type ());
   }
 
   return xvimagesink_type;
 }
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
-  if (!gst_element_register (plugin, "xvimagesink",
-          GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
-    return FALSE;
-
-  GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
-      "xvimagesink element");
-  GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
-
-  return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
-    GST_VERSION_MINOR,
-    "xvimagesink",
-    "XFree86 video output plugin using Xv extension",
-    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
index 88c6e40..5eb4e70 100644 (file)
@@ -43,7 +43,6 @@
 #include <stdlib.h>
 
 G_BEGIN_DECLS
-
 #define GST_TYPE_XVIMAGESINK \
   (gst_xvimagesink_get_type())
 #define GST_XVIMAGESINK(obj) \
@@ -54,15 +53,15 @@ G_BEGIN_DECLS
   (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XVIMAGESINK))
 #define GST_IS_XVIMAGESINK_CLASS(klass) \
   (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XVIMAGESINK))
-
 typedef struct _GstXContext GstXContext;
 typedef struct _GstXWindow GstXWindow;
 typedef struct _GstXvImageFormat GstXvImageFormat;
-typedef struct _GstMetaXvImage GstMetaXvImage;
 
 typedef struct _GstXvImageSink GstXvImageSink;
 typedef struct _GstXvImageSinkClass GstXvImageSinkClass;
 
+#include "xvimagepool.h"
+
 /*
  * GstXContext:
  * @disp: the X11 Display of this context
@@ -92,7 +91,8 @@ typedef struct _GstXvImageSinkClass GstXvImageSinkClass;
  * Structure used to store various informations collected/calculated for a
  * Display.
  */
-struct _GstXContext {
+struct _GstXContext
+{
   Display *disp;
 
   Screen *screen;
@@ -116,7 +116,7 @@ struct _GstXContext {
 
   XvPortID xv_port_id;
   guint nb_adaptors;
-  gchar ** adaptors;
+  gchar **adaptors;
   gint im_format;
 
   GList *formats_list;
@@ -142,7 +142,8 @@ struct _GstXContext {
  *
  * Structure used to store informations about a Window.
  */
-struct _GstXWindow {
+struct _GstXWindow
+{
   Window win;
   gint width, height;
   gboolean internal;
@@ -156,51 +157,18 @@ struct _GstXWindow {
  *
  * Structure storing image format to #GstCaps association.
  */
-struct _GstXvImageFormat {
+struct _GstXvImageFormat
+{
   gint format;
   GstCaps *caps;
 };
 
-/**
- * GstXImageData:
- * @xvimagesink: a reference to our #GstXvImageSink
- * @xvimage: the XvImage of this buffer
- * @width: the width in pixels of XvImage @xvimage
- * @height: the height in pixels of XvImage @xvimage
- * @im_format: the image format of XvImage @xvimage
- * @size: the size in bytes of XvImage @xvimage
- *
- * Structure with additional information about an XvImage.
- */
-struct _GstMetaXvImage {
-  GstMeta meta;
-
-  /* Reference to the xvimagesink we belong to */
-  GstXvImageSink *xvimagesink;
-
-  XvImage *xvimage;
-
-#ifdef HAVE_XSHM
-  XShmSegmentInfo SHMInfo;
-#endif /* HAVE_XSHM */
-
-  gint width, height, im_format;
-  size_t size;
-};
-
-const GstMetaInfo * gst_meta_xvimage_get_info (void);
-
-#define GST_META_XVIMAGE_GET(buf) ((GstMetaXvImage *)gst_buffer_get_meta(buf,gst_meta_xvimage_get_info()))
-#define GST_META_XVIMAGE_ADD(buf) ((GstMetaXvImage *)gst_buffer_add_meta(buf,gst_meta_xvimage_get_info(), NULL))
-
 
 /**
  * GstXvImageSink:
  * @display_name: the name of the Display we want to render to
  * @xcontext: our instance's #GstXContext
  * @xwindow: the #GstXWindow we are rendering to
- * @xvimage: internal #GstXvImage used to store incoming buffers and render when
- * not using the buffer_alloc optimization mechanism
  * @cur_image: a reference to the last #GstXvImage that was put to @xwindow. It
  * is used when Expose events are received to redraw the latest video frame
  * @event_thread: a thread listening for events on @xwindow and handling them
@@ -230,7 +198,8 @@ const GstMetaInfo * gst_meta_xvimage_get_info (void);
  *
  * The #GstXvImageSink data structure.
  */
-struct _GstXvImageSink {
+struct _GstXvImageSink
+{
   /* Our element stuff */
   GstVideoSink videosink;
 
@@ -255,9 +224,8 @@ struct _GstXvImageSink {
   /* object-set pixel aspect ratio */
   GValue *par;
 
-  GMutex *pool_lock;
-  gboolean pool_invalid;
-  GSList *image_pool;
+  /* the buffer pool */
+  GstBufferPool *pool;
 
   gboolean synchronous;
   gboolean double_buffer;
@@ -282,14 +250,14 @@ struct _GstXvImageSink {
   /* port attributes */
   gboolean autopaint_colorkey;
   gint colorkey;
-  
+
   gboolean draw_borders;
-  
+
   /* port features */
   gboolean have_autopaint_colorkey;
   gboolean have_colorkey;
   gboolean have_double_buffer;
-  
+
   /* stream metadata */
   gchar *media_title;
 
@@ -298,12 +266,12 @@ struct _GstXvImageSink {
   gboolean have_render_rect;
 };
 
-struct _GstXvImageSinkClass {
+struct _GstXvImageSinkClass
+{
   GstVideoSinkClass parent_class;
 };
 
-GType gst_xvimagesink_get_type(void);
+GType gst_xvimagesink_get_type (void);
 
 G_END_DECLS
-
 #endif /* __GST_XVIMAGESINK_H__ */