mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
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:
parent
38c749ca2f
commit
c803ca4af5
6 changed files with 628 additions and 170 deletions
|
@ -898,7 +898,7 @@ AG_GST_CHECK_FEATURE(DIRECTFB, [directfb], dfbvideosink , [
|
|||
dnl **** Wayland ****
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_WAYLAND, true)
|
||||
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-protocol.h, HAVE_WAYLAND_CLIENT_PROTOCOL="yes", HAVE_WAYLAND_CLIENT_PROTOCOL="no")
|
||||
if test "x$HAVE_WAYLAND_CLIENT" = "xno"; then
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,20 +192,36 @@ 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)
|
||||
{
|
||||
|
@ -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,92 +325,62 @@ 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)
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
oldpool = sink->pool;
|
||||
sink->pool = newpool;
|
||||
if (oldpool)
|
||||
gst_object_unref (oldpool);
|
||||
|
||||
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 void
|
||||
redraw (void *data, struct wl_callback *callback, uint32_t time)
|
||||
{
|
||||
|
||||
GstWaylandSink *sink = (GstWaylandSink *) data;
|
||||
|
||||
sink->render_busy = FALSE;
|
||||
}
|
||||
static const struct wl_callback_listener frame_callback_listener;
|
||||
|
||||
static void
|
||||
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->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_LOG_OBJECT (sink,
|
||||
"Waiting to get the signal from compositor to render the next frame..");
|
||||
return GST_FLOW_OK;
|
||||
GST_WARNING_OBJECT (sink, "could not create image");
|
||||
return ret;
|
||||
}
|
||||
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
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
311
ext/wayland/waylandpool.c
Normal file
311
ext/wayland/waylandpool.c
Normal 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
79
ext/wayland/waylandpool.h
Normal 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__*/
|
Loading…
Reference in a new issue