From 3bb8700577ab4f741db00831796c25ac4ea7d888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Brzezi=C5=84ski?= Date: Tue, 13 Dec 2022 18:42:11 +0100 Subject: [PATCH] macos: Add wrapper API to run a NSApplication in the main thread On macOS, a Cocoa event loop is needed in the main thread to ensure things like opening a GL window work correctly. In the past, this was patched into glib via Cerbero, but that prevented us from updating it. This workaround simply runs an NSApplication and then calls the main function on a secondary thread, allowing GStreamer to correctly display windows and/or system permission prompts, for example. Part-of: --- .../examples/tutorials/basic-tutorial-1.c | 16 ++- .../examples/tutorials/basic-tutorial-12.c | 16 ++- .../examples/tutorials/basic-tutorial-13.c | 16 ++- .../examples/tutorials/basic-tutorial-15.c | 16 ++- .../examples/tutorials/basic-tutorial-2.c | 16 ++- .../examples/tutorials/basic-tutorial-3.c | 16 ++- .../examples/tutorials/basic-tutorial-4.c | 16 ++- .../examples/tutorials/basic-tutorial-5.c | 16 ++- .../examples/tutorials/basic-tutorial-6.c | 16 ++- .../examples/tutorials/basic-tutorial-7.c | 16 ++- .../examples/tutorials/basic-tutorial-8.c | 16 ++- .../examples/tutorials/basic-tutorial-9.c | 16 ++- .../examples/tutorials/playback-tutorial-1.c | 16 ++- .../examples/tutorials/playback-tutorial-2.c | 16 ++- .../examples/tutorials/playback-tutorial-3.c | 16 ++- .../examples/tutorials/playback-tutorial-4.c | 16 ++- .../examples/tutorials/playback-tutorial-5.c | 16 ++- .../examples/tutorials/playback-tutorial-6.c | 16 ++- .../examples/tutorials/playback-tutorial-7.c | 16 ++- subprojects/gstreamer/gst/gst.h | 7 ++ subprojects/gstreamer/gst/gstmacos.h | 43 ++++++++ subprojects/gstreamer/gst/gstmacos.m | 101 ++++++++++++++++++ subprojects/gstreamer/gst/meson.build | 9 ++ subprojects/gstreamer/meson.build | 15 ++- 24 files changed, 458 insertions(+), 21 deletions(-) create mode 100644 subprojects/gstreamer/gst/gstmacos.h create mode 100644 subprojects/gstreamer/gst/gstmacos.m diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-1.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-1.c index 573d4b2e90..35ae853e0b 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-1.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-1.c @@ -1,7 +1,11 @@ #include +#ifdef __APPLE__ +#include +#endif + int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { GstElement *pipeline; GstBus *bus; @@ -38,3 +42,13 @@ main (int argc, char *argv[]) gst_object_unref (pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-12.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-12.c index d3f0eb9f18..f01f60fac4 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-12.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-12.c @@ -1,6 +1,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + typedef struct _CustomData { gboolean is_live; @@ -59,7 +63,7 @@ cb_message (GstBus * bus, GstMessage * msg, CustomData * data) } int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { GstElement *pipeline; GstBus *bus; @@ -106,3 +110,13 @@ main (int argc, char *argv[]) gst_object_unref (pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-13.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-13.c index 880702c32d..b7640f643e 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-13.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-13.c @@ -2,6 +2,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + typedef struct _CustomData { GstElement *pipeline; @@ -103,7 +107,7 @@ handle_keyboard (GIOChannel * source, GIOCondition cond, CustomData * data) } int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { CustomData data; GstStateChangeReturn ret; @@ -160,3 +164,13 @@ main (int argc, char *argv[]) gst_object_unref (data.pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-15.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-15.c index dcf2db1a13..882a9d6e42 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-15.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-15.c @@ -1,5 +1,9 @@ #include +#ifdef __APPLE__ +#include +#endif + /* Setup the video texture once its size is known */ void size_change (ClutterActor * texture, gint width, gint height, @@ -42,7 +46,7 @@ size_change (ClutterActor * texture, gint width, gint height, } int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { GstElement *pipeline, *sink; ClutterTimeline *timeline; @@ -106,3 +110,13 @@ main (int argc, char *argv[]) gst_object_unref (pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-2.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-2.c index 4ccea592e2..6f795ca59c 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-2.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-2.c @@ -1,7 +1,11 @@ #include +#ifdef __APPLE__ +#include +#endif + int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { GstElement *pipeline, *source, *sink; GstBus *bus; @@ -80,3 +84,13 @@ main (int argc, char *argv[]) gst_object_unref (pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-3.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-3.c index 320382d578..722c44a189 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-3.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-3.c @@ -1,5 +1,9 @@ #include +#ifdef __APPLE__ +#include +#endif + /* Structure to contain all our information, so we can pass it to callbacks */ typedef struct _CustomData { @@ -15,7 +19,7 @@ static void pad_added_handler (GstElement * src, GstPad * pad, CustomData * data); int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { CustomData data; GstBus *bus; @@ -166,3 +170,13 @@ exit: /* Unreference the sink pad */ gst_object_unref (sink_pad); } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-4.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-4.c index b3a522982f..6b5b92dbf7 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-4.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-4.c @@ -1,5 +1,9 @@ #include +#ifdef __APPLE__ +#include +#endif + /* Structure to contain all our information, so we can pass it around */ typedef struct _CustomData { @@ -15,7 +19,7 @@ typedef struct _CustomData static void handle_message (CustomData * data, GstMessage * msg); int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { CustomData data; GstBus *bus; @@ -170,3 +174,13 @@ handle_message (CustomData * data, GstMessage * msg) } gst_message_unref (msg); } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-5.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-5.c index 34c75c978f..7aab34c1b7 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-5.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-5.c @@ -4,6 +4,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + #include #if defined (GDK_WINDOWING_X11) #include @@ -372,7 +376,7 @@ application_cb (GstBus * bus, GstMessage * msg, CustomData * data) } int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { CustomData data; GstStateChangeReturn ret; @@ -443,3 +447,13 @@ main (int argc, char *argv[]) gst_object_unref (data.playbin); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-6.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-6.c index 2c06b3a9cc..3b6cb69803 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-6.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-6.c @@ -1,5 +1,9 @@ #include +#ifdef __APPLE__ +#include +#endif + /* Functions below print the Capabilities in a human-friendly format */ static gboolean print_field (GQuark field, const GValue * value, gpointer pfx) @@ -110,7 +114,7 @@ print_pad_capabilities (GstElement * element, gchar * pad_name) } int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { GstElement *pipeline, *source, *sink; GstElementFactory *source_factory, *sink_factory; @@ -222,3 +226,13 @@ main (int argc, char *argv[]) gst_object_unref (sink_factory); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-7.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-7.c index 7cb9c1372f..d2b24134bf 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-7.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-7.c @@ -1,7 +1,11 @@ #include +#ifdef __APPLE__ +#include +#endif + int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { GstElement *pipeline, *audio_source, *tee, *audio_queue, *audio_convert, *audio_resample, *audio_sink; @@ -96,3 +100,13 @@ main (int argc, char *argv[]) gst_object_unref (pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-8.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-8.c index 27749f95b7..50b620547f 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-8.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-8.c @@ -2,6 +2,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + #define CHUNK_SIZE 1024 /* Amount of bytes we are sending in each buffer */ #define SAMPLE_RATE 44100 /* Samples per second we are sending */ @@ -134,7 +138,7 @@ error_cb (GstBus * bus, GstMessage * msg, CustomData * data) } int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { CustomData data; GstPad *tee_audio_pad, *tee_video_pad, *tee_app_pad; @@ -268,3 +272,13 @@ main (int argc, char *argv[]) gst_object_unref (data.pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/basic-tutorial-9.c b/subprojects/gst-docs/examples/tutorials/basic-tutorial-9.c index a1ed3b9505..f252f4f044 100644 --- a/subprojects/gst-docs/examples/tutorials/basic-tutorial-9.c +++ b/subprojects/gst-docs/examples/tutorials/basic-tutorial-9.c @@ -2,6 +2,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + /* Structure to contain all our information, so we can pass it around */ typedef struct _CustomData { @@ -181,7 +185,7 @@ on_finished_cb (GstDiscoverer * discoverer, CustomData * data) } int -main (int argc, char **argv) +tutorial_main (int argc, char **argv) { CustomData data; GError *err = NULL; @@ -238,3 +242,13 @@ main (int argc, char **argv) return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/playback-tutorial-1.c b/subprojects/gst-docs/examples/tutorials/playback-tutorial-1.c index b9daae3e02..b2f783eef8 100644 --- a/subprojects/gst-docs/examples/tutorials/playback-tutorial-1.c +++ b/subprojects/gst-docs/examples/tutorials/playback-tutorial-1.c @@ -1,6 +1,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + /* Structure to contain all our information, so we can pass it around */ typedef struct _CustomData { @@ -32,7 +36,7 @@ static gboolean handle_keyboard (GIOChannel * source, GIOCondition cond, CustomData * data); int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { CustomData data; GstBus *bus; @@ -240,3 +244,13 @@ handle_keyboard (GIOChannel * source, GIOCondition cond, CustomData * data) g_free (str); return TRUE; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/playback-tutorial-2.c b/subprojects/gst-docs/examples/tutorials/playback-tutorial-2.c index 5e3688ffd6..69837db5e7 100644 --- a/subprojects/gst-docs/examples/tutorials/playback-tutorial-2.c +++ b/subprojects/gst-docs/examples/tutorials/playback-tutorial-2.c @@ -1,6 +1,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + /* Structure to contain all our information, so we can pass it around */ typedef struct _CustomData { @@ -32,7 +36,7 @@ static gboolean handle_keyboard (GIOChannel * source, GIOCondition cond, CustomData * data); int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { CustomData data; GstBus *bus; @@ -244,3 +248,13 @@ handle_keyboard (GIOChannel * source, GIOCondition cond, CustomData * data) g_free (str); return TRUE; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/playback-tutorial-3.c b/subprojects/gst-docs/examples/tutorials/playback-tutorial-3.c index b29c8e00a7..60a049b5a2 100644 --- a/subprojects/gst-docs/examples/tutorials/playback-tutorial-3.c +++ b/subprojects/gst-docs/examples/tutorials/playback-tutorial-3.c @@ -2,6 +2,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + #define CHUNK_SIZE 1024 /* Amount of bytes we are sending in each buffer */ #define SAMPLE_RATE 44100 /* Samples per second we are sending */ @@ -133,7 +137,7 @@ source_setup (GstElement * pipeline, GstElement * source, CustomData * data) } int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { CustomData data; GstBus *bus; @@ -170,3 +174,13 @@ main (int argc, char *argv[]) gst_object_unref (data.pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/playback-tutorial-4.c b/subprojects/gst-docs/examples/tutorials/playback-tutorial-4.c index bba675120f..abbfd92b9b 100644 --- a/subprojects/gst-docs/examples/tutorials/playback-tutorial-4.c +++ b/subprojects/gst-docs/examples/tutorials/playback-tutorial-4.c @@ -1,6 +1,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + #define GRAPH_LENGTH 78 /* playbin flags */ @@ -122,7 +126,7 @@ refresh_ui (CustomData * data) } int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { GstElement *pipeline; GstBus *bus; @@ -186,3 +190,13 @@ main (int argc, char *argv[]) g_print ("\n"); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/playback-tutorial-5.c b/subprojects/gst-docs/examples/tutorials/playback-tutorial-5.c index dc65ae4d1e..e397b4d146 100644 --- a/subprojects/gst-docs/examples/tutorials/playback-tutorial-5.c +++ b/subprojects/gst-docs/examples/tutorials/playback-tutorial-5.c @@ -3,6 +3,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + typedef struct _CustomData { GstElement *pipeline; @@ -109,7 +113,7 @@ handle_keyboard (GIOChannel * source, GIOCondition cond, CustomData * data) } int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { CustomData data; GstStateChangeReturn ret; @@ -163,3 +167,13 @@ main (int argc, char *argv[]) gst_object_unref (data.pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/playback-tutorial-6.c b/subprojects/gst-docs/examples/tutorials/playback-tutorial-6.c index fac6c7f1af..052004068a 100644 --- a/subprojects/gst-docs/examples/tutorials/playback-tutorial-6.c +++ b/subprojects/gst-docs/examples/tutorials/playback-tutorial-6.c @@ -1,5 +1,9 @@ #include +#ifdef __APPLE__ +#include +#endif + /* playbin2 flags */ typedef enum { @@ -22,7 +26,7 @@ filter_vis_features (GstPluginFeature * feature, gpointer data) } int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { GstElement *pipeline, *vis_plugin; GstBus *bus; @@ -99,3 +103,13 @@ main (int argc, char *argv[]) gst_object_unref (pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gst-docs/examples/tutorials/playback-tutorial-7.c b/subprojects/gst-docs/examples/tutorials/playback-tutorial-7.c index cd5e061fa4..58a7b821f2 100644 --- a/subprojects/gst-docs/examples/tutorials/playback-tutorial-7.c +++ b/subprojects/gst-docs/examples/tutorials/playback-tutorial-7.c @@ -1,7 +1,11 @@ #include +#ifdef __APPLE__ +#include +#endif + int -main (int argc, char *argv[]) +tutorial_main (int argc, char *argv[]) { GstElement *pipeline, *bin, *equalizer, *convert, *sink; GstPad *pad, *ghost_pad; @@ -60,3 +64,13 @@ main (int argc, char *argv[]) gst_object_unref (pipeline); return 0; } + +int +main (int argc, char *argv[]) +{ +#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE + return gst_macos_main (tutorial_main, argc, argv, NULL); +#else + return tutorial_main (argc, argv); +#endif +} diff --git a/subprojects/gstreamer/gst/gst.h b/subprojects/gstreamer/gst/gst.h index 4423813aec..7bd59cd8a4 100644 --- a/subprojects/gstreamer/gst/gst.h +++ b/subprojects/gstreamer/gst/gst.h @@ -95,6 +95,13 @@ /* API compatibility stuff */ #include +#ifdef __APPLE__ +# include +# if TARGET_OS_MAC && !TARGET_OS_IPHONE +# include +# endif +#endif + G_BEGIN_DECLS GST_API diff --git a/subprojects/gstreamer/gst/gstmacos.h b/subprojects/gstreamer/gst/gstmacos.h new file mode 100644 index 0000000000..8e1f21ab58 --- /dev/null +++ b/subprojects/gstreamer/gst/gstmacos.h @@ -0,0 +1,43 @@ +#ifndef __GST_MACOS_H__ +#define __GST_MACOS_H__ + +#include +#include + +G_BEGIN_DECLS + +/** + * GstMainFunc: + * @argc: the amount of arguments passed in @argv + * @argv: (array length=argc): an array of arguments passed to the main function + * @user_data: (nullable): user data passed to the main function + * + * Represents a simple pointer to the main() function of a program. + * It is used to pass that function along with its arguments to + * gst_macos_main(), which ensures correct behaviour of various + * GStreamer elements (e.g glimagesink) on macOS. + */ +typedef int (*GstMainFunc) (int argc, char** argv, gpointer user_data); + +/** + * GstMainFuncSimple: + * @user_data: (nullable): user data passed to the main function + * + * Simplified version of #GstMainFunc, meant to be used with + * gst_macos_main_simple(), which does not require argc/argv to be passed. + */ +typedef int (*GstMainFuncSimple) (gpointer user_data); + +GST_API +int gst_macos_main (GstMainFunc main_func, + int argc, + char *argv[], + gpointer user_data); + +GST_API +int gst_macos_main_simple (GstMainFuncSimple main_func, + gpointer user_data); + +G_END_DECLS + +#endif /* __GST_MACOS_H__ */ diff --git a/subprojects/gstreamer/gst/gstmacos.m b/subprojects/gstreamer/gst/gstmacos.m new file mode 100644 index 0000000000..e0cd09bb93 --- /dev/null +++ b/subprojects/gstreamer/gst/gstmacos.m @@ -0,0 +1,101 @@ +#include "gstmacos.h" +#include + +typedef struct _ThreadArgs ThreadArgs; + +struct _ThreadArgs { + void* main_func; + int argc; + char **argv; + gpointer user_data; + gboolean is_simple; +}; + +int +gst_thread_func (ThreadArgs *args) +{ + int ret; + if (args->is_simple) { + ret = ((GstMainFuncSimple) args->main_func) (args->user_data); + } else { + ret = ((GstMainFunc) args->main_func) (args->argc, args->argv, args->user_data); + } + + [NSApp terminate: nil]; + return ret; +} + +int +run_main_with_nsapp (ThreadArgs args) +{ + GThread *gst_thread; + + [NSApplication sharedApplication]; + gst_thread = g_thread_new ("macos-gst-thread", (GThreadFunc) gst_thread_func, &args); + [NSApp run]; + + return GPOINTER_TO_INT (g_thread_join (gst_thread)); +} + +/** + * gst_macos_main: + * @main_func: (scope async): pointer to the main function to be called + * @argc: the amount of arguments passed in @argv + * @argv: (array length=argc): an array of arguments to be passed to the main function + * @user_data: (nullable): user data to be passed to the main function + * + * Starts an NSApplication on the main thread before calling + * the provided main() function on a secondary thread. + * + * This ensures that GStreamer can correctly perform actions + * such as creating a GL window, which require a Cocoa main loop + * to be running on the main thread. + * + * Do not call this function more than once - especially while + * another one is still running - as that will cause unpredictable + * behaviour and most likely completely fail. + * + * Returns: the return value of the provided main_func + * + * Since: 1.22 + */ +int +gst_macos_main (GstMainFunc main_func, int argc, char **argv, gpointer user_data) +{ + ThreadArgs args; + + args.argc = argc; + args.argv = argv; + args.main_func = main_func; + args.user_data = user_data; + args.is_simple = FALSE; + + return run_main_with_nsapp (args); +} + +/** + * gst_macos_main_simple: + * @main_func: (scope async): pointer to the main function to be called + * @user_data: (nullable): user data to be passed to the main function + * + * Simplified variant of gst_macos_main(), meant to be used with bindings + * for languages which do not have to pass argc and argv like C does. + * See gst_macos_main() for a more detailed description. + * + * Returns: the return value of the provided main_func + * + * Since: 1.22 + */ +int +gst_macos_main_simple (GstMainFuncSimple main_func, gpointer user_data) +{ + ThreadArgs args; + + args.argc = 0; + args.argv = NULL; + args.main_func = main_func; + args.user_data = user_data; + args.is_simple = TRUE; + + return run_main_with_nsapp (args); +} diff --git a/subprojects/gstreamer/gst/meson.build b/subprojects/gstreamer/gst/meson.build index 3356b848d4..4293c78e4d 100644 --- a/subprojects/gstreamer/gst/meson.build +++ b/subprojects/gstreamer/gst/meson.build @@ -148,6 +148,11 @@ gst_headers = files( 'gstparse.h', 'math-compat.h', ) +if host_system == 'darwin' + gst_headers += 'gstmacos.h' + gst_sources += 'gstmacos.m' +endif + install_headers(gst_headers, subdir : 'gstreamer-1.0/gst') extra_deps = [] @@ -156,6 +161,10 @@ if host_system == 'android' extra_deps += cc.find_library('log') endif +if host_system == 'darwin' + extra_deps += dependency('appleframeworks', modules : ['Cocoa']) +endif + gst_registry = get_option('registry') if gst_registry gst_registry_sources = files('gstregistrybinary.c') diff --git a/subprojects/gstreamer/meson.build b/subprojects/gstreamer/meson.build index 7331c66150..32cb7aef9a 100644 --- a/subprojects/gstreamer/meson.build +++ b/subprojects/gstreamer/meson.build @@ -16,8 +16,6 @@ else endif gst_version_is_dev = gst_version_minor % 2 == 1 and gst_version_micro < 90 -host_system = host_machine.system() - apiversion = '1.0' soversion = 0 # maintaining compatibility with the previous libtool versioning @@ -33,6 +31,19 @@ libexecdir = get_option('libexecdir') helpers_install_dir = join_paths(libexecdir, 'gstreamer-1.0') cc = meson.get_compiler('c') +host_system = host_machine.system() + +if host_system == 'darwin' + ios_test_code = '''#include + #if ! TARGET_OS_IPHONE + #error "Not iOS/tvOS/watchOS/iPhoneSimulator" + #endif''' + if cc.compiles(ios_test_code, name : 'building for iOS') + host_system = 'ios' + endif + + add_languages('objc', native: false, required: true) +endif cdata = configuration_data()