summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosep Torra <n770galaxy@gmail.com>2013-03-22 17:38:57 +0100
committerJosep Torra <n770galaxy@gmail.com>2013-05-10 09:34:30 +0200
commit65a5473ee7f5b151e4f0b975e168c72deb9910f3 (patch)
tree075fb14f164000d16d70923d3ed021fc61b8ddea
parent28beb68797c6a260a37bedfa0c0d6026b3dd0a84 (diff)
egl: helper library to manage EGL display and memory
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac155
-rw-r--r--gst/Makefile.am5
-rw-r--r--gst/egl/Makefile.am29
-rw-r--r--gst/egl/egl.c653
-rw-r--r--gst/egl/egl.h85
-rw-r--r--gst/egl/gstreamer-egl-0.10.pc.in12
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}
+