diff options
author | Josep Torra <n770galaxy@gmail.com> | 2013-03-22 17:38:57 +0100 |
---|---|---|
committer | Josep Torra <n770galaxy@gmail.com> | 2013-05-10 09:34:30 +0200 |
commit | 65a5473ee7f5b151e4f0b975e168c72deb9910f3 (patch) | |
tree | 075fb14f164000d16d70923d3ed021fc61b8ddea | |
parent | 28beb68797c6a260a37bedfa0c0d6026b3dd0a84 (diff) |
egl: helper library to manage EGL display and memory
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 155 | ||||
-rw-r--r-- | gst/Makefile.am | 5 | ||||
-rw-r--r-- | gst/egl/Makefile.am | 29 | ||||
-rw-r--r-- | gst/egl/egl.c | 653 | ||||
-rw-r--r-- | gst/egl/egl.h | 85 | ||||
-rw-r--r-- | gst/egl/gstreamer-egl-0.10.pc.in | 12 |
7 files changed, 940 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 25368d5..46e81e4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = common omx tools config +SUBDIRS = common gst omx tools config ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index a565315..98a74f5 100644 --- a/configure.ac +++ b/configure.ac @@ -223,6 +223,158 @@ elif test x"$ac_cv_omx_target_struct_packing" != x"none"; then AC_DEFINE_UNQUOTED(GST_OMX_STRUCT_PACKING, $ac_cv_omx_target_struct_packing, [The struct packing used for OpenMAX structures]) fi +dnl *** gst-libs/gst/egl *** +AC_ARG_WITH([egl-window-system], + AS_HELP_STRING([--with-egl-window-system],[EGL window system to use (x11, mali-fb, rpi, none)]), + [EGL_WINDOW_SYSTEM="$withval"], + [EGL_WINDOW_SYSTEM="auto"]) + +if test x"$EGL_WINDOW_SYSTEM" = x"auto"; then + dnl Mali + old_LIBS=$LIBS + old_CFLAGS=$CFLAGS + LIBS="$LIBS -lUMP $EGL_LIBS" + CFLAGS="$CFLAGS $EGL_CFLAGS" + AC_CHECK_LIB([Mali], [mali_image_create], [EGL_WINDOW_SYSTEM="mali-fb"], [EGL_WINDOW_SYSTEM="auto"]) + LIBS=$old_LIBS + CFLAGS=$old_CFLAGS + + dnl RPi + if test x"$EGL_WINDOW_SYSTEM" = x"auto"; then + old_LIBS=$LIBS + old_CFLAGS=$CFLAGS + LIBS="$LIBS -lvcos -lvchiq_arm" + CFLAGS="$CFLAGS" + AC_CHECK_LIB([bcm_host], [bcm_host_init], + [ + LIBS="$LIBS -lbcm_host" + AC_CHECK_HEADER([bcm_host.h], [EGL_WINDOW_SYSTEM="rpi"], [EGL_WINDOW_SYSTEM="auto"]) + ]) + LIBS=$old_LIBS + CFLAGS=$old_CFLAGS + fi + + if test x"$EGL_WINDOW_SYSTEM" = x"auto"; then + if test x"$HAVE_X11" = x"yes"; then + EGL_WINDOW_SYSTEM="x11" + fi + fi + + if test x"$EGL_WINDOW_SYSTEM" = x"auto"; then + EGL_WINDOW_SYSTEM="none" + fi +fi + +case "$EGL_WINDOW_SYSTEM" in + x11|none) + PKG_CHECK_MODULES(EGL, egl, HAVE_EGL="yes", [ + HAVE_EGL="no" + old_LIBS=$LIBS + old_CFLAGS=$CFLAGS + + AC_CHECK_LIB([EGL], [eglGetProcAddress], + [ + AC_CHECK_HEADER([EGL/egl.h], + [ + HAVE_EGL="yes" + EGL_LIBS="-lEGL" + EGL_CFLAGS="" + ] + ) + ] + ) + + LIBS=$old_LIBS + CFLAGS=$old_CFLAGS + ]) + + if test x"$HAVE_EGL" = x"yes" -a x"$EGL_WINDOW_SYSTEM" = x"x11"; then + if test x"$HAVE_X11" != x"yes"; then + AC_MSG_ERROR([libX11 not found and is required for EGL X11 window system]) + else + AC_DEFINE(USE_EGL_X11, [1], [Use X11 EGL window system]) + EGL_CFLAGS="$EGL_CFLAGS $X11_CFLAGS" + EGL_LIBS="$EGL_LIBS $X11_LIBS" + fi + fi + ;; + mali-fb) + dnl FIXME: Mali EGL depends on GLESv1 or GLESv2 + HAVE_EGL="no" + old_LIBS=$LIBS + old_CFLAGS=$CFLAGS + AC_CHECK_HEADER([EGL/fbdev_window.h], + [ + LIBS="$LIBS -lUMP" + AC_CHECK_LIB([Mali], [mali_image_create], + [ + LIBS="$LIBS -lMali" + AC_CHECK_LIB([GLESv2], [glEnable], + [ + AC_CHECK_HEADER([GLES2/gl2.h], + [ + AC_CHECK_LIB([EGL], [eglGetProcAddress], + [ + AC_CHECK_HEADER([EGL/egl.h], + [ + HAVE_EGL="yes" + EGL_LIBS="-lGLESv2 -lEGL -lMali -lUMP" + EGL_CFLAGS="" + AC_DEFINE(USE_EGL_MALI_FB, [1], [Use Mali FB EGL window system]) + ]) + ]) + ]) + ]) + ]) + ]) + LIBS=$old_LIBS + CFLAGS=$old_CFLAGS + ;; + rpi) + old_LIBS=$LIBS + old_CFLAGS=$CFLAGS + + dnl FIXME: EGL of RPi depends on GLESv1 or GLESv2 + dnl FIXME: GLESv2 of RPi depends on EGL... WTF! + LIBS="$LIBS -lvcos -lvchiq_arm" + AC_CHECK_LIB([bcm_host], [bcm_host_init], + [ + LIBS="$LIBS -lbcm_host" + AC_CHECK_HEADER(bcm_host.h, + [ + LIBS="$LIBS -lGLESv2" + AC_CHECK_LIB([EGL], [eglGetProcAddress], + [ + LIBS="$LIBS -lEGL" + AC_CHECK_HEADER([EGL/egl.h], + [ + AC_CHECK_LIB([GLESv2], [glEnable], + [ + AC_CHECK_HEADER([GLES2/gl2.h], + [ + HAVE_EGL="yes" + EGL_LIBS="-lGLESv2 -lEGL -lbcm_host -lvcos -lvchiq_arm" + EGL_CFLAGS="" + AC_DEFINE(USE_EGL_RPI, [1], [Use RPi EGL window system]) + ]) + ]) + ]) + ]) + ]) + ]) + + LIBS=$old_LIBS + CFLAGS=$old_CFLAGS + ;; + *) + AC_MSG_ERROR([invalid EGL window system specified]) + ;; +esac + +AC_SUBST(EGL_LIBS) +AC_SUBST(EGL_CFLAGS) +AM_CONDITIONAL(HAVE_EGL, test x"$HAVE_EGL" = x"yes") + dnl *** set variables based on configure arguments *** dnl set license and copyright notice @@ -345,6 +497,9 @@ dnl *** output files *** AC_CONFIG_FILES( Makefile +gst/Makefile +gst/egl/Makefile +gst/egl/gstreamer-egl-$GST_MAJORMINOR.pc omx/Makefile common/Makefile common/m4/Makefile diff --git a/gst/Makefile.am b/gst/Makefile.am new file mode 100644 index 0000000..7f6ddb1 --- /dev/null +++ b/gst/Makefile.am @@ -0,0 +1,5 @@ +if HAVE_EGL +SUBDIRS = egl +endif + +DIST_SUBDIRS = egl diff --git a/gst/egl/Makefile.am b/gst/egl/Makefile.am new file mode 100644 index 0000000..4719bfe --- /dev/null +++ b/gst/egl/Makefile.am @@ -0,0 +1,29 @@ +lib_LTLIBRARIES = libgstegl-@GST_MAJORMINOR@.la + +pcfiles = gstreamer-egl-@GST_MAJORMINOR@.pc + +libgstegl_@GST_MAJORMINOR@_la_SOURCES = egl.c + +libgstegl_@GST_MAJORMINOR@includedir = \ + $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/egl + +libgstegl_@GST_MAJORMINOR@include_HEADERS = egl.h + +libgstegl_@GST_MAJORMINOR@_la_CFLAGS = \ + $(GST_CFLAGS) \ + $(EGL_CFLAGS) + +libgstegl_@GST_MAJORMINOR@_la_LIBADD = \ + $(GST_LIBS) \ + $(EGL_LIBS) + +libgstegl_@GST_MAJORMINOR@_la_LDFLAGS = \ + $(GST_LIB_LDFLAGS) \ + $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = $(pcfiles) + +EXTRA_DIST = $(pcfiles) + diff --git a/gst/egl/egl.c b/gst/egl/egl.c new file mode 100644 index 0000000..d05fae1 --- /dev/null +++ b/gst/egl/egl.c @@ -0,0 +1,653 @@ +/* + * GStreamer EGL Library + * Copyright (C) 2013 Fluendo S.A. + * @author: Josep Torra <josep@fluendo.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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(USE_EGL_RPI) && defined (__GNUC__) + +#ifndef __VCCOREVER__ +#define __VCCOREVER__ 0x04000000 +#endif + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +#pragma GCC optimize ("gnu89-inline") +#endif + +#define EGL_EGLEXT_PROTOTYPES +#include <gst/egl/egl.h> + +#if defined(USE_EGL_RPI) && defined (__GNUC__) +#pragma GCC reset_options +#pragma GCC diagnostic pop +#endif + +#define DEBUG_MAGIC_CHECK 0 + +#if DEBUG_MAGIC_CHECK +#define EGLMEMORY_MAGIC 0x5fce5fce +#define EGLMEMORY_POOL_MAGIC 0x5fce9001 + +#define EGLMEMORY_POOL_MAGIC_ASSERT(pool) G_STMT_START { \ + g_assert (pool->magic == EGLMEMORY_POOL_MAGIC); \ +} G_STMT_END +#define EGLMEMORY_MAGIC_ASSERT(mem) G_STMT_START { \ + g_assert (mem->magic == EGLMEMORY_MAGIC); \ +} G_STMT_END +#else +#define EGLMEMORY_POOL_MAGIC_ASSERT(pool) G_STMT_START{ }G_STMT_END +#define EGLMEMORY_MAGIC_ASSERT(mem) G_STMT_START{ }G_STMT_END +#endif + +struct _GstEGLImageMemory +{ + volatile gint refcount; + +#if DEBUG_MAGIC_CHECK + guint32 magic; +#endif + + EGLClientBuffer client_buffer; + EGLImageKHR image; + + gpointer user_data; + GDestroyNotify destroy_data; + + GstEGLImageMemoryPool *pool; +}; + +#define GST_EGL_IMAGE_MEMORY(mem) ((GstEGLImageMemory *)(mem)) + +struct _GstEGLImageMemoryPool +{ + volatile gint refcount; + +#if DEBUG_MAGIC_CHECK + guint32 magic; +#endif + + GMutex *lock; + GCond *cond; + + GstEGLDisplay *display; + GstEGLImageMemory *memory; + + gint size; + volatile gint unused; + volatile gint active; + + gpointer user_data; + GstDestroyNotifyEGLImageMemoryPool destroy_data; +}; + +#define GST_EGL_IMAGE_MEMORY_POOL_LOCK(pool) G_STMT_START { \ + g_mutex_lock (pool->lock); \ +} G_STMT_END + +#define GST_EGL_IMAGE_MEMORY_POOL_UNLOCK(pool) G_STMT_START { \ + g_mutex_unlock (pool->lock); \ +} G_STMT_END + +#define GST_EGL_IMAGE_MEMORY_POOL_WAIT_RELEASED(pool) G_STMT_START { \ + g_cond_wait (pool->cond, pool->lock); \ +} G_STMT_END + +#define GST_EGL_IMAGE_MEMORY_POOL_SIGNAL_UNUSED(pool) G_STMT_START { \ + g_cond_signal (pool->cond); \ +} G_STMT_END + +#define GST_EGL_IMAGE_MEMORY_POOL_IS_FULL(pool) (g_atomic_int_get (&pool->unused) == 0) +#define GST_EGL_IMAGE_MEMORY_POOL_IS_EMPTY(pool) (g_atomic_int_get (&pool->unused) == pool->size) + +#define GST_EGL_IMAGE_MEMORY_POOL_SET_ACTIVE(pool,active) \ + g_atomic_int_set (&pool->active, active) +#define GST_EGL_IMAGE_MEMORY_POOL_IS_ACTIVE(pool) (g_atomic_int_get (&pool->active) == TRUE) + +struct _GstEGLDisplay +{ + volatile gint refcount; + + EGLDisplay display; + EGLContext context; +}; + +/** + * gst_egl_image_memory_ref + * @mem: a #GstEGLImageMemory + * + * Increase the refcount of @mem. + * + */ +GstEGLImageMemory * +gst_egl_image_memory_ref (GstEGLImageMemory * mem) +{ + g_return_val_if_fail (mem != NULL, NULL); + + EGLMEMORY_MAGIC_ASSERT (mem); + + g_atomic_int_inc (&mem->refcount); + + return mem; +} + +static void +gst_egl_image_memory_free (GstEGLImageMemory * mem) +{ + GstEGLImageMemoryPool *pool = mem->pool; + + /* We grab the pool lock as we will make changes to number of unused + * memories. */ + GST_EGL_IMAGE_MEMORY_POOL_LOCK (pool); + + /* We have one more unused memory */ + g_atomic_int_inc (&pool->unused); + + /* Wake up potential waiters */ + GST_EGL_IMAGE_MEMORY_POOL_SIGNAL_UNUSED (pool); + + GST_EGL_IMAGE_MEMORY_POOL_UNLOCK (pool); + + if (mem->destroy_data) { + mem->destroy_data (mem->user_data); + } + + /* Remove our ref to the pool. That could destroy the pool so it is + * important to do that when we released the lock */ + mem->pool = gst_egl_image_memory_pool_unref (pool); +} + +/** + * gst_egl_image_memory_unref: + * @mem: a #GstEGLImageMemory + * + * Unref @mem and when the refcount reaches 0 frees the resources + * and return NULL. + * + */ +GstEGLImageMemory * +gst_egl_image_memory_unref (GstEGLImageMemory * mem) +{ + g_return_val_if_fail (mem != NULL, NULL); + + EGLMEMORY_MAGIC_ASSERT (mem); + + if (g_atomic_int_dec_and_test (&mem->refcount)) { + gst_egl_image_memory_free (mem); + mem = NULL; + } + + return mem; +} + +/** + * gst_egl_image_memory_get_image: + * @mem: a #GstEGLImageMemory + * + * Gives the #EGLImageKHR used by the #GstEGLImageMemory. + * + */ +EGLImageKHR +gst_egl_image_memory_get_image (GstEGLImageMemory * mem) +{ + return mem->image; +} + +/** + * gst_egl_image_memory_pool_new: + * @size: a number of memories managed by the pool + * @display: a #GstEGLDisplay display + * @user_data: user data passed to the callback + * @destroy_data: #GstDestroyNotifyEGLImageMemoryPool for user_data + * + * Create a new GstEGLImageMemoryPool instance with the provided images. + * + * Returns: a new #GstEGLImageMemoryPool + * + */ +GstEGLImageMemoryPool * +gst_egl_image_memory_pool_new (gint size, GstEGLDisplay * display, + gpointer user_data, GstDestroyNotifyEGLImageMemoryPool destroy_data) +{ + GstEGLImageMemoryPool *pool; + + pool = g_new0 (GstEGLImageMemoryPool, 1); + + pool->refcount = 1; + pool->lock = g_mutex_new (); + pool->cond = g_cond_new (); + pool->display = gst_egl_display_ref (display); + pool->memory = (GstEGLImageMemory *) g_new0 (GstEGLImageMemory, size); + pool->size = pool->unused = size; + pool->user_data = user_data; + pool->destroy_data = destroy_data; + +#if DEBUG_MAGIC_CHECK + { + gint i; + pool->magic = EGLMEMORY_POOL_MAGIC; + for (i = 0; i < size; i++) { + GstEGLImageMemory *mem = &pool->memory[i]; + mem->magic = EGLMEMORY_MAGIC; + } + } +#endif + + return pool; +} + +/** + * gst_egl_image_memory_pool_ref: + * @pool: a #GstEGLImageMemoryPool + * + * Increase the refcount of @pool. + * + */ +GstEGLImageMemoryPool * +gst_egl_image_memory_pool_ref (GstEGLImageMemoryPool * pool) +{ + g_return_val_if_fail (pool != NULL, NULL); + + EGLMEMORY_POOL_MAGIC_ASSERT (pool); + + g_atomic_int_inc (&pool->refcount); + + return pool; +} + +static void +gst_egl_image_memory_pool_free (GstEGLImageMemoryPool * pool) +{ + if (g_atomic_int_get (&pool->unused) != pool->size) { + g_critical ("refcounting problem detected, some memory is still in use"); + } + + if (pool->destroy_data) { + pool->destroy_data (pool, pool->user_data); + } + + gst_egl_display_unref (pool->display); + g_mutex_free (pool->lock); + g_cond_free (pool->cond); + + g_free (pool->memory); + g_free (pool); +} + +/** + * gst_egl_image_memory_pool_unref: + * @pool: a #GstEGLImageMemoryPool + * + * Unref @pool and when the refcount reaches 0 frees the resources + * and return NULL. + * + */ +GstEGLImageMemoryPool * +gst_egl_image_memory_pool_unref (GstEGLImageMemoryPool * pool) +{ + g_return_val_if_fail (pool != NULL, NULL); + + EGLMEMORY_POOL_MAGIC_ASSERT (pool); + + if (g_atomic_int_dec_and_test (&pool->refcount)) { + gst_egl_image_memory_pool_free (pool); + pool = NULL; + } + return pool; +} + +/** + * gst_egl_image_memory_pool_get_size: + * @pool: a #GstEGLImageMemoryPool + * + * Gives the number of memories that are managed by the pool. + * + */ +gint +gst_egl_image_memory_pool_get_size (GstEGLImageMemoryPool * pool) +{ + g_return_val_if_fail (pool != NULL, 0); + + return pool->size; +} + +/** + * gst_egl_image_memory_pool_set_resources: + * @pool: a #GstEGLImageMemoryPool + * @idx: memory index + * @client_buffer: an #EGLClientBuffer to store in the pool + * @image: an #EGLImageKHR to store in the pool. + * + * Stores @client_buffer and @image at @idx memory slot. + * + */ +gboolean +gst_egl_image_memory_pool_set_resources (GstEGLImageMemoryPool * pool, gint idx, + EGLClientBuffer client_buffer, EGLImageKHR image) +{ + GstEGLImageMemory *mem; + + g_return_val_if_fail (pool != NULL, FALSE); + g_return_val_if_fail (idx >= 0 && idx < pool->size, FALSE); + + mem = &pool->memory[idx]; + mem->client_buffer = client_buffer; + mem->image = image; + + return TRUE; +} + +/** + * gst_egl_image_memory_pool_get_resources: + * @pool: a #GstEGLImageMemoryPool + * @idx: memory index + * @client_buffer: (out) (allow-none): the #EGLClientBuffer at @idx + * @image: (out) (allow-none): the #EGLImageKHR at @idx + * + * Retrieves @client_buffer and @image at @idx memory slot. + * + */ +gboolean +gst_egl_image_memory_pool_get_resources (GstEGLImageMemoryPool * pool, gint idx, + EGLClientBuffer * client_buffer, EGLImageKHR * image) +{ + GstEGLImageMemory *mem; + + g_return_val_if_fail (pool != NULL, FALSE); + g_return_val_if_fail (idx >= 0 && idx < pool->size, FALSE); + + mem = &pool->memory[idx]; + + if (client_buffer) + *client_buffer = mem->client_buffer; + + if (image) + *image = mem->image; + + return TRUE; +} + +/** + * gst_egl_image_memory_pool_get_display: + * @pool: a #GstEGLImageMemoryPool + * + * Provides a reference to the #GstEGLDisplay used by the pool + */ +GstEGLDisplay * +gst_egl_image_memory_pool_get_display (GstEGLImageMemoryPool * pool) +{ + g_return_val_if_fail (pool != NULL, NULL); + + EGLMEMORY_POOL_MAGIC_ASSERT (pool); + + g_return_val_if_fail (pool->display != NULL, NULL); + + return gst_egl_display_ref (pool->display); +} + +/** + * gst_egl_image_memory_pool_get_images: + * @pool: a #GstEGLImageMemoryPool + * + * Provides a #GList of EGL images + */ +GList * +gst_egl_image_memory_pool_get_images (GstEGLImageMemoryPool * pool) +{ + gint i; + GList *images = NULL; + + g_return_val_if_fail (pool != NULL, NULL); + + for (i = 0; i < pool->size; i++) { + GstEGLImageMemory *mem = &pool->memory[i]; + images = g_list_append (images, mem->image); + } + + return images; +} + +/** + * gst_egl_image_memory_pool_set_active: + * @pool: a #GstEGLImageMemoryPool + * @active: a #gboolean that indicates the pool is active + * + * Change @pool active state and unblocks any wait condition if needed. + * + */ +void +gst_egl_image_memory_pool_set_active (GstEGLImageMemoryPool * pool, + gboolean active) +{ + g_return_if_fail (pool != NULL); + + EGLMEMORY_POOL_MAGIC_ASSERT (pool); + + GST_EGL_IMAGE_MEMORY_POOL_SET_ACTIVE (pool, active); + + if (!active) { + GST_EGL_IMAGE_MEMORY_POOL_SIGNAL_UNUSED (pool); + } +} + +/** + * gst_egl_image_memory_pool_wait_released: + * @pool: a #GstEGLImageMemoryPool + * + * Waits until none of the memory is in use. + * + */ +void +gst_egl_image_memory_pool_wait_released (GstEGLImageMemoryPool * pool) +{ + g_return_if_fail (pool != NULL); + + EGLMEMORY_POOL_MAGIC_ASSERT (pool); + + GST_EGL_IMAGE_MEMORY_POOL_LOCK (pool); + while (!GST_EGL_IMAGE_MEMORY_POOL_IS_EMPTY (pool)) { + GST_EGL_IMAGE_MEMORY_POOL_WAIT_RELEASED (pool); + } + GST_EGL_IMAGE_MEMORY_POOL_UNLOCK (pool); +} + +/** + * gst_egl_image_memory_pool_acquire_buffer: + * @pool: a #GstEGLImageMemoryPool + * @idx: ordinal that specifies a #GstEGLImageMemory in the pool + * @user_data: user data passed to the callback + * @destroy_data: #GDestroyNotify for user_data + * + * Provides an specified #GstEGLImageMemory wrapped by a #GstBuffer. + * + */ +GstBuffer * +gst_egl_image_memory_pool_acquire_buffer (GstEGLImageMemoryPool * pool, + gint idx, gpointer user_data, GDestroyNotify destroy_data) +{ + GstBuffer *ret; + GstEGLImageMemory *mem; + + g_return_val_if_fail (pool != NULL, NULL); + g_return_val_if_fail (idx >= 0 && idx < pool->size, NULL); + + GST_EGL_IMAGE_MEMORY_POOL_LOCK (pool); + if (!GST_EGL_IMAGE_MEMORY_POOL_IS_ACTIVE (pool)) { + GST_EGL_IMAGE_MEMORY_POOL_UNLOCK (pool); + return NULL; + } + + mem = &pool->memory[idx]; + + g_atomic_int_add (&pool->unused, -1); + g_atomic_int_set (&mem->refcount, 1); + mem->pool = gst_egl_image_memory_pool_ref (pool); + mem->user_data = user_data; + mem->destroy_data = destroy_data; + + ret = gst_buffer_new (); + GST_BUFFER_MALLOCDATA (ret) = GST_BUFFER_DATA (ret) = (guint8 *) mem; + GST_BUFFER_FREE_FUNC (ret) = (GFreeFunc) gst_egl_image_memory_unref; + GST_BUFFER_SIZE (ret) = sizeof (GstEGLImageMemory); + + GST_EGL_IMAGE_MEMORY_POOL_UNLOCK (pool); + + return ret; +} + +G_DEFINE_BOXED_TYPE (GstEGLImageMemoryPool, gst_egl_image_memory_pool, + (GBoxedCopyFunc) gst_egl_image_memory_pool_ref, + (GBoxedFreeFunc) gst_egl_image_memory_pool_unref); + +/** + * gst_egl_display_new: + * @display: a #EGLDisplay display + * + * Create a new #GstEGLDisplay that wraps and refcount @display. + * + * Returns: a new #GstEGLDisplay + * + */ +GstEGLDisplay * +gst_egl_display_new (EGLDisplay display) +{ + GstEGLDisplay *gdisplay; + + gdisplay = g_slice_new (GstEGLDisplay); + gdisplay->display = display; + gdisplay->refcount = 1; + + return gdisplay; +} + +/** + * gst_egl_display_ref + * @display: a #GstEGLDisplay + * + * Increase the refcount of @display. + * + */ +GstEGLDisplay * +gst_egl_display_ref (GstEGLDisplay * display) +{ + g_return_val_if_fail (display != NULL, NULL); + + g_atomic_int_inc (&display->refcount); + + return display; +} + +/** + * gst_egl_display_unref: + * @display: a #GstEGLDisplay + * + * Decrease the refcount of @display and when the refcount + * is 0 terminates the wrapped EGL display. + * + */ +void +gst_egl_display_unref (GstEGLDisplay * display) +{ + g_return_if_fail (display != NULL); + + if (g_atomic_int_dec_and_test (&display->refcount)) { + if (display->display != EGL_NO_DISPLAY) + eglTerminate (display->display); + g_slice_free (GstEGLDisplay, display); + } +} + +/** + * gst_egl_display_get + * @display: a #GstEGLDisplay + * + * Gives the #EGLDisplay wrapped. + * + */ +EGLDisplay +gst_egl_display_get (GstEGLDisplay * display) +{ + g_return_val_if_fail (display != NULL, EGL_NO_DISPLAY); + + return display->display; +} + +/** + * gst_message_new_need_egl_pool: + * @src: (transfer none): The object originating the message. + * @size: number of required images + * @width: width in pixels of the images + * @height: height in pixels of the images + * + * Create a new need egl pool message. This message is posted to + * require the application to provide a #GstEGLImageMemoryPool through + * the pool property in the @src element. + * + * Returns: (transfer full): The new need egl pool message. + * + */ +GstMessage * +gst_message_new_need_egl_pool (GstObject * src, gint size, gint width, + gint height) +{ + GstStructure *structure; + + structure = gst_structure_new ("need-egl-pool", + "size", G_TYPE_INT, size, "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, NULL); + + return gst_message_new_custom (GST_MESSAGE_ELEMENT, src, structure); +} + +/** + * gst_message_parse_need_egl_pool: + * @message: A valid need_egl_pool #GstMessage. + * @size: (out) (allow-none): number of required images + * @width: (out) (allow-none): width in pixels of the images + * @height: (out) (allow-none): height in pixels of the images + * + * Extracts the details from the GstMessage. see also + * gst_message_new_need_egl_pool(). + * + */ +void +gst_message_parse_need_egl_pool (GstMessage * message, gint * size, + gint * width, gint * height) +{ + g_return_if_fail (GST_IS_MESSAGE (message)); + g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT); + g_return_if_fail (gst_structure_has_name (message->structure, + "need-egl-pool")); + + if (size) + *size = + g_value_get_int (gst_structure_get_value (message->structure, "size")); + + if (width) + *width = + g_value_get_int (gst_structure_get_value (message->structure, "width")); + + if (height) + *height = + g_value_get_int (gst_structure_get_value (message->structure, + "height")); +} diff --git a/gst/egl/egl.h b/gst/egl/egl.h new file mode 100644 index 0000000..917d28f --- /dev/null +++ b/gst/egl/egl.h @@ -0,0 +1,85 @@ +/* + * GStreamer EGL Library + * Copyright (C) 2013 Fluendo S.A. + * @author: Josep Torra <josep@fluendo.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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_EGL_H__ +#define __GST_EGL_H__ + +#include <gst/gst.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +G_BEGIN_DECLS + +typedef struct _GstEGLImageMemory GstEGLImageMemory; +typedef struct _GstEGLImageMemoryPool GstEGLImageMemoryPool; +typedef struct _GstEGLDisplay GstEGLDisplay; +typedef void (*GstDestroyNotifyEGLImageMemoryPool) (GstEGLImageMemoryPool * + pool, gpointer user_data); + +/* GstEGLImageMemory handling */ +GstEGLImageMemory *gst_egl_image_memory_ref (GstEGLImageMemory * mem); +GstEGLImageMemory *gst_egl_image_memory_unref (GstEGLImageMemory * mem); +EGLImageKHR gst_egl_image_memory_get_image (GstEGLImageMemory * mem); + +/* GstEGLImageMemoryPool handling */ +#define GST_TYPE_EGL_IMAGE_MEMORY_POOL (gst_egl_image_memory_pool_get_type()) +GType gst_egl_image_memory_pool_get_type (void); + +GstEGLImageMemoryPool *gst_egl_image_memory_pool_new (gint size, + GstEGLDisplay * display, gpointer user_data, + GstDestroyNotifyEGLImageMemoryPool destroy_data); +GstEGLImageMemoryPool *gst_egl_image_memory_pool_ref (GstEGLImageMemoryPool * + pool); +GstEGLImageMemoryPool *gst_egl_image_memory_pool_unref (GstEGLImageMemoryPool * + pool); +gint gst_egl_image_memory_pool_get_size (GstEGLImageMemoryPool * pool); + +gboolean gst_egl_image_memory_pool_set_resources (GstEGLImageMemoryPool * pool, + gint idx, EGLClientBuffer client_buffer, EGLImageKHR image); + +gboolean gst_egl_image_memory_pool_get_resources (GstEGLImageMemoryPool * pool, + gint idx, EGLClientBuffer * client_buffer, EGLImageKHR * image); + +GstEGLDisplay *gst_egl_image_memory_pool_get_display (GstEGLImageMemoryPool * + pool); +GList *gst_egl_image_memory_pool_get_images (GstEGLImageMemoryPool * pool); +void gst_egl_image_memory_pool_set_active (GstEGLImageMemoryPool * pool, + gboolean active); +void gst_egl_image_memory_pool_wait_released (GstEGLImageMemoryPool * pool); +GstBuffer *gst_egl_image_memory_pool_acquire_buffer (GstEGLImageMemoryPool * + pool, gint idx, gpointer user_data, GDestroyNotify destroy_data); + +/* EGLDisplay wrapper with refcount, connection is closed after last ref is gone */ +GstEGLDisplay *gst_egl_display_new (EGLDisplay display); +GstEGLDisplay *gst_egl_display_ref (GstEGLDisplay * display); +void gst_egl_display_unref (GstEGLDisplay * display); +EGLDisplay gst_egl_display_get (GstEGLDisplay * display); + +/* Helper functions to manage pool requests */ +GstMessage *gst_message_new_need_egl_pool (GstObject * src, gint size, + gint width, gint height); +void gst_message_parse_need_egl_pool (GstMessage * message, gint * size, + gint * width, gint * height); + +G_END_DECLS + +#endif /* __GST_EGL_H__ */ diff --git a/gst/egl/gstreamer-egl-0.10.pc.in b/gst/egl/gstreamer-egl-0.10.pc.in new file mode 100644 index 0000000..1473f44 --- /dev/null +++ b/gst/egl/gstreamer-egl-0.10.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ + +Name: GStreamer EGL helper lib +Description: GStreamer EGL helper lib +Requires: gstreamer-@GST_MAJORMINOR@ +Version: @VERSION@ +Libs: -L${libdir} -lgstegl-@GST_MAJORMINOR@ +Cflags: -I${includedir} + |