From c5d115bf88f0d2fb64f58b21b72a3195eae98d0a Mon Sep 17 00:00:00 2001
From: Pooja Prajod <a0132412@ti.com>
Date: Fri, 20 Jan 2017 14:41:45 +0530
Subject: [PATCH 1/5] gstdrmallocator: Add DRM allocator support

Add DRM based allocator support.

The following changes are included :
1. Use DRM dumb buffers and associated APIs for
dmabuf allocation.
2. Have DRM device fd a member of allocator object
3. Allocate GstMemory objects with mem_type as 'dmabuf'

Signed-off-by: Pooja Prajod <a0132412@ti.com>
---
 configure.ac                              |   5 +
 gst-libs/gst/Makefile.am                  |   4 +-
 gst-libs/gst/drm/Makefile.am              |  33 +++++
 gst-libs/gst/drm/gstdrmallocator.c        | 206 ++++++++++++++++++++++++++++++
 gst-libs/gst/drm/gstdrmallocator.h        |  77 +++++++++++
 pkgconfig/Makefile.am                     |   3 +
 pkgconfig/gstreamer-drm-uninstalled.pc.in |  11 ++
 pkgconfig/gstreamer-drm.pc.in             |  12 ++
 8 files changed, 349 insertions(+), 2 deletions(-)
 create mode 100644 gst-libs/gst/drm/Makefile.am
 create mode 100644 gst-libs/gst/drm/gstdrmallocator.c
 create mode 100644 gst-libs/gst/drm/gstdrmallocator.h
 create mode 100644 pkgconfig/gstreamer-drm-uninstalled.pc.in
 create mode 100644 pkgconfig/gstreamer-drm.pc.in

diff --git a/configure.ac b/configure.ac
index 5e85e56..e254605 100644
--- a/configure.ac
+++ b/configure.ac
@@ -621,6 +621,8 @@ if test x$with_egl_module_name != x; then
   AC_DEFINE_UNQUOTED(GST_GL_LIBEGL_MODULE_NAME, "$with_egl_module_name", [EGL module name])
 fi
 
