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
This commit is contained in:
Sreerenj Balachandran 2012-08-08 17:10:28 +03:00 committed by Tim-Philipp Müller
parent 38c749ca2f
commit c803ca4af5
6 changed files with 628 additions and 170 deletions

View file

@ -898,7 +898,7 @@ AG_GST_CHECK_FEATURE(DIRECTFB, [directfb], dfbvideosink , [
dnl **** Wayland **** dnl **** Wayland ****
translit(dnm, m, l) AM_CONDITIONAL(USE_WAYLAND, true) translit(dnm, m, l) AM_CONDITIONAL(USE_WAYLAND, true)
AG_GST_CHECK_FEATURE(WAYLAND, [wayland sink], wayland , [ AG_GST_CHECK_FEATURE(WAYLAND, [wayland sink], wayland , [
PKG_CHECK_MODULES(WAYLAND, wayland-server <= 0.85.0 wayland-client <= 0.85.0, [ PKG_CHECK_MODULES(WAYLAND, wayland-server >= 0.95.0 wayland-client >= 0.95.0, [
AC_CHECK_HEADER(wayland-client.h, HAVE_WAYLAND_CLIENT="yes", HAVE_WAYLAND_CLIENT="no") AC_CHECK_HEADER(wayland-client.h, HAVE_WAYLAND_CLIENT="yes", HAVE_WAYLAND_CLIENT="no")
AC_CHECK_HEADER(wayland-client-protocol.h, HAVE_WAYLAND_CLIENT_PROTOCOL="yes", HAVE_WAYLAND_CLIENT_PROTOCOL="no") AC_CHECK_HEADER(wayland-client-protocol.h, HAVE_WAYLAND_CLIENT_PROTOCOL="yes", HAVE_WAYLAND_CLIENT_PROTOCOL="no")
if test "x$HAVE_WAYLAND_CLIENT" = "xno"; then if test "x$HAVE_WAYLAND_CLIENT" = "xno"; then

View file

@ -1,6 +1,6 @@
plugin_LTLIBRARIES = libgstwaylandsink.la 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) \ libgstwaylandsink_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
$(WAYLAND_CFLAGS) $(WAYLAND_CFLAGS)
libgstwaylandsink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ 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_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstwaylandsink_la_LIBTOOLFLAGS = --tag=disable-static libgstwaylandsink_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstwaylandsink.h noinst_HEADERS = gstwaylandsink.h waylandpool.h

View file

@ -1,5 +1,4 @@
/* /* GStreamer Wayland video sink
* GStreamer Wayland video sink
* *
* Copyright (C) 2011 Intel Corporation * Copyright (C) 2011 Intel Corporation
* Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com> * Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
@ -47,7 +46,6 @@
enum enum
{ {
SIGNAL_0, SIGNAL_0,
SIGNAL_FRAME_READY,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -73,44 +71,6 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
#define gst_wayland_sink_parent_class parent_class #define gst_wayland_sink_parent_class parent_class
G_DEFINE_TYPE (GstWaylandSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK); 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, static void gst_wayland_sink_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec); guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_wayland_sink_set_property (GObject * object, 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_stop (GstBaseSink * bsink);
static gboolean gst_wayland_sink_preroll (GstBaseSink * bsink, static gboolean gst_wayland_sink_preroll (GstBaseSink * bsink,
GstBuffer * buffer); GstBuffer * buffer);
static gboolean
gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query);
static gboolean gst_wayland_sink_render (GstBaseSink * bsink, static gboolean gst_wayland_sink_render (GstBaseSink * bsink,
GstBuffer * buffer); GstBuffer * buffer);
@ -130,9 +92,11 @@ static int event_mask_update (uint32_t mask, void *data);
static struct display *create_display (void); static struct display *create_display (void);
static void display_handle_global (struct wl_display *display, uint32_t id, static void display_handle_global (struct wl_display *display, uint32_t id,
const char *interface, uint32_t version, void *data); 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, static void create_window (GstWaylandSink * sink, struct display *display,
int width, int height); int width, int height);
static void shm_pool_destroy (struct shm_pool *pool);
static void static void
gst_wayland_sink_class_init (GstWaylandSinkClass * klass) 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->start = GST_DEBUG_FUNCPTR (gst_wayland_sink_start);
gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_wayland_sink_stop); gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_wayland_sink_stop);
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_wayland_sink_preroll); 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); gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_wayland_sink_render);
g_object_class_install_property (gobject_class, PROP_WAYLAND_DISPLAY, g_object_class_install_property (gobject_class, PROP_WAYLAND_DISPLAY,
@ -173,9 +139,10 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
static void static void
gst_wayland_sink_init (GstWaylandSink * sink) gst_wayland_sink_init (GstWaylandSink * sink)
{ {
sink->render_busy = FALSE;
sink->display = NULL; sink->display = NULL;
sink->window = NULL; sink->window = NULL;
sink->shm_pool = NULL;
sink->pool = NULL;
g_mutex_init (&sink->wayland_lock); g_mutex_init (&sink->wayland_lock);
} }
@ -225,20 +192,36 @@ destroy_display (struct display *display)
wl_compositor_destroy (display->compositor); wl_compositor_destroy (display->compositor);
wl_display_flush (display->display); wl_display_flush (display->display);
wl_display_destroy (display->display); wl_display_disconnect (display->display);
free (display); free (display);
} }
static void static void
destroy_window (struct window *window) 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) if (window->shell_surface)
wl_shell_surface_destroy (window->shell_surface); wl_shell_surface_destroy (window->shell_surface);
if (window->surface) if (window->surface)
wl_surface_destroy (window->surface); wl_surface_destroy (window->surface);
free (window); 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 static void
gst_wayland_sink_finalize (GObject * object) gst_wayland_sink_finalize (GObject * object)
{ {
@ -250,6 +233,8 @@ gst_wayland_sink_finalize (GObject * object)
destroy_window (sink->window); destroy_window (sink->window);
if (sink->display) if (sink->display)
destroy_display (sink->display); destroy_display (sink->display);
if (sink->shm_pool)
shm_pool_destroy (sink->shm_pool);
g_mutex_clear (&sink->wayland_lock); g_mutex_clear (&sink->wayland_lock);
@ -259,7 +244,21 @@ gst_wayland_sink_finalize (GObject * object)
static GstCaps * static GstCaps *
gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) 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 static int
@ -308,7 +307,7 @@ create_display (void)
display = malloc (sizeof *display); display = malloc (sizeof *display);
display->display = wl_display_connect (NULL); display->display = wl_display_connect (NULL);
assert (display->display); g_return_val_if_fail (display->display, NULL);
wl_display_add_global_listener (display->display, wl_display_add_global_listener (display->display,
display_handle_global, display); display_handle_global, display);
@ -326,92 +325,62 @@ create_display (void)
return display; 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 static gboolean
gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
{ {
GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
const GstStructure *structure; GstBufferPool *newpool, *oldpool;
gboolean ret = TRUE; 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); 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); sink->video_width = info.width;
ret &= gst_structure_get_int (structure, "height", &sink->video_height); sink->video_height = info.height;
size = info.size;
if (!ret) /* create a new pool for the new configuration */
newpool = gst_wayland_buffer_pool_new (sink);
if (!newpool) {
GST_DEBUG_OBJECT (sink, "Failed to create new pool");
return FALSE; return FALSE;
}
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;
oldpool = sink->pool;
sink->pool = newpool;
if (oldpool)
gst_object_unref (oldpool);
return TRUE; return TRUE;
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_listener; static const struct wl_callback_listener frame_callback_listener;
static void
redraw (void *data, struct wl_callback *callback, uint32_t time)
{
GstWaylandSink *sink = (GstWaylandSink *) data;
sink->render_busy = FALSE;
}
static void static void
create_window (GstWaylandSink * sink, struct display *display, int width, create_window (GstWaylandSink * sink, struct display *display, int width,
@ -428,15 +397,15 @@ create_window (GstWaylandSink * sink, struct display *display, int width,
window->display = display; window->display = display;
window->width = width; window->width = width;
window->height = height; window->height = height;
window->redraw_pending = FALSE;
window->surface = wl_compositor_create_surface (display->compositor); window->surface = wl_compositor_create_surface (display->compositor);
window->shell_surface = wl_shell_get_shell_surface (display->shell, window->shell_surface = wl_shell_get_shell_surface (display->shell,
window->surface); window->surface);
/* wl_shell_surface_set_toplevel (window->shell_surface); */ wl_shell_surface_set_toplevel (window->shell_surface);
#ifdef WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT
wl_shell_surface_set_fullscreen (window->shell_surface, wl_shell_surface_set_fullscreen (window->shell_surface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL); WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL);
#endif
sink->window = window; sink->window = window;
@ -467,6 +436,84 @@ gst_wayland_sink_stop (GstBaseSink * bsink)
return TRUE; 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 static GstFlowReturn
gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer) 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); 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 static GstFlowReturn
gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
{ {
@ -481,14 +540,21 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
GstVideoRectangle src, dst, res; GstVideoRectangle src, dst, res;
GstBuffer *to_render; GstBuffer *to_render;
GstWlMeta *meta; GstWlMeta *meta;
GstFlowReturn ret;
struct window *window;
struct display *display;
GST_LOG_OBJECT (sink, "render buffer %p", buffer); GST_LOG_OBJECT (sink, "render buffer %p", buffer);
if (!sink->window) if (!sink->window)
create_window (sink, sink->display, sink->video_width, sink->video_height); create_window (sink, sink->display, sink->video_width, sink->video_height);
if (sink->render_busy) window = sink->window;
goto was_busy; 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); meta = gst_buffer_get_wl_meta (buffer);
@ -497,10 +563,17 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
to_render = buffer; to_render = buffer;
} else { } else {
GstMapInfo src; GstMapInfo src;
GST_LOG_OBJECT (sink, "buffer %p not from our pool, copying", buffer); 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_map (buffer, &src, GST_MAP_READ);
gst_buffer_fill (to_render, 0, src.data, src.size); 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); 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_attach (sink->window->surface, meta->wbuffer, 0, 0);
wl_surface_damage (sink->window->surface, 0, 0, res.w, res.h); wl_surface_damage (sink->window->surface, 0, 0, res.w, res.h);
wl_display_iterate (display->display, WL_DISPLAY_WRITABLE);
if (sink->callback) window->redraw_pending = TRUE;
wl_callback_destroy (sink->callback); window->callback = wl_surface_frame (window->surface);
wl_callback_add_listener (window->callback, &frame_callback_listener, window);
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);
if (buffer != to_render) if (buffer != to_render)
gst_buffer_unref (to_render); gst_buffer_unref (to_render);
return GST_FLOW_OK; return GST_FLOW_OK;
was_busy: no_buffer:
{ {
GST_LOG_OBJECT (sink, GST_WARNING_OBJECT (sink, "could not create image");
"Waiting to get the signal from compositor to render the next frame.."); return ret;
return GST_FLOW_OK; }
no_pool:
{
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 static gboolean
plugin_init (GstPlugin * plugin) plugin_init (GstPlugin * plugin)
{ {

View file

@ -38,6 +38,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/video/video.h> #include <gst/video/video.h>
#include <gst/video/gstvideosink.h> #include <gst/video/gstvideosink.h>
#include <gst/video/gstvideometa.h>
#include <wayland-client.h> #include <wayland-client.h>
@ -70,29 +71,23 @@ struct window
int width, height; int width, height;
struct wl_surface *surface; struct wl_surface *surface;
struct wl_shell_surface *shell_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 _GstWaylandSink GstWaylandSink;
typedef struct _GstWaylandSinkClass GstWaylandSinkClass; typedef struct _GstWaylandSinkClass GstWaylandSinkClass;
typedef struct _GstWlMeta GstWlMeta; #include "waylandpool.h"
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;
};
struct _GstWaylandSink struct _GstWaylandSink
{ {
@ -100,15 +95,14 @@ struct _GstWaylandSink
struct display *display; struct display *display;
struct window *window; struct window *window;
struct wl_callback *callback; struct shm_pool *shm_pool;
GstBufferPool *pool;
GMutex wayland_lock; GMutex wayland_lock;
gint video_width; gint video_width;
gint video_height; gint video_height;
guint bpp;
gboolean render_busy;
}; };
struct _GstWaylandSinkClass struct _GstWaylandSinkClass

311
ext/wayland/waylandpool.c Normal file
View file

@ -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);
}

79
ext/wayland/waylandpool.h Normal file
View file

@ -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__*/