summaryrefslogtreecommitdiff
path: root/sys/inteldrm/gstinteldmabufupload.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/inteldrm/gstinteldmabufupload.c')
-rw-r--r--sys/inteldrm/gstinteldmabufupload.c402
1 files changed, 402 insertions, 0 deletions
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)