diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am index bfda193d7c..bdc05f6233 100644 --- a/gst-libs/gst/gl/Makefile.am +++ b/gst-libs/gst/gl/Makefile.am @@ -2,7 +2,7 @@ lib_LTLIBRARIES = libgstgl-@GST_API_VERSION@.la SUBDIRS = glprototypes -DIST_SUBDIRS = glprototypes android x11 win32 cocoa wayland dispmanx egl +DIST_SUBDIRS = glprototypes android x11 win32 cocoa wayland dispmanx egl eagl noinst_HEADERS = @@ -87,6 +87,11 @@ SUBDIRS += android libgstgl_@GST_API_VERSION@_la_LIBADD += android/libgstgl-android.la endif +if HAVE_WINDOW_EAGL +SUBDIRS += eagl +libgstgl_@GST_API_VERSION@_la_LIBADD += eagl/libgstgl-eagl.la +endif + if USE_EGL SUBDIRS += egl libgstgl_@GST_API_VERSION@_la_LIBADD += egl/libgstgl-egl.la diff --git a/gst-libs/gst/gl/eagl/Makefile.am b/gst-libs/gst/gl/eagl/Makefile.am new file mode 100644 index 0000000000..03ef61f616 --- /dev/null +++ b/gst-libs/gst/gl/eagl/Makefile.am @@ -0,0 +1,34 @@ +## Process this file with automake to produce Makefile.in + +noinst_LTLIBRARIES = libgstgl-eagl.la + +libgstgl_eagl_la_SOURCES = \ + gstglwindow_eagl.m \ + gstglcontext_eagl.m + +noinst_HEADERS = \ + gstglwindow_eagl.h \ + gstglcontext_eagl.h + +libgstgl_eagl_la_CFLAGS = \ + -I$(top_srcdir)/gst-libs \ + -I$(top_builddir)/gst-libs \ + $(GL_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) + +libgstgl_eagl_la_OBJCFLAGS = \ + -I$(top_srcdir)/gst-libs \ + -I$(top_builddir)/gst-libs \ + $(GL_CFLAGS) \ + $(GL_OBJCFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) + +libgstgl_eagl_la_LDFLAGS = \ + $(GST_LIB_LDFLAGS) \ + $(GST_ALL_LDFLAGS) + +libgstgl_eagl_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) --tag=CC diff --git a/gst-libs/gst/gl/eagl/gstglcontext_eagl.h b/gst-libs/gst/gl/eagl/gstglcontext_eagl.h new file mode 100644 index 0000000000..90adbf2adf --- /dev/null +++ b/gst-libs/gst/gl/eagl/gstglcontext_eagl.h @@ -0,0 +1,69 @@ +/* + * GStreamer + * Copyright (C) 2014 Sebastian Dröge + * + * 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_GL_CONTEXT_EAGL_H__ +#define __GST_GL_CONTEXT_EAGL_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_GL_TYPE_CONTEXT_EAGL (gst_gl_context_eagl_get_type()) +#define GST_GL_CONTEXT_EAGL(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_CONTEXT_EAGL, GstGLContextEagl)) +#define GST_GL_CONTEXT_EAGL_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_CONTEXT_EAGL, GstGLContextEaglClass)) +#define GST_GL_IS_CONTEXT_EAGL(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_CONTEXT_EAGL)) +#define GST_GL_IS_CONTEXT_EAGL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_CONTEXT_EAGL)) +#define GST_GL_CONTEXT_EAGL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_CONTEXT_EAGL, GstGLContextEaglClass)) + +typedef struct _GstGLContextEagl GstGLContextEagl; +typedef struct _GstGLContextEaglPrivate GstGLContextEaglPrivate; +typedef struct _GstGLContextEaglClass GstGLContextEaglClass; + +struct _GstGLContextEagl { + /*< private >*/ + GstGLContext parent; + + /*< private >*/ + GstGLContextEaglPrivate *priv; + + gpointer _reserved[GST_PADDING]; +}; + +struct _GstGLContextEaglClass { + /*< private >*/ + GstGLContextClass parent_class; + + /*< private >*/ + gpointer _reserved[GST_PADDING_LARGE]; + + GstGLContextEaglPrivate *priv; +}; + +GType gst_gl_context_eagl_get_type (void); + +GstGLContextEagl * gst_gl_context_eagl_new (void); + +void gst_gl_context_eagl_prepare_draw (GstGLContextEagl * context); +void gst_gl_context_eagl_finish_draw (GstGLContextEagl * context); + +G_END_DECLS + +#endif /* __GST_GL_CONTEXT_EAGL_H__ */ diff --git a/gst-libs/gst/gl/eagl/gstglcontext_eagl.m b/gst-libs/gst/gl/eagl/gstglcontext_eagl.m new file mode 100644 index 0000000000..69c3a068ef --- /dev/null +++ b/gst-libs/gst/gl/eagl/gstglcontext_eagl.m @@ -0,0 +1,342 @@ +/* + * GStreamer + * Copyright (C) 2014 Sebastian Dröge + * + * 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 + +#import +#import +#include + +#include "gstglcontext_eagl.h" + +static gboolean gst_gl_context_eagl_create_context (GstGLContext * context, + GstGLAPI gl_api, GstGLContext * other_context, GError ** error); +static void gst_gl_context_eagl_destroy_context (GstGLContext * context); +static gboolean gst_gl_context_eagl_choose_format (GstGLContext * context, + GError ** error); +static guintptr gst_gl_context_eagl_get_gl_context (GstGLContext * window); +static gboolean gst_gl_context_eagl_activate (GstGLContext * context, + gboolean activate); +static void gst_gl_context_eagl_swap_buffers (GstGLContext * context); +static GstGLAPI gst_gl_context_eagl_get_gl_api (GstGLContext * context); +static GstGLPlatform gst_gl_context_eagl_get_gl_platform (GstGLContext * + context); + +struct _GstGLContextEaglPrivate +{ + EAGLContext *eagl_context; + + /* Used if we render to a window */ + CAEAGLLayer *eagl_layer; + GLuint framebuffer; + GLuint color_renderbuffer; + GLuint depth_renderbuffer; +}; + +#define GST_GL_CONTEXT_EAGL_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_CONTEXT_EAGL, GstGLContextEaglPrivate)) + +G_DEFINE_TYPE (GstGLContextEagl, gst_gl_context_eagl, GST_GL_TYPE_CONTEXT); + +static void +gst_gl_context_eagl_class_init (GstGLContextEaglClass * klass) +{ + GstGLContextClass *context_class; + + context_class = (GstGLContextClass *) klass; + + g_type_class_add_private (klass, sizeof (GstGLContextEaglPrivate)); + + context_class->destroy_context = + GST_DEBUG_FUNCPTR (gst_gl_context_eagl_destroy_context); + context_class->create_context = + GST_DEBUG_FUNCPTR (gst_gl_context_eagl_create_context); + context_class->choose_format = + GST_DEBUG_FUNCPTR (gst_gl_context_eagl_choose_format); + context_class->get_gl_context = + GST_DEBUG_FUNCPTR (gst_gl_context_eagl_get_gl_context); + context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_context_eagl_activate); + context_class->swap_buffers = + GST_DEBUG_FUNCPTR (gst_gl_context_eagl_swap_buffers); + context_class->get_gl_api = + GST_DEBUG_FUNCPTR (gst_gl_context_eagl_get_gl_api); + context_class->get_gl_platform = + GST_DEBUG_FUNCPTR (gst_gl_context_eagl_get_gl_platform); +} + +static void +gst_gl_context_eagl_init (GstGLContextEagl * context) +{ + context->priv = GST_GL_CONTEXT_EAGL_GET_PRIVATE (context); +} + +/* Must be called in the gl thread */ +GstGLContextEagl * +gst_gl_context_eagl_new (void) +{ + GstGLContextEagl *context = g_object_new (GST_GL_TYPE_CONTEXT_EAGL, NULL); + + return context; +} + +static gboolean +gst_gl_context_eagl_create_context (GstGLContext * context, GstGLAPI gl_api, + GstGLContext * other_context, GError ** error) +{ + GstGLContextEagl *context_eagl = GST_GL_CONTEXT_EAGL (context); + GstGLContextEaglPrivate *priv = context_eagl->priv; + GstGLWindow *window = gst_gl_context_get_window (context); + UIView *window_handle = nil; + + dispatch_sync (dispatch_get_main_queue (), ^{ + if (other_context) { + EAGLContext *external_gl_context = (EAGLContext *) + gst_gl_context_get_gl_context (other_context); + EAGLSharegroup *share_group = [external_gl_context sharegroup]; + + priv->eagl_context = [[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES2 sharegroup:share_group]; + [share_group release]; + } else { + priv->eagl_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + } + }); + + if (window) + window_handle = (UIView *) gst_gl_window_get_window_handle (window); + + if (window_handle) { + __block GLuint framebuffer; + __block GLuint color_renderbuffer; + __block GLuint depth_renderbuffer; + __block GLint width; + __block GLint height; + __block CAEAGLLayer *eagl_layer; + GLenum status; + + dispatch_sync (dispatch_get_main_queue (), ^{ + eagl_layer = (CAEAGLLayer *)[window_handle layer]; + [EAGLContext setCurrentContext:priv->eagl_context]; + + /* Allocate framebuffer */ + glGenFramebuffers (1, &framebuffer); + glBindFramebuffer (GL_FRAMEBUFFER, framebuffer); + /* Allocate color render buffer */ + glGenRenderbuffers (1, &color_renderbuffer); + glBindRenderbuffer (GL_RENDERBUFFER, color_renderbuffer); + [priv->eagl_context renderbufferStorage: GL_RENDERBUFFER fromDrawable:eagl_layer]; + glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, color_renderbuffer); + /* Get renderbuffer width/height */ + glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, + &width); + glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, + &height); + /* allocate depth render buffer */ + glGenRenderbuffers (1, &depth_renderbuffer); + glBindRenderbuffer (GL_RENDERBUFFER, depth_renderbuffer); + glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, + height); + glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depth_renderbuffer); + [EAGLContext setCurrentContext:nil]; + }); + + [EAGLContext setCurrentContext:priv->eagl_context]; + + glBindFramebuffer (GL_FRAMEBUFFER, framebuffer); + /* check creation status */ + status = glCheckFramebufferStatus (GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + GST_ERROR ("Failed to make complete framebuffer object %x", status); + if (window) + gst_object_unref (window); + return FALSE; + } + glBindFramebuffer (GL_FRAMEBUFFER, 0); + + priv->eagl_layer = eagl_layer; + priv->framebuffer = framebuffer; + priv->color_renderbuffer = color_renderbuffer; + priv->depth_renderbuffer = depth_renderbuffer; + } else { + priv->eagl_layer = NULL; + priv->framebuffer = 0; + priv->color_renderbuffer = 0; + priv->depth_renderbuffer = 0; + } + + if (window) + gst_object_unref (window); + + return TRUE; +} + +static void +gst_gl_context_eagl_destroy_context (GstGLContext * context) +{ + GstGLContextEagl *context_eagl; + + context_eagl = GST_GL_CONTEXT_EAGL (context); + + if (!context_eagl->priv->eagl_context) + return; + + if (context_eagl->priv->eagl_layer) { + gst_gl_context_eagl_activate (context, TRUE); + + [context_eagl->priv->eagl_context renderbufferStorage: GL_RENDERBUFFER fromDrawable:nil]; + + glDeleteFramebuffers (1, &context_eagl->priv->framebuffer); + context_eagl->priv->framebuffer = 0; + + glDeleteRenderbuffers (1, &context_eagl->priv->depth_renderbuffer); + context_eagl->priv->depth_renderbuffer = 0; + glDeleteRenderbuffers (1, &context_eagl->priv->color_renderbuffer); + context_eagl->priv->color_renderbuffer = 0; + + context_eagl->priv->eagl_layer = nil; + gst_gl_context_eagl_activate (context, FALSE); + } + + [context_eagl->priv->eagl_context release]; + context_eagl->priv->eagl_context = nil; +} + +static gboolean +gst_gl_context_eagl_choose_format (GstGLContext * context, GError ** error) +{ + GstGLContextEagl *context_eagl; + GstGLWindow *window; + UIView *window_handle = nil; + + context_eagl = GST_GL_CONTEXT_EAGL (context); + window = gst_gl_context_get_window (context); + + if (!window) + return TRUE; + + if (window) + window_handle = (UIView *) gst_gl_window_get_window_handle (window); + + if (!window_handle) { + gst_object_unref (window); + return TRUE; + } + + dispatch_sync (dispatch_get_main_queue (), ^{ + CAEAGLLayer *eagl_layer; + NSDictionary * dict =[NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, + kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; + + eagl_layer = (CAEAGLLayer *)[window_handle layer]; + [eagl_layer setOpaque:YES]; + [eagl_layer setDrawableProperties:dict]; + }); + + gst_object_unref (window); + + return TRUE; +} + +static guintptr +gst_gl_context_eagl_get_gl_context (GstGLContext * context) +{ + return (guintptr) GST_GL_CONTEXT_EAGL (context)->priv->eagl_context; +} + +void +gst_gl_context_eagl_prepare_draw (GstGLContextEagl * context) +{ + if (!context->priv->eagl_layer) + return; + + glBindFramebuffer (GL_FRAMEBUFFER, context->priv->framebuffer); + glBindRenderbuffer (GL_RENDERBUFFER, context->priv->color_renderbuffer); +} + +void +gst_gl_context_eagl_finish_draw (GstGLContextEagl * context) +{ + if (!context->priv->eagl_layer) + return; + + glBindRenderbuffer (GL_RENDERBUFFER, 0); + glBindFramebuffer (GL_FRAMEBUFFER, 0); +} + +static void +gst_gl_context_eagl_swap_buffers (GstGLContext * context) +{ + GstGLContextEagl *context_eagl; + + context_eagl = GST_GL_CONTEXT_EAGL (context); + + if (!context_eagl->priv->eagl_layer) + return; + + [context_eagl->priv->eagl_context presentRenderbuffer:GL_RENDERBUFFER]; +} + +static gboolean +gst_gl_context_eagl_activate (GstGLContext * context, gboolean activate) +{ + GstGLContextEagl *context_eagl; + + context_eagl = GST_GL_CONTEXT_EAGL (context); + + if (activate) { + EAGLContext *cur_ctx =[EAGLContext currentContext]; + + if (cur_ctx == context_eagl->priv->eagl_context) { + GST_DEBUG ("Already attached the context to thread %p", g_thread_self ()); + return TRUE; + } + + GST_DEBUG ("Attaching context to thread %p", g_thread_self ()); + if ([EAGLContext setCurrentContext:context_eagl->priv->eagl_context] == NO) { + GST_ERROR ("Couldn't make context current"); + return FALSE; + } + } else { + GST_DEBUG ("Detaching context from thread %p", g_thread_self ()); + if ([EAGLContext setCurrentContext:nil] == NO) { + GST_ERROR ("Couldn't unbind context"); + return FALSE; + } + } + + return TRUE; +} + +static GstGLAPI +gst_gl_context_eagl_get_gl_api (GstGLContext * context) +{ + return GST_GL_API_GLES2; +} + +static GstGLPlatform +gst_gl_context_eagl_get_gl_platform (GstGLContext * context) +{ + return GST_GL_PLATFORM_EAGL; +} + diff --git a/gst-libs/gst/gl/eagl/gstglwindow_eagl.h b/gst-libs/gst/gl/eagl/gstglwindow_eagl.h new file mode 100644 index 0000000000..6e71b7e3c0 --- /dev/null +++ b/gst-libs/gst/gl/eagl/gstglwindow_eagl.h @@ -0,0 +1,64 @@ +/* + * GStreamer + * Copyright (C) 2014 Sebastian Dröge + * + * 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_GL_WINDOW_EAGL_H__ +#define __GST_GL_WINDOW_EAGL_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_GL_TYPE_WINDOW_EAGL (gst_gl_window_eagl_get_type()) +#define GST_GL_WINDOW_EAGL(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_WINDOW_EAGL, GstGLWindowEagl)) +#define GST_GL_WINDOW_EAGL_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_WINDOW_EAGL, GstGLWindowEaglClass)) +#define GST_GL_IS_WINDOW_EAGL(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_WINDOW_EAGL)) +#define GST_GL_IS_WINDOW_EAGL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_WINDOW_EAGL)) +#define GST_GL_WINDOW_EAGL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_WINDOW_EAGL, GstGLWindowEaglClass)) + +typedef struct _GstGLWindowEagl GstGLWindowEagl; +typedef struct _GstGLWindowEaglPrivate GstGLWindowEaglPrivate; +typedef struct _GstGLWindowEaglClass GstGLWindowEaglClass; + +struct _GstGLWindowEagl { + /*< private >*/ + GstGLWindow parent; + + /*< private >*/ + GstGLWindowEaglPrivate *priv; + + gpointer _reserved[GST_PADDING]; +}; + +struct _GstGLWindowEaglClass { + /*< private >*/ + GstGLWindowClass parent_class; + + /*< private >*/ + gpointer _reserved[GST_PADDING_LARGE]; +}; + +GType gst_gl_window_eagl_get_type (void); + +GstGLWindowEagl * gst_gl_window_eagl_new (void); + +G_END_DECLS + +#endif /* __GST_GL_WINDOW_EAGL_H__ */ diff --git a/gst-libs/gst/gl/eagl/gstglwindow_eagl.m b/gst-libs/gst/gl/eagl/gstglwindow_eagl.m new file mode 100644 index 0000000000..c9f4c3f182 --- /dev/null +++ b/gst-libs/gst/gl/eagl/gstglwindow_eagl.m @@ -0,0 +1,254 @@ +/* + * GStreamer + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it un der 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 + +#import +#import + +#include "gstglwindow_eagl.h" +#include "gstglcontext_eagl.h" + +#define GST_GL_WINDOW_EAGL_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW_EAGL, GstGLWindowEaglPrivate)) + +#define GST_CAT_DEFAULT gst_gl_window_eagl_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_GET (GST_CAT_DEFAULT, "glwindow"); +#define gst_gl_window_eagl_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstGLWindowEagl, gst_gl_window_eagl, + GST_GL_TYPE_WINDOW, DEBUG_INIT); + +static guintptr gst_gl_window_eagl_get_display (GstGLWindow * window); +static guintptr gst_gl_window_eagl_get_window_handle (GstGLWindow * window); +static void gst_gl_window_eagl_set_window_handle (GstGLWindow * window, + guintptr handle); +static void gst_gl_window_eagl_draw (GstGLWindow * window, guint width, + guint height); +static void gst_gl_window_eagl_run (GstGLWindow * window); +static void gst_gl_window_eagl_quit (GstGLWindow * window); +static void gst_gl_window_eagl_send_message_async (GstGLWindow * window, + GstGLWindowCB callback, gpointer data, GDestroyNotify destroy); +static gboolean gst_gl_window_eagl_open (GstGLWindow * window, GError ** error); +static void gst_gl_window_eagl_close (GstGLWindow * window); + +struct _GstGLWindowEaglPrivate +{ + UIView *view; + + GMainContext *main_context; + GMainLoop *loop; +}; + +static void +gst_gl_window_eagl_class_init (GstGLWindowEaglClass * klass) +{ + GstGLWindowClass *window_class; + + window_class = (GstGLWindowClass *) klass; + + g_type_class_add_private (klass, sizeof (GstGLWindowEaglPrivate)); + + window_class->get_display = + GST_DEBUG_FUNCPTR (gst_gl_window_eagl_get_display); + window_class->get_window_handle = + GST_DEBUG_FUNCPTR (gst_gl_window_eagl_get_window_handle); + window_class->set_window_handle = + GST_DEBUG_FUNCPTR (gst_gl_window_eagl_set_window_handle); + window_class->draw_unlocked = GST_DEBUG_FUNCPTR (gst_gl_window_eagl_draw); + window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_eagl_draw); + window_class->run = GST_DEBUG_FUNCPTR (gst_gl_window_eagl_run); + window_class->quit = GST_DEBUG_FUNCPTR (gst_gl_window_eagl_quit); + window_class->send_message_async = + GST_DEBUG_FUNCPTR (gst_gl_window_eagl_send_message_async); + window_class->open = GST_DEBUG_FUNCPTR (gst_gl_window_eagl_open); + window_class->close = GST_DEBUG_FUNCPTR (gst_gl_window_eagl_close); +} + +static void +gst_gl_window_eagl_init (GstGLWindowEagl * window) +{ + window->priv = GST_GL_WINDOW_EAGL_GET_PRIVATE (window); +} + +/* Must be called in the gl thread */ +GstGLWindowEagl * +gst_gl_window_eagl_new (void) +{ + GstGLWindowEagl *window = g_object_new (GST_GL_TYPE_WINDOW_EAGL, NULL); + + return window; +} + +static guintptr +gst_gl_window_eagl_get_display (GstGLWindow * window) +{ + return 0; +} + +static guintptr +gst_gl_window_eagl_get_window_handle (GstGLWindow * window) +{ + return (guintptr) GST_GL_WINDOW_EAGL (window)->priv->view; +} + +static void +gst_gl_window_eagl_set_window_handle (GstGLWindow * window, guintptr handle) +{ + GstGLWindowEagl *window_eagl; + + window_eagl = GST_GL_WINDOW_EAGL (window); + + window_eagl->priv->view = (UIView *) handle; +} + +static gboolean +gst_gl_window_eagl_open (GstGLWindow * window, GError ** error) +{ + GstGLWindowEagl *window_eagl; + + window_eagl = GST_GL_WINDOW_EAGL (window); + + window_eagl->priv->main_context = g_main_context_new (); + window_eagl->priv->loop = + g_main_loop_new (window_eagl->priv->main_context, FALSE); + + return TRUE; +} + +static void +gst_gl_window_eagl_close (GstGLWindow * window) +{ + GstGLWindowEagl *window_eagl; + + window_eagl = GST_GL_WINDOW_EAGL (window); + + g_main_loop_unref (window_eagl->priv->loop); + g_main_context_unref (window_eagl->priv->main_context); +} + +static void +gst_gl_window_eagl_run (GstGLWindow * window) +{ + GstGLWindowEagl *window_eagl; + + window_eagl = GST_GL_WINDOW_EAGL (window); + + GST_LOG ("starting main loop"); + g_main_loop_run (window_eagl->priv->loop); + GST_LOG ("exiting main loop"); +} + +static void +gst_gl_window_eagl_quit (GstGLWindow * window) +{ + GstGLWindowEagl *window_eagl; + + window_eagl = GST_GL_WINDOW_EAGL (window); + + GST_LOG ("sending quit"); + + g_main_loop_quit (window_eagl->priv->loop); + + GST_LOG ("quit sent"); +} + +typedef struct _GstGLMessage +{ + GstGLWindowCB callback; + gpointer data; + GDestroyNotify destroy; +} GstGLMessage; + +static gboolean +_run_message (GstGLMessage * message) +{ + if (message->callback) + message->callback (message->data); + + if (message->destroy) + message->destroy (message->data); + + g_slice_free (GstGLMessage, message); + + return FALSE; +} + +static void +gst_gl_window_eagl_send_message_async (GstGLWindow * window, + GstGLWindowCB callback, gpointer data, GDestroyNotify destroy) +{ + GstGLWindowEagl *window_eagl; + GstGLMessage *message; + + window_eagl = GST_GL_WINDOW_EAGL (window); + message = g_slice_new (GstGLMessage); + + message->callback = callback; + message->data = data; + message->destroy = destroy; + + g_main_context_invoke (window_eagl->priv->main_context, + (GSourceFunc) _run_message, message); +} + +struct draw +{ + GstGLWindowEagl *window; + guint width, height; +}; + +static void +draw_cb (gpointer data) +{ + struct draw *draw_data = data; + GstGLWindowEagl *window_eagl = draw_data->window; + GstGLWindow *window = GST_GL_WINDOW (window_eagl); + GstGLContext *context = gst_gl_window_get_context (window); + GstGLContextEagl *eagl_context = GST_GL_CONTEXT_EAGL (context); + GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context); + + gst_gl_context_eagl_prepare_draw (eagl_context); + + if (window->draw) + window->draw (window->draw_data); + + context_class->swap_buffers (context); + + gst_gl_context_eagl_finish_draw (eagl_context); + + gst_object_unref (context); +} + +static void +gst_gl_window_eagl_draw (GstGLWindow * window, guint width, guint height) +{ + struct draw draw_data; + + draw_data.window = GST_GL_WINDOW_EAGL (window); + draw_data.width = width; + draw_data.height = height; + + gst_gl_window_send_message (window, (GstGLWindowCB) draw_cb, &draw_data); +} diff --git a/gst-libs/gst/gl/gstglapi.h b/gst-libs/gst/gl/gstglapi.h index ef5980f0c6..8605710232 100644 --- a/gst-libs/gst/gl/gstglapi.h +++ b/gst-libs/gst/gl/gstglapi.h @@ -54,8 +54,13 @@ #ifndef GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES 1 #endif -# include -# include +# if __APPLE__ +# include +# include +# else +# include +# include +# endif # if !GST_GL_HAVE_OPENGL # include # endif @@ -110,6 +115,7 @@ typedef enum GST_GL_PLATFORM_GLX = (1 << 1), GST_GL_PLATFORM_WGL = (1 << 2), GST_GL_PLATFORM_CGL = (1 << 3), + GST_GL_PLATFORM_EAGL = (1 << 4), GST_GL_PLATFORM_ANY = G_MAXUINT32 } GstGLPlatform; diff --git a/gst-libs/gst/gl/gstglcontext.c b/gst-libs/gst/gl/gstglcontext.c index 10796fe28d..23dfc0b96b 100644 --- a/gst-libs/gst/gl/gstglcontext.c +++ b/gst-libs/gst/gl/gstglcontext.c @@ -61,6 +61,9 @@ #if GST_GL_HAVE_PLATFORM_WGL #include "win32/gstglcontext_wgl.h" #endif +#if GST_GL_HAVE_PLATFORM_EAGL +#include "eagl/gstglcontext_eagl.h" +#endif #define USING_OPENGL(display) (display->gl_api & GST_GL_API_OPENGL) #define USING_OPENGL3(display) (display->gl_api & GST_GL_API_OPENGL3) @@ -218,6 +221,10 @@ gst_gl_context_new (GstGLDisplay * display) context = GST_GL_CONTEXT (gst_gl_context_wgl_new ()); } #endif +#if GST_GL_HAVE_PLATFORM_EAGL + if (!context && (!user_choice || g_strstr_len (user_choice, 5, "eagl"))) + context = GST_GL_CONTEXT (gst_gl_context_eagl_new ()); +#endif if (!context) { /* subclass returned a NULL context */ diff --git a/gst-libs/gst/gl/gstgles2.h b/gst-libs/gst/gl/gstgles2.h index 8fa87190f2..195ca7d755 100644 --- a/gst-libs/gst/gl/gstgles2.h +++ b/gst-libs/gst/gl/gstgles2.h @@ -28,6 +28,12 @@ G_BEGIN_DECLS /* SUPPORTED */ +/* FIXME: On iOS this exists but maps to an actual BGRA extension */ +#ifdef __APPLE__ +#ifdef GL_BGRA +#undef GL_BGRA +#endif +#endif //FIXME: #define GL_RGB16 GL_RGB565 diff --git a/gst-libs/gst/gl/gstglwindow.c b/gst-libs/gst/gl/gstglwindow.c index 3272d78874..49ab3cac6c 100644 --- a/gst-libs/gst/gl/gstglwindow.c +++ b/gst-libs/gst/gl/gstglwindow.c @@ -55,6 +55,9 @@ #if GST_GL_HAVE_WINDOW_ANDROID #include "android/gstglwindow_android_egl.h" #endif +#if GST_GL_HAVE_WINDOW_EAGL +#include "eagl/gstglwindow_eagl.h" +#endif #if GST_GL_HAVE_WINDOW_DISPMANX #include "dispmanx/gstglwindow_dispmanx_egl.h" #endif @@ -177,6 +180,10 @@ gst_gl_window_new (GstGLDisplay * display) #if GST_GL_HAVE_WINDOW_ANDROID if (!window && (!user_choice || g_strstr_len (user_choice, 7, "android"))) window = GST_GL_WINDOW (gst_gl_window_android_egl_new ()); +#endif +#if GST_GL_HAVE_WINDOW_EAGL + if (!window && (!user_choice || g_strstr_len (user_choice, 7, "eagl"))) + window = GST_GL_WINDOW (gst_gl_window_eagl_new ()); #endif if (!window) { /* subclass returned a NULL window */