From 192b37980f26c2434e36eef574a6f10f7757cd75 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 10 Jul 2013 11:31:17 +0200 Subject: [PATCH] [735/906] gl: Add support for Android https://bugzilla.gnome.org/show_bug.cgi?id=703340 --- gst-libs/gst/gl/Makefile.am | 16 +- gst-libs/gst/gl/android/Makefile.am | 23 ++ gst-libs/gst/gl/android/gstglwindow_android_egl.c | 326 ++++++++++++++++++++++ gst-libs/gst/gl/android/gstglwindow_android_egl.h | 69 +++++ gst-libs/gst/gl/gstglegl.c | 5 + gst-libs/gst/gl/gstglwindow.c | 7 + 6 files changed, 435 insertions(+), 11 deletions(-) create mode 100644 gst-libs/gst/gl/android/Makefile.am create mode 100644 gst-libs/gst/gl/android/gstglwindow_android_egl.c create mode 100644 gst-libs/gst/gl/android/gstglwindow_android_egl.h diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am index f1117b4..9f47797 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 x11 win32 cocoa wayland +DIST_SUBDIRS = glprototypes android x11 win32 cocoa wayland noinst_HEADERS = @@ -49,21 +49,15 @@ SUBDIRS += wayland libgstgl_@GST_API_VERSION@_la_LIBADD += wayland/libgstgl-wayland.la endif -if USE_EGL - -if HAVE_WINDOW_WAYLAND -libgstgl_@GST_API_VERSION@_la_SOURCES += gstglegl.c -noinst_HEADERS += gstglegl.h +if HAVE_WINDOW_ANDROID +SUBDIRS += android +libgstgl_@GST_API_VERSION@_la_LIBADD += android/libgstgl-android.la endif -if !HAVE_WINDOW_WAYLAND -if HAVE_WINDOW_X11 +if USE_EGL libgstgl_@GST_API_VERSION@_la_SOURCES += gstglegl.c noinst_HEADERS += gstglegl.h endif -endif - -endif libgstgl_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/gl libgstgl_@GST_API_VERSION@include_HEADERS = \ diff --git a/gst-libs/gst/gl/android/Makefile.am b/gst-libs/gst/gl/android/Makefile.am new file mode 100644 index 0000000..8c17682 --- /dev/null +++ b/gst-libs/gst/gl/android/Makefile.am @@ -0,0 +1,23 @@ +## Process this file with automake to produce Makefile.in + +noinst_LTLIBRARIES = libgstgl-android.la + +libgstgl_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/gl +libgstglandroidincludedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/gl/android + +libgstgl_android_la_SOURCES = \ + gstglwindow_android_egl.c + +libgstglandroidinclude_HEADERS = \ + gstglwindow_android_egl.h + +libgstgl_android_la_CFLAGS = \ + $(GL_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + -I$(top_srcdir)/gst-libs + +libgstgl_android_la_LDFLAGS = \ + $(GST_LIB_LDFLAGS) \ + $(GST_ALL_LDFLAGS) diff --git a/gst-libs/gst/gl/android/gstglwindow_android_egl.c b/gst-libs/gst/gl/android/gstglwindow_android_egl.c new file mode 100644 index 0000000..f87f2a9 --- /dev/null +++ b/gst-libs/gst/gl/android/gstglwindow_android_egl.c @@ -0,0 +1,326 @@ +/* + * GStreamer + * Copyright (C) 2008 Julien Isorce + * Copyright (C) 2012 Matthew Waters + * Copyright (C) 2013 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. + */ + +/* TODO: - Window resize handling + * - Event handling input event handling + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstglwindow_android_egl.h" + +#define GST_CAT_DEFAULT gst_gl_window_debug + +#define gst_gl_window_android_egl_parent_class parent_class +G_DEFINE_TYPE (GstGLWindowAndroidEGL, gst_gl_window_android_egl, + GST_GL_TYPE_WINDOW); + +static guintptr gst_gl_window_android_egl_get_gl_context (GstGLWindow * window); +static gboolean gst_gl_window_android_egl_activate (GstGLWindow * window, + gboolean activate); +static void gst_gl_window_android_egl_set_window_handle (GstGLWindow * window, + guintptr handle); +static void gst_gl_window_android_egl_draw (GstGLWindow * window, guint width, + guint height); +static void gst_gl_window_android_egl_run (GstGLWindow * window); +static void gst_gl_window_android_egl_quit (GstGLWindow * window, + GstGLWindowCB callback, gpointer data); +static void gst_gl_window_android_egl_send_message (GstGLWindow * window, + GstGLWindowCB callback, gpointer data); +static void gst_gl_window_android_egl_destroy_context (GstGLWindowAndroidEGL * + window_egl); +static gboolean gst_gl_window_android_egl_create_context (GstGLWindow + * window, GstGLAPI gl_api, guintptr external_gl_context, GError ** error); +static GstGLAPI gst_gl_window_android_egl_get_gl_api (GstGLWindow * window); +static gpointer gst_gl_window_android_egl_get_proc_address (GstGLWindow * + window, const gchar * name); +static void gst_gl_window_android_egl_close (GstGLWindow * window); + +static void +gst_gl_window_android_egl_class_init (GstGLWindowAndroidEGLClass * klass) +{ + GstGLWindowClass *window_class = (GstGLWindowClass *) klass; + + window_class->create_context = + GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_create_context); + window_class->get_gl_context = + GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_get_gl_context); + window_class->activate = + GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_activate); + window_class->set_window_handle = + GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_set_window_handle); + window_class->draw_unlocked = + GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_draw); + window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_draw); + window_class->run = GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_run); + window_class->quit = GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_quit); + window_class->send_message = + GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_send_message); + window_class->get_gl_api = + GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_get_gl_api); + window_class->get_proc_address = + GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_get_proc_address); + window_class->close = GST_DEBUG_FUNCPTR (gst_gl_window_android_egl_close); +} + +static void +gst_gl_window_android_egl_init (GstGLWindowAndroidEGL * window) +{ +} + +/* Must be called in the gl thread */ +GstGLWindowAndroidEGL * +gst_gl_window_android_egl_new (void) +{ + GstGLWindowAndroidEGL *window; + + GST_DEBUG ("creating Android EGL window"); + + window = g_object_new (GST_GL_TYPE_WINDOW_ANDROID_EGL, NULL); + + gst_gl_window_set_need_lock (GST_GL_WINDOW (window), FALSE); + + return window; +} + +static void +gst_gl_window_android_egl_close (GstGLWindow * window) +{ + GstGLWindowAndroidEGL *window_egl; + + window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + + gst_gl_window_android_egl_destroy_context (window_egl); +} + +gboolean +gst_gl_window_android_egl_create_context (GstGLWindow * window, + GstGLAPI gl_api, guintptr external_gl_context, GError ** error) +{ + GstGLWindowAndroidEGL *window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + + if (!window_egl->native_window) { + g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_WRONG_CONFIG, + "No native window set"); + return FALSE; + } + + window_egl->main_context = g_main_context_new (); + window_egl->loop = g_main_loop_new (window_egl->main_context, FALSE); + + window_egl->egl = + gst_gl_egl_create_context (eglGetDisplay (EGL_DEFAULT_DISPLAY), + window_egl->native_window, gl_api, external_gl_context, error); + if (!window_egl->egl) + goto failure; + + return TRUE; + +failure: + return FALSE; +} + +static void +gst_gl_window_android_egl_destroy_context (GstGLWindowAndroidEGL * window_egl) +{ + gst_gl_egl_activate (window_egl->egl, FALSE); + gst_gl_egl_destroy_context (window_egl->egl); + window_egl->egl = NULL; + + g_main_loop_unref (window_egl->loop); + g_main_context_unref (window_egl->main_context); +} + +static gboolean +gst_gl_window_android_egl_activate (GstGLWindow * window, gboolean activate) +{ + GstGLWindowAndroidEGL *window_egl; + + window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + + return gst_gl_egl_activate (window_egl->egl, activate); +} + +static guintptr +gst_gl_window_android_egl_get_gl_context (GstGLWindow * window) +{ + GstGLWindowAndroidEGL *window_egl; + + window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + + return gst_gl_egl_get_gl_context (window_egl->egl); +} + +static GstGLAPI +gst_gl_window_android_egl_get_gl_api (GstGLWindow * window) +{ + GstGLWindowAndroidEGL *window_egl; + + window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + + return gst_gl_egl_get_gl_api (window_egl->egl); +} + +static void +gst_gl_window_android_egl_swap_buffers (GstGLWindow * window) +{ + GstGLWindowAndroidEGL *window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + + gst_gl_egl_swap_buffers (window_egl->egl); +} + +static void +gst_gl_window_android_egl_run (GstGLWindow * window) +{ + GstGLWindowAndroidEGL *window_egl; + + window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + + GST_LOG ("starting main loop"); + g_main_loop_run (window_egl->loop); + GST_LOG ("exiting main loop"); +} + +static void +gst_gl_window_android_egl_quit (GstGLWindow * window, GstGLWindowCB callback, + gpointer data) +{ + GstGLWindowAndroidEGL *window_egl; + + window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + + if (callback) + gst_gl_window_android_egl_send_message (window, callback, data); + + GST_LOG ("sending quit"); + + g_main_loop_quit (window_egl->loop); + + GST_LOG ("quit sent"); +} + +typedef struct _GstGLMessage +{ + GMutex lock; + GCond cond; + gboolean fired; + + GstGLWindowCB callback; + gpointer data; +} GstGLMessage; + +static gboolean +_run_message (GstGLMessage * message) +{ + g_mutex_lock (&message->lock); + + if (message->callback) + message->callback (message->data); + + message->fired = TRUE; + g_cond_signal (&message->cond); + g_mutex_unlock (&message->lock); + + return FALSE; +} + +static void +gst_gl_window_android_egl_send_message (GstGLWindow * window, + GstGLWindowCB callback, gpointer data) +{ + GstGLWindowAndroidEGL *window_egl; + GstGLMessage message; + + window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + message.callback = callback; + message.data = data; + message.fired = FALSE; + g_mutex_init (&message.lock); + g_cond_init (&message.cond); + + g_main_context_invoke (window_egl->main_context, (GSourceFunc) _run_message, + &message); + + g_mutex_lock (&message.lock); + + while (!message.fired) + g_cond_wait (&message.cond, &message.lock); + g_mutex_unlock (&message.lock); +} + +static void +gst_gl_window_android_egl_set_window_handle (GstGLWindow * window, + guintptr handle) +{ + GstGLWindowAndroidEGL *window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + + window_egl->native_window = (EGLNativeWindowType) handle; +} + +struct draw +{ + GstGLWindowAndroidEGL *window; + guint width, height; +}; + +static void +draw_cb (gpointer data) +{ + struct draw *draw_data = data; + GstGLWindowAndroidEGL *window_egl = draw_data->window; + GstGLWindow *window = GST_GL_WINDOW (window_egl); + + if (window->draw) + window->draw (window->draw_data); + + gst_gl_window_android_egl_swap_buffers (window); +} + +static void +gst_gl_window_android_egl_draw (GstGLWindow * window, guint width, guint height) +{ + struct draw draw_data; + + draw_data.window = GST_GL_WINDOW_ANDROID_EGL (window); + draw_data.width = width; + draw_data.height = height; + + gst_gl_window_send_message (window, (GstGLWindowCB) draw_cb, &draw_data); +} + +static gpointer +gst_gl_window_android_egl_get_proc_address (GstGLWindow * window, + const gchar * name) +{ + GstGLWindowAndroidEGL *window_egl; + gpointer result; + + window_egl = GST_GL_WINDOW_ANDROID_EGL (window); + + if (!(result = gst_gl_egl_get_proc_address (window_egl->egl, name))) { + result = gst_gl_window_default_get_proc_address (window, name); + } + + return result; +} diff --git a/gst-libs/gst/gl/android/gstglwindow_android_egl.h b/gst-libs/gst/gl/android/gstglwindow_android_egl.h new file mode 100644 index 0000000..7ec7049 --- /dev/null +++ b/gst-libs/gst/gl/android/gstglwindow_android_egl.h @@ -0,0 +1,69 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * Copyright (C) 2013 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_ANDROID_EGL_H__ +#define __GST_GL_WINDOW_ANDROID_EGL_H__ + +#include + +#include +#include "../gstglegl.h" + +G_BEGIN_DECLS + +#define GST_GL_TYPE_WINDOW_ANDROID_EGL (gst_gl_window_android_egl_get_type()) +#define GST_GL_WINDOW_ANDROID_EGL(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_WINDOW_ANDROID_EGL, GstGLWindowAndroidEGL)) +#define GST_GL_WINDOW_ANDROID_EGL_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_WINDOW_ANDROID_EGL, GstGLWindowAndroidEGLClass)) +#define GST_GL_IS_WINDOW_ANDROID_EGL(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_WINDOW_ANDROID_EGL)) +#define GST_GL_IS_WINDOW_ANDROID_EGL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_WINDOW_ANDROID_EGL)) +#define GST_GL_WINDOW_ANDROID_EGL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_WINDOW_ANDROID_EGL, GstGLWindowAndroidEGL_Class)) + +typedef struct _GstGLWindowAndroidEGL GstGLWindowAndroidEGL; +typedef struct _GstGLWindowAndroidEGLClass GstGLWindowAndroidEGLClass; + +struct _GstGLWindowAndroidEGL { + /*< private >*/ + GstGLWindow parent; + + GstGLEGL *egl; + EGLNativeWindowType native_window; + + GMainContext *main_context; + GMainLoop *loop; + + gpointer _reserved[GST_PADDING]; +}; + +struct _GstGLWindowAndroidEGLClass { + /*< private >*/ + GstGLWindowClass parent_class; + + /*< private >*/ + gpointer _reserved[GST_PADDING]; +}; + +GType gst_gl_window_android_egl_get_type (void); + +GstGLWindowAndroidEGL * gst_gl_window_android_egl_new (void); + +G_END_DECLS + +#endif /* __GST_GL_WINDOW_ANDROID_H__ */ diff --git a/gst-libs/gst/gl/gstglegl.c b/gst-libs/gst/gl/gstglegl.c index 4097a52..480937c 100644 --- a/gst-libs/gst/gl/gstglegl.c +++ b/gst-libs/gst/gl/gstglegl.c @@ -274,6 +274,11 @@ gst_gl_egl_get_proc_address (GstGLEGL * egl, const gchar * name) { gpointer result; + /* FIXME: On Android this returns wrong addresses for non-EGL functions */ +#ifdef GST_GL_HAVE_WINDOW_ANDROID + return NULL; +#endif + result = eglGetProcAddress (name); return result; diff --git a/gst-libs/gst/gl/gstglwindow.c b/gst-libs/gst/gl/gstglwindow.c index 1aa1b8c..6ac8c3b 100644 --- a/gst-libs/gst/gl/gstglwindow.c +++ b/gst-libs/gst/gl/gstglwindow.c @@ -40,6 +40,9 @@ #if GST_GL_HAVE_WINDOW_WAYLAND #include "wayland/gstglwindow_wayland_egl.h" #endif +#if GST_GL_HAVE_WINDOW_ANDROID +#include "android/gstglwindow_android_egl.h" +#endif #define USING_OPENGL(display) (display->gl_api & GST_GL_API_OPENGL) #define USING_OPENGL3(display) (display->gl_api & GST_GL_API_OPENGL3) @@ -142,6 +145,10 @@ gst_gl_window_new (GstGLDisplay * display) if (!window && (!user_choice || g_strstr_len (user_choice, 7, "wayland"))) window = GST_GL_WINDOW (gst_gl_window_wayland_egl_new ()); #endif +#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 (!window) { /* subclass returned a NULL window */ GST_WARNING ("Could not create window. user specified %s", -- 2.7.4