diff options
author | Sreerenj Balachandran <sreerenj.balachandran@intel.com> | 2012-08-08 17:10:28 +0300 |
---|---|---|
committer | Tim-Philipp Müller <tim@centricular.net> | 2012-08-21 10:24:45 +0100 |
commit | c803ca4af55520e8eb7c69911491ae118c3a4fd8 (patch) | |
tree | 15259e2cbc174dbd126692e0fdbf8f5b8c00c120 /ext/wayland | |
parent | 38c749ca2fee21d66ff6bae848146007fbd0e52e (diff) | |
download | gstreamer-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.am | 4 | ||||
-rw-r--r-- | ext/wayland/gstwaylandsink.c | 362 | ||||
-rw-r--r-- | ext/wayland/gstwaylandsink.h | 38 | ||||
-rw-r--r-- | ext/wayland/waylandpool.c | 311 | ||||
-rw-r--r-- | ext/wayland/waylandpool.h | 79 |
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, ¶ms); + 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__*/ |