summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Kiagiadakis <george.kiagiadakis@collabora.com>2014-06-26 08:33:27 (GMT)
committerGeorge Kiagiadakis <george.kiagiadakis@collabora.com>2014-06-26 12:46:52 (GMT)
commit727732c6de87949278cd53436ba2c430956cd8f9 (patch)
tree1ab220633cd4a1edbed5066c46cc9071387ca762
parent7a6183802dbb8d4cafa1a81a33c57f0fc2cb2e10 (diff)
downloadgst-plugins-bad-inteldmabufupload.tar.gz
gst-plugins-bad-inteldmabufupload.tar.xz
inteldrm: Add a new 'inteldmabufupload' elementinteldmabufupload
The purpose of this element is mainly to test video sinks that implement dmabuf support, using the dmabuf support of the intel video drivers. The element is based on GstBaseTransform. It provides a custom buffer pool, which allocates buffer objects using libdrm_intel and exports them to dmabuf objects. The GstMemory of those buffers is allocated from the GstDmabufAllocator. This buffer pool is provided upstream, so either upstream uses it and we have a zero-copy upload, or upstream doesn't use it, in which case this element will copy the contents of the upstream buffers into these dmabuf buffers. The src caps are transformed to have a "memory:dmabuf" caps feature. Example usage: gst-launch-1.0 videotestsrc ! inteldmabufupload ! waylandsink
-rw-r--r--configure.ac10
-rw-r--r--sys/Makefile.am10
-rw-r--r--sys/inteldrm/Makefile.am20
-rw-r--r--sys/inteldrm/gstinteldmabufupload.c402
-rw-r--r--sys/inteldrm/gstinteldmabufupload.h69
-rw-r--r--sys/inteldrm/intelbufmgrpool.c222
-rw-r--r--sys/inteldrm/intelbufmgrpool.h56
7 files changed, 787 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac
index eb6b41f..8dadd65 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2123,6 +2123,14 @@ AG_GST_CHECK_FEATURE(FLUIDSYNTH, [fluidsynth], fluidsynth, [
])
])
+dnl *** inteldrm ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_INTELDRM, true)
+AG_GST_CHECK_FEATURE(INTELDRM, [inteldrm], inteldrm, [
+ PKG_CHECK_MODULES(INTELDRM, libdrm_intel, HAVE_INTELDRM="yes", [
+ HAVE_INTELDRM="no"
+ ])
+])
+
dnl *** kate ***
translit(dnm, m, l) AM_CONDITIONAL(USE_KATE, true)
AG_GST_CHECK_FEATURE(KATE, [Kate], kate, [
@@ -2991,6 +2999,7 @@ AM_CONDITIONAL(USE_FLITE, false)
AM_CONDITIONAL(USE_FLUIDSYNTH, false)
AM_CONDITIONAL(USE_GSM, false)
AM_CONDITIONAL(USE_HLS, false)
+AM_CONDITIONAL(USE_INTELDRM, false)
AM_CONDITIONAL(USE_KATE, false)
AM_CONDITIONAL(USE_TIGER, false)
AM_CONDITIONAL(USE_LADSPA, false)
@@ -3226,6 +3235,7 @@ sys/dshowsrcwrapper/Makefile
sys/dshowvideosink/Makefile
sys/dvb/Makefile
sys/fbdev/Makefile
+sys/inteldrm/Makefile
sys/linsys/Makefile
sys/opensles/Makefile
sys/osxvideo/Makefile
diff --git a/sys/Makefile.am b/sys/Makefile.am
index 28528be..02701f5 100644
--- a/sys/Makefile.am
+++ b/sys/Makefile.am
@@ -76,6 +76,12 @@ else
FBDEV_DIR=
endif
+if USE_INTELDRM
+INTELDRM_DIR=inteldrm
+else
+INTELDRM_DIR=
+endif
+
if USE_DVB
DVB_DIR=dvb
else
@@ -160,9 +166,9 @@ else
UVCH264_DIR=
endif
-SUBDIRS = $(ACM_DIR) $(ANDROID_MEDIA_DIR) $(APPLE_MEDIA_DIR) $(AVC_DIR) $(BLUEZ_DIR) $(D3DVIDEOSINK_DIR) $(DECKLINK_DIR) $(DIRECTDRAW_DIR) $(DIRECTSOUND_DIR) $(WINKS_DIR) $(DVB_DIR) $(FBDEV_DIR) $(LINSYS_DIR) $(OPENSLES_DIR) $(OSX_VIDEO_DIR) $(PVR_DIR) $(QT_DIR) $(SHM_DIR) $(UVCH264_DIR) $(VCD_DIR) $(VDPAU_DIR) $(WININET_DIR) $(WINSCREENCAP_DIR) $(WASAPI_DIR)
+SUBDIRS = $(ACM_DIR) $(ANDROID_MEDIA_DIR) $(APPLE_MEDIA_DIR) $(AVC_DIR) $(BLUEZ_DIR) $(D3DVIDEOSINK_DIR) $(DECKLINK_DIR) $(DIRECTDRAW_DIR) $(DIRECTSOUND_DIR) $(WINKS_DIR) $(DVB_DIR) $(FBDEV_DIR) $(INTELDRM_DIR) $(LINSYS_DIR) $(OPENSLES_DIR) $(OSX_VIDEO_DIR) $(PVR_DIR) $(QT_DIR) $(SHM_DIR) $(UVCH264_DIR) $(VCD_DIR) $(VDPAU_DIR) $(WININET_DIR) $(WINSCREENCAP_DIR) $(WASAPI_DIR)
-DIST_SUBDIRS = acmenc acmmp3dec androidmedia applemedia applemedia-nonpublic avc bluez d3dvideosink decklink directdraw directsound dvb linsys fbdev dshowdecwrapper dshowsrcwrapper dshowvideosink \
+DIST_SUBDIRS = acmenc acmmp3dec androidmedia applemedia applemedia-nonpublic avc bluez d3dvideosink decklink directdraw directsound dvb linsys fbdev inteldrm dshowdecwrapper dshowsrcwrapper dshowvideosink \
opensles osxvideo pvr2d qtwrapper shm uvch264 vcd vdpau wasapi wininet winks winscreencap
include $(top_srcdir)/common/parallel-subdirs.mak
diff --git a/sys/inteldrm/Makefile.am b/sys/inteldrm/Makefile.am
new file mode 100644
index 0000000..3457a13
--- /dev/null
+++ b/sys/inteldrm/Makefile.am
@@ -0,0 +1,20 @@
+plugin_LTLIBRARIES = libgstinteldrm.la
+
+libgstinteldrm_la_SOURCES = \
+ gstinteldmabufupload.c \
+ intelbufmgrpool.c
+
+libgstinteldrm_la_CFLAGS = $(GST_CFLAGS) \
+ $(GST_PLUGINS_BAD_CFLAGS) \
+ $(INTELDRM_CFLAGS)
+libgstinteldrm_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) \
+ $(INTELDRM_LIBS) \
+ -lgstvideo-$(GST_API_VERSION) \
+ -lgstallocators-$(GST_API_VERSION)
+libgstinteldrm_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstinteldrm_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = \
+ gstinteldmabufupload.h \
+ intelbufmgrpool.h
diff --git a/sys/inteldrm/gstinteldmabufupload.c b/sys/inteldrm/gstinteldmabufupload.c
new file mode 100644
index 0000000..29e0406
--- /dev/null
+++ b/sys/inteldrm/gstinteldmabufupload.c
@@ -0,0 +1,402 @@
+/*
+ * GStreamer intel dmabuf upload element
+ *
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * 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 Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include "gstinteldmabufupload.h"
+#include "intelbufmgrpool.h"
+#include <gst/allocators/gstdmabuf.h>
+#include <gst/video/video.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+GST_DEBUG_CATEGORY (gstinteldmabufupload_debug);
+#define GST_CAT_DEFAULT gstinteldmabufupload_debug
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
+ ("{ BGRx, BGRA, RGBx, xBGR, xRGB, RGBA, ABGR, ARGB }"))
+ );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
+ ("memory:" GST_ALLOCATOR_DMABUF,
+ "{ BGRx, BGRA, RGBx, xBGR, xRGB, RGBA, ABGR, ARGB }"))
+ );
+
+GST_DEFINE_MINI_OBJECT_TYPE (GstIntelBufmgrContext, gst_intel_bufmgr_context);
+
+G_DEFINE_TYPE (GstIntelDmabufUpload, gst_intel_dmabuf_upload,
+ GST_TYPE_BASE_TRANSFORM);
+
+enum
+{
+ PROP_0,
+ PROP_DEVICE,
+ N_PROPERTIES
+};
+
+static void
+gst_intel_bufmgr_context_free (GstIntelBufmgrContext * c)
+{
+ drm_intel_bufmgr_destroy (c->bufmgr);
+ close (c->drm_fd);
+
+ g_slice_free (GstIntelBufmgrContext, c);
+}
+
+static GstIntelBufmgrContext *
+gst_intel_bufmgr_context_new (gint fd, drm_intel_bufmgr * bufmgr)
+{
+ GstIntelBufmgrContext *c;
+
+ c = g_slice_new0 (GstIntelBufmgrContext);
+
+ gst_mini_object_init ((GstMiniObject *) c, 0,
+ gst_intel_bufmgr_context_get_type (), NULL, NULL,
+ (GstMiniObjectFreeFunction) gst_intel_bufmgr_context_free);
+
+ c->drm_fd = fd;
+ c->bufmgr = bufmgr;
+
+ return c;
+}
+
+static void
+gst_intel_dmabuf_upload_finalize (GObject * gobject)
+{
+ GstIntelDmabufUpload *self = GST_INTEL_DMABUF_UPLOAD (gobject);
+
+ if (self->device)
+ g_free (self->device);
+
+ G_OBJECT_CLASS (gst_intel_dmabuf_upload_parent_class)->finalize (gobject);
+}
+
+static void
+gst_intel_dmabuf_upload_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstIntelDmabufUpload *self = GST_INTEL_DMABUF_UPLOAD (object);
+
+ switch (property_id) {
+ case PROP_DEVICE:
+ GST_OBJECT_LOCK (self);
+ if (self->device)
+ g_free (self->device);
+ self->device = g_value_dup_string (value);
+ GST_OBJECT_UNLOCK (self);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_intel_dmabuf_upload_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstIntelDmabufUpload *self = GST_INTEL_DMABUF_UPLOAD (object);
+
+ switch (property_id) {
+ case PROP_DEVICE:
+ GST_OBJECT_LOCK (self);
+ g_value_set_string (value, self->device);
+ GST_OBJECT_UNLOCK (self);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+gst_intel_dmabuf_upload_start (GstBaseTransform * trans)
+{
+ GstIntelDmabufUpload *self = GST_INTEL_DMABUF_UPLOAD (trans);
+ gint drm_fd;
+ drm_intel_bufmgr *bufmgr;
+
+ gst_base_transform_set_passthrough (trans, TRUE);
+
+ GST_OBJECT_LOCK (self);
+
+ if (!self->device) {
+ GST_ERROR_OBJECT (self, "No suitable device has been found or set");
+ GST_OBJECT_UNLOCK (self);
+ return FALSE;
+ }
+
+ drm_fd = open (self->device, O_RDWR);
+ if (drm_fd < 0) {
+ GST_ERROR_OBJECT (self, "Failed to open device %s", self->device);
+ GST_OBJECT_UNLOCK (self);
+ return FALSE;
+ }
+
+ GST_OBJECT_UNLOCK (self);
+
+ bufmgr = drm_intel_bufmgr_gem_init (drm_fd, 32);
+ if (!bufmgr) {
+ GST_ERROR_OBJECT (self, "Failed to initialize drm_intel_bufmgr");
+ close (drm_fd);
+ return FALSE;
+ }
+
+ self->context = gst_intel_bufmgr_context_new (drm_fd, bufmgr);
+
+ return TRUE;
+}
+
+static gboolean
+gst_intel_dmabuf_upload_stop (GstBaseTransform * trans)
+{
+ GstIntelDmabufUpload *self = GST_INTEL_DMABUF_UPLOAD (trans);
+
+ g_clear_object (&self->pool);
+ if (self->context) {
+ gst_mini_object_unref ((GstMiniObject *) self->context);
+ self->context = NULL;
+ }
+
+ return TRUE;
+}
+
+static GstCaps *
+gst_intel_dmabuf_upload_transform_caps (GstBaseTransform * trans,
+ GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+{
+ GstCaps *ret = gst_caps_copy (caps);
+ GstCapsFeatures *features;
+ gint i;
+
+ for (i = 0; i < gst_caps_get_size (ret); i++) {
+ if (direction == GST_PAD_SINK) {
+ features = gst_caps_features_new ("memory:" GST_ALLOCATOR_DMABUF, NULL);
+ gst_caps_set_features (ret, i, features);
+ } else {
+ features = gst_caps_get_features (ret, i);
+ if (gst_caps_features_contains (features, "memory:" GST_ALLOCATOR_DMABUF))
+ gst_caps_features_remove (features, "memory:" GST_ALLOCATOR_DMABUF);
+ }
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_intel_dmabuf_upload_set_caps (GstBaseTransform * trans, GstCaps * incaps,
+ GstCaps * outcaps)
+{
+ GstIntelDmabufUpload *self = GST_INTEL_DMABUF_UPLOAD (trans);
+ GstVideoInfo info;
+ gsize size;
+ GstBufferPool *pool;
+ GstStructure *config;
+
+ /* extract info from caps */
+ if (!gst_video_info_from_caps (&info, incaps))
+ goto invalid_format;
+
+ size = info.size;
+
+ if (!gst_video_info_from_caps (&info, outcaps) || size != info.size)
+ goto size_mismatch;
+
+ pool = gst_intel_bufmgr_pool_new (self->context);
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set_params (config, incaps, size, 1, 0);
+ if (!gst_buffer_pool_set_config (pool, config))
+ goto config_failed;
+
+ gst_object_replace ((GstObject **) & self->pool, (GstObject *) pool);
+ gst_object_unref (pool);
+
+ return TRUE;
+
+invalid_format:
+ {
+ GST_WARNING_OBJECT (self,
+ "Could not extract image format from caps %" GST_PTR_FORMAT, incaps);
+ return FALSE;
+ }
+size_mismatch:
+ {
+ GST_WARNING_OBJECT (self,
+ "Frame size mismatch between the input and output caps");
+ return FALSE;
+ }
+config_failed:
+ {
+ GST_WARNING_OBJECT (self, "Failed to set buffer pool config");
+ gst_object_unref (pool);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_intel_dmabuf_upload_propose_allocation (GstBaseTransform * trans,
+ GstQuery * decide_query, GstQuery * query)
+{
+ GstIntelDmabufUpload *self = GST_INTEL_DMABUF_UPLOAD (trans);
+ GstStructure *config;
+ guint size, min_bufs, max_bufs;
+
+ config = gst_buffer_pool_get_config (self->pool);
+ gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
+
+ gst_query_add_allocation_pool (query, self->pool, size, min_bufs, max_bufs);
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_intel_dmabuf_upload_prepare_output_buffer (GstBaseTransform * trans,
+ GstBuffer * inbuf, GstBuffer ** outbuf)
+{
+ GstIntelDmabufUpload *self = GST_INTEL_DMABUF_UPLOAD (trans);
+ gint i, n = gst_buffer_n_memory (inbuf);
+
+ /* if upstream has used our pool, we can passthrough 100%
+ * otherwise, we need to copy to a buffer from our pool */
+ for (i = 0; i < n; i++) {
+ if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, i))) {
+
+ if (!gst_buffer_pool_is_active (self->pool) &&
+ !gst_buffer_pool_set_active (self->pool, TRUE)) {
+ GST_ERROR_OBJECT (trans, "failed to activate buffer pool");
+ return GST_FLOW_ERROR;
+ }
+
+ gst_buffer_pool_acquire_buffer (self->pool, outbuf, NULL);
+ return GST_FLOW_OK;
+ }
+ }
+
+ GST_LOG_OBJECT (trans, "passthrough: reusing input buffer");
+ *outbuf = inbuf;
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_intel_dmabuf_upload_transform (GstBaseTransform * trans, GstBuffer * inbuf,
+ GstBuffer * outbuf)
+{
+ if (inbuf != outbuf) {
+ GstMapInfo src;
+
+ GST_LOG_OBJECT (trans, "Copying buffer contents from %p to %p", inbuf,
+ outbuf);
+
+ if (!gst_buffer_map (inbuf, &src, GST_MAP_READ)) {
+ GST_ERROR_OBJECT (trans, "Failed to map incoming buffer");
+ return GST_FLOW_ERROR;
+ }
+ gst_buffer_fill (outbuf, 0, src.data, src.size);
+ gst_buffer_unmap (inbuf, &src);
+ }
+
+ return GST_FLOW_OK;
+}
+
+static void
+gst_intel_dmabuf_upload_class_init (GstIntelDmabufUploadClass * klass)
+{
+ GstBaseTransformClass *transform_class = (GstBaseTransformClass *) klass;
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+ transform_class->start = GST_DEBUG_FUNCPTR (gst_intel_dmabuf_upload_start);
+ transform_class->stop = GST_DEBUG_FUNCPTR (gst_intel_dmabuf_upload_stop);
+
+ transform_class->transform_caps =
+ GST_DEBUG_FUNCPTR (gst_intel_dmabuf_upload_transform_caps);
+ transform_class->set_caps =
+ GST_DEBUG_FUNCPTR (gst_intel_dmabuf_upload_set_caps);
+ transform_class->propose_allocation =
+ GST_DEBUG_FUNCPTR (gst_intel_dmabuf_upload_propose_allocation);
+
+ transform_class->prepare_output_buffer =
+ GST_DEBUG_FUNCPTR (gst_intel_dmabuf_upload_prepare_output_buffer);
+ transform_class->transform =
+ GST_DEBUG_FUNCPTR (gst_intel_dmabuf_upload_transform);
+
+ gobject_class->finalize = gst_intel_dmabuf_upload_finalize;
+ gobject_class->set_property = gst_intel_dmabuf_upload_set_property;
+ gobject_class->get_property = gst_intel_dmabuf_upload_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_DEVICE,
+ g_param_spec_string ("device", "Device",
+ "The render dri device used for buffer allocation",
+ NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "intel dmabuf upload", "Filter/Converter/Video",
+ "Upload buffers to intel prime dmabuf objects",
+ "George Kiagiadakis <george.kiagiadakis@collabora.com>");
+
+}
+
+static void
+gst_intel_dmabuf_upload_init (GstIntelDmabufUpload * self)
+{
+ GDir *dir;
+ const gchar *filename;
+
+ /* Find some /dev/dri/renderD* device. This won't work with card0 as we need
+ * to be authenticated; instead, boot with drm.rnodes=1 and use that */
+ dir = g_dir_open ("/dev/dri", 0, NULL);
+ if (dir) {
+ while ((filename = g_dir_read_name (dir))) {
+ if (g_str_has_prefix (filename, "renderD")) {
+ self->device = g_strdup_printf ("/dev/dri/%s", filename);
+ break;
+ }
+ }
+
+ g_dir_close (dir);
+ }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (gstinteldmabufupload_debug, "inteldmabufupload", 0,
+ "intel dmabuf upload");
+
+ return gst_element_register (plugin, "inteldmabufupload", GST_RANK_MARGINAL,
+ GST_TYPE_INTEL_DMABUF_UPLOAD);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, inteldrm,
+ "Intel DRM DMA-BUF/PRIME Utilities",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/inteldrm/gstinteldmabufupload.h b/sys/inteldrm/gstinteldmabufupload.h
new file mode 100644
index 0000000..f3230b6
--- /dev/null
+++ b/sys/inteldrm/gstinteldmabufupload.h
@@ -0,0 +1,69 @@
+/*
+ * GStreamer intel dmabuf upload element
+ *
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * 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 Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GST_INTEL_DMABUF_UPLOAD_H__
+#define __GST_INTEL_DMABUF_UPLOAD_H__
+
+#include <gst/base/base.h>
+#include <libdrm/intel_bufmgr.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_INTEL_DMABUF_UPLOAD (gst_intel_dmabuf_upload_get_type ())
+#define GST_INTEL_DMABUF_UPLOAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_INTEL_DMABUF_UPLOAD, GstIntelDmabufUpload))
+#define GST_IS_INTEL_DMABUF_UPLOAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_INTEL_DMABUF_UPLOAD))
+#define GST_INTEL_DMABUF_UPLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_INTEL_DMABUF_UPLOAD, GstIntelDmabufUploadClass))
+#define GST_IS_INTEL_DMABUF_UPLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_INTEL_DMABUF_UPLOAD))
+#define GST_INTEL_DMABUF_UPLOAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_INTEL_DMABUF_UPLOAD, GstIntelDmabufUploadClass))
+
+typedef struct _GstIntelBufmgrContext GstIntelBufmgrContext;
+typedef struct _GstIntelDmabufUpload GstIntelDmabufUpload;
+typedef struct _GstIntelDmabufUploadClass GstIntelDmabufUploadClass;
+
+struct _GstIntelBufmgrContext
+{
+ GstMiniObject parent_instance;
+
+ int drm_fd;
+ drm_intel_bufmgr *bufmgr;
+};
+
+struct _GstIntelDmabufUpload
+{
+ GstBaseTransform parent_instance;
+
+ gchar *device;
+
+ GstBufferPool *pool;
+ GstIntelBufmgrContext *context;
+};
+
+struct _GstIntelDmabufUploadClass
+{
+ GstBaseTransformClass parent_class;
+};
+
+GType gst_intel_bufmgr_context_get_type (void);
+GType gst_intel_dmabuf_upload_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_INTEL_DMABUF_UPLOAD_H__ */
diff --git a/sys/inteldrm/intelbufmgrpool.c b/sys/inteldrm/intelbufmgrpool.c
new file mode 100644
index 0000000..c380397
--- /dev/null
+++ b/sys/inteldrm/intelbufmgrpool.c
@@ -0,0 +1,222 @@
+/*
+ * GStreamer intel bufmgr upload element
+ *
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * 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 Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#include "intelbufmgrpool.h"
+
+#include <libdrm/i915_drm.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gstinteldmabufupload_debug);
+#define GST_CAT_DEFAULT gstinteldmabufupload_debug
+
+#define parent_class gst_intel_bufmgr_pool_parent_class
+G_DEFINE_TYPE (GstIntelBufmgrPool, gst_intel_bufmgr_pool, GST_TYPE_BUFFER_POOL);
+
+static G_DEFINE_QUARK (GstIntelBufmgrBoQDataQuark, gst_intel_bufmgr_bo_qdata);
+
+static GstFlowReturn gst_intel_bufmgr_pool_alloc_buffer (GstBufferPool * pool,
+ GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
+
+static gpointer
+gst_intel_bufmgr_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
+{
+ drm_intel_bo *bo;
+
+ /* make memory sharing work, theoretically */
+ if (mem->parent)
+ return gst_intel_bufmgr_mem_map (mem->parent, maxsize, flags);
+
+ bo = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
+ gst_intel_bufmgr_bo_qdata_quark ());
+
+ if (drm_intel_gem_bo_map_gtt (bo) != 0) {
+ GST_ERROR ("failed to map drm_intel_bo");
+ return NULL;
+ }
+
+ return bo->virtual;
+}
+
+static void
+gst_intel_bufmgr_mem_unmap (GstMemory * mem)
+{
+ drm_intel_bo *bo;
+
+ /* make memory sharing work, theoretically */
+ if (mem->parent) {
+ gst_intel_bufmgr_mem_unmap (mem->parent);
+ return;
+ }
+
+ bo = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
+ gst_intel_bufmgr_bo_qdata_quark ());
+
+ drm_intel_gem_bo_unmap_gtt (bo);
+}
+
+static gboolean
+gst_intel_bufmgr_pool_set_config (GstBufferPool * pool, GstStructure * config)
+{
+ GstIntelBufmgrPool *self = GST_INTEL_BUFMGR_POOL (pool);
+ GstVideoInfo info;
+ GstCaps *caps;
+ GstBuffer *tmp;
+ guint size, min_bufs, max_bufs;
+ gboolean ret;
+
+ if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_bufs,
+ &max_bufs))
+ 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;
+
+ self->info = info;
+
+ /* Acquire a buffer and configure the size in the base class.
+ * This is necessary to allow buffers to be reused in GstBufferPool,
+ * because if the size does not match, GstBufferPool thinks that the
+ * buffer has been modified and it discards it instead of reusing it.
+ * Unfortunately, the size is determined by the downstream drm_intel_bo
+ * allocator and not by us, so we have to allocate a buffer to find
+ * out what its size ends up being.
+ */
+ if (gst_intel_bufmgr_pool_alloc_buffer (pool, &tmp, NULL) != GST_FLOW_OK)
+ return FALSE;
+
+ size = gst_buffer_get_size (tmp);
+ gst_buffer_pool_config_set_params (config, caps, size, min_bufs, max_bufs);
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT
+ (GST_BUFFER_POOL_CLASS, set_config, (pool, config), TRUE);
+
+ gst_buffer_unref (tmp);
+
+ return ret;
+
+ /* 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 GstFlowReturn
+gst_intel_bufmgr_pool_alloc_buffer (GstBufferPool * pool, GstBuffer ** buffer,
+ GstBufferPoolAcquireParams * params)
+{
+ GstIntelBufmgrPool *self = GST_INTEL_BUFMGR_POOL (pool);
+ GstMemory *mem;
+ drm_intel_bo *bo;
+ gint dmabuf_fd;
+ uint32_t tiling = I915_TILING_NONE;
+ gulong stride;
+
+ bo = drm_intel_bo_alloc_tiled (self->context->bufmgr, "gst", self->info.width,
+ self->info.height, self->info.finfo->pixel_stride[0], &tiling, &stride,
+ 0);
+
+ if (!bo) {
+ GST_ERROR_OBJECT (pool, "Allocating a drm_intel_bo failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (drm_intel_bo_gem_export_to_prime (bo, &dmabuf_fd) != 0) {
+ GST_ERROR_OBJECT (pool, "Failed to export drm_intel_bo to a dmabuf");
+ drm_intel_bo_unreference (bo);
+ return GST_FLOW_ERROR;
+ }
+
+ mem = gst_dmabuf_allocator_alloc (self->allocator, dmabuf_fd, bo->size);
+ gst_mini_object_set_qdata (GST_MINI_OBJECT (mem),
+ gst_intel_bufmgr_bo_qdata_quark (), bo,
+ (GDestroyNotify) drm_intel_bo_unreference);
+
+ *buffer = gst_buffer_new ();
+ gst_buffer_append_memory (*buffer, mem);
+
+ self->info.stride[0] = stride;
+ (void) gst_buffer_add_video_meta_full (*buffer, 0, self->info.finfo->format,
+ self->info.width, self->info.height, self->info.finfo->n_planes,
+ self->info.offset, self->info.stride);
+
+ GST_DEBUG_OBJECT (pool, "Allocated buffer. width %d, height %d, format %s, "
+ "stride %d", self->info.width, self->info.height,
+ gst_video_format_to_string (self->info.finfo->format),
+ self->info.stride[0]);
+
+ return GST_FLOW_OK;
+}
+
+static void
+gst_intel_bufmgr_pool_finalize (GObject * object)
+{
+ GstIntelBufmgrPool *self = GST_INTEL_BUFMGR_POOL (object);
+
+ g_object_unref (self->allocator);
+ gst_mini_object_unref ((GstMiniObject *) self->context);
+}
+
+static void
+gst_intel_bufmgr_pool_class_init (GstIntelBufmgrPoolClass * klass)
+{
+ GstBufferPoolClass *bpool_class = (GstBufferPoolClass *) klass;
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ bpool_class->set_config =
+ GST_DEBUG_FUNCPTR (gst_intel_bufmgr_pool_set_config);
+ bpool_class->alloc_buffer =
+ GST_DEBUG_FUNCPTR (gst_intel_bufmgr_pool_alloc_buffer);
+
+ object_class->finalize = GST_DEBUG_FUNCPTR (gst_intel_bufmgr_pool_finalize);
+}
+
+static void
+gst_intel_bufmgr_pool_init (GstIntelBufmgrPool * self)
+{
+ self->allocator = gst_dmabuf_allocator_new ();
+ self->allocator->mem_map = gst_intel_bufmgr_mem_map;
+ self->allocator->mem_unmap = gst_intel_bufmgr_mem_unmap;
+}
+
+GstBufferPool *
+gst_intel_bufmgr_pool_new (GstIntelBufmgrContext * context)
+{
+ GstIntelBufmgrPool *self = g_object_new (GST_TYPE_INTEL_BUFMGR_POOL, NULL);
+ self->context =
+ (GstIntelBufmgrContext *) gst_mini_object_ref ((GstMiniObject *) context);
+ return (GstBufferPool *) self;
+}
diff --git a/sys/inteldrm/intelbufmgrpool.h b/sys/inteldrm/intelbufmgrpool.h
new file mode 100644
index 0000000..1eed15d
--- /dev/null
+++ b/sys/inteldrm/intelbufmgrpool.h
@@ -0,0 +1,56 @@
+/*
+ * GStreamer intel dmabuf upload element
+ *
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * 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 Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GST_INTEL_BUFMGR_POOL_H__
+#define __GST_INTEL_BUFMGR_POOL_H__
+
+#include "gstinteldmabufupload.h"
+#include <gst/allocators/allocators.h>
+#include <gst/video/video.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_INTEL_BUFMGR_POOL (gst_intel_bufmgr_pool_get_type ())
+#define GST_INTEL_BUFMGR_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_INTEL_BUFMGR_POOL, GstIntelBufmgrPool))
+
+typedef struct _GstIntelBufmgrPool GstIntelBufmgrPool;
+typedef struct _GstIntelBufmgrPoolClass GstIntelBufmgrPoolClass;
+
+struct _GstIntelBufmgrPool
+{
+ GstBufferPool parent_instance;
+ GstAllocator *allocator;
+ GstVideoInfo info;
+ GstIntelBufmgrContext *context;
+};
+
+struct _GstIntelBufmgrPoolClass
+{
+ GstBufferPoolClass parent_class;
+};
+
+GType gst_intel_bufmgr_pool_get_type (void);
+
+GstBufferPool * gst_intel_bufmgr_pool_new (GstIntelBufmgrContext *context);
+
+G_END_DECLS
+
+#endif /* __GST_INTEL_BUFMGR_POOL_H__ */