diff --git a/gst-libs/gst/gl/cocoa/Makefile.am b/gst-libs/gst/gl/cocoa/Makefile.am index 171d18c6a4..f45583ddd3 100644 --- a/gst-libs/gst/gl/cocoa/Makefile.am +++ b/gst-libs/gst/gl/cocoa/Makefile.am @@ -5,9 +5,11 @@ noinst_LTLIBRARIES = libgstgl-cocoa.la libgstgl_cocoa_la_SOURCES = \ gstglwindow_cocoa.m \ gstglcontext_cocoa.m \ + gstgldisplay_cocoa.m \ gstglcaopengllayer.m noinst_HEADERS = \ + gstgldisplay_cocoa.h \ gstglwindow_cocoa.h \ gstgl_cocoa_private.h diff --git a/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m b/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m index fd8891e8d0..f2fc4297fa 100644 --- a/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m +++ b/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m @@ -44,165 +44,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_gl_context_cocoa_debug); G_DEFINE_TYPE_WITH_CODE (GstGLContextCocoa, gst_gl_context_cocoa, GST_GL_TYPE_CONTEXT, GST_DEBUG_CATEGORY_INIT (gst_gl_context_cocoa_debug, "glcontext_cocoa", 0, "Cocoa GL Context"); ); -/* Define this if the GLib patch from - * https://bugzilla.gnome.org/show_bug.cgi?id=741450 - * is used - */ -#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION - -static gboolean gst_gl_window_cocoa_nsapp_iteration (gpointer data); - -static GMutex nsapp_lock; -static GCond nsapp_cond; -static gint nsapp_count = 0; -static gint nsapp_source_id = 0; - -static gboolean -gst_gl_window_cocoa_init_nsapp (gpointer data) -{ - NSAutoreleasePool *pool = nil; - - g_mutex_lock (&nsapp_lock); - - pool = [[NSAutoreleasePool alloc] init]; - - /* The sharedApplication class method initializes - * the display environment and connects your program - * to the window server and the display server - */ - - /* TODO: so consider to create GstGLDisplayCocoa - * in gst/gl/cocoa/gstgldisplay_cocoa.h/c - */ - - /* has to be called in the main thread */ - if ([NSThread isMainThread]) { - [NSApplication sharedApplication]; - - GST_DEBUG ("NSApp initialized from a GTimeoutSource"); - - nsapp_source_id = g_timeout_add (60, gst_gl_window_cocoa_nsapp_iteration, NULL); - } - - [pool release]; - - g_cond_signal (&nsapp_cond); - g_mutex_unlock (&nsapp_lock); - - return FALSE; -} - -static gboolean -gst_gl_window_cocoa_nsapp_iteration (gpointer data) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSEvent *event = nil; - - if ([NSThread isMainThread]) { - - while ((event = ([NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate dateWithTimeIntervalSinceNow:0.05] - inMode:NSDefaultRunLoopMode dequeue:YES])) != nil) { - - [NSApp sendEvent:event]; - } - } - - [pool release]; - - return TRUE; -} - -static void -gst_gl_context_cocoa_check_nsapp_loop (gboolean activate) -{ - g_mutex_lock (&nsapp_lock); - - if (activate) ++nsapp_count; - else --nsapp_count; - - if (nsapp_count == 0) { - if (nsapp_source_id) - g_source_remove (nsapp_source_id); - nsapp_source_id = 0; - } - - g_mutex_unlock (&nsapp_lock); -} - -static gpointer -gst_gl_context_cocoa_setup_nsapp (gpointer data) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - /* [NSApplication sharedApplication] will usually be - * called in your application so it's not necessary - * to do that the following. Except for debugging - * purpose like when using gst-launch. - * So here we handle the two cases where the first - * GstGLContext is either created in the main thread - * or from another thread like a streaming thread - */ - - if ([NSThread isMainThread]) { - /* In the main thread so just do the call now */ - - /* The sharedApplication class method initializes - * the display environment and connects your program - * to the window server and the display server - */ - - /* TODO: so consider to create GstGLDisplayCocoa - * in gst/gl/cocoa/gstgldisplay_cocoa.h/c - */ - - /* has to be called in the main thread */ - [NSApplication sharedApplication]; - - GST_DEBUG ("NSApp initialized"); - } else { - /* Not in the main thread, assume there is a - * glib main loop running this is for debugging - * purposes so that's ok to let us a chance - */ - GMainContext *context; - gboolean is_loop_running = FALSE; - gint64 end_time = 0; - - context = g_main_context_default (); - - if (g_main_context_is_owner (context)) { - /* At the thread running the default GLib main context but - * not the Cocoa main thread - * We can't do anything here - */ - } else if (g_main_context_acquire (context)) { - /* No main loop running on the default main context, - * we can't do anything here */ - g_main_context_release (context); - } else { - /* Main loop running on the default main context but it - * is not running in this thread */ - g_mutex_lock (&nsapp_lock); - g_idle_add_full (G_PRIORITY_HIGH, gst_gl_window_cocoa_init_nsapp, NULL, NULL); - end_time = g_get_monotonic_time () + 500 * 1000; - is_loop_running = g_cond_wait_until (&nsapp_cond, &nsapp_lock, end_time); - g_mutex_unlock (&nsapp_lock); - - if (!is_loop_running) { - GST_WARNING ("no mainloop running"); - } - } - } - - [pool release]; - - return NULL; -} - -#endif - static void gst_gl_context_cocoa_class_init (GstGLContextCocoaClass * klass) { @@ -336,12 +177,6 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api, CGLError ret; gint npix; -#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION - static GOnce once = G_ONCE_INIT; - g_once (&once, gst_gl_context_cocoa_setup_nsapp, context); - gst_gl_context_cocoa_check_nsapp_loop (TRUE); -#endif - priv->gl_context = nil; if (other_context) priv->external_gl_context = (CGLContextObj) gst_gl_context_get_gl_context (other_context); @@ -377,9 +212,6 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api, window_cocoa); if (!context_cocoa->priv->gl_context) { -#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION - gst_gl_context_cocoa_check_nsapp_loop (FALSE); -#endif goto error; } @@ -407,9 +239,6 @@ static void gst_gl_context_cocoa_destroy_context (GstGLContext *context) { /* FIXME: Need to release context and other things? */ -#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION - gst_gl_context_cocoa_check_nsapp_loop (FALSE); -#endif } static guintptr diff --git a/gst-libs/gst/gl/cocoa/gstgldisplay_cocoa.h b/gst-libs/gst/gl/cocoa/gstgldisplay_cocoa.h new file mode 100644 index 0000000000..5551f0f29c --- /dev/null +++ b/gst-libs/gst/gl/cocoa/gstgldisplay_cocoa.h @@ -0,0 +1,62 @@ +/* + * GStreamer + * Copyright (C) 2015 Julien Isorce + * + * 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_DISPLAY_COCOA_H__ +#define __GST_GL_DISPLAY_COCOA_H__ + +#include + +#include +#include + +G_BEGIN_DECLS + +GType gst_gl_display_cocoa_get_type (void); + +#define GST_TYPE_GL_DISPLAY_COCOA (gst_gl_display_cocoa_get_type()) +#define GST_GL_DISPLAY_COCOA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DISPLAY_COCOA,GstGLDisplayCocoa)) +#define GST_GL_DISPLAY_COCOA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_GL_DISPLAY_COCOA,GstGLDisplayCocoaClass)) +#define GST_IS_GL_DISPLAY_COCOA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DISPLAY_COCOA)) +#define GST_IS_GL_DISPLAY_COCOA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_GL_DISPLAY_COCOA)) +#define GST_GL_DISPLAY_COCOA_CAST(obj) ((GstGLDisplayCocoa*)(obj)) + +typedef struct _GstGLDisplayCocoa GstGLDisplayCocoa; +typedef struct _GstGLDisplayCocoaClass GstGLDisplayCocoaClass; + +/** + * GstGLDisplayCocoa: + * + * Initialized NSApp if the application has not done it. + */ +struct _GstGLDisplayCocoa +{ + GstGLDisplay parent; +}; + +struct _GstGLDisplayCocoaClass +{ + GstGLDisplayClass object_class; +}; + +GstGLDisplayCocoa *gst_gl_display_cocoa_new (void); + +G_END_DECLS + +#endif /* __GST_GL_DISPLAY_COCOA_H__ */ diff --git a/gst-libs/gst/gl/cocoa/gstgldisplay_cocoa.m b/gst-libs/gst/gl/cocoa/gstgldisplay_cocoa.m new file mode 100644 index 0000000000..f7c0252194 --- /dev/null +++ b/gst-libs/gst/gl/cocoa/gstgldisplay_cocoa.m @@ -0,0 +1,247 @@ +/* + * GStreamer + * Copyright (C) 2015 Julien Isorce + * + * 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 + +#include + +#include + +GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug); +#define GST_CAT_DEFAULT gst_gl_display_debug + +G_DEFINE_TYPE (GstGLDisplayCocoa, gst_gl_display_cocoa, GST_TYPE_GL_DISPLAY); + +static void gst_gl_display_cocoa_finalize (GObject * object); +static guintptr gst_gl_display_cocoa_get_handle (GstGLDisplay * display); + +/* Define this if the GLib patch from + * https://bugzilla.gnome.org/show_bug.cgi?id=741450 + * is used + */ +#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION + +static GstGLDisplayCocoa *singleton = NULL; +static gint nsapp_source_id = 0; +static GMutex nsapp_lock; +static GCond nsapp_cond; + +static gboolean +gst_gl_display_cocoa_nsapp_iteration (gpointer data) +{ + NSAutoreleasePool *pool = nil; + NSEvent *event = nil; + + if (![NSThread isMainThread]) { + GST_WARNING ("NSApp iteration not running in the main thread"); + return FALSE; + } + + pool = [[NSAutoreleasePool alloc] init]; + + while ((event = ([NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate dateWithTimeIntervalSinceNow:0.05] + inMode:NSDefaultRunLoopMode dequeue:YES])) != nil) { + [NSApp sendEvent:event]; + } + + [pool release]; + + return TRUE; +} + +static void +gst_gl_display_cocoa_open_and_attach_source (gpointer data) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + if ([NSThread isMainThread]) { + /* The sharedApplication class method initializes + * the display environment and connects your program + * to the window server and the display server. + * It has to be done in the main thread. + */ + [NSApplication sharedApplication]; + + GST_DEBUG ("Custom NSApp initialization done"); + + nsapp_source_id = g_timeout_add (60, gst_gl_display_cocoa_nsapp_iteration, + NULL); + + GST_DEBUG ("NSApp iteration loop attached, id %d", nsapp_source_id); + } + + [pool release]; +} + +static gboolean +gst_gl_display_cocoa_init_nsapp (gpointer data) +{ + g_mutex_lock (&nsapp_lock); + + gst_gl_display_cocoa_open_and_attach_source (data); + + g_cond_signal (&nsapp_cond); + g_mutex_unlock (&nsapp_lock); + + return FALSE; +} + +static GstGLDisplayCocoa * +gst_gl_display_cocoa_setup_nsapp (gpointer data) +{ + GMainContext *context = g_main_context_default (); + gint delta_ms = 0; + + g_mutex_lock (&nsapp_lock); + + if (singleton) { + GST_DEBUG ("Get existing display"); + singleton = gst_object_ref (singleton); + g_mutex_unlock (&nsapp_lock); + return singleton; + } + + if (NSApp != nil && !singleton) { + GstGLDisplayCocoa *ret = g_object_new (GST_TYPE_GL_DISPLAY_COCOA, NULL); + g_mutex_unlock (&nsapp_lock); + return ret; + } + + /* All application have to start with [NSApplication sharedApplication] + * so if NSApp is nil here let's assume this is a debugging application + * that runs a glib main loop. */ + g_assert (NSApp == nil); + + GST_DEBUG ("The application has not initialized NSApp"); + + if ([NSThread isMainThread]) { + + GST_DEBUG ("Setting up NSApp from the main thread"); + if (g_main_context_is_owner (context)) { + GST_DEBUG ("The main thread own the context"); + gst_gl_display_cocoa_open_and_attach_source (data); + } else if (g_main_context_acquire (context)) { + GST_DEBUG ("The main loop should be shortly running in the main thread"); + gst_gl_display_cocoa_open_and_attach_source (data); + g_main_context_release (context); + } else { + GST_WARNING ("Main loop running in another thread"); + } + } else { + + GST_DEBUG ("Setting up NSApp not from the main thread"); + + if (g_main_context_is_owner (context)) { + GST_WARNING ("Default context not own by the main thread"); + delta_ms = -1; + } else if (g_main_context_acquire (context)) { + GST_DEBUG ("The main loop should be shortly running in the main thread"); + delta_ms = 1000; + g_main_context_release (context); + } else { + GST_DEBUG ("Main loop running in main thread"); + delta_ms = 500; + } + + if (delta_ms > 0) { + gint64 end_time = g_get_monotonic_time () + delta_ms * 1000;; + g_idle_add_full (G_PRIORITY_HIGH, gst_gl_display_cocoa_init_nsapp, data, NULL); + g_cond_wait_until (&nsapp_cond, &nsapp_lock, end_time); + } + } + + if (NSApp == nil) { + GST_ERROR ("Custom NSApp initialization failed"); + } else { + GST_DEBUG ("Create display"); + singleton = g_object_new (GST_TYPE_GL_DISPLAY_COCOA, NULL); + } + + g_mutex_unlock (&nsapp_lock); + + return singleton; +} + +#endif + +static void +gst_gl_display_cocoa_class_init (GstGLDisplayCocoaClass * klass) +{ + GST_GL_DISPLAY_CLASS (klass)->get_handle = + GST_DEBUG_FUNCPTR (gst_gl_display_cocoa_get_handle); + + G_OBJECT_CLASS (klass)->finalize = gst_gl_display_cocoa_finalize; +} + +static void +gst_gl_display_cocoa_init (GstGLDisplayCocoa * display_cocoa) +{ + GstGLDisplay *display = (GstGLDisplay *) display_cocoa; + display->type = GST_GL_DISPLAY_TYPE_COCOA; +} + +static void +gst_gl_display_cocoa_finalize (GObject * object) +{ +#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION + g_mutex_lock (&nsapp_lock); + if (singleton) { + GST_DEBUG ("Destroy display"); + singleton = NULL; + if (nsapp_source_id) { + GST_DEBUG ("Remove NSApp loop iteration, id %d", nsapp_source_id); + g_source_remove (nsapp_source_id); + } + nsapp_source_id = 0; + g_mutex_unlock (&nsapp_lock); + } + g_mutex_unlock (&nsapp_lock); +#endif + + G_OBJECT_CLASS (gst_gl_display_cocoa_parent_class)->finalize (object); +} + +/** + * gst_gl_display_cocoa_new: + * + * Create a new #GstGLDisplayCocoa. + * + * Returns: (transfer full): a new #GstGLDisplayCocoa or %NULL + */ +GstGLDisplayCocoa * +gst_gl_display_cocoa_new (void) +{ + GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay"); + +#ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION + return gst_gl_display_cocoa_setup_nsapp (NULL); +#else + return g_object_new (GST_TYPE_GL_DISPLAY_COCOA, NULL); +#endif +} + +static guintptr +gst_gl_display_cocoa_get_handle (GstGLDisplay * display) +{ + return (guintptr) NSApp; +} diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index 96721705a6..c50384566c 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/gstgldisplay.c @@ -56,6 +56,9 @@ #include "gl.h" #include "gstgldisplay.h" +#if GST_GL_HAVE_WINDOW_COCOA +#include +#endif #if GST_GL_HAVE_WINDOW_X11 #include #endif @@ -159,8 +162,11 @@ gst_gl_display_new (void) GST_STR_NULL (user_choice), GST_STR_NULL (platform_choice)); #if GST_GL_HAVE_WINDOW_COCOA - if (!display && (!user_choice || g_strstr_len (user_choice, 5, "cocoa"))) - display = g_object_new (GST_TYPE_GL_DISPLAY, NULL); + if (!display && (!user_choice || g_strstr_len (user_choice, 5, "cocoa"))) { + display = GST_GL_DISPLAY (gst_gl_display_cocoa_new ()); + if (!display) + return NULL; + } #endif #if GST_GL_HAVE_WINDOW_X11 if (!display && (!user_choice || g_strstr_len (user_choice, 3, "x11")))