waylandsink: replace the custom buffer pool with an allocator
authorGeorge Kiagiadakis <george.kiagiadakis@collabora.com>
Mon, 23 Jun 2014 13:40:02 +0000 (16:40 +0300)
committerGeorge Kiagiadakis <george.kiagiadakis@collabora.com>
Sat, 11 Oct 2014 12:57:13 +0000 (14:57 +0200)
This reduces the complexity of having a custom buffer pool, as
we don't really need it. We only need the custom allocation part.
And since the wl_buffer is no longer saved in a GstMeta, we can
create it and add it on the buffers in the sink's render()
function, which removes the reference cycle caused by the pool
holding a reference to the display and also allows more generic
scenarios (the allocator being used in another pool, or buffers
being allocated without a pool [if anything stupid does that]).

This commit also simplifies the propose_allocation() function,
which doesn't really need to do all these complicated checks,
since there is always a correct buffer pool available, created
in set_caps().

The other side effect of this commit is that a new wl_shm_pool
is now created for every GstMemory, which means that we use
as much shm memory as we actually need and no more. Previously,
the created wl_shm_pool would allocate space for 15 buffers, no
matter if they were being used or not.

ext/wayland/Makefile.am
ext/wayland/gstwaylandsink.c
ext/wayland/waylandpool.c [deleted file]
ext/wayland/waylandpool.h [deleted file]
ext/wayland/wlshmallocator.c [new file with mode: 0644]
ext/wayland/wlshmallocator.h [new file with mode: 0644]

index 73aae2c..e12d99a 100644 (file)
@@ -2,7 +2,7 @@ plugin_LTLIBRARIES = libgstwaylandsink.la
 
 libgstwaylandsink_la_SOURCES =  \
        gstwaylandsink.c \
-       waylandpool.c \
+       wlshmallocator.c \
        wlbuffer.c \
        wldisplay.c \
        wlwindow.c \
@@ -21,7 +21,7 @@ libgstwaylandsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
 
 noinst_HEADERS = \
        gstwaylandsink.h \
-       waylandpool.h \
+       wlshmallocator.h \
        wlbuffer.h \
        wldisplay.h \
        wlwindow.h \
@@ -39,7 +39,7 @@ CLEANFILES = scaler-protocol.c scaler-client-protocol.h
 
 gstwaylandsink.c: scaler-client-protocol.h
 
-waylandpool.c: scaler-client-protocol.h
+wlshmallocator.c: scaler-client-protocol.h
 
 wlbuffer.c: scaler-client-protocol.h
 
index 1e2c11d..e081280 100644 (file)
@@ -43,8 +43,8 @@
 
 #include "gstwaylandsink.h"
 #include "wlvideoformat.h"
-#include "waylandpool.h"
 #include "wlbuffer.h"
+#include "wlshmallocator.h"
 
 #include <gst/wayland/wayland.h>
 #include <gst/video/videooverlay.h>
@@ -362,9 +362,9 @@ gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
          * - see the comment on wlbuffer.c for details */
         gst_wl_display_stop (sink->display);
         g_clear_object (&sink->display);
-        g_clear_object (&sink->pool);
       }
       g_mutex_unlock (&sink->display_lock);
+      g_clear_object (&sink->pool);
       break;
     default:
       break;
@@ -451,7 +451,6 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
   GArray *formats;
   gint i;
   GstStructure *structure;
-  static GstAllocationParams params = { 0, 0, 0, 15, };
 
   sink = GST_WAYLAND_SINK (bsink);
 
@@ -476,13 +475,14 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
     goto unsupported_format;
 
   /* create a new pool for the new configuration */
-  newpool = gst_wayland_buffer_pool_new (sink->display);
+  newpool = gst_video_buffer_pool_new ();
   if (!newpool)
     goto pool_failed;
 
   structure = gst_buffer_pool_get_config (newpool);
   gst_buffer_pool_config_set_params (structure, caps, info.size, 2, 0);
-  gst_buffer_pool_config_set_allocator (structure, NULL, &params);
+  gst_buffer_pool_config_set_allocator (structure, gst_wl_shm_allocator_get (),
+      NULL);
   if (!gst_buffer_pool_set_config (newpool, structure))
     goto config_failed;
 
