gl: add GstGLDisplayCocoa
authorJulien Isorce <j.isorce@samsung.com>
Wed, 11 Mar 2015 00:06:55 +0000 (00:06 +0000)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:31:58 +0000 (19:31 +0000)
https://bugzilla.gnome.org/show_bug.cgi?id=746012

gst-libs/gst/gl/cocoa/Makefile.am
gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m
gst-libs/gst/gl/cocoa/gstgldisplay_cocoa.h [new file with mode: 0644]
gst-libs/gst/gl/cocoa/gstgldisplay_cocoa.m [new file with mode: 0644]
gst-libs/gst/gl/gstgldisplay.c

index 171d18c..f45583d 100644 (file)
@@ -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
 
index fd8891e..f2fc429 100644 (file)
@@ -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 (file)
index 0000000..5551f0f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * GStreamer
+ * Copyright (C) 2015 Julien Isorce <julien.isorce@gmail.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_GL_DISPLAY_COCOA_H__
+#define __GST_GL_DISPLAY_COCOA_H__
+
+#include <gst/gst.h>
+
+#include <gst/gl/gstgl_fwd.h>
+#include <gst/gl/gstgldisplay.h>
+
+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 (file)
index 0000000..f7c0252
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * GStreamer
+ * Copyright (C) 2015 Julien Isorce <julien.isorce@gmail.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
+
+#include <Cocoa/Cocoa.h>
+
+#include <gst/gl/cocoa/gstgldisplay_cocoa.h>
+
+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;
+}
index 9672170..c503845 100644 (file)
@@ -56,6 +56,9 @@
 #include "gl.h"
 #include "gstgldisplay.h"
 
+#if GST_GL_HAVE_WINDOW_COCOA
+#include <gst/gl/cocoa/gstgldisplay_cocoa.h>
+#endif
 #if GST_GL_HAVE_WINDOW_X11
 #include <gst/gl/x11/gstgldisplay_x11.h>
 #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")))