+PKG_CHECK_MODULES([DRM], [libdrm libdrm_omap], HAVE_KMS=yes, HAVE_KMS=no)
+
 AC_ARG_ENABLE([wgl],
      [  --enable-wgl            Enable WGL support @<:@default=auto@:>@],
      [case "${enableval}" in
@@ -3590,6 +3592,7 @@ gst-libs/Makefile
 gst-libs/gst/Makefile
 gst-libs/gst/adaptivedemux/Makefile
 gst-libs/gst/basecamerabinsrc/Makefile
+gst-libs/gst/drm/Makefile
 gst-libs/gst/gl/Makefile
 gst-libs/gst/gl/android/Makefile
 gst-libs/gst/gl/cocoa/Makefile
@@ -3749,6 +3752,8 @@ pkgconfig/gstreamer-plugins-bad.pc
 pkgconfig/gstreamer-plugins-bad-uninstalled.pc
 pkgconfig/gstreamer-codecparsers.pc
 pkgconfig/gstreamer-codecparsers-uninstalled.pc
+pkgconfig/gstreamer-drm.pc
+pkgconfig/gstreamer-drm-uninstalled.pc
 pkgconfig/gstreamer-insertbin.pc
 pkgconfig/gstreamer-insertbin-uninstalled.pc
 pkgconfig/gstreamer-gl.pc
diff --git a/gst-libs/gst/Makefile.am b/gst-libs/gst/Makefile.am
index 7d0b309..5ec3967 100644
--- a/gst-libs/gst/Makefile.am
+++ b/gst-libs/gst/Makefile.am
@@ -11,7 +11,7 @@ WAYLAND_DIR=wayland
 endif
 
 SUBDIRS = uridownloader adaptivedemux interfaces basecamerabinsrc codecparsers \
-	 insertbin mpegts base video audio player $(GL_DIR) $(WAYLAND_DIR)
+	 insertbin mpegts base video audio player drm $(GL_DIR) $(WAYLAND_DIR)
 
 noinst_HEADERS = gst-i18n-plugin.h gettext.h glib-compat-private.h
 DIST_SUBDIRS = uridownloader adaptivedemux interfaces gl basecamerabinsrc \
@@ -24,7 +24,7 @@ adaptivedemux: uridownloader
 
 INDEPENDENT_SUBDIRS = \
 	interfaces basecamerabinsrc codecparsers insertbin uridownloader \
-	mpegts base player $(GL_DIR) $(WAYLAND_DIR)
+	mpegts base player drm $(GL_DIR) $(WAYLAND_DIR)
 
 .PHONY: independent-subdirs $(INDEPENDENT_SUBDIRS)
 
diff --git a/gst-libs/gst/drm/Makefile.am b/gst-libs/gst/drm/Makefile.am
new file mode 100644
index 0000000..9a45dfb
--- /dev/null
+++ b/gst-libs/gst/drm/Makefile.am
@@ -0,0 +1,33 @@
+lib_LTLIBRARIES = libgstdrm-@GST_API_VERSION@.la
+
+CLEANFILES = $(BUILT_SOURCES)
+
+libgstdrm_@GST_API_VERSION@_la_SOURCES = \
+	gstdrmallocator.c 
+
+libgstdrm_@GST_API_VERSION@includedir = \
+	$(includedir)/gstreamer-@GST_API_VERSION@/gst/drm
+
+libgstdrm_@GST_API_VERSION@include_HEADERS = \
+	gstdrmallocator.h 
+
+libgstdrm_@GST_API_VERSION@_la_CFLAGS = \
+	$(DRM_CFLAGS) \
+	$(OMAPDRM_CFLAGS) \
+	$(GST_PLUGINS_BAD_CFLAGS) \
+	$(GST_PLUGINS_BASE_CFLAGS) \
+	-DGST_USE_UNSTABLE_API \
+	$(GST_CFLAGS)
+
+libgstdrm_@GST_API_VERSION@_la_LIBADD = \
+	$(DRM_LIBS) \
+	$(GST_PLUGINS_BASE_LIBS) \
+	$(GST_BASE_LIBS) \
+        -lgstallocators-$(GST_API_VERSION) \
+	$(GST_LIBS) 
+
+libgstdrm_@GST_API_VERSION@_la_LDFLAGS = \
+	$(DRM_LDFLAGS) \
+	$(GST_LIB_LDFLAGS) \
+	$(GST_ALL_LDFLAGS) \
+	$(GST_LT_LDFLAGS)
diff --git a/gst-libs/gst/drm/gstdrmallocator.c b/gst-libs/gst/drm/gstdrmallocator.c
new file mode 100644
index 0000000..b557ad2
--- /dev/null
+++ b/gst-libs/gst/drm/gstdrmallocator.c
@@ -0,0 +1,206 @@
+/*
+ * GStreamer
+ *
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * Authors:
+ *  Pooja Prajod <poojaprajod@ti.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+/**
+ * SECTION:GstDRMAllocator
+ * @short_description: GStreamer DRM allocator support
+ *
+ * Since: 1.6.3
+ */
+
+
+#include "gstdrmallocator.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#define INVALID_DRM_FD (-1)
+
+GST_DEBUG_CATEGORY (drmallocator_debug);
+#define GST_CAT_DEFAULT drmallocator_debug
+
+#define gst_drm_allocator_parent_class parent_class
+G_DEFINE_TYPE (GstDRMAllocator, gst_drm_allocator, GST_TYPE_FD_ALLOCATOR);
+
+static GstMemory *
+gst_drm_allocator_alloc (GstAllocator * allocator, gsize size,
+    GstAllocationParams * params)
+{
+  GstDRMAllocator *self = GST_DRM_ALLOCATOR (allocator);
+  int fd = -1;
+  int DrmDeviceFD = self->DrmDeviceFD;
+  GstMemory *mem;
+  /* Variable for DRM Dumb Buffers */
+
+  struct drm_mode_create_dumb creq;
+  struct drm_mode_destroy_dumb dreq;
+  int ret ;
+  
+  GST_LOG_OBJECT (self, "DRM Memory alloc");  
+  
+  memset(&creq, 0, sizeof(struct drm_mode_create_dumb));
+  /* 
+   We have only total size as argument to _allocator_alloc.
+   Since the DDR storage is linear, it is as good as saying
+   the buffer is of width = size and height = 1
+  */
+  creq.width = size;
+  creq.height = 1;
+  creq.bpp = 8;
+
+  /* Create a DRM dumb buffer */
+  ret = drmIoctl (DrmDeviceFD, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
+  if (ret < 0) {
+    GST_ERROR_OBJECT (self, "Create DRM dumb buffer failed");
+    return NULL;
+  }
+  /* Get a dmabuf fd from the dumb buffer handle */
+  drmPrimeHandleToFD (DrmDeviceFD, creq.handle, DRM_CLOEXEC | O_RDWR, &fd);
+
+  if (fd < 0) {
+    GST_ERROR_OBJECT (self, "Invalid fd returned: %d", fd);
+    goto fail;
+  }
+
+  /* Get a dmabuf gstmemory with the fd */
+  mem = gst_fd_allocator_alloc (allocator, fd, size, 0);  
+
+  if (G_UNLIKELY (!mem)) {
+    GST_ERROR_OBJECT (self, "GstDmaBufMemory allocation failed");
+    close (fd);
+    goto fail;
+  }
+
+  return mem;
+
+  fail:
+    memset(&dreq, 0, sizeof(struct drm_mode_destroy_dumb));
+    dreq.handle = creq.handle;
+    drmIoctl (DrmDeviceFD, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
+    return NULL;
+}
+
+static void
+gst_drm_allocator_free (GstAllocator * allocator, GstMemory * mem)
+{
+  GstDRMAllocator *self = GST_DRM_ALLOCATOR (allocator);
+  uint32_t handle = 0;
+  int DrmDeviceFD = self->DrmDeviceFD;
+  int fd = -1;
+
+  GST_LOG_OBJECT (self, "DRM Memory free");
+
+  g_return_if_fail (GST_IS_ALLOCATOR (allocator));
+  g_return_if_fail (mem != NULL);
+  g_return_if_fail (gst_is_drm_memory (mem));
+
+  fd = gst_fd_memory_get_fd (mem);
+  drmPrimeFDToHandle(DrmDeviceFD, fd, &handle);    
+
+  /* Incase there are some mapped memory, we unmap and ready it to be cleaned*/
+  GST_ALLOCATOR_CLASS (parent_class)->free (allocator, mem);
+
+  if (handle) {
+    struct drm_mode_destroy_dumb dreq;
+    memset(&dreq, 0, sizeof(struct drm_mode_destroy_dumb));
+    dreq.handle = handle;
+    drmIoctl (DrmDeviceFD, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
+  }
+  
+  close (fd);
+}
+
+static void
+gst_drm_allocator_finalize (GObject * obj)
+{
+  GstDRMAllocator *self = GST_DRM_ALLOCATOR (obj);
+  GST_LOG_OBJECT (obj, "DRM Allocator finalize");
+
+  close (self->DrmDeviceFD);
+  self->DrmDeviceFD = INVALID_DRM_FD;
+
+  G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_drm_allocator_class_init (GstDRMAllocatorClass * klass)
+{
+  GstAllocatorClass *drm_alloc = (GstAllocatorClass *) klass;
+
+  drm_alloc->alloc = GST_DEBUG_FUNCPTR (gst_drm_allocator_alloc);
+  drm_alloc->free = GST_DEBUG_FUNCPTR (gst_drm_allocator_free);
+  GST_DEBUG_CATEGORY_INIT (drmallocator_debug, "drmallocator", 0,
+    "GstDRMAllocator debug");
+
+}
+
+static void
+gst_drm_allocator_init (GstDRMAllocator * self)
+{
+  GstAllocator *alloc = GST_ALLOCATOR_CAST (self);
+  GObjectClass *object_class = G_OBJECT_CLASS (GST_DRM_ALLOCATOR_GET_CLASS(self));
+  
+  if (self->DrmDeviceFD <= 0) {
+    self->DrmDeviceFD = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
+    if (self->DrmDeviceFD < 0) {
+      GST_ERROR_OBJECT (self, "Failed to open DRM device");
+    } else {
+      drmDropMaster (self->DrmDeviceFD);
+    }
+  }
+
+  alloc->mem_type = GST_ALLOCATOR_DMABUF;
+
+  object_class->finalize = gst_drm_allocator_finalize;
+
+  GST_OBJECT_FLAG_UNSET (self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
+}
+
+void
+gst_drm_allocator_register (void)
+{
+  gst_allocator_register (GST_ALLOCATOR_DRM,
+      g_object_new (GST_TYPE_DRM_ALLOCATOR, NULL));
+}
+
+GstAllocator *
+gst_drm_allocator_get (void)
+{
+  GstAllocator *alloc;
+  alloc = gst_allocator_find (GST_ALLOCATOR_DRM);
+  if (!alloc) {
+    gst_drm_allocator_register();
+    alloc = gst_allocator_find (GST_ALLOCATOR_DRM);
+  }
+  return alloc; 
+}
+
+gboolean
+gst_is_drm_memory (GstMemory * mem)
+{
+  return gst_memory_is_type (mem, GST_ALLOCATOR_DMABUF);
+}
diff --git a/gst-libs/gst/drm/gstdrmallocator.h b/gst-libs/gst/drm/gstdrmallocator.h
new file mode 100644
index 0000000..1ca93ba
--- /dev/null
+++ b/gst-libs/gst/drm/gstdrmallocator.h
@@ -0,0 +1,77 @@
+/*
+ * GStreamer
+ *
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * Authors:
+ *  Pooja Prajod <poojaprajod@ti.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+/**
+ * SECTION:GstDRMAllocator
+ * @short_description: GStreamer DRM allocator support
+ *
+ * Since: 1.6.3
+ */
+
+#ifndef __GSTDRMALLOCATOR_H__
+#define __GSTDRMALLOCATOR_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/allocators/allocators.h>
+#include <stdint.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <fcntl.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DRM_ALLOCATOR                  (gst_drm_allocator_get_type ())
+#define GST_DRM_ALLOCATOR(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DRM_ALLOCATOR, GstDRMAllocator))
+#define GST_IS_DRM_ALLOCATOR(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DRM_ALLOCATOR))
+#define GST_DRM_ALLOCATOR_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DRM_ALLOCATOR, GstDRMAllocatorClass))
+#define GST_IS_DRM_ALLOCATOR_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DRM_ALLOCATOR))
+#define GST_DRM_ALLOCATOR_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DRM_ALLOCATOR, GstDRMAllocatorClass))
+
+#define GST_ALLOCATOR_DRM "DRM"
+
+typedef struct _GstDRMAllocator GstDRMAllocator;
+typedef struct _GstDRMAllocatorClass GstDRMAllocatorClass;
+
+struct _GstDRMAllocator
+{
+  GstFdAllocator parent;
+  int DrmDeviceFD;
+};
+
+struct _GstDRMAllocatorClass
+{
+  GstFdAllocatorClass parent_class;
+};
+
+void gst_drm_allocator_register (void);
+GstAllocator * gst_drm_allocator_get (void);
+
+gboolean gst_is_drm_memory (GstMemory * mem);
+
+GType gst_drm_allocator_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GSTDRMALLOCATOR_H__ */
diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am
index 88c7e52..5fdccbf 100644
--- a/pkgconfig/Makefile.am
+++ b/pkgconfig/Makefile.am
@@ -2,6 +2,7 @@
 ### all of the standard pc files we need to generate
 pcverfiles =  \
 	gstreamer-plugins-bad-@GST_API_VERSION@.pc \
+        gstreamer-drm-@GST_API_VERSION@.pc \
 	gstreamer-codecparsers-@GST_API_VERSION@.pc \
 	gstreamer-insertbin-@GST_API_VERSION@.pc \
 	gstreamer-mpegts-@GST_API_VERSION@.pc \
@@ -12,6 +13,7 @@ pcverfiles =  \
 
 pcverfiles_uninstalled = \
 	gstreamer-plugins-bad-@GST_API_VERSION@-uninstalled.pc \
+        gstreamer-drm-@GST_API_VERSION@-uninstalled.pc \
 	gstreamer-codecparsers-@GST_API_VERSION@-uninstalled.pc \
 	gstreamer-insertbin-@GST_API_VERSION@-uninstalled.pc \
 	gstreamer-mpegts-@GST_API_VERSION@-uninstalled.pc \
@@ -43,6 +45,7 @@ pkgconfig_DATA = $(pcverfiles)
 CLEANFILES = $(pcverfiles) $(pcverfiles_uninstalled)
 pcinfiles = \
            gstreamer-plugins-bad.pc.in gstreamer-plugins-bad-uninstalled.pc.in \
+           gstreamer-drm.pc.in gstreamer-drm-uninstalled.pc.in \
            gstreamer-codecparsers.pc.in gstreamer-codecparsers-uninstalled.pc.in \
            gstreamer-gl.pc.in gstreamer-gl-uninstalled.pc.in \
            gstreamer-insertbin.pc.in gstreamer-insertbin-uninstalled.pc.in \
diff --git a/pkgconfig/gstreamer-drm-uninstalled.pc.in b/pkgconfig/gstreamer-drm-uninstalled.pc.in
new file mode 100644
index 0000000..9dcf978
--- /dev/null
+++ b/pkgconfig/gstreamer-drm-uninstalled.pc.in
@@ -0,0 +1,11 @@
+prefix=
+exec_prefix=
+libdir=${pcfiledir}/../gst-libs/gst/drm
+includedir=${pcfiledir}/../gst-libs
+
+Name: GStreamer DRM Allocator, Uninstalled
+Description: DRM Allocator for GStreamer elements, uninstalled
+Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@
+Version: @VERSION@
+Libs: -L${libdir} ${libdir}/libgstdrm-@GST_MAJORMINOR@.la
+Cflags: -I${includedir}
diff --git a/pkgconfig/gstreamer-drm.pc.in b/pkgconfig/gstreamer-drm.pc.in
new file mode 100644
index 0000000..d155e80
--- /dev/null
+++ b/pkgconfig/gstreamer-drm.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/gstreamer-@GST_MAJORMINOR@
+
+Name: GStreamer DRM Allocator
+Description: DRM Allocator for GStreamer elements
+Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@
+Version: @VERSION@
+Libs: -L${libdir} -lgstdrm-@GST_MAJORMINOR@
+Cflags: -I${includedir}
+
-- 
1.9.1

