gstreamer/gst-libs/gst/egl/egl.c
Sebastian Dröge 275e104be6 egl: Add destroy notify instead of always calling eglTerminate() on the display
In some scenarios, for example in QtWebKit, might be difficult to obtain full
control on the egl display and it might be only accessible indirectly via
eglGetCurrentDisplay().

https://bugzilla.gnome.org/show_bug.cgi?id=700058
2013-05-10 12:50:05 +02:00

379 lines
9.2 KiB
C

/*
* GStreamer EGL Library
* Copyright (C) 2012 Collabora Ltd.
* @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
* *
* 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
typedef struct
{
GstMemory parent;
GstEGLDisplay *display;
EGLImageKHR image;
GstVideoGLTextureType type;
GstVideoGLTextureOrientation orientation;
gpointer user_data;
GDestroyNotify user_data_destroy;
} GstEGLImageMemory;
#define GST_EGL_IMAGE_MEMORY(mem) ((GstEGLImageMemory*)(mem))
gboolean
gst_egl_image_memory_is_mappable (void)
{
return FALSE;
}
gboolean
gst_is_egl_image_memory (GstMemory * mem)
{
g_return_val_if_fail (mem != NULL, FALSE);
g_return_val_if_fail (mem->allocator != NULL, FALSE);
return g_strcmp0 (mem->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0;
}
EGLImageKHR
gst_egl_image_memory_get_image (GstMemory * mem)
{
g_return_val_if_fail (gst_is_egl_image_memory (mem), EGL_NO_IMAGE_KHR);
if (mem->parent)
mem = mem->parent;
return GST_EGL_IMAGE_MEMORY (mem)->image;
}
GstEGLDisplay *
gst_egl_image_memory_get_display (GstMemory * mem)
{
g_return_val_if_fail (gst_is_egl_image_memory (mem), NULL);
if (mem->parent)
mem = mem->parent;
return gst_egl_display_ref (GST_EGL_IMAGE_MEMORY (mem)->display);
}
GstVideoGLTextureType
gst_egl_image_memory_get_type (GstMemory * mem)
{
g_return_val_if_fail (gst_is_egl_image_memory (mem), -1);
if (mem->parent)
mem = mem->parent;
return GST_EGL_IMAGE_MEMORY (mem)->type;
}
GstVideoGLTextureOrientation
gst_egl_image_memory_get_orientation (GstMemory * mem)
{
g_return_val_if_fail (gst_is_egl_image_memory (mem),
GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL);
if (mem->parent)
mem = mem->parent;
return GST_EGL_IMAGE_MEMORY (mem)->orientation;
}
void
gst_egl_image_memory_set_orientation (GstMemory * mem,
GstVideoGLTextureOrientation orientation)
{
g_return_if_fail (gst_is_egl_image_memory (mem));
if (mem->parent)
mem = mem->parent;
GST_EGL_IMAGE_MEMORY (mem)->orientation = orientation;
}
static GstMemory *
gst_egl_image_allocator_alloc_vfunc (GstAllocator * allocator, gsize size,
GstAllocationParams * params)
{
g_warning
("Use gst_egl_image_allocator_alloc() to allocate from this allocator");
return NULL;
}
static void
gst_egl_image_allocator_free_vfunc (GstAllocator * allocator, GstMemory * mem)
{
GstEGLImageMemory *emem = (GstEGLImageMemory *) mem;
EGLDisplay display;
g_return_if_fail (gst_is_egl_image_memory (mem));
/* Shared memory should not destroy all the data */
if (!mem->parent) {
display = gst_egl_display_get (emem->display);
eglDestroyImageKHR (display, emem->image);
if (emem->user_data_destroy)
emem->user_data_destroy (emem->user_data);
gst_egl_display_unref (emem->display);
}
g_slice_free (GstEGLImageMemory, emem);
}
static gpointer
gst_egl_image_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
{
return NULL;
}
static void
gst_egl_image_mem_unmap (GstMemory * mem)
{
}
static GstMemory *
gst_egl_image_mem_share (GstMemory * mem, gssize offset, gssize size)
{
GstMemory *sub;
GstMemory *parent;
if (offset != 0)
return NULL;
if (size != -1 && size != mem->size)
return NULL;
/* find the real parent */
if ((parent = mem->parent) == NULL)
parent = (GstMemory *) mem;
if (size == -1)
size = mem->size - offset;
sub = (GstMemory *) g_slice_new (GstEGLImageMemory);
/* the shared memory is always readonly */
gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) |
GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->allocator, parent,
mem->maxsize, mem->align, mem->offset + offset, size);
return sub;
}
static GstMemory *
gst_egl_image_mem_copy (GstMemory * mem, gssize offset, gssize size)
{
return NULL;
}
static gboolean
gst_egl_image_mem_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
{
return FALSE;
}
typedef GstAllocator GstEGLImageAllocator;
typedef GstAllocatorClass GstEGLImageAllocatorClass;
GType gst_egl_image_allocator_get_type (void);
G_DEFINE_TYPE (GstEGLImageAllocator, gst_egl_image_allocator,
GST_TYPE_ALLOCATOR);
#define GST_TYPE_EGL_IMAGE_ALLOCATOR (gst_egl_image_mem_allocator_get_type())
#define GST_IS_EGL_IMAGE_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EGL_IMAGE_ALLOCATOR))
static void
gst_egl_image_allocator_class_init (GstEGLImageAllocatorClass * klass)
{
GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
allocator_class->alloc = gst_egl_image_allocator_alloc_vfunc;
allocator_class->free = gst_egl_image_allocator_free_vfunc;
}
static void
gst_egl_image_allocator_init (GstEGLImageAllocator * allocator)
{
GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
alloc->mem_type = GST_EGL_IMAGE_MEMORY_TYPE;
alloc->mem_map = gst_egl_image_mem_map;
alloc->mem_unmap = gst_egl_image_mem_unmap;
alloc->mem_share = gst_egl_image_mem_share;
alloc->mem_copy = gst_egl_image_mem_copy;
alloc->mem_is_span = gst_egl_image_mem_is_span;
GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
}
static gpointer
gst_egl_image_allocator_init_instance (gpointer data)
{
return g_object_new (gst_egl_image_allocator_get_type (), NULL);
}
GstAllocator *
gst_egl_image_allocator_obtain (void)
{
static GOnce once = G_ONCE_INIT;
g_once (&once, gst_egl_image_allocator_init_instance, NULL);
g_return_val_if_fail (once.retval != NULL, NULL);
return GST_ALLOCATOR (g_object_ref (once.retval));
}
GstMemory *
gst_egl_image_allocator_alloc (GstAllocator * allocator,
GstEGLDisplay * display, GstVideoGLTextureType type, gint width,
gint height, gsize * size)
{
return NULL;
}
GstMemory *
gst_egl_image_allocator_wrap (GstAllocator * allocator,
GstEGLDisplay * display, EGLImageKHR image, GstVideoGLTextureType type,
GstMemoryFlags flags, gsize size, gpointer user_data,
GDestroyNotify user_data_destroy)
{
GstEGLImageMemory *mem;
g_return_val_if_fail (display != NULL, NULL);
g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);
if (!allocator) {
allocator = gst_egl_image_allocator_obtain ();
}
mem = g_slice_new (GstEGLImageMemory);
gst_memory_init (GST_MEMORY_CAST (mem), flags,
allocator, NULL, size, 0, 0, size);
mem->display = gst_egl_display_ref (display);
mem->image = image;
mem->type = type;
mem->orientation = GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL;
mem->user_data = user_data;
mem->user_data_destroy = user_data_destroy;
return GST_MEMORY_CAST (mem);
}
void
gst_context_set_egl_display (GstContext * context, GstEGLDisplay * display)
{
GstStructure *s;
s = gst_context_writable_structure (context);
gst_structure_set (s, GST_EGL_DISPLAY_CONTEXT_TYPE, GST_TYPE_EGL_DISPLAY,
display, NULL);
}
gboolean
gst_context_get_egl_display (GstContext * context, GstEGLDisplay ** display)
{
const GstStructure *s;
s = gst_context_get_structure (context);
return gst_structure_get (s, GST_EGL_DISPLAY_CONTEXT_TYPE,
GST_TYPE_EGL_DISPLAY, display, NULL);
}
struct _GstEGLDisplay
{
EGLDisplay display;
volatile gint refcount;
GDestroyNotify destroy_notify;
};
GstEGLDisplay *
gst_egl_display_new (EGLDisplay display, GDestroyNotify destroy_notify)
{
GstEGLDisplay *gdisplay;
gdisplay = g_slice_new (GstEGLDisplay);
gdisplay->display = display;
gdisplay->refcount = 1;
gdisplay->destroy_notify = destroy_notify;
return gdisplay;
}
GstEGLDisplay *
gst_egl_display_ref (GstEGLDisplay * display)
{
g_return_val_if_fail (display != NULL, NULL);
g_atomic_int_inc (&display->refcount);
return 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->destroy_notify)
display->destroy_notify (display->display);
g_slice_free (GstEGLDisplay, display);
}
}
EGLDisplay
gst_egl_display_get (GstEGLDisplay * display)
{
g_return_val_if_fail (display != NULL, EGL_NO_DISPLAY);
return display->display;
}
G_DEFINE_BOXED_TYPE (GstEGLDisplay, gst_egl_display,
(GBoxedCopyFunc) gst_egl_display_ref,
(GBoxedFreeFunc) gst_egl_display_unref);