@@ -524,76 +524,18 @@ static gboolean
 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
 {
   GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
-  GstBufferPool *pool = NULL;
   GstStructure *config;
-  GstCaps *caps;
-  guint size;
-  gboolean need_pool;
-
-  gst_query_parse_allocation (query, &caps, &need_pool);
-
-  if (caps == NULL)
-    goto no_caps;
-
-  if (sink->pool)
-    pool = gst_object_ref (sink->pool);
+  guint size, min_bufs, max_bufs;
 
-  if (pool != NULL) {
-    GstCaps *pcaps;
-
-    /* we had a pool, check caps */
-    config = gst_buffer_pool_get_config (pool);
-    gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
-
-    if (!gst_caps_is_equal (caps, pcaps)) {
-      /* different caps, we can't use this pool */
-      gst_object_unref (pool);
-      pool = NULL;
-    }
-    gst_structure_free (config);
-  }
+  config = gst_buffer_pool_get_config (sink->pool);
+  gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
 
-  if (pool == NULL && need_pool) {
-    GstVideoInfo info;
-
-    if (!gst_video_info_from_caps (&info, caps))
-      goto invalid_caps;
-
-    GST_DEBUG_OBJECT (sink, "create new pool");
-    pool = gst_wayland_buffer_pool_new (sink->display);
-
-    /* the normal size of a frame */
-    size = info.size;
-
-    config = gst_buffer_pool_get_config (pool);
-    gst_buffer_pool_config_set_params (config, caps, size, 2, 0);
-    if (!gst_buffer_pool_set_config (pool, config))
-      goto config_failed;
-  }
-  if (pool) {
-    gst_query_add_allocation_pool (query, pool, size, 2, 0);
-    gst_object_unref (pool);
-  }
+  /* we do have a pool for sure (created in set_caps),
+   * so let's propose it anyway, but also propose the allocator on its own */
+  gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
+  gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
 
   return TRUE;
-
-  /* ERRORS */
-no_caps:
-  {
-    GST_DEBUG_OBJECT (bsink, "no caps specified");
-    return FALSE;
-  }
-invalid_caps:
-  {
-    GST_DEBUG_OBJECT (bsink, "invalid caps specified");
-    return FALSE;
-  }
-config_failed:
-  {
-    GST_DEBUG_OBJECT (bsink, "failed setting config");
-    gst_object_unref (pool);
-    return FALSE;
-  }
 }
 
 static GstFlowReturn
@@ -691,26 +633,63 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
 
   wlbuffer = gst_buffer_get_wl_buffer (buffer);
 
-  if (wlbuffer && wlbuffer->display == sink->display) {
-    GST_LOG_OBJECT (sink, "buffer %p from our pool, writing directly", buffer);
+  if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
+    GST_LOG_OBJECT (sink, "buffer %p has a wl_buffer from our display, "
+        "writing directly", buffer);
     to_render = buffer;
   } else {
-    GstMapInfo src;
-    GST_LOG_OBJECT (sink, "buffer %p not from our pool, copying", buffer);
+    GstMemory *mem;
+    struct wl_buffer *wbuf = NULL;
+
+    GST_LOG_OBJECT (sink, "buffer %p does not have a wl_buffer from our "
+        "display, creating it", buffer);
 
-    if (!sink->pool)
-      goto no_pool;
+    mem = gst_buffer_peek_memory (buffer, 0);
 
-    if (!gst_buffer_pool_set_active (sink->pool, TRUE))
-      goto activate_failed;
+    if (gst_is_wl_shm_memory (mem)) {
+      wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
+          &sink->video_info);
+    }
 
-    ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
-    if (ret != GST_FLOW_OK)
-      goto no_buffer;
+    if (wbuf) {
+      gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
+      to_render = buffer;
+    } else {
+      GstMapInfo src;
+      /* we don't know how to create a wl_buffer directly from the provided
+       * memory, so we have to copy the data to a memory that we know how
+       * to handle... */
+
+      GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, "
+          "copying to wl_shm memory", buffer);
+
+      /* sink->pool always exists (created in set_caps), but it may not
+       * be active if upstream is not using it */
+      if (!gst_buffer_pool_is_active (sink->pool) &&
+          !gst_buffer_pool_set_active (sink->pool, TRUE))
+        goto activate_failed;
+
+      ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
+      if (ret != GST_FLOW_OK)
+        goto no_buffer;
+
+      /* the first time we acquire a buffer,
+       * we need to attach a wl_buffer on it */
+      wlbuffer = gst_buffer_get_wl_buffer (buffer);
+      if (G_UNLIKELY (!wlbuffer)) {
+        mem = gst_buffer_peek_memory (to_render, 0);
+        wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
+            &sink->video_info);
+        if (G_UNLIKELY (!wbuf))
+          goto no_wl_buffer;
+
+        gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
+      }
 
