Add ion dmabuf support in gldownload

Support copy into dma-fb buffer if support the buffer format

Upstream Status: Inappropriate [i.MX specific]

Signed-off-by: Haihua Hu <jared.hu@nxp.com>
diff --git a/ext/gl/gstgldownloadelement.c b/ext/gl/gstgldownloadelement.c
index a24a73d..77dfc46 100644
--- a/ext/gl/gstgldownloadelement.c
+++ b/ext/gl/gstgldownloadelement.c
@@ -34,6 +34,10 @@
 #include <gst/gl/gstglphymemory.h>
 #endif
 
+#if GST_GL_HAVE_IONDMA
+#include <gst/gl/gstglmemorydma.h>
+#endif
+
 GST_DEBUG_CATEGORY_STATIC (gst_gl_download_element_debug);
 #define GST_CAT_DEFAULT gst_gl_download_element_debug
 
@@ -399,11 +403,26 @@
     GstBuffer * inbuf, GstBuffer ** outbuf)
 {
   GstGLDownloadElement *dl = GST_GL_DOWNLOAD_ELEMENT (bt);
+  GstCaps *src_caps = gst_pad_get_current_caps (bt->srcpad);
   gint i, n;
   GstGLMemory *glmem;
 
-#if GST_GL_HAVE_PHYMEM
   glmem = gst_buffer_peek_memory (inbuf, 0);
+#if GST_GL_HAVE_IONDMA
+  if (gst_is_gl_memory_dma (glmem)) {
+    GstGLContext *context = GST_GL_BASE_FILTER (bt)->context;
+    GstVideoInfo info;
+
+    gst_video_info_from_caps (&info, src_caps);
+    *outbuf = gst_gl_memory_dma_buffer_to_gstbuffer (context, &info, inbuf);
+
+    GST_DEBUG_OBJECT (dl, "gl download with dma buf.");
+
+    return GST_FLOW_OK;
+  }
+#endif
+
+#if GST_GL_HAVE_PHYMEM
   if (gst_is_gl_physical_memory (glmem)) {
     GstGLContext *context = GST_GL_BASE_FILTER (bt)->context;
     GstVideoInfo info;
@@ -411,7 +430,7 @@
     gst_video_info_from_caps (&info, src_caps);
     *outbuf = gst_gl_phymem_buffer_to_gstbuffer (context, &info, inbuf);
 
-    GST_DEBUG_OBJECT (download, "gl download with direct viv.");
+    GST_DEBUG_OBJECT (dl, "gl download with direct viv.");
 
     return GST_FLOW_OK;
   }
@@ -485,6 +504,7 @@
   GstCaps *caps;
   GstStructure *config;
   gsize size;
+  GstVideoFormat fmt;
 
   gst_query_parse_allocation (query, &caps, NULL);
   if (!gst_video_info_from_caps (&info, caps)) {
@@ -492,12 +512,21 @@
     return FALSE;
   }
 
-  GST_DEBUG_OBJECT (bt, "video format is %s", gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&info)));
-
   gst_allocation_params_init (&params);
 
+  fmt = GST_VIDEO_INFO_FORMAT (&info);
+
+  GST_DEBUG_OBJECT (bt, "video format is %s", gst_video_format_to_string (fmt));
+
+#if GST_GL_HAVE_IONDMA
+  if (fmt == GST_VIDEO_FORMAT_RGBA || fmt == GST_VIDEO_FORMAT_RGB16) {
+    allocator = gst_gl_memory_dma_allocator_obtain ();
+    GST_DEBUG_OBJECT (bt, "obtain dma memory allocator %p.", allocator);
+  }
+#endif
+
 #if GST_GL_HAVE_PHYMEM
