summaryrefslogtreecommitdiff
path: root/ext/wayland
diff options
context:
space:
mode:
authorSreerenj Balachandran <sreerenj.balachandran@intel.com>2012-08-08 17:10:28 +0300
committerTim-Philipp Müller <tim@centricular.net>2012-08-21 10:24:45 +0100
commitc803ca4af55520e8eb7c69911491ae118c3a4fd8 (patch)
tree15259e2cbc174dbd126692e0fdbf8f5b8c00c120 /ext/wayland
parent38c749ca2fee21d66ff6bae848146007fbd0e52e (diff)
downloadgstreamer-plugins-bad-c803ca4af55520e8eb7c69911491ae118c3a4fd8.tar.gz
wayland: More fixes based on wayland-0.95.0 and gstreamer-1.0 apis
- bump wayland version to 0.95.0 which will lead to stable 1.0 release - avoid memcopy and use propose_allocation for GstBufferPool allocation - using WaylandBufferPool - shm: Allocate shm buffers through new wl_shm_pool interface (the shm buffer allocation is a two step process now: first allocate a wl_shm_pool, then allocate a buffer from the pool) https://bugzilla.gnome.org/show_bug.cgi?id=681453
Diffstat (limited to 'ext/wayland')
-rw-r--r--ext/wayland/Makefile.am4
-rw-r--r--ext/wayland/gstwaylandsink.c362
-rw-r--r--ext/wayland/gstwaylandsink.h38
-rw-r--r--ext/wayland/waylandpool.c311
-rw-r--r--ext/wayland/waylandpool.h79
5 files changed, 626 insertions, 168 deletions
diff --git a/ext/wayland/Makefile.am b/ext/wayland/Makefile.am
index e346b4c6c..dfdcf2105 100644
--- a/ext/wayland/Makefile.am
+++ b/ext/wayland/Makefile.am
@@ -1,6 +1,6 @@
plugin_LTLIBRARIES = libgstwaylandsink.la
-libgstwaylandsink_la_SOURCES = gstwaylandsink.c
+libgstwaylandsink_la_SOURCES = gstwaylandsink.c waylandpool.c
libgstwaylandsink_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
$(WAYLAND_CFLAGS)
libgstwaylandsink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
@@ -9,4 +9,4 @@ libgstwaylandsink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
libgstwaylandsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstwaylandsink_la_LIBTOOLFLAGS = --tag=disable-static
-noinst_HEADERS = gstwaylandsink.h
+noinst_HEADERS = gstwaylandsink.h waylandpool.h
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index a1af0aea8..e82a524ea 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -1,5 +1,4 @@
-/*
- * GStreamer Wayland video sink
+/* GStreamer Wayland video sink
*
* Copyright (C) 2011 Intel Corporation
* Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
@@ -47,7 +46,6 @@
enum
{
SIGNAL_0,
- SIGNAL_FRAME_READY,
LAST_SIGNAL
};
@@ -73,44 +71,6 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
#define gst_wayland_sink_parent_class parent_class
G_DEFINE_TYPE (GstWaylandSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK);
-/* wl metadata */
-GType
-gst_wl_meta_api_get_type (void)
-{
- static volatile GType type;
- static const gchar *tags[] =
- { "memory", "size", "colorspace", "orientation", NULL };
-
- if (g_once_init_enter (&type)) {
- GType _type = gst_meta_api_type_register ("GstWlMetaAPI", tags);
- g_once_init_leave (&type, _type);
- }
- return type;
-}
-
-static void
-gst_wl_meta_free (GstWlMeta * meta, GstBuffer * buffer)
-{
- gst_object_unref (meta->sink);
- munmap (meta->data, meta->size);
- wl_buffer_destroy (meta->wbuffer);
-}
-
-const GstMetaInfo *
-gst_wl_meta_get_info (void)
-{
- static const GstMetaInfo *wl_meta_info = NULL;
-
- if (wl_meta_info == NULL) {
- wl_meta_info =
- gst_meta_register (GST_WL_META_API_TYPE, "GstWlMeta",
- sizeof (GstWlMeta), (GstMetaInitFunction) NULL,
- (GstMetaFreeFunction) gst_wl_meta_free,
- (GstMetaTransformFunction) NULL);
- }
- return wl_meta_info;
-}
-
static void gst_wayland_sink_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_wayland_sink_set_property (GObject * object,
@@ -123,6 +83,8 @@ static gboolean gst_wayland_sink_start (GstBaseSink * bsink);
static gboolean gst_wayland_sink_stop (GstBaseSink * bsink);
static gboolean gst_wayland_sink_preroll (GstBaseSink * bsink,
GstBuffer * buffer);
+static gboolean
+gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query);
static gboolean gst_wayland_sink_render (GstBaseSink * bsink,
GstBuffer * buffer);
@@ -130,9 +92,11 @@ static int event_mask_update (uint32_t mask, void *data);
static struct display *create_display (void);
static void display_handle_global (struct wl_display *display, uint32_t id,
const char *interface, uint32_t version, void *data);
-static void redraw (void *data, struct wl_callback *callback, uint32_t time);
+static void frame_redraw_callback (void *data, struct wl_callback *callback,
+ uint32_t time);
static void create_window (GstWaylandSink * sink, struct display *display,
int width, int height);
+static void shm_pool_destroy (struct shm_pool *pool);
static void
gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
@@ -162,6 +126,8 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_wayland_sink_start);
gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_wayland_sink_stop);
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_wayland_sink_preroll);
+ gstbasesink_class->propose_allocation =
+ GST_DEBUG_FUNCPTR (gst_wayland_sink_propose_allocation);
gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_wayland_sink_render);
g_object_class_install_property (gobject_class, PROP_WAYLAND_DISPLAY,
@@ -173,9 +139,10 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
static void
gst_wayland_sink_init (GstWaylandSink * sink)
{
- sink->render_busy = FALSE;
sink->display = NULL;
sink->window = NULL;
+ sink->shm_pool = NULL;
+ sink->pool = NULL;
g_mutex_init (&sink->wayland_lock);
}
@@ -225,21 +192,37 @@ destroy_display (struct display *display)
wl_compositor_destroy (display->compositor);
wl_display_flush (display->display);
- wl_display_destroy (display->display);
+ wl_display_disconnect (display->display);
free (display);
}
static void
destroy_window (struct window *window)
{
+ if (window->callback)
+ wl_callback_destroy (window->callback);
+
+ if (window->buffer)
+ wl_buffer_destroy (window->buffer);
+
if (window->shell_surface)
wl_shell_surface_destroy (window->shell_surface);
+
if (window->surface)
wl_surface_destroy (window->surface);
+
free (window);
}
static void
+shm_pool_destroy (struct shm_pool *pool)
+{
+ munmap (pool->data, pool->size);
+ wl_shm_pool_destroy (pool->pool);
+ free (pool);
+}
+
+static void
gst_wayland_sink_finalize (GObject * object)
{
GstWaylandSink *sink = GST_WAYLAND_SINK (object);
@@ -250,6 +233,8 @@ gst_wayland_sink_finalize (GObject * object)
destroy_window (sink->window);
if (sink->display)
destroy_display (sink->display);
+ if (sink->shm_pool)
+ shm_pool_destroy (sink->shm_pool);
g_mutex_clear (&sink->wayland_lock);
@@ -259,7 +244,21 @@ gst_wayland_sink_finalize (GObject * object)
static GstCaps *
gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
{
- return gst_static_pad_template_get_caps (&sink_template);
+ GstWaylandSink *sink;
+ GstCaps *caps;
+
+ sink = GST_WAYLAND_SINK (bsink);
+
+ caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
+ return caps;
}
static int
@@ -308,7 +307,7 @@ create_display (void)
display = malloc (sizeof *display);
display->display = wl_display_connect (NULL);
- assert (display->display);
+ g_return_val_if_fail (display->display, NULL);
wl_display_add_global_listener (display->display,
display_handle_global, display);
@@ -326,93 +325,63 @@ create_display (void)
return display;
}
-static GstBuffer *
-wayland_buffer_create (GstWaylandSink * sink)
-{
- char filename[1024];
- int fd, size, stride;
- static void *data;
- static int init = 0;
- GstBuffer *buffer;
- GstWlMeta *wmeta;
-
- GST_DEBUG_OBJECT (sink, "Creating wayland-shm buffers");
-
- snprintf (filename, 256, "%s-%d-%s", "/tmp/wayland-shm", init++, "XXXXXX");
-
- fd = mkstemp (filename);
- if (fd < 0) {
- GST_ERROR_OBJECT (sink, "open %s failed:", filename);
- return NULL;
- }
-
- stride = sink->video_width * 4;
- size = stride * sink->video_height;
-
- if (ftruncate (fd, size) < 0) {
- GST_ERROR_OBJECT (sink, "ftruncate failed:");
- close (fd);
- return NULL;
- }
-
- data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- unlink (filename);
- if (data == MAP_FAILED) {
- GST_ELEMENT_ERROR (sink, LIBRARY, SHUTDOWN, (NULL),
- ("mmap() failed: %s", strerror (errno)));
- close (fd);
- return NULL;
- }
-
- buffer = gst_buffer_new ();
-
- wmeta = (GstWlMeta *) gst_buffer_add_meta (buffer, GST_WL_META_INFO, NULL);
- wmeta->sink = gst_object_ref (sink);
- wmeta->wbuffer = wl_shm_create_buffer (sink->display->shm, fd,
- sink->video_width, sink->video_height, stride, WL_SHM_FORMAT_XRGB8888);
- wmeta->data = data;
- wmeta->size = size;
-
- close (fd);
-
- gst_buffer_append_memory (buffer,
- gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data,
- size, 0, size, NULL, NULL));
-
- return buffer;
-}
-
static gboolean
gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
{
GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
- const GstStructure *structure;
- gboolean ret = TRUE;
+ GstBufferPool *newpool, *oldpool;
+ GstVideoInfo info;
+ GstStructure *structure;
+ static GstAllocationParams params = { 0, 0, 0, 15, };
+ guint size;
+
+ sink = GST_WAYLAND_SINK (bsink);
GST_LOG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
- structure = gst_caps_get_structure (caps, 0);
+ if (!gst_video_info_from_caps (&info, caps))
+ goto invalid_format;
- ret &= gst_structure_get_int (structure, "width", &sink->video_width);
- ret &= gst_structure_get_int (structure, "height", &sink->video_height);
+ sink->video_width = info.width;
+ sink->video_height = info.height;
+ size = info.size;
- if (!ret)
- return FALSE;
+ /* create a new pool for the new configuration */
+ newpool = gst_wayland_buffer_pool_new (sink);
- return TRUE;
-}
+ if (!newpool) {
+ GST_DEBUG_OBJECT (sink, "Failed to create new pool");
+ return FALSE;
+ }
-static const struct wl_callback_listener frame_listener;
+ structure = gst_buffer_pool_get_config (newpool);
+ gst_buffer_pool_config_set_params (structure, caps, size, 2, 0);
+ gst_buffer_pool_config_set_allocator (structure, NULL, &params);
+ if (!gst_buffer_pool_set_config (newpool, structure))
+ goto config_failed;
-static void
-redraw (void *data, struct wl_callback *callback, uint32_t time)
-{
+ oldpool = sink->pool;
+ sink->pool = newpool;
+ if (oldpool)
+ gst_object_unref (oldpool);
- GstWaylandSink *sink = (GstWaylandSink *) data;
+ return TRUE;
- sink->render_busy = FALSE;
+invalid_format:
+ {
+ GST_DEBUG_OBJECT (sink,
+ "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
+ return FALSE;
+ }
+config_failed:
+ {
+ GST_DEBUG_OBJECT (bsink, "failed setting config");
+ return FALSE;
+ }
}
+static const struct wl_callback_listener frame_callback_listener;
+
static void
create_window (GstWaylandSink * sink, struct display *display, int width,
int height)
@@ -428,15 +397,15 @@ create_window (GstWaylandSink * sink, struct display *display, int width,
window->display = display;
window->width = width;
window->height = height;
+ window->redraw_pending = FALSE;
+
window->surface = wl_compositor_create_surface (display->compositor);
window->shell_surface = wl_shell_get_shell_surface (display->shell,
window->surface);
- /* wl_shell_surface_set_toplevel (window->shell_surface); */
-#ifdef WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT
+ wl_shell_surface_set_toplevel (window->shell_surface);
wl_shell_surface_set_fullscreen (window->shell_surface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL);
-#endif
sink->window = window;
@@ -467,6 +436,84 @@ gst_wayland_sink_stop (GstBaseSink * bsink)
return TRUE;
}
+static gboolean
+gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
+{
+ GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
+ GstBufferPool *pool;
+ GstStructure *config;
+ GstCaps *caps;
+ guint size;
+ gboolean need_pool;
+
+ gst_query_parse_allocation (query, &caps, &need_pool);
+
+ if (caps == NULL)
+ goto no_caps;
+
+ g_mutex_lock (&sink->wayland_lock);
+ if ((pool = sink->pool))
+ gst_object_ref (pool);
+ g_mutex_unlock (&sink->wayland_lock);
+
+ 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);
+ }
+
+ 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);
+
+ /* 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);
+ }
+
+ 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
gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
{
@@ -474,6 +521,18 @@ gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
return gst_wayland_sink_render (bsink, buffer);
}
+static void
+frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct window *window = (struct window *) data;
+ window->redraw_pending = FALSE;
+ wl_callback_destroy (callback);
+}
+
+static const struct wl_callback_listener frame_callback_listener = {
+ frame_redraw_callback
+};
+
static GstFlowReturn
gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
{
@@ -481,14 +540,21 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
GstVideoRectangle src, dst, res;
GstBuffer *to_render;
GstWlMeta *meta;
+ GstFlowReturn ret;
+ struct window *window;
+ struct display *display;
GST_LOG_OBJECT (sink, "render buffer %p", buffer);
-
if (!sink->window)
create_window (sink, sink->display, sink->video_width, sink->video_height);
- if (sink->render_busy)
- goto was_busy;
+ window = sink->window;
+ display = sink->display;
+
+ /* Wait for the previous frame to complete redraw */
+ if (window->redraw_pending) {
+ wl_display_iterate (display->display, WL_DISPLAY_READABLE);
+ }
meta = gst_buffer_get_wl_meta (buffer);
@@ -497,10 +563,17 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
to_render = buffer;
} else {
GstMapInfo src;
-
GST_LOG_OBJECT (sink, "buffer %p not from our pool, copying", buffer);
- to_render = wayland_buffer_create (sink);
+ if (!sink->pool)
+ goto no_pool;
+
+ if (!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;
gst_buffer_map (buffer, &src, GST_MAP_READ);
gst_buffer_fill (to_render, 0, src.data, src.size);
@@ -516,36 +589,37 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
gst_video_sink_center_rect (src, dst, &res, FALSE);
- sink->render_busy = TRUE;
-
- wl_buffer_damage (meta->wbuffer, 0, 0, res.w, res.h);
wl_surface_attach (sink->window->surface, meta->wbuffer, 0, 0);
wl_surface_damage (sink->window->surface, 0, 0, res.w, res.h);
-
- if (sink->callback)
- wl_callback_destroy (sink->callback);
-
- sink->callback = wl_surface_frame (sink->window->surface);
- wl_callback_add_listener (sink->callback, &frame_listener, sink);
- wl_display_iterate (sink->display->display, sink->display->mask);
+ wl_display_iterate (display->display, WL_DISPLAY_WRITABLE);
+ window->redraw_pending = TRUE;
+ window->callback = wl_surface_frame (window->surface);
+ wl_callback_add_listener (window->callback, &frame_callback_listener, window);
if (buffer != to_render)
gst_buffer_unref (to_render);
-
return GST_FLOW_OK;
-was_busy:
+no_buffer:
+ {
+ GST_WARNING_OBJECT (sink, "could not create image");
+ return ret;
+ }
+no_pool:
{
- GST_LOG_OBJECT (sink,
- "Waiting to get the signal from compositor to render the next frame..");
- return GST_FLOW_OK;
+ GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
+ ("Internal error: can't allocate images"),
+ ("We don't have a bufferpool negotiated"));
+ return GST_FLOW_ERROR;
+ }
+activate_failed:
+ {
+ GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
+ ret = GST_FLOW_ERROR;
+ return ret;
}
}
-static const struct wl_callback_listener frame_listener = {
- redraw
-};
-
static gboolean
plugin_init (GstPlugin * plugin)
{
diff --git a/ext/wayland/gstwaylandsink.h b/ext/wayland/gstwaylandsink.h
index abef5e6f0..1a278e91c 100644
--- a/ext/wayland/gstwaylandsink.h
+++ b/ext/wayland/gstwaylandsink.h
@@ -38,6 +38,7 @@
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideosink.h>
+#include <gst/video/gstvideometa.h>
#include <wayland-client.h>
@@ -70,29 +71,23 @@ struct window
int width, height;
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
+ struct wl_buffer *buffer;
+ struct wl_callback *callback;
+ guint redraw_pending :1;
+
+};
+
+struct shm_pool {
+ struct wl_shm_pool *pool;
+ size_t size;
+ size_t used;
+ void *data;
};
typedef struct _GstWaylandSink GstWaylandSink;
typedef struct _GstWaylandSinkClass GstWaylandSinkClass;
-typedef struct _GstWlMeta GstWlMeta;
-
-GType gst_wl_meta_api_get_type (void);
-#define GST_WL_META_API_TYPE (gst_wl_meta_api_get_type())
-const GstMetaInfo * gst_wl_meta_get_info (void);
-#define GST_WL_META_INFO (gst_wl_meta_get_info())
-
-#define gst_buffer_get_wl_meta(b) ((GstWlMeta*)gst_buffer_get_meta((b),GST_WL_META_API_TYPE))
-
-struct _GstWlMeta {
- GstMeta meta;
-
- GstWaylandSink *sink;
-
- struct wl_buffer *wbuffer;
- void *data;
- size_t size;
-};
+#include "waylandpool.h"
struct _GstWaylandSink
{
@@ -100,15 +95,14 @@ struct _GstWaylandSink
struct display *display;
struct window *window;
- struct wl_callback *callback;
+ struct shm_pool *shm_pool;
+
+ GstBufferPool *pool;
GMutex wayland_lock;
gint video_width;
gint video_height;
- guint bpp;
-
- gboolean render_busy;
};
struct _GstWaylandSinkClass
diff --git a/ext/wayland/waylandpool.c b/ext/wayland/waylandpool.c
new file mode 100644
index 000000000..dd12d1005
--- /dev/null
+++ b/ext/wayland/waylandpool.c
@@ -0,0 +1,311 @@
+/* GStreamer
+ * Copyright (C) 2012 Intel Corporation
+ * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+
+ * 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 "gstwaylandsink.h"
+
+/* Debugging category */
+#include <gst/gstinfo.h>
+
+/* Helper functions */
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+
+/* wl metadata */
+GType
+gst_wl_meta_api_get_type (void)
+{
+ static volatile GType type;
+ static const gchar *tags[] =
+ { "memory", "size", "colorspace", "orientation", NULL };
+
+ if (g_once_init_enter (&type)) {
+ GType _type = gst_meta_api_type_register ("GstWlMetaAPI", tags);
+ g_once_init_leave (&type, _type);
+ }
+ return type;
+}
+
+static void
+gst_wl_meta_free (GstWlMeta * meta, GstBuffer * buffer)
+{
+ gst_object_unref (meta->sink);
+ munmap (meta->data, meta->size);
+ wl_buffer_destroy (meta->wbuffer);
+}
+
+const GstMetaInfo *
+gst_wl_meta_get_info (void)
+{
+ static const GstMetaInfo *wl_meta_info = NULL;
+
+ if (wl_meta_info == NULL) {
+ wl_meta_info =
+ gst_meta_register (GST_WL_META_API_TYPE, "GstWlMeta",
+ sizeof (GstWlMeta), (GstMetaInitFunction) NULL,
+ (GstMetaFreeFunction) gst_wl_meta_free,
+ (GstMetaTransformFunction) NULL);
+ }
+ return wl_meta_info;
+}
+
+/* bufferpool */
+static void gst_wayland_buffer_pool_finalize (GObject * object);
+
+#define gst_wayland_buffer_pool_parent_class parent_class
+G_DEFINE_TYPE (GstWaylandBufferPool, gst_wayland_buffer_pool,
+ GST_TYPE_BUFFER_POOL);
+
+static gboolean
+wayland_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
+{
+ GstWaylandBufferPool *wpool = GST_WAYLAND_BUFFER_POOL_CAST (pool);
+ GstVideoInfo info;
+ 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 (&info, caps))
+ goto wrong_caps;
+
+ GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
+ caps);
+
+ /*Fixme: Enable metadata checking handling based on the config of pool */
+
+ wpool->caps = gst_caps_ref (caps);
+ wpool->info = info;
+ wpool->width = info.width;
+ wpool->height = info.height;
+
+ 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 struct wl_shm_pool *
+make_shm_pool (struct display *display, int size, void **data)
+{
+ struct wl_shm_pool *pool;
+ int fd;
+ char filename[1024];
+ static int init = 0;
+
+ snprintf (filename, 256, "%s-%d-%s", "/tmp/wayland-shm", init++, "XXXXXX");
+
+ fd = mkstemp (filename);
+ if (fd < 0) {
+ GST_ERROR ("open %s failed:", filename);
+ return NULL;
+ }
+ if (ftruncate (fd, size) < 0) {
+ GST_ERROR ("ftruncate failed:..!");
+ close (fd);
+ return NULL;
+ }
+
+ *data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (*data == MAP_FAILED) {
+ GST_ERROR ("mmap failed: ");
+ close (fd);
+ return NULL;
+ }
+
+ pool = wl_shm_create_pool (display->shm, fd, size);
+
+ close (fd);
+
+ return pool;
+}
+
+static struct shm_pool *
+shm_pool_create (struct display *display, size_t size)
+{
+ struct shm_pool *pool = malloc (sizeof *pool);
+
+ if (!pool)
+ return NULL;
+
+ pool->pool = make_shm_pool (display, size, &pool->data);
+ if (!pool->pool) {
+ free (pool);
+ return NULL;
+ }
+
+ pool->size = size;
+ pool->used = 0;
+
+ return pool;
+}
+
+static void *
+shm_pool_allocate (struct shm_pool *pool, size_t size, int *offset)
+{
+ if (pool->used + size > pool->size)
+ return NULL;
+
+ *offset = pool->used;
+ pool->used += size;
+
+ return (char *) pool->data + *offset;
+}
+
+/* Start allocating from the beginning of the pool again */
+static void
+shm_pool_reset (struct shm_pool *pool)
+{
+ pool->used = 0;
+}
+
+static GstWlMeta *
+gst_buffer_add_wayland_meta (GstBuffer * buffer, GstWaylandBufferPool * wpool)
+{
+ GstWlMeta *wmeta;
+ GstWaylandSink *sink;
+ void *data;
+ gint offset;
+ guint stride = 0;
+ guint size = 0;
+
+ sink = wpool->sink;
+ stride = wpool->width * 4;
+ size = stride * wpool->height;
+
+ wmeta = (GstWlMeta *) gst_buffer_add_meta (buffer, GST_WL_META_INFO, NULL);
+ wmeta->sink = gst_object_ref (sink);
+
+ /*Fixme: size calculation should be more grcefull, have to consider the padding */
+ if (!sink->shm_pool) {
+ sink->shm_pool = shm_pool_create (sink->display, size * 15);
+ shm_pool_reset (sink->shm_pool);
+ }
+
+ if (!sink->shm_pool) {
+ GST_ERROR ("Failed to create shm_pool");
+ return NULL;
+ }
+
+ data = shm_pool_allocate (sink->shm_pool, size, &offset);
+ if (!data)
+ return NULL;
+
+ wmeta->wbuffer = wl_shm_pool_create_buffer (sink->shm_pool->pool, offset,
+ sink->video_width, sink->video_height, stride, WL_SHM_FORMAT_XRGB8888);
+
+ wmeta->data = data;
+ wmeta->size = size;
+
+ gst_buffer_append_memory (buffer,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data,
+ size, 0, size, NULL, NULL));
+
+
+ return wmeta;
+}
+
+static GstFlowReturn
+wayland_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
+ GstBufferPoolAcquireParams * params)
+{
+ GstWaylandBufferPool *w_pool = GST_WAYLAND_BUFFER_POOL_CAST (pool);
+ GstBuffer *w_buffer;
+ GstWlMeta *meta;
+
+ w_buffer = gst_buffer_new ();
+ meta = gst_buffer_add_wayland_meta (w_buffer, w_pool);
+ if (meta == NULL) {
+ gst_buffer_unref (w_buffer);
+ goto no_buffer;
+ }
+ *buffer = w_buffer;
+
+ 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 (GstWaylandSink * waylandsink)
+{
+ GstWaylandBufferPool *pool;
+
+ g_return_val_if_fail (GST_IS_WAYLAND_SINK (waylandsink), NULL);
+ pool = g_object_new (GST_TYPE_WAYLAND_BUFFER_POOL, NULL);
+ pool->sink = gst_object_ref (waylandsink);
+
+ return GST_BUFFER_POOL_CAST (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 = wayland_buffer_pool_set_config;
+ gstbufferpool_class->alloc_buffer = wayland_buffer_pool_alloc;
+}
+
+static void
+gst_wayland_buffer_pool_init (GstWaylandBufferPool * pool)
+{
+}
+
+static void
+gst_wayland_buffer_pool_finalize (GObject * object)
+{
+ GstWaylandBufferPool *pool = GST_WAYLAND_BUFFER_POOL_CAST (object);
+
+ gst_object_unref (pool->sink);
+
+ G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object);
+}
diff --git a/ext/wayland/waylandpool.h b/ext/wayland/waylandpool.h
new file mode 100644
index 000000000..c1821d0a6
--- /dev/null
+++ b/ext/wayland/waylandpool.h
@@ -0,0 +1,79 @@
+/* GStreamer Wayland buffer pool
+ * Copyright (C) 2012 Intel Corporation
+ * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ * 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_WAYLAND_BUFFER_POOL_H__
+#define __GST_WAYLAND_BUFFER_POOL_H__
+
+G_BEGIN_DECLS
+
+#include "gstwaylandsink.h"
+typedef struct _GstWlMeta GstWlMeta;
+
+typedef struct _GstWaylandBufferPool GstWaylandBufferPool;
+typedef struct _GstWaylandBufferPoolClass GstWaylandBufferPoolClass;
+
+GType gst_wl_meta_api_get_type (void);
+#define GST_WL_META_API_TYPE (gst_wl_meta_api_get_type())
+const GstMetaInfo * gst_wl_meta_get_info (void);
+#define GST_WL_META_INFO (gst_wl_meta_get_info())
+
+#define gst_buffer_get_wl_meta(b) ((GstWlMeta*)gst_buffer_get_meta((b),GST_WL_META_API_TYPE))
+
+struct _GstWlMeta {
+ GstMeta meta;
+
+ GstWaylandSink *sink;
+
+ struct wl_buffer *wbuffer;
+ void *data;
+ size_t size;
+};
+
+/* buffer pool functions */
+#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))
+
+struct _GstWaylandBufferPool
+{
+ GstBufferPool bufferpool;
+
+ GstWaylandSink *sink;
+
+ /*Fixme: keep all these in GstWaylandBufferPoolPrivate*/
+ GstCaps *caps;
+ GstVideoInfo info;
+ guint width;
+ guint height;
+};
+
+struct _GstWaylandBufferPoolClass
+{
+ GstBufferPoolClass parent_class;
+};
+
+GType gst_wayland_buffer_pool_get_type (void);
+
+GstBufferPool *gst_wayland_buffer_pool_new (GstWaylandSink * waylandsink);
+
+G_END_DECLS
+
+#endif /*__GST_WAYLAND_BUFFER_POOL_H__*/