[wayland] add wl_drm support to wayland sink

Message ID CA+M3ks5C_y2DJ_6O4Xxky+c4S2s+WMzaqsuQhcvP1KMBjLow4A@mail.gmail.com
State Under Review
Headers show

Commit Message

Benjamin Gaignard Nov. 6, 2013, 3:33 p.m.
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 <benjamin.gaignard@linaro.org>
---
 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__*/

Patch

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, &registry_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 <gst/video/gstvideometa.h>

 #include <wayland-client.h>
+#ifdef HAVE_WAYLAND_DRM
+#include <wayland-drm-client-protocol.h>
+#include <xf86drm.h>
+#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 <gst/gstinfo.h>
+
+/* Helper functions */
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+
+#include "gst/allocators/gstdmabuf.h"
+#include "waylanddrmpool.h"
+#include <libkms/libkms.h>
+
+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);