-  if (gst_is_gl_physical_memory_supported_fmt (&info)) {
+  if (!allocator && gst_is_gl_physical_memory_supported_fmt (&info)) {
     allocator = gst_phy_mem_allocator_obtain ();
     GST_DEBUG_OBJECT (bt, "obtain physical memory allocator %p.", allocator);
   }
diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am
index efa749a..0ea84a1 100644
--- a/gst-libs/gst/gl/Makefile.am
+++ b/gst-libs/gst/gl/Makefile.am
@@ -153,6 +153,12 @@
 libgstgl_@GST_API_VERSION@_la_LIBADD += -lg2d
 endif
 
+if HAVE_IONDMA
+libgstgl_@GST_API_VERSION@_la_SOURCES += gstglmemorydma.c
+libgstgl_@GST_API_VERSION@include_HEADERS += gstglmemorydma.h
+endif
+
+
 configexecincludedir = $(libdir)/gstreamer-@GST_API_VERSION@/include/gst/gl
 nodist_configexecinclude_HEADERS = $(built_sys_header_configure)
 
diff --git a/gst-libs/gst/gl/gstgl_fwd.h b/gst-libs/gst/gl/gstgl_fwd.h
index 19ca6f3..0543003 100644
--- a/gst-libs/gst/gl/gstgl_fwd.h
+++ b/gst-libs/gst/gl/gstgl_fwd.h
@@ -51,6 +51,10 @@
 typedef struct _GstGLMemoryAllocator GstGLMemoryAllocator;
 typedef struct _GstGLMemoryAllocatorClass GstGLMemoryAllocatorClass;
 
+typedef struct _GstGLMemoryDMA GstGLMemoryDMA;
+typedef struct _GstGLMemoryDMAAllocator GstGLMemoryDMAAllocator;
+typedef struct _GstGLMemoryDMAAllocatorClass GstGLMemoryDMAAllocatorClass;
+
 typedef struct _GstGLMemoryPBO GstGLMemoryPBO;
 typedef struct _GstGLMemoryPBOAllocator GstGLMemoryPBOAllocator;
 typedef struct _GstGLMemoryPBOAllocatorClass GstGLMemoryPBOAllocatorClass;
diff --git a/gst-libs/gst/gl/gstglmemorydma.c b/gst-libs/gst/gl/gstglmemorydma.c
new file mode 100644
index 0000000..6609d46
--- /dev/null
+++ b/gst-libs/gst/gl/gstglmemorydma.c
@@ -0,0 +1,260 @@
+/*
+ * GStreamer
+ * Copyright (c) 2016, Freescale Semiconductor, Inc. 
+ *
+ * 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 Foundatdma; either
+ * versdma 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 Foundatdma, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglfuncs.h"
+
+#include <string.h>
+
+#include <gst/allocators/gstdmabuf.h>
+#include <gst/gl/gstglmemorydma.h>
+
+#if GST_GL_HAVE_IONDMA
+#include <gst/allocators/gstionmemory.h>
+#endif
+
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_DMA_MEMORY);
+#define GST_CAT_DEFAULT GST_CAT_GL_DMA_MEMORY
+
+#define parent_class gst_gl_memory_dma_allocator_parent_class
+G_DEFINE_TYPE (GstGLMemoryDMAAllocator, gst_gl_memory_dma_allocator,
+    GST_TYPE_GL_MEMORY_ALLOCATOR);
+
+static void
+gst_gl_memory_dma_init_instance (void)
+{
+  GstAllocator *ion_allocator = NULL;
+  GstGLMemoryDMAAllocator *_gl_allocator;
+
+  GST_DEBUG_CATEGORY_INIT (GST_CAT_GL_DMA_MEMORY, "glmemorydma", 0, "OpenGL dma memory");
+
+#if GST_GL_HAVE_IONDMA
+  ion_allocator = gst_ion_allocator_obtain();
+#endif
+
+  if (!ion_allocator)
+    return;
+
+  gst_gl_memory_init_once ();
+
+  _gl_allocator = (GstGLMemoryDMAAllocator *) g_object_new (GST_TYPE_GL_MEMORY_DMA_ALLOCATOR, NULL);
+  _gl_allocator->ion_allocator = ion_allocator;
+
+  gst_allocator_register (GST_GL_MEMORY_DMA_ALLOCATOR_NAME,
+      gst_object_ref (_gl_allocator));
+}
+
+GstAllocator *
+gst_gl_memory_dma_allocator_obtain (void)
+{
+
+  static GOnce once = G_ONCE_INIT;
+  GstAllocator *allocator;
+
+  g_once (&once, (GThreadFunc) gst_gl_memory_dma_init_instance, NULL);
+
+  allocator = gst_allocator_find (GST_GL_MEMORY_DMA_ALLOCATOR_NAME);
+  if (allocator == NULL)
+    GST_WARNING ("No allocator named %s found", GST_GL_MEMORY_DMA_ALLOCATOR_NAME);
+
+  return allocator;
+}
+
+static void
+gst_gl_memory_dma_allocator_dispose (GObject * object)
+{
+  GstGLMemoryDMAAllocator *gl_dma_alloc= GST_GL_MEMORY_DMA_ALLOCATOR (object);
+
+  if (gl_dma_alloc->ion_allocator) {
+    GST_DEBUG ("free ion allocator");
+    gst_object_unref (gl_dma_alloc->ion_allocator);
+    gl_dma_alloc->ion_allocator = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static gboolean
+_gl_mem_create (GstGLMemoryDMA * gl_mem, GError ** error)
+{
+  GstGLContext *context = gl_mem->mem.mem.context;
+  GstGLBaseMemoryAllocatorClass *alloc_class;
+  guint dma_fd;
+
+  alloc_class = GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (parent_class);
+  if (!alloc_class->create ((GstGLBaseMemory *) gl_mem, error))
+    return FALSE;
+
+  dma_fd = gst_dmabuf_memory_get_fd ((GstMemory*) gl_mem->dma);
+
+  gl_mem->eglimage = 
+    gst_egl_image_from_dmabuf (context, dma_fd, &gl_mem->mem.info, 0,0);
+
+  if (!gl_mem->eglimage) {
+    GST_CAT_ERROR (GST_CAT_GL_DMA_MEMORY, "Can't allocate eglimage memory");
+    return FALSE;
+  }
+
+  const GstGLFuncs *gl = context->gl_vtable;
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->BindTexture (GL_TEXTURE_2D, gl_mem->mem.tex_id);
+  gl->EGLImageTargetTexture2D (GL_TEXTURE_2D,
+      gst_egl_image_get_image (gl_mem->eglimage));
+
+  GST_CAT_DEBUG (GST_CAT_GL_DMA_MEMORY, "generated dma buffer %p fd %u texid %u",
+      gl_mem, dma_fd, gl_mem->mem.tex_id);
+
+  return TRUE;
+}
+
+static GstMemory *
+_gl_mem_alloc (GstAllocator * allocator, gsize size,
+    GstAllocationParams * params)
+{
+  g_warning ("Use gst_gl_base_memory_alloc () to allocate from this "
+      "GstGLMemoryDMA allocator");
+
+  return NULL;
+}
+
+static void
+_gl_mem_destroy (GstGLMemoryDMA * gl_mem)
+{
+  GST_CAT_DEBUG (GST_CAT_GL_DMA_MEMORY, "destroy gl dma buffer %p", gl_mem);
+
+  if (gl_mem->eglimage)
+    gst_egl_image_unref (gl_mem->eglimage);
+  gl_mem->eglimage = NULL;
+  if (gl_mem->dma)
+    gst_memory_unref (GST_MEMORY_CAST (gl_mem->dma));
+  gl_mem->dma = NULL;
+
+  GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (parent_class)->destroy ((GstGLBaseMemory
+          *) gl_mem);
+}
+
+static GstGLMemoryDMA *
+_gl_mem_dma_alloc (GstGLBaseMemoryAllocator * allocator,
+    GstGLVideoAllocationParams * params)
+{
+  GstGLMemoryDMA *mem;
+  guint alloc_flags;
+  gsize size;
+  GstGLMemoryDMAAllocator *gl_dma_alloc = GST_GL_MEMORY_DMA_ALLOCATOR (allocator);
+
+  alloc_flags = params->parent.alloc_flags;
+
+  g_return_val_if_fail (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
+      NULL);
+
+  mem = g_new0 (GstGLMemoryDMA, 1);
+
+  mem->params = params->parent.alloc_params;
+
+  size = gst_gl_get_plane_data_size (params->v_info, params->valign, params->plane);
+  mem->dma = gst_allocator_alloc (gl_dma_alloc->ion_allocator, size, mem->params);
+
+  if (!mem->dma) {
+    GST_CAT_ERROR (GST_CAT_GL_DMA_MEMORY, "Can't allocate dma memory size %d", size);
+    g_free(mem);
+    return NULL;
+  }
+
+  gst_gl_memory_init (GST_GL_MEMORY_CAST (mem), GST_ALLOCATOR_CAST (allocator),
+      NULL, params->parent.context, params->target, params->tex_format,
+      params->parent.alloc_params, params->v_info, params->plane,
+      params->valign, params->parent.user_data, params->parent.notify);
+
+  return mem;
+}
+
+static void
+gst_gl_memory_dma_allocator_class_init (GstGLMemoryDMAAllocatorClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstGLBaseMemoryAllocatorClass *gl_base;
+  GstAllocatorClass *allocator_class;
+
+  gl_base = (GstGLBaseMemoryAllocatorClass *) klass;
+  allocator_class = (GstAllocatorClass *) klass;
+
+  gl_base->alloc = (GstGLBaseMemoryAllocatorAllocFunction) _gl_mem_dma_alloc;
+  gl_base->create = (GstGLBaseMemoryAllocatorCreateFunction) _gl_mem_create;
+  gl_base->destroy = (GstGLBaseMemoryAllocatorDestroyFunction) _gl_mem_destroy;
+  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_gl_memory_dma_allocator_dispose);
+
+  allocator_class->alloc = _gl_mem_alloc;
+}
+
+static void
+gst_gl_memory_dma_allocator_init (GstGLMemoryDMAAllocator * allocator)
+{
+  GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
+
+  alloc->mem_type = GST_GL_MEMORY_DMA_ALLOCATOR_NAME;
+
+  GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
+}
+
+gboolean
+gst_is_gl_memory_dma (GstMemory * mem)
+{
+  return mem != NULL && mem->allocator != NULL
+      && g_type_is_a (G_OBJECT_TYPE (mem->allocator),
+      GST_TYPE_GL_MEMORY_DMA_ALLOCATOR);
+}
+
+static void
+_finish_texture (GstGLContext * ctx, gpointer *data)
+{
+  GstGLFuncs *gl = ctx->gl_vtable;
+
+  gl->Finish ();
+}
+
+GstBuffer *
+gst_gl_memory_dma_buffer_to_gstbuffer (GstGLContext *ctx, GstVideoInfo * info,
+    GstBuffer * glbuf)
+{
+  GstBuffer *buf;
+  GstGLMemoryDMA *glmem;
+
+  gst_gl_context_thread_add (ctx, (GstGLContextThreadFunc) _finish_texture, NULL);
+
+  glmem = gst_buffer_peek_memory (glbuf, 0);
+
+  buf = gst_buffer_new ();
+  gst_buffer_append_memory (buf, (GstMemory *) glmem->dma);
+  gst_memory_ref ((GstMemory *)glmem->dma);
+
+  gst_buffer_add_video_meta_full (buf, 0,
+      GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
+      GST_VIDEO_INFO_HEIGHT (info), 1, info->offset, info->stride);
+  GST_BUFFER_FLAGS (buf) = GST_BUFFER_FLAGS (glbuf);
+  GST_BUFFER_PTS (buf) = GST_BUFFER_PTS (glbuf);
+  GST_BUFFER_DTS (buf) = GST_BUFFER_DTS (glbuf);
+  GST_BUFFER_DURATION (buf) = GST_BUFFER_DURATION (glbuf);
+
+  return buf;
+}
diff --git a/gst-libs/gst/gl/gstglmemorydma.h b/gst-libs/gst/gl/gstglmemorydma.h
new file mode 100644
index 0000000..863425a
--- /dev/null
+++ b/gst-libs/gst/gl/gstglmemorydma.h
@@ -0,0 +1,82 @@
+/*
+ * GStreamer
+ * Copyright (c) 2016, Freescale Semiconductor, Inc. 
+ *
+ * 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 Foundatdma; either
+ * versdma 2 of the License, or (at your optdma) any later versdma.
+ *
+ * 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 Foundatdma, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_GL_MEMORY_DMA_H_
+#define _GST_GL_MEMORY_DMA_H_
+
+#include <gst/gst.h>
+#include <gst/gstallocator.h>
+#include <gst/gstmemory.h>
+#include <gst/video/video.h>
+
+#include <gst/gl/gl.h>
+#include <gst/gl/egl/gstglcontext_egl.h>
+#include <gst/gl/egl/gsteglimage.h>
+
+#include <gst/gl/gstglmemory.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_MEMORY_DMA_ALLOCATOR (gst_gl_memory_dma_allocator_get_type())
+GST_GL_API
+GType gst_gl_memory_dma_allocator_get_type(void);
+
+#define GST_IS_GL_MEMORY_DMA_ALLOCATOR(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GL_MEMORY_DMA_ALLOCATOR))
+#define GST_IS_GL_MEMORY_DMA_ALLOCATOR_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GL_MEMORY_DMA_ALLOCATOR))
+#define GST_GL_MEMORY_DMA_ALLOCATOR_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GL_MEMORY_DMA_ALLOCATOR, GstGLMemoryDMAAllocatorClass))
+#define GST_GL_MEMORY_DMA_ALLOCATOR(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GL_MEMORY_DMA_ALLOCATOR, GstGLMemoryDMAAllocator))
+#define GST_GL_MEMORY_DMA_ALLOCATOR_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GL_MEMORY_DMA_ALLOCATOR, GstGLAllocatorClass))
+#define GST_GL_MEMORY_DMA_ALLOCATOR_CAST(obj)            ((GstGLMemoryDMAAllocator *)(obj))
+
+struct _GstGLMemoryDMA
+{
+  GstGLMemory   mem;
+
+  /* <private> */
+  GstEGLImage	*eglimage;
+  GstMemory     *dma;
+  GstAllocationParams *params;
+};
+
+#define GST_GL_MEMORY_DMA_ALLOCATOR_NAME   "GLMemoryDMA"
+
+struct _GstGLMemoryDMAAllocator
+{
+  GstGLMemoryAllocator parent;
+  GstAllocator  *ion_allocator;
+};
+
+struct _GstGLMemoryDMAAllocatorClass
+{
+  GstGLMemoryAllocatorClass parent_class;
+};
+
+GST_GL_API
+GstAllocator *gst_gl_memory_dma_allocator_obtain (void);
+
+GST_GL_API
+gboolean      gst_is_gl_memory_dma                      (GstMemory * mem);
+
+GST_GL_API
+GstBuffer *   gst_gl_memory_dma_buffer_to_gstbuffer     (GstGLContext * ctx, GstVideoInfo * info, GstBuffer * glbuf);
+
+G_END_DECLS
+
+#endif /* _GST_GL_MEMORY_DMA_H_ */