diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am index 333e801490..1b825ccbdb 100644 --- a/gst-libs/gst/gl/Makefile.am +++ b/gst-libs/gst/gl/Makefile.am @@ -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 index 0000000000..ea7d7b24ab --- /dev/null +++ b/gst-libs/gst/gl/gstglmemory.c @@ -0,0 +1,320 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * + * 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 + +#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, ©_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 index 0000000000..2d52d62564 --- /dev/null +++ b/gst-libs/gst/gl/gstglmemory.h @@ -0,0 +1,69 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * + * 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 +#include + +#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 index 0000000000..fb98990a5f --- /dev/null +++ b/tests/check/libs/gstglmemory.c @@ -0,0 +1,125 @@ +/* GStreamer + * + * unit test for state changes on all elements + * + * Copyright (C) <2012> Matthew Waters + * + * 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 + +#include + +#include + +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);