[514/906] add GstGLMemory and allocator
authorMatthew Waters <ystreet00@gmail.com>
Fri, 6 Jul 2012 08:22:22 +0000 (18:22 +1000)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:31:24 +0000 (19:31 +0000)
implement custom GstMemory for GL textures
currently map/unmap returns NULL although it might be favourable to upload/download/cache the image data

gst-libs/gst/gl/Makefile.am
gst-libs/gst/gl/gstglmemory.c [new file with mode: 0644]
gst-libs/gst/gl/gstglmemory.h [new file with mode: 0644]
tests/check/libs/gstglmemory.c [new file with mode: 0644]

index 333e801..1b825cc 100644 (file)
@@ -10,6 +10,7 @@ EXTRA_DIST = \
 
 libgstgl_@GST_API_VERSION@_la_SOURCES = \
        gstgldisplay.c \
+       gstglmemory.c \
        gstglfilter.c \
        gstglmixer.c \
         gstglshader.c \
@@ -32,6 +33,7 @@ libgstgl_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@
 libgstgl_@GST_API_VERSION@include_HEADERS = \
        gstglwindow.h \
        gstgldisplay.h \
+       gstglmemory.h \
        gstgles2.h \
        gstglfilter.h \
        gstglmixer.h \
diff --git a/gst-libs/gst/gl/gstglmemory.c b/gst-libs/gst/gl/gstglmemory.c
new file mode 100644 (file)
index 0000000..ea7d7b2
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/video/video.h>
+
+#include "gstglmemory.h"
+
+/*GST_DEBUG_CATEGORY_STATIC (GST_CAT_GL_MEMORY);
+#define GST_CAT_DEFUALT GST_CAT_GL_MEMORY
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_MEMORY);*/
+
+static GstAllocator *_gl_allocator;
+
+typedef struct
+{
+  GstGLMemory *src;
+  GLuint tex_id;
+} GstGLMemoryCopyParams;
+
+static void
+_gl_mem_init (GstGLMemory * mem, GstAllocator * allocator, GstMemory * parent,
+    GstGLDisplay * display, GstVideoFormat v_format, gsize width, gsize height)
+{
+  gst_memory_init (GST_MEMORY_CAST (mem), GST_MEMORY_FLAG_NO_SHARE,
+      allocator, parent, 0, 0, 0, 0);
+
+  mem->display = g_object_ref (display);
+  mem->gl_format = GL_RGBA;
+  mem->v_format = v_format;
+  mem->width = width;
+  mem->height = height;
+
+  GST_DEBUG ("new GL memory");
+}
+
+static GstGLMemory *
+_gl_mem_new (GstAllocator * allocator, GstMemory * parent,
+    GstGLDisplay * display, GstVideoFormat v_format, gsize width, gsize height)
+{
+  GstGLMemory *mem;
+  GLuint tex_id;
+
+  gst_gl_display_gen_texture (display, &tex_id, v_format, width, height);
+  if (!tex_id) {
+    GST_WARNING ("Could not create GL texture with display:%p", display);
+  }
+
+  GST_TRACE ("created texture %u", tex_id);
+
+  mem = g_slice_alloc (sizeof (GstGLMemory));
+  _gl_mem_init (mem, allocator, parent, display, v_format, width, height);
+
+  mem->tex_id = tex_id;
+
+  return mem;
+}
+
+GstMemory *
+_gl_allocator_alloc_func (GstAllocator * allocator, gsize size,
+    GstAllocationParams * params, gpointer user_data)
+{
+  g_warning ("use gst_gl_memory_alloc () to allocate from this "
+      "GstGLMemory allocator");
+
+  return NULL;
+}
+
+gpointer
+_gl_mem_map_func (GstGLMemory * gl_mem, gsize maxsize, GstMapFlags flags)
+{
+  /* should we perform a {up,down}load? */
+  return NULL;
+}
+
+void
+_gl_mem_unmap_func (GstGLMemory * gl_mem)
+{
+}
+
+void
+_gl_mem_free_func (GstGLMemory * gl_mem)
+{
+  gst_gl_display_del_texture (gl_mem->display, &gl_mem->tex_id);
+
+  g_object_unref (gl_mem->display);
+
+  g_slice_free (GstGLMemory, gl_mem);
+}
+
+void
+_gl_mem_copy_thread (GstGLDisplay * display, gpointer data)
+{
+  GstGLMemoryCopyParams *copy_params;
+  GstGLMemory *src;
+  GLuint tex_id;
+  GLuint rboId, fboId;
+  GLenum status;
+  gsize width, height;
+  GLuint gl_format;
+  GstVideoFormat v_format;
+
+  copy_params = (GstGLMemoryCopyParams *) data;
+  src = copy_params->src;
+  width = src->width;
+  height = src->height;
+  v_format = src->v_format;
+  gl_format = src->gl_format;
+
+  if (!GLEW_EXT_framebuffer_object) {
+    //turn off the pipeline because Frame buffer object is a not present
+    gst_gl_display_set_error (display,
+        "Context, EXT_framebuffer_object not supported");
+    return;
+  }
+
+  gst_gl_display_gen_texture_thread (src->display, &tex_id, v_format, width,
+      height);
+  if (!tex_id) {
+    GST_WARNING ("Could not create GL texture with display:%p", src->display);
+  }
+
+  GST_DEBUG ("created texture %i", tex_id);
+
+  /* create a framebuffer object */
+  glGenFramebuffersEXT (1, &fboId);
+  glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fboId);
+
+  /* create a renderbuffer object */
+  glGenRenderbuffersEXT (1, &rboId);
+  glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, rboId);
+
+#ifndef OPENGL_ES2
+  glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width,
+      height);
+  glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
+      width, height);
+#else
+  glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16,
+      width, height);
+#endif
+  /* attach the renderbuffer to depth attachment point */
+  glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+      GL_RENDERBUFFER_EXT, rboId);
+
+#ifndef OPENGL_ES2
+  glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
+      GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboId);
+#endif
+
+  glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+      GL_TEXTURE_RECTANGLE_ARB, src->tex_id, 0);
+
+  /* check FBO status */
+  status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
+
+  if (status != GL_FRAMEBUFFER_COMPLETE) {
+    switch (status) {
+      case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+        GST_ERROR ("GL_FRAMEBUFFER_UNSUPPORTED");
+        break;
+
+      case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
+        GST_ERROR ("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+        break;
+
+      case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
+        GST_ERROR ("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
+        break;
+
+      case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
+        GST_ERROR ("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
+        break;
+
+      case GL_FRAMEBUFFER_UNDEFINED:
+        GST_ERROR ("GL_FRAMEBUFFER_UNDEFINED");
+        break;
+
+      default:
+        GST_ERROR ("General FBO error");
+    }
+    goto fbo_error;
+  }
+
+  /* copy tex */
+  glBindTexture (GL_TEXTURE_RECTANGLE_ARB, tex_id);
+  glCopyTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_format, 0, 0,
+      width, height, 0);
+  glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
+
+  glBindFramebuffer (GL_FRAMEBUFFER_EXT, 0);
+
+  glDeleteRenderbuffers (1, &rboId);
+  glDeleteFramebuffers (1, &fboId);
+
+  copy_params->tex_id = tex_id;
+
+fbo_error:
+  {
+    glDeleteRenderbuffers (1, &rboId);
+    glDeleteFramebuffers (1, &fboId);
+
+    copy_params->tex_id = 0;
+  }
+}
+
+GstMemory *
+_gl_mem_copy_func (GstGLMemory * src, gssize offset, gssize size)
+{
+  GstGLMemory *dest;
+  GstGLMemoryCopyParams copy_params;
+
+  copy_params = (GstGLMemoryCopyParams) {
+  src, 0,};
+
+  gst_gl_display_thread_add (src->display, _gl_mem_copy_thread, &copy_params);
+
+  dest = g_slice_alloc (sizeof (GstGLMemory));
+  _gl_mem_init (dest, src->mem.allocator, NULL, src->display, src->v_format,
+      src->width, src->height);
+
+  if (!copy_params.tex_id)
+    GST_WARNING ("Could not copy GL Memory");
+
+  dest->tex_id = copy_params.tex_id;
+
+  return (GstMemory *) dest;
+}
+
+GstGLMemory *
+gst_gl_memory_copy (GstGLMemory * src)
+{
+  return (GstGLMemory *) _gl_mem_copy_func (src, 0, 0);
+}
+
+GstMemory *
+_gl_mem_share_func (GstGLMemory * mem, gssize offset, gssize size)
+{
+  return NULL;
+}
+
+gboolean
+_gl_mem_is_span_func (GstGLMemory * mem1, GstGLMemory * mem2, gsize * offset)
+{
+  return FALSE;
+}
+
+static void
+_gl_mem_destroy_notify (gpointer user_data)
+{
+  GST_LOG ("GLTexture memory allocator freed");
+}
+
+/**
+ * gst_gl_memory_alloc:
+ * @display:a #GstGLDisplay
+ * @format: the format for the texture
+ * @width: width of the texture
+ * @height: height of the texture
+ * 
+ * Returns: a GstMemory object with a GL texture specified by @format, @width and @height
+ *          from @display
+ */
+GstMemory *
+gst_gl_memory_alloc (GstGLDisplay * display, GstVideoFormat format,
+    gsize width, gsize height)
+{
+  return (GstMemory *) _gl_mem_new (_gl_allocator, NULL, display, format, width,
+      height);
+}
+
+/**
+ * gst_gl_memory_init:
+ *
+ * Initializes the GL Memory allocator. It is safe to call this function multiple times
+ *
+ * Returns: a #GstAllocator
+ */
+void
+gst_gl_memory_init (void)
+{
+  static volatile gsize _init = 0;
+  static const GstMemoryInfo mem_info = {
+    GST_GL_MEMORY_ALLOCATOR,
+    (GstAllocatorAllocFunction) _gl_allocator_alloc_func,
+    (GstMemoryMapFunction) _gl_mem_map_func,
+    (GstMemoryUnmapFunction) _gl_mem_unmap_func,
+    (GstMemoryFreeFunction) _gl_mem_free_func,
+    (GstMemoryCopyFunction) _gl_mem_copy_func,
+    (GstMemoryShareFunction) _gl_mem_share_func,
+    (GstMemoryIsSpanFunction) _gl_mem_is_span_func,
+  };
+
+  if (g_once_init_enter (&_init)) {
+    _gl_allocator = gst_allocator_new (&mem_info, NULL, _gl_mem_destroy_notify);
+    gst_allocator_register (GST_GL_MEMORY_ALLOCATOR,
+        gst_allocator_ref (_gl_allocator));
+    g_once_init_leave (&_init, 1);
+  }
+}
diff --git a/gst-libs/gst/gl/gstglmemory.h b/gst-libs/gst/gl/gstglmemory.h
new file mode 100644 (file)
index 0000000..2d52d62
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_GL_MEMORY_H_
+#define _GST_GL_MEMORY_H_
+
+#include <gst/gst.h>
+#include <gst/gstmemory.h>
+
+#include "gstgldisplay.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_MEMORY (gst_gl_memory_get_type())
+GType gst_gl_memory_get_type(void);
+
+typedef struct _GstGLMemoryInitParams GstGLMemoryInitParams;
+typedef struct _GstGLMemory GstGLMemory;
+
+/**
+ * GstGLMemory:
+ * @mem: the parent object
+ * @display: the #GstGLDisplay to use
+ * @tex_id: the texture id
+ * @gl_format: the format of the texture
+ * @width: width of the texture
+ * @height: height of the texture
+ *
+ * Represents information about a GL texture
+ */
+struct _GstGLMemory
+{
+  GstMemory          mem;
+
+  GstGLDisplay      *display;
+  GLuint             tex_id;
+  GstVideoFormat     v_format;
+  GLenum             gl_format;
+  GLuint             width;
+  GLuint             height;
+};
+
+#define GST_GL_MEMORY_ALLOCATOR   "GLMemory"
+
+void gst_gl_memory_init (void);
+
+GstMemory * gst_gl_memory_alloc (GstGLDisplay * display, GstVideoFormat format,
+                                gsize width, gsize height);
+
+G_END_DECLS
+
+#endif /* _GST_GL_MEMORY_H_ */
diff --git a/tests/check/libs/gstglmemory.c b/tests/check/libs/gstglmemory.c
new file mode 100644 (file)
index 0000000..fb98990
--- /dev/null
@@ -0,0 +1,125 @@
+/* GStreamer
+ *
+ * unit test for state changes on all elements
+ *
+ * Copyright (C) <2012> Matthew Waters <ystreet00@gmail.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/check/gstcheck.h>
+
+#include <gst/gl/gstglmemory.h>
+
+#include <stdio.h>
+
+static GstGLDisplay *display;
+
+void
+setup (void)
+{
+  display = gst_gl_display_new ();
+  gst_gl_display_create_context (display, 0);
+  gst_gl_memory_init ();
+}
+
+void
+teardown (void)
+{
+  g_object_unref (display);
+}
+
+GST_START_TEST (test_basic)
+{
+  GstMemory *mem, *mem2;
+  GstGLMemory *gl_mem, *gl_mem2;
+  GstAllocator *gl_allocator;
+  GstVideoInfo vinfo;
+  gint i;
+  static GstVideoFormat formats[15] = {
+    GST_VIDEO_FORMAT_RGBx, GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_xRGB,
+    GST_VIDEO_FORMAT_xBGR, GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_BGRA,
+    GST_VIDEO_FORMAT_ARGB, GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_RGB,
+    GST_VIDEO_FORMAT_BGR, GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_UYVY,
+    GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_AYUV,
+  };
+
+  for (i = 0; i < G_N_ELEMENTS (formats); i++) {
+    gsize width = 320, height = 240;
+
+    gst_video_info_set_format (&vinfo, formats[i], width, height);
+    gl_allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR);
+    fail_if (gl_allocator == NULL);
+
+    /* test allocator creation */
+    ASSERT_WARNING (mem = gst_allocator_alloc (gl_allocator, 0, NULL););
+    mem = gst_gl_memory_alloc (display, formats[i], width, height);
+    fail_if (mem == NULL);
+    gl_mem = (GstGLMemory *) mem;
+
+    /* test init params */
+    fail_if (gl_mem->width != width);
+    fail_if (gl_mem->height != height);
+    fail_if (gl_mem->v_format != formats[i]);
+    fail_if (gl_mem->display != display);
+    fail_if (gl_mem->tex_id == 0);
+
+    /* copy the memory */
+    mem2 = gst_memory_copy (mem, 0, -1);
+    fail_if (mem == NULL);
+    gl_mem2 = (GstGLMemory *) mem2;
+
+    /* test params */
+    fail_if (gl_mem->tex_id == gl_mem2->tex_id);
+    fail_if (gl_mem->width != gl_mem->width);
+    fail_if (gl_mem->height != gl_mem->height);
+    fail_if (gl_mem->v_format != gl_mem->v_format);
+    fail_if (gl_mem->gl_format != gl_mem->gl_format);
+    fail_if (gl_mem->display != gl_mem->display);
+    fail_if (gl_mem->tex_id == 0);
+
+    if (display->error_message)
+      printf ("%s\n", display->error_message);
+    fail_if (display->error_message != NULL);
+
+    gst_memory_unref (mem);
+    gst_memory_unref (mem2);
+
+    gst_allocator_unref (gl_allocator);
+  }
+}
+
+GST_END_TEST;
+
+
+Suite *
+gst_gl_memory_suite (void)
+{
+  Suite *s = suite_create ("GstGLMemory");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_checked_fixture (tc_chain, setup, teardown);
+  tcase_add_test (tc_chain, test_basic);
+
+  return s;
+}
+
+GST_CHECK_MAIN (gst_gl_memory);