From patchwork Wed Nov 6 15:33:22 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Gaignard X-Patchwork-Id: 21383 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vc0-f197.google.com (mail-vc0-f197.google.com [209.85.220.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 4B53225E16 for ; Wed, 6 Nov 2013 15:33:25 +0000 (UTC) Received: by mail-vc0-f197.google.com with SMTP id ld13sf18023430vcb.4 for ; Wed, 06 Nov 2013 07:33:24 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:mime-version:date:message-id :subject:from:to:cc:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe:content-type; bh=aIdmR0g4RMmqogZhfnVcPD3OYYwKFh/NMGX1KuIl8Cw=; b=QP88KMoeKI/lSByeeN1kJtRMugREIXMizO6ls7K10lSKYIwISrtU+39y/fInQ/57G2 QT8H/FhCrB1wpsavdDbZb3zJRUHYCDUjsyN5uXQtre5ASHypfOc0P5bcUSt2rZ+wZiz0 HZQb3Nm30v2K/BqXdtbBZ/t3doYp85MrOoQGKlcijc2Zszm1uyXB4pgv+hfIa3J9weWk H7mjzCxWD4/Z90ZSq0ls7NKGBy2ufH2r6vFOgE/gjVdk4u3TGfsdEaQvC6qihIp16qVE vY0ozzV/SjGYOKVnvD5B0ol5YzaHaLxBK6Pey7LMIDjTsVqVhudWqksroHJoCCpCRSaD B95A== X-Gm-Message-State: ALoCoQl7/ba1kBJoDpLCRQgRNsyjwYzJ7eZIGnqkdgfSoY8kdq9+P2A9SqhL762O7/spolOsHvO3 X-Received: by 10.236.142.38 with SMTP id h26mr150108yhj.57.1383752004634; Wed, 06 Nov 2013 07:33:24 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.109.226 with SMTP id hv2ls698134qeb.22.gmail; Wed, 06 Nov 2013 07:33:24 -0800 (PST) X-Received: by 10.58.210.66 with SMTP id ms2mr2914517vec.10.1383752004504; Wed, 06 Nov 2013 07:33:24 -0800 (PST) Received: from mail-vc0-f172.google.com (mail-vc0-f172.google.com [209.85.220.172]) by mx.google.com with ESMTPS id hr2si7997746vdb.76.2013.11.06.07.33.24 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 06 Nov 2013 07:33:24 -0800 (PST) Received-SPF: neutral (google.com: 209.85.220.172 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.172; Received: by mail-vc0-f172.google.com with SMTP id ks9so6762373vcb.31 for ; Wed, 06 Nov 2013 07:33:24 -0800 (PST) X-Received: by 10.52.169.227 with SMTP id ah3mr319737vdc.45.1383752004244; Wed, 06 Nov 2013 07:33:24 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp291915vcz; Wed, 6 Nov 2013 07:33:23 -0800 (PST) X-Received: by 10.152.22.131 with SMTP id d3mr2786211laf.35.1383752002846; Wed, 06 Nov 2013 07:33:22 -0800 (PST) Received: from mail-la0-f53.google.com (mail-la0-f53.google.com [209.85.215.53]) by mx.google.com with ESMTPS id dz9si12256460lbc.5.2013.11.06.07.33.22 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 06 Nov 2013 07:33:22 -0800 (PST) Received-SPF: neutral (google.com: 209.85.215.53 is neither permitted nor denied by best guess record for domain of benjamin.gaignard@linaro.org) client-ip=209.85.215.53; Received: by mail-la0-f53.google.com with SMTP id eh20so5678272lab.12 for ; Wed, 06 Nov 2013 07:33:22 -0800 (PST) MIME-Version: 1.0 X-Received: by 10.152.9.198 with SMTP id c6mr2403851lab.36.1383752002071; Wed, 06 Nov 2013 07:33:22 -0800 (PST) Received: by 10.114.99.2 with HTTP; Wed, 6 Nov 2013 07:33:22 -0800 (PST) Date: Wed, 6 Nov 2013 16:33:22 +0100 Message-ID: Subject: [wayland] add wl_drm support to wayland sink From: Benjamin Gaignard To: Benjamin Gaignard Cc: Patch Tracking X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: benjamin.gaignard@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.172 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Use wayland_drm protocol to create a pool of buffer. The benefit is to be able to use dmabuf and so allow zero copy between hardware accelerated elements. Signed-off-by: Benjamin Gaignard --- configure.ac | 10 +- ext/wayland/Makefile.am | 17 ++- ext/wayland/gstwaylandsink.c | 158 ++++++++++++++++++++++-- ext/wayland/gstwaylandsink.h | 33 +++++- ext/wayland/waylanddrmpool.c | 270 ++++++++++++++++++++++++++++++++++++++++++ ext/wayland/waylanddrmpool.h | 63 ++++++++++ 6 files changed, 528 insertions(+), 23 deletions(-) create mode 100644 ext/wayland/waylanddrmpool.c create mode 100644 ext/wayland/waylanddrmpool.h + +G_END_DECLS + +#endif /*__GST_WAYLAND_DRM_BUFFER_POOL_H__*/ diff --git a/configure.ac b/configure.ac index bdcb470..af0cdea 100644 --- a/configure.ac +++ b/configure.ac @@ -1245,9 +1245,13 @@ 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-client >= 1.0.0, [ - HAVE_WAYLAND="yes" ], [ HAVE_WAYLAND="no" - ]) + PKG_CHECK_MODULES(WAYLAND, wayland-client >= 1.0.0, + [HAVE_WAYLAND="yes" ], [ HAVE_WAYLAND="no"]) + PKG_CHECK_MODULES(WAYLAND_DRM, egl >= 9.2.2, + [HAVE_WAYLAND_DRM="yes" + AC_DEFINE(HAVE_WAYLAND_DRM, 1, [Define if wayland DRM protocol is available])], + [ HAVE_WAYLAND_DRM="no"]) + AM_CONDITIONAL(USE_WAYLAND_DRM, test "x$HAVE_WAYLAND_DRM" = "xyes") ]) dnl *** DTS *** diff --git a/ext/wayland/Makefile.am b/ext/wayland/Makefile.am index e8edf73..0de5610 100644 --- a/ext/wayland/Makefile.am +++ b/ext/wayland/Makefile.am @@ -1,12 +1,21 @@ plugin_LTLIBRARIES = libgstwaylandsink.la -libgstwaylandsink_la_SOURCES = gstwaylandsink.c waylandpool.c +if USE_WAYLAND_DRM +wayland_drm_src = waylanddrmpool.c +wayland_drm_lib = -lgstallocators-$(GST_API_VERSION) +else +wayland_drm_src = +wayland_drm_lib = +endif + +libgstwaylandsink_la_SOURCES = gstwaylandsink.c waylandpool.c $(wayland_drm_src) libgstwaylandsink_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ - $(WAYLAND_CFLAGS) + $(WAYLAND_CFLAGS) $(WAYLAND_DRM_CFLAGS) libgstwaylandsink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ -lgstvideo-$(GST_API_VERSION) \ - $(WAYLAND_LIBS) + $(WAYLAND_LIBS) $(WAYLAND_DRM_LIBS) \ + $(wayland_drm_lib) libgstwaylandsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstwaylandsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) -noinst_HEADERS = gstwaylandsink.h waylandpool.h +noinst_HEADERS = gstwaylandsink.h waylandpool.h waylanddrmpool.h diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c index bf2c3eb..0bf4c23 100644 --- a/ext/wayland/gstwaylandsink.c +++ b/ext/wayland/gstwaylandsink.c @@ -53,10 +53,12 @@ enum enum { PROP_0, - PROP_WAYLAND_DISPLAY + PROP_WAYLAND_DISPLAY, + PROP_MODE }; GST_DEBUG_CATEGORY (gstwayland_debug); +GST_DEBUG_CATEGORY (gstwayland_debug_pool); #define GST_CAT_DEFAULT gstwayland_debug #if G_BYTE_ORDER == G_BIG_ENDIAN @@ -65,6 +67,27 @@ GST_DEBUG_CATEGORY (gstwayland_debug); #define CAPS "{BGRx, BGRA}" #endif +#define DEFAULT_MODE GST_WAYLAND_POOL_AUTO + +#define GST_TYPE_WAYLAND_POOL_MODE (gst_wayland_pool_mode_get_type ()) +static GType +gst_wayland_pool_mode_get_type (void) +{ + static GType wayland_pool_mode_type = 0; + static const GEnumValue pool_modes[] = { + {GST_WAYLAND_POOL_DRM, "use DRM to allocated pool buffers", "DRM"}, + {GST_WAYLAND_POOL_SHM, "use shared memory to allocated pool buffers", "SHM"}, + {GST_WAYLAND_POOL_AUTO, "use DRM or share memory", "AUTO"}, + {0, NULL, NULL} + }; + + if (!wayland_pool_mode_type) { + wayland_pool_mode_type = + g_enum_register_static ("GstWaylandPoolMode", pool_modes); + } + return wayland_pool_mode_type; +} + static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, @@ -92,7 +115,7 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query); static gboolean gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer); -static struct display *create_display (void); +static struct display *create_display (GstWaylandSink * wsink); static void registry_handle_global (void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version); static void frame_redraw_callback (void *data, @@ -115,8 +138,29 @@ static const wl_VideoFormat formats[] = { {WL_SHM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_BGRx}, {WL_SHM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_BGRA}, #endif +#ifdef HAVE_WAYLAND_DRM +#if G_BYTE_ORDER == G_BIG_ENDIAN + {WL_DRM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_xRGB}, + {WL_DRM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_ARGB}, +#else + {WL_DRM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_BGRx}, + {WL_DRM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_BGRA}, +#endif +#endif }; +static int +gst_wayland_wl_format_to_index (uint32_t wl_format) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (formats); i++) + if (formats[i].wl_format == wl_format) + return i; + + return -1; +} + static uint32_t gst_wayland_format_to_wl_format (GstVideoFormat format) { @@ -179,6 +223,11 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) g_param_spec_pointer ("wayland-display", "Wayland Display", "Wayland Display handle created by the application ", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_MODE, + g_param_spec_enum ("mode", "Mode", + "buffer allocation method", GST_TYPE_WAYLAND_POOL_MODE, + DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void @@ -188,7 +237,7 @@ gst_wayland_sink_init (GstWaylandSink * sink) sink->window = NULL; sink->shm_pool = NULL; sink->pool = NULL; - + sink->pool_mode = DEFAULT_MODE; g_mutex_init (&sink->wayland_lock); } @@ -202,6 +251,9 @@ gst_wayland_sink_get_property (GObject * object, case PROP_WAYLAND_DISPLAY: g_value_set_pointer (value, sink->display); break; + case PROP_MODE: + g_value_set_enum (value, sink->pool_mode); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -218,6 +270,9 @@ gst_wayland_sink_set_property (GObject * object, case PROP_WAYLAND_DISPLAY: sink->display = g_value_get_pointer (value); break; + case PROP_MODE: + sink->pool_mode = g_value_get_enum (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -310,14 +365,61 @@ static void shm_format (void *data, struct wl_shm *wl_shm, uint32_t format) { struct display *d = data; - - d->formats |= (1 << format); + int index = gst_wayland_wl_format_to_index (format); + if (index != -1) + d->formats |= (1 << index); } struct wl_shm_listener shm_listenter = { shm_format }; +#ifdef HAVE_WAYLAND_DRM + +static void +drm_handle_device (void *data, struct wl_drm *wl_drm, const char *name) +{ + struct display *d = data; + GstWaylandSink *sink = d->sink; + + sink->device_name = strdup (name); + if (!sink->device_name) { + GST_WARNING_OBJECT (sink, "no device name"); + return; + } + GST_DEBUG_OBJECT (sink, "drm device name %s", sink->device_name); + sink->authenticated = FALSE; + + return; +} + +static void +drm_handle_format (void *data, struct wl_drm *wl_drm, uint32_t format) +{ + struct display *d = data; + GstWaylandSink *sink = d->sink; + int index = gst_wayland_wl_format_to_index (format); + GST_DEBUG_OBJECT (sink, "server supported format %.4s", (char *) &format); + if (index != -1) + d->formats |= (1 << index); +} + +static void +drm_handle_authenticated (void *data, struct wl_drm *wl_drm) +{ + struct display *d = data; + GstWaylandSink *sink = d->sink; + sink->authenticated = TRUE; + GST_DEBUG_OBJECT (sink, "authenticated"); +} + +struct wl_drm_listener drm_listenter = { + drm_handle_device, + drm_handle_format, + drm_handle_authenticated +}; +#endif + static void registry_handle_global (void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) @@ -333,6 +435,12 @@ registry_handle_global (void *data, struct wl_registry *registry, d->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1); wl_shm_add_listener (d->shm, &shm_listenter, d); } +#ifdef HAVE_WAYLAND_DRM + else if (strcmp (interface, "wl_drm") == 0) { + d->drm = wl_registry_bind (registry, id, &wl_drm_interface, 1); + wl_drm_add_listener (d->drm, &drm_listenter, d); + } +#endif } static const struct wl_registry_listener registry_listener = { @@ -340,7 +448,7 @@ static const struct wl_registry_listener registry_listener = { }; static struct display * -create_display (void) +create_display (GstWaylandSink * wsink) { struct display *display; @@ -351,6 +459,7 @@ create_display (void) free (display); return NULL; } + display->sink = wsink; display->registry = wl_display_get_registry (display->display); wl_registry_add_listener (display->registry, ®istry_listener, display); @@ -388,11 +497,12 @@ static gboolean gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) { GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); - GstBufferPool *newpool, *oldpool; + GstBufferPool *newpool = NULL, *oldpool = NULL; GstVideoInfo info; GstStructure *structure; static GstAllocationParams params = { 0, 0, 0, 15, }; guint size; + int index; sink = GST_WAYLAND_SINK (bsink); @@ -404,7 +514,11 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) if (!gst_wayland_sink_format_from_caps (&sink->format, caps)) goto invalid_format; - if (!(sink->display->formats & (1 << sink->format))) { + index = gst_wayland_wl_format_to_index (sink->format); + if (index == -1) + goto invalid_format; + + if (!(sink->display->formats & (1 << index))) { GST_DEBUG_OBJECT (sink, "%s not available", gst_wayland_format_to_string (sink->format)); return FALSE; @@ -415,7 +529,17 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) size = info.size; /* create a new pool for the new configuration */ - newpool = gst_wayland_buffer_pool_new (sink); +#ifdef HAVE_WAYLAND_DRM + if (sink->pool_mode == GST_WAYLAND_POOL_AUTO + || sink->pool_mode == GST_WAYLAND_POOL_DRM) + newpool = gst_wayland_drm_buffer_pool_new (sink); + if (!newpool ) +#endif + { + if (sink->pool_mode == GST_WAYLAND_POOL_AUTO + || sink->pool_mode == GST_WAYLAND_POOL_SHM) + newpool = gst_wayland_buffer_pool_new (sink); + } if (!newpool) { GST_DEBUG_OBJECT (sink, "Failed to create new pool"); @@ -515,7 +639,7 @@ gst_wayland_sink_start (GstBaseSink * bsink) GST_DEBUG_OBJECT (sink, "start"); if (!sink->display) - sink->display = create_display (); + sink->display = create_display (sink); if (sink->display == NULL) { GST_ELEMENT_ERROR (bsink, RESOURCE, OPEN_READ_WRITE, @@ -579,8 +703,13 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) goto invalid_caps; GST_DEBUG_OBJECT (sink, "create new pool"); - pool = gst_wayland_buffer_pool_new (sink); - +#ifdef HAVE_WAYLAND_DRM + pool = gst_wayland_drm_buffer_pool_new (sink); + if (!pool) +#endif + { + pool = gst_wayland_buffer_pool_new (sink); + } /* the normal size of a frame */ size = info.size; @@ -725,7 +854,10 @@ static gboolean plugin_init (GstPlugin * plugin) { GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0, - " wayland video sink"); + "wayland video sink"); + + GST_DEBUG_CATEGORY_INIT (gstwayland_debug_pool, "waylandpool", 0, + "wayland pool"); return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL, GST_TYPE_WAYLAND_SINK); diff --git a/ext/wayland/gstwaylandsink.h b/ext/wayland/gstwaylandsink.h index cb3383e..65f9892 100644 --- a/ext/wayland/gstwaylandsink.h +++ b/ext/wayland/gstwaylandsink.h @@ -41,6 +41,10 @@ #include #include +#ifdef HAVE_WAYLAND_DRM +#include +#include +#endif #define GST_TYPE_WAYLAND_SINK \ (gst_wayland_sink_get_type()) @@ -55,6 +59,9 @@ #define GST_WAYLAND_SINK_GET_CLASS(inst) \ (G_TYPE_INSTANCE_GET_CLASS ((inst), GST_TYPE_WAYLAND_SINK, GstWaylandSinkClass)) +typedef struct _GstWaylandSink GstWaylandSink; +typedef struct _GstWaylandSinkClass GstWaylandSinkClass; + struct display { struct wl_display *display; @@ -62,7 +69,11 @@ struct display struct wl_compositor *compositor; struct wl_shell *shell; struct wl_shm *shm; +#ifdef HAVE_WAYLAND_DRM + struct wl_drm *drm; +#endif uint32_t formats; + GstWaylandSink *sink; }; struct window @@ -84,10 +95,21 @@ struct shm_pool { void *data; }; -typedef struct _GstWaylandSink GstWaylandSink; -typedef struct _GstWaylandSinkClass GstWaylandSinkClass; - #include "waylandpool.h" +#ifdef HAVE_WAYLAND_DRM +#include "waylanddrmpool.h" +#endif + +/** + * GST_WAYLAND_POOL_DRM: use DRM to allocated pool buffers + * GST_WAYLAND_POOL_SHM: use shared memory to allocated pool buffers + * GST_WAYLAND_POOL_AUTO: use DRM or share memory + */ +typedef enum { + GST_WAYLAND_POOL_DRM, + GST_WAYLAND_POOL_SHM, + GST_WAYLAND_POOL_AUTO +} GstWaylandPoolMode; struct _GstWaylandSink { @@ -104,6 +126,11 @@ struct _GstWaylandSink gint video_width; gint video_height; uint32_t format; +#ifdef HAVE_WAYLAND_DRM + gboolean authenticated; + char *device_name; +#endif + GstWaylandPoolMode pool_mode; }; struct _GstWaylandSinkClass diff --git a/ext/wayland/waylanddrmpool.c b/ext/wayland/waylanddrmpool.c new file mode 100644 index 0000000..ec5cbb2 --- /dev/null +++ b/ext/wayland/waylanddrmpool.c @@ -0,0 +1,270 @@ +/* GStreamer + * Copyright (C) 2013 Linaro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Debugging category */ +#include + +/* Helper functions */ +#include +#include +#include + +#include "gst/allocators/gstdmabuf.h" +#include "waylanddrmpool.h" +#include + +GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug_pool); +#define GST_CAT_DEFAULT gstwayland_debug_pool + +/* bufferpool */ +static void gst_wayland_drm_buffer_pool_finalize (GObject * object); + +#define gst_wayland_drm_buffer_pool_parent_class parent_class +G_DEFINE_TYPE (GstWaylandDRMBufferPool, gst_wayland_drm_buffer_pool, + GST_TYPE_BUFFER_POOL); + +static void +wayland_drm_pool_mem_unmap (GstMemory * gmem) +{ + /* do nothing, except avoid doing munmap */ +} + +static gboolean +wayland_drm_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) +{ + GstWaylandDRMBufferPool *wpool = GST_WAYLAND_DRM_BUFFER_POOL_CAST (pool); + GstVideoInfo info; + GstCaps *caps; + GstAllocator *allocator; + + 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); + + allocator = gst_dmabuf_allocator_obtain (); + /* hook to avoid unmap issue on drm buffer */ + allocator->mem_unmap = wayland_drm_pool_mem_unmap; + + if (wpool->allocator) + gst_object_unref (wpool->allocator); + if ((wpool->allocator = allocator)) + gst_object_ref (allocator); + + 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 int +create_dumb (int drm_fd, uint32_t width, uint32_t height, int *prime_fd, int *stride) +{ + struct drm_mode_create_dumb create_arg; + gint ret; + + *prime_fd = -1; + *stride = 0; + + memset (&create_arg, 0, sizeof (create_arg)); + create_arg.bpp = 32; + create_arg.width = width; + create_arg.height = height; + + GST_WARNING ("Create DUMB buffer %dx%d", width, height); + ret = drmIoctl (drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg); + if (ret) { + GST_ERROR ("DRM_IOCTL_MODE_CREATE_DUMB failed %s (0x%x) on fd %d", + strerror (errno), errno, drm_fd); + return ret; + } + + *stride = create_arg.pitch; + + ret = drmPrimeHandleToFD (drm_fd, create_arg.handle, DRM_CLOEXEC, prime_fd); + if (ret) { + struct drm_mode_destroy_dumb destroy_arg; + + GST_WARNING ("Can't get fd from handle"); + + memset (&destroy_arg, 0, sizeof destroy_arg); + destroy_arg.handle = create_arg.handle; + drmIoctl (drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); + } + + return ret; +} + +static GstWlMeta * +gst_buffer_add_wayland_meta (GstBuffer * buffer, + GstWaylandDRMBufferPool * wpool) +{ + GstWlMeta *wmeta; + GstWaylandSink *sink; + int prime_fd, stride, ret; + + sink = wpool->sink; + + if (!sink->display->drm) { + GST_ERROR_OBJECT (wpool, "no drm access"); + return NULL; + } + + ret = create_dumb (wpool->fd, wpool->width, wpool->height, &prime_fd, &stride); + if (ret || prime_fd == -1) + return NULL; + + GST_DEBUG_OBJECT (wpool, "drm buffer prime fd %d", prime_fd); + wmeta = (GstWlMeta *) gst_buffer_add_meta (buffer, GST_WL_META_INFO, NULL); + wmeta->sink = gst_object_ref (sink); + wmeta->size = wpool->width * wpool->height * 4; + wmeta->wbuffer = + wl_drm_create_prime_buffer (sink->display->drm, prime_fd, wpool->width, + wpool->height, WL_DRM_FORMAT_XRGB8888, 0, stride, 0, 0, 0, 0); + + GST_DEBUG_OBJECT (wpool, "Add drm buffer to pool"); + + gst_buffer_append_memory (buffer, + gst_dmabuf_allocator_alloc (wpool->allocator, prime_fd, wmeta->size)); + + return wmeta; +} + +static GstFlowReturn +wayland_drm_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, + GstBufferPoolAcquireParams * params) +{ + GstWaylandDRMBufferPool *wpool = GST_WAYLAND_DRM_BUFFER_POOL_CAST (pool); + GstBuffer *w_buffer; + GstWlMeta *meta; + + if (wpool->fd == -1 && wpool->device_name) { + wpool->fd = open (wpool->device_name, O_RDWR, 0); + } + + if (wpool->fd == -1) { + GST_ERROR_OBJECT (wpool, "%s not open", wpool->device_name); + return GST_FLOW_ERROR; + } + + if (!wpool->sink->authenticated) { + drm_magic_t magic; + drmGetMagic (wpool->fd, &magic); + wl_drm_authenticate (wpool->sink->display->drm, magic); + wl_display_roundtrip (wpool->sink->display->display); + } + + if (!wpool->sink->authenticated) { + GST_ERROR_OBJECT (wpool, "client not authenficated !"); + return GST_FLOW_ERROR; + } + + w_buffer = gst_buffer_new (); + meta = gst_buffer_add_wayland_meta (w_buffer, wpool); + if (meta == NULL) { + gst_buffer_unref (w_buffer); + goto no_buffer; + } + *buffer = w_buffer; + + return GST_FLOW_OK; + + /* ERROR */ +no_buffer: + { + GST_WARNING_OBJECT (wpool, "can't create buffer"); + return GST_FLOW_ERROR; + } +} + +GstBufferPool * +gst_wayland_drm_buffer_pool_new (GstWaylandSink * sink) +{ + GstWaylandDRMBufferPool *wpool; + + g_return_val_if_fail (GST_IS_WAYLAND_SINK (sink), NULL); + wpool = g_object_new (GST_TYPE_WAYLAND_DRM_BUFFER_POOL, NULL); + wpool->sink = gst_object_ref (sink); + wpool->fd = -1; + wpool->device_name = strdup (sink->device_name); + + return GST_BUFFER_POOL_CAST (wpool); +} + +static void +gst_wayland_drm_buffer_pool_class_init (GstWaylandDRMBufferPoolClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass; + + gobject_class->finalize = gst_wayland_drm_buffer_pool_finalize; + + gstbufferpool_class->set_config = wayland_drm_buffer_pool_set_config; + gstbufferpool_class->alloc_buffer = wayland_drm_buffer_pool_alloc; +} + +static void +gst_wayland_drm_buffer_pool_init (GstWaylandDRMBufferPool * pool) +{ + +} + +static void +gst_wayland_drm_buffer_pool_finalize (GObject * object) +{ + GstWaylandDRMBufferPool *pool = GST_WAYLAND_DRM_BUFFER_POOL_CAST (object); + + if (pool->allocator) + gst_object_unref (pool->allocator); + + gst_object_unref (pool->sink); + + G_OBJECT_CLASS (gst_wayland_drm_buffer_pool_parent_class)->finalize (object); +} diff --git a/ext/wayland/waylanddrmpool.h b/ext/wayland/waylanddrmpool.h new file mode 100644 index 0000000..89b5d21 --- /dev/null +++ b/ext/wayland/waylanddrmpool.h @@ -0,0 +1,63 @@ +/* GStreamer Wayland DRM buffer pool + * Copyright (C) 2013 Linaro + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_WAYLAND_DRM_BUFFER_POOL_H__ +#define __GST_WAYLAND_DRM_BUFFER_POOL_H__ + +G_BEGIN_DECLS + +#include "gstwaylandsink.h" +#include "waylandpool.h" + +typedef struct _GstWaylandDRMBufferPool GstWaylandDRMBufferPool; +typedef struct _GstWaylandDRMBufferPoolClass GstWaylandDRMBufferPoolClass; + +/* buffer pool functions */ +#define GST_TYPE_WAYLAND_DRM_BUFFER_POOL (gst_wayland_drm_buffer_pool_get_type()) +#define GST_IS_WAYLAND_DRM_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WAYLAND_DRM_BUFFER_POOL)) +#define GST_WAYLAND_DRM_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WAYLAND_DRM_BUFFER_POOL, GstWaylandDRMBufferPool)) +#define GST_WAYLAND_DRM_BUFFER_POOL_CAST(obj) ((GstWaylandDRMBufferPool*)(obj)) + +struct _GstWaylandDRMBufferPool +{ + GstBufferPool bufferpool; + + GstWaylandSink *sink; + GstAllocator *allocator; + gint fd; + gchar *device_name; + + GstCaps *caps; + GstVideoInfo info; + guint width; + guint height; +}; + +struct _GstWaylandDRMBufferPoolClass +{ + GstBufferPoolClass parent_class; +}; + +GType gst_wayland_drm_buffer_pool_get_type (void); + +GstBufferPool *gst_wayland_drm_buffer_pool_new (GstWaylandSink * waylandsink);