-    gst_buffer_map (buffer, &src, GST_MAP_READ);
-    gst_buffer_fill (to_render, 0, src.data, src.size);
-    gst_buffer_unmap (buffer, &src);
+      gst_buffer_map (buffer, &src, GST_MAP_READ);
+      gst_buffer_fill (to_render, 0, src.data, src.size);
+      gst_buffer_unmap (buffer, &src);
+    }
   }
 
   gst_buffer_replace (&sink->last_buffer, to_render);
@@ -730,14 +709,12 @@ no_window_size:
   }
 no_buffer:
   {
-    GST_WARNING_OBJECT (sink, "could not create image");
+    GST_WARNING_OBJECT (sink, "could not create buffer");
     goto done;
   }
-no_pool:
+no_wl_buffer:
   {
-    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
-        ("Internal error: can't allocate images"),
-        ("We don't have a bufferpool negotiated"));
+    GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
     ret = GST_FLOW_ERROR;
     goto done;
   }
@@ -887,6 +864,8 @@ plugin_init (GstPlugin * plugin)
   GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0,
       " wayland video sink");
 
+  gst_wl_shm_allocator_register ();
+
   return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL,
       GST_TYPE_WAYLAND_SINK);
 }
diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c
deleted file mode 100644 (file)
index 94758c8..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/* GStreamer
- * Copyright (C) 2012 Intel Corporation
- * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
- * Copyright (C) 2014 Collabora Ltd.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "waylandpool.h"
-#include "wldisplay.h"
-#include "wlvideoformat.h"
-#include "wlbuffer.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-
-GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
-#define GST_CAT_DEFAULT gstwayland_debug
-
-/* bufferpool */
-static void gst_wayland_buffer_pool_finalize (GObject * object);
-static gboolean gst_wayland_buffer_pool_set_config (GstBufferPool * pool,
-    GstStructure * config);
-static gboolean gst_wayland_buffer_pool_start (GstBufferPool * pool);
-static gboolean gst_wayland_buffer_pool_stop (GstBufferPool * pool);
-static GstFlowReturn gst_wayland_buffer_pool_alloc (GstBufferPool * pool,
-    GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
-
-#define gst_wayland_buffer_pool_parent_class parent_class
-G_DEFINE_TYPE (GstWaylandBufferPool, gst_wayland_buffer_pool,
-    GST_TYPE_BUFFER_POOL);
-
-static void
-gst_wayland_buffer_pool_class_init (GstWaylandBufferPoolClass * klass)
-{
-  GObjectClass *gobject_class = (GObjectClass *) klass;
-  GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
-
-  gobject_class->finalize = gst_wayland_buffer_pool_finalize;
-
-  gstbufferpool_class->set_config = gst_wayland_buffer_pool_set_config;
-  gstbufferpool_class->start = gst_wayland_buffer_pool_start;
-  gstbufferpool_class->stop = gst_wayland_buffer_pool_stop;
-  gstbufferpool_class->alloc_buffer = gst_wayland_buffer_pool_alloc;
-}
-
-static void
-gst_wayland_buffer_pool_init (GstWaylandBufferPool * self)
-{
-  gst_video_info_init (&self->info);
-}
-
-static void
-gst_wayland_buffer_pool_finalize (GObject * object)
-{
-  GstWaylandBufferPool *pool = GST_WAYLAND_BUFFER_POOL_CAST (object);
-
-  if (pool->wl_pool)
-    gst_wayland_buffer_pool_stop (GST_BUFFER_POOL (pool));
-
-  g_object_unref (pool->display);
-
-  G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object);
-}
-
-static gboolean
-gst_wayland_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
-{
-  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
-  GstCaps *caps;
-
-  if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
-    goto wrong_config;
-
-  if (caps == NULL)
-    goto no_caps;
-
-  /* now parse the caps from the config */
-  if (!gst_video_info_from_caps (&self->info, caps))
-    goto wrong_caps;
-
-  GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT,
-      GST_VIDEO_INFO_WIDTH (&self->info), GST_VIDEO_INFO_HEIGHT (&self->info),
-      caps);
-
-  /*Fixme: Enable metadata checking handling based on the config of pool */
-
-  return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
-  /* 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;
-  }
-}
-
-static gboolean
-gst_wayland_buffer_pool_start (GstBufferPool * pool)
-{
-  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
-  guint size = 0;
-  int fd;
-  char filename[1024];
-  static int init = 0;
-
-  GST_DEBUG_OBJECT (self, "Initializing wayland buffer pool");
-
-  /* configure */
-  size = GST_VIDEO_INFO_SIZE (&self->info) * 15;
-
-  /* allocate shm pool */
-  snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
-      "wayland-shm", init++, "XXXXXX");
-
-  fd = mkstemp (filename);
-  if (fd < 0) {
-    GST_ERROR_OBJECT (pool, "opening temp file %s failed: %s", filename,
-        strerror (errno));
-    return FALSE;
-  }
-  if (ftruncate (fd, size) < 0) {
-    GST_ERROR_OBJECT (pool, "ftruncate failed: %s", strerror (errno));
-    close (fd);
-    return FALSE;
-  }
-
-  self->data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-  if (self->data == MAP_FAILED) {
-    GST_ERROR_OBJECT (pool, "mmap failed: %s", strerror (errno));
-    close (fd);
-    return FALSE;
-  }
-
-  self->wl_pool = wl_shm_create_pool (self->display->shm, fd, size);
-  unlink (filename);
-  close (fd);
-
-  self->size = size;
-  self->used = 0;
-
-  return GST_BUFFER_POOL_CLASS (parent_class)->start (pool);
-}
-
-static gboolean
-gst_wayland_buffer_pool_stop (GstBufferPool * pool)
-{
-  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
-
-  GST_DEBUG_OBJECT (self, "Stopping wayland buffer pool");
-
-  munmap (self->data, self->size);
-  wl_shm_pool_destroy (self->wl_pool);
-
-  self->wl_pool = NULL;
-  self->size = 0;
-  self->used = 0;
-
-  return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool);
-}
-
-static GstFlowReturn
-gst_wayland_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
-    GstBufferPoolAcquireParams * params)
-{
-  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
-  gint width, height, stride;
-  gsize size;
-  enum wl_shm_format format;
-  gint offset;
-  void *data;
-  struct wl_buffer *wbuffer;
-
-  width = GST_VIDEO_INFO_WIDTH (&self->info);
-  height = GST_VIDEO_INFO_HEIGHT (&self->info);
-  stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 0);
-  size = GST_VIDEO_INFO_SIZE (&self->info);
-  format =
-      gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT (&self->info));
-
-  GST_DEBUG_OBJECT (self, "Allocating buffer of size %" G_GSSIZE_FORMAT
-      " (%d x %d, stride %d), format %s", size, width, height, stride,
-      gst_wayland_format_to_string (format));
-
-  /* try to reserve another memory block from the shm pool */
-  if (self->used + size > self->size)
-    goto no_buffer;
-
-  offset = self->used;
-  self->used += size;
-  data = ((gchar *) self->data) + offset;
-
-  *buffer = gst_buffer_new ();
-
-  /* add the allocated memory on the GstBuffer */
-  gst_buffer_append_memory (*buffer,
-      gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data,
-          size, 0, size, NULL, NULL));
-
-  /* create wl_buffer and attach it on the GstBuffer via GstWlBuffer */
-  wbuffer = wl_shm_pool_create_buffer (self->wl_pool, offset, width, height,
-      stride, format);
-  gst_buffer_add_wl_buffer (*buffer, wbuffer, self->display);
-
-  return GST_FLOW_OK;
-
-  /* ERROR */
-no_buffer:
-  {
-    GST_WARNING_OBJECT (pool, "can't create buffer");
-    return GST_FLOW_ERROR;
-  }
-}
-
-GstBufferPool *
-gst_wayland_buffer_pool_new (GstWlDisplay * display)
-{
-  GstWaylandBufferPool *pool;
-
-  g_return_val_if_fail (GST_IS_WL_DISPLAY (display), NULL);
-  pool = g_object_new (GST_TYPE_WAYLAND_BUFFER_POOL, NULL);
-  pool->display = g_object_ref (display);
-
-  return GST_BUFFER_POOL_CAST (pool);
-}
diff --git a/ext/wayland/waylandpool.h b/ext/wayland/waylandpool.h
deleted file mode 100644 (file)
index e0944d0..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* GStreamer Wayland buffer pool
- * Copyright (C) 2012 Intel Corporation
- * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
- * Copyright (C) 2014 Collabora Ltd.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef __GST_WAYLAND_BUFFER_POOL_H__
-#define __GST_WAYLAND_BUFFER_POOL_H__
-
-#include <gst/video/video.h>
-
-#include "wldisplay.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_WAYLAND_BUFFER_POOL      (gst_wayland_buffer_pool_get_type())
-#define GST_IS_WAYLAND_BUFFER_POOL(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WAYLAND_BUFFER_POOL))
-#define GST_WAYLAND_BUFFER_POOL(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WAYLAND_BUFFER_POOL, GstWaylandBufferPool))
-#define GST_WAYLAND_BUFFER_POOL_CAST(obj) ((GstWaylandBufferPool*)(obj))
-
-typedef struct _GstWaylandBufferPool GstWaylandBufferPool;
-typedef struct _GstWaylandBufferPoolClass GstWaylandBufferPoolClass;
-
-/* buffer pool */
-struct _GstWaylandBufferPool
-{
-  GstBufferPool bufferpool;
-  GstWlDisplay *display;
-
-  /* external configuration */
-  GstVideoInfo info;
-
-  /* allocation data */
-  struct wl_shm_pool *wl_pool;
-  size_t size;
-  size_t used;
-  void *data;
-};
-
-struct _GstWaylandBufferPoolClass
-{
-  GstBufferPoolClass parent_class;
-};
-
-GType gst_wayland_buffer_pool_get_type (void);
-
-GstBufferPool *gst_wayland_buffer_pool_new (GstWlDisplay * display);
-
-G_END_DECLS
-
-#endif /*__GST_WAYLAND_BUFFER_POOL_H__*/
diff --git a/ext/wayland/wlshmallocator.c b/ext/wayland/wlshmallocator.c
new file mode 100644 (file)
index 0000000..78d6334
--- /dev/null
@@ -0,0 +1,181 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2012 Intel Corporation
+ * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "wlshmallocator.h"
+#include "wlvideoformat.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
+#define GST_CAT_DEFAULT gstwayland_debug
+
+G_DEFINE_TYPE (GstWlShmAllocator, gst_wl_shm_allocator, GST_TYPE_ALLOCATOR);
+
+static GstMemory *
+gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size,
+    GstAllocationParams * params)
+{
+  GstWlShmAllocator *self = GST_WL_SHM_ALLOCATOR (allocator);
+  char filename[1024];
+  static int init = 0;
+  int fd;
+  gpointer data;
+  GstWlShmMemory *mem;
+
+  /* TODO: make use of the allocation params, if necessary */
+
+  /* allocate shm pool */
+  snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
+      "wayland-shm", init++, "XXXXXX");
+
+  fd = mkstemp (filename);
+  if (fd < 0) {
+    GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename,
+        strerror (errno));
+    return NULL;
+  }
+  if (ftruncate (fd, size) < 0) {
+    GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno));
+    close (fd);
+    return NULL;
+  }
+
+  data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (data == MAP_FAILED) {
+    GST_ERROR_OBJECT (self, "mmap failed: %s", strerror (errno));
+    close (fd);
+    return NULL;
+  }
+
+  unlink (filename);
+
+  mem = g_slice_new0 (GstWlShmMemory);
+  gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL,
+      size, 0, 0, size);
+  mem->data = data;
+  mem->fd = fd;
+
+  return (GstMemory *) mem;
+}
+
+static void
+gst_wl_shm_allocator_free (GstAllocator * allocator, GstMemory * memory)
+{
+  GstWlShmMemory *shm_mem = (GstWlShmMemory *) memory;
+
+  if (shm_mem->fd != -1)
+    close (shm_mem->fd);
+  munmap (shm_mem->data, memory->maxsize);
+
+  g_slice_free (GstWlShmMemory, shm_mem);
+}
+
+static gpointer
+gst_wl_shm_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
+{
+  return ((GstWlShmMemory *) mem)->data;
+}
+
+static void
+gst_wl_shm_mem_unmap (GstMemory * mem)
+{
+}
+
+static void
+gst_wl_shm_allocator_class_init (GstWlShmAllocatorClass * klass)
+{
+  GstAllocatorClass *alloc_class = (GstAllocatorClass *) klass;
+
+  alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_alloc);
+  alloc_class->free = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_free);
+}
+
+static void
+gst_wl_shm_allocator_init (GstWlShmAllocator * self)
+{
+  self->parent_instance.mem_type = GST_ALLOCATOR_WL_SHM;
+  self->parent_instance.mem_map = gst_wl_shm_mem_map;
+  self->parent_instance.mem_unmap = gst_wl_shm_mem_unmap;
+
+  GST_OBJECT_FLAG_SET (self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
+}
+
+void
+gst_wl_shm_allocator_register (void)
+{
+  gst_allocator_register (GST_ALLOCATOR_WL_SHM,
+      g_object_new (GST_TYPE_WL_SHM_ALLOCATOR, NULL));
+}
+
+GstAllocator *
+gst_wl_shm_allocator_get (void)
+{
+  return gst_allocator_find (GST_ALLOCATOR_WL_SHM);
+}
+
+gboolean
+gst_is_wl_shm_memory (GstMemory * mem)
+{
+  return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM);
+}
+
+struct wl_buffer *
+gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display,
+    const GstVideoInfo * info)
+{
+  GstWlShmMemory *shm_mem = (GstWlShmMemory *) mem;
+  gint width, height, stride;
+  gsize size;
+  enum wl_shm_format format;
+  struct wl_shm_pool *wl_pool;
+  struct wl_buffer *wbuffer;
+
+  width = GST_VIDEO_INFO_WIDTH (info);
+  height = GST_VIDEO_INFO_HEIGHT (info);
+  stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
+  size = GST_VIDEO_INFO_SIZE (info);
+  format = gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT (info));
+
+  g_return_val_if_fail (gst_is_wl_shm_memory (mem), NULL);
+  g_return_val_if_fail (size <= mem->size, NULL);
+  g_return_val_if_fail (shm_mem->fd != -1, NULL);
+
+  GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
+      G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height,
+      stride, gst_wayland_format_to_string (format));
+
+  wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size);
+  wbuffer = wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride,
+      format);
+
+  close (shm_mem->fd);
+  shm_mem->fd = -1;
+  wl_shm_pool_destroy (wl_pool);
+
+  return wbuffer;
+}
diff --git a/ext/wayland/wlshmallocator.h b/ext/wayland/wlshmallocator.h
new file mode 100644 (file)
index 0000000..f12882c
--- /dev/null
@@ -0,0 +1,74 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2012 Intel Corporation
+ * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WL_SHM_ALLOCATOR_H__
+#define __GST_WL_SHM_ALLOCATOR_H__
+
+#include <gst/video/video.h>
+#include <wayland-client-protocol.h>
+#include "wldisplay.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_WL_SHM_ALLOCATOR                  (gst_wl_shm_allocator_get_type ())
+#define GST_WL_SHM_ALLOCATOR(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocator))
+#define GST_IS_WL_SHM_ALLOCATOR(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_SHM_ALLOCATOR))
+#define GST_WL_SHM_ALLOCATOR_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocatorClass))
+#define GST_IS_WL_SHM_ALLOCATOR_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_SHM_ALLOCATOR))
+#define GST_WL_SHM_ALLOCATOR_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocatorClass))
+
+#define GST_ALLOCATOR_WL_SHM "wl_shm"
+
+typedef struct _GstWlShmMemory GstWlShmMemory;
+typedef struct _GstWlShmAllocator GstWlShmAllocator;
+typedef struct _GstWlShmAllocatorClass GstWlShmAllocatorClass;
+
+struct _GstWlShmMemory
+{
+  GstMemory parent;
+
+  gpointer data;
+  gint fd;
+};
+
+struct _GstWlShmAllocator
+{
+  GstAllocator parent_instance;
+};
+
+struct _GstWlShmAllocatorClass
+{
+  GstAllocatorClass parent_class;
+};
+
+GType gst_wl_shm_allocator_get_type (void);
+
+void gst_wl_shm_allocator_register (void);
+GstAllocator * gst_wl_shm_allocator_get (void);
+
+gboolean gst_is_wl_shm_memory (GstMemory * mem);
+struct wl_buffer * gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem,
+    GstWlDisplay * display, const GstVideoInfo * info);
+
+G_END_DECLS
+
+#endif /* __GST_WL_SHM_ALLOCATOR_H__ */