diff --git a/sys/osxvideo/osxvideosink.h b/sys/osxvideo/osxvideosink.h index cf0410f644..2517bb37f2 100644 --- a/sys/osxvideo/osxvideosink.h +++ b/sys/osxvideo/osxvideosink.h @@ -68,6 +68,12 @@ typedef struct _GstOSXVideoSinkClass GstOSXVideoSinkClass; #define GST_TYPE_OSXVIDEOBUFFER (gst_osxvideobuffer_get_type()) +typedef enum { + GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_NOT_RUNNING = 0, + GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_RUNNING = 1, + GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_UNKNOWN = 2, +} GstOSXVideoSinkRunLoopState; + /* OSXWindow stuff */ struct _GstOSXWindow { gint width, height; @@ -83,24 +89,19 @@ struct _GstOSXVideoSink { GstOSXWindow *osxwindow; void *osxvideosinkobject; NSView *superview; - NSThread *ns_app_thread; -#ifdef RUN_NS_APP_THREAD - GMutex loop_thread_lock; - GCond loop_thread_cond; -#else - guint cocoa_timeout; -#endif - GMutex mrl_check_lock; - GCond mrl_check_cond; - gboolean mrl_check_done; - gboolean main_run_loop_running; - gboolean app_started; gboolean keep_par; gboolean embed; }; struct _GstOSXVideoSinkClass { GstVideoSinkClass parent_class; + + GstOSXVideoSinkRunLoopState run_loop_state; +#ifdef RUN_NS_APP_THREAD + NSThread *ns_app_thread; +#else + guint cocoa_timeout; +#endif }; GType gst_osx_video_sink_get_type(void); diff --git a/sys/osxvideo/osxvideosink.m b/sys/osxvideo/osxvideosink.m index c75c681d9d..8c172e5383 100644 --- a/sys/osxvideo/osxvideosink.m +++ b/sys/osxvideo/osxvideosink.m @@ -53,6 +53,8 @@ extern void _CFRunLoopSetCurrent(CFRunLoopRef rl); extern pthread_t _CFMainPThread; #endif + + static GstStaticPadTemplate gst_osx_video_sink_sink_template_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, @@ -76,7 +78,10 @@ enum }; static void gst_osx_video_sink_osxwindow_destroy (GstOSXVideoSink * osxvideosink); - +static GMutex _run_loop_check_mutex; +static GMutex _run_loop_mutex; +static GCond _run_loop_cond; +static GstOSXVideoSinkClass *sink_class = NULL; static GstVideoSinkClass *parent_class = NULL; /* Helper to trigger calls from the main thread */ @@ -87,7 +92,7 @@ gst_osx_video_sink_call_from_main_thread(GstOSXVideoSink *osxvideosink, NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [object performSelector:function onThread:osxvideosink->ns_app_thread + [object performSelector:function onThread:sink_class->ns_app_thread withObject:data waitUntilDone:waitUntilDone]; [pool release]; } @@ -121,9 +126,6 @@ gst_osx_videosink_check_main_run_loop (GstOSXVideoSink *sink) /* check if the main run loop is running */ gboolean is_running; - if (sink->mrl_check_done) { - return; - } /* the easy way */ is_running = [[NSRunLoop mainRunLoop] currentMode] != nil; if (is_running) { @@ -137,15 +139,15 @@ gst_osx_videosink_check_main_run_loop (GstOSXVideoSink *sink) GstOSXVideoSinkObject * object = (GstOSXVideoSinkObject *) sink->osxvideosinkobject; gint64 abstime; - g_mutex_lock (&sink->mrl_check_lock); + g_mutex_lock (&_run_loop_mutex); [object performSelectorOnMainThread: @selector(checkMainRunLoop) withObject:nil waitUntilDone:NO]; /* Wait 100 ms */ abstime = g_get_monotonic_time () + 100 * 1000; - is_running = g_cond_wait_until (&sink->mrl_check_cond, - &sink->mrl_check_lock, abstime); - g_mutex_unlock (&sink->mrl_check_lock); + is_running = g_cond_wait_until (&_run_loop_cond, + &_run_loop_mutex, abstime); + g_mutex_unlock (&_run_loop_mutex); [pool release]; } @@ -154,8 +156,12 @@ exit: { GST_DEBUG_OBJECT(sink, "The main runloop %s is running", is_running ? "" : " not "); - sink->main_run_loop_running = is_running; - sink->mrl_check_done = TRUE; + if (is_running) { + sink_class->run_loop_state = GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_RUNNING; + sink_class->ns_app_thread = [NSThread mainThread]; + } else { + sink_class->run_loop_state = GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_NOT_RUNNING; + } } } @@ -168,13 +174,26 @@ gst_osx_video_sink_run_cocoa_loop (GstOSXVideoSink * sink ) * Since the sink needs to create it's own Cocoa window when no * external NSView is passed to the sink through the GstVideoOverlay API, * we need to run the cocoa mainloop somehow. + * This run loop can only be started once, by the first sink needing it */ - if (!sink->main_run_loop_running) { + + g_mutex_lock (&_run_loop_check_mutex); + + if (sink_class->run_loop_state == GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_UNKNOWN) { + gst_osx_videosink_check_main_run_loop (sink); + } + + if (sink_class->run_loop_state == GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_RUNNING) { + g_mutex_unlock (&_run_loop_check_mutex); + return; + } + + if (sink_class->ns_app_thread == NULL) { #ifdef RUN_NS_APP_THREAD /* run the main runloop in a separate thread */ /* override [NSThread isMainThread] with our own implementation so that we can - * make it believe our dedicated thread is the main thread + * make it believe our dedicated thread is the main thread */ Method origIsMainThread = class_getClassMethod([NSThread class], NSSelectorFromString(@"isMainThread")); @@ -183,30 +202,31 @@ gst_osx_video_sink_run_cocoa_loop (GstOSXVideoSink * sink ) method_exchangeImplementations(origIsMainThread, ourIsMainThread); - sink->ns_app_thread = [[NSThread alloc] + sink_class->ns_app_thread = [[NSThread alloc] initWithTarget:sink->osxvideosinkobject selector:@selector(nsAppThread) object:nil]; - [sink->ns_app_thread start]; + [sink_class->ns_app_thread start]; - g_mutex_lock (&sink->loop_thread_lock); - while (!sink->app_started) - g_cond_wait (&sink->loop_thread_cond, &sink->loop_thread_lock); - g_mutex_unlock (&sink->loop_thread_lock); + g_mutex_lock (&_run_loop_mutex); + g_cond_wait (&_run_loop_cond, &_run_loop_mutex); + g_mutex_unlock (&_run_loop_mutex); #else /* assume that there is a GMainLoop and iterate the main runloop from there */ - sink->cocoa_timeout = g_timeout_add (10, + sink_class->cocoa_timeout = g_timeout_add (10, (GSourceFunc) run_ns_app_loop, NULL); #endif } + + g_mutex_unlock (&_run_loop_check_mutex); } static void gst_osx_video_sink_stop_cocoa_loop (GstOSXVideoSink * osxvideosink) { #ifndef RUN_NS_APP_THREAD - if (osxvideosink->cocoa_timeout) - g_source_remove(osxvideosink->cocoa_timeout); + if (sink_class->cocoa_timeout) + g_source_remove(sink_klass->cocoa_timeout); #endif } @@ -250,10 +270,8 @@ gst_osx_video_sink_osxwindow_create (GstOSXVideoSink * osxvideosink, gint width, GST_INFO_OBJECT (osxvideosink, "'have-ns-view' message sent"); - osxvideosink->ns_app_thread = [NSThread mainThread]; - gst_osx_videosink_check_main_run_loop (osxvideosink); gst_osx_video_sink_run_cocoa_loop (osxvideosink); - [osxwindow->gstview setMainThread:osxvideosink->ns_app_thread]; + [osxwindow->gstview setMainThread:sink_class->ns_app_thread]; /* check if have-ns-view was handled and osxwindow->gstview was added to a * superview @@ -408,7 +426,6 @@ gst_osx_video_sink_change_state (GstElement * element, case GST_STATE_CHANGE_PAUSED_TO_READY: GST_VIDEO_SINK_WIDTH (osxvideosink) = 0; GST_VIDEO_SINK_HEIGHT (osxvideosink) = 0; - osxvideosink->app_started = FALSE; gst_osx_video_sink_osxwindow_destroy (osxvideosink); break; case GST_STATE_CHANGE_READY_TO_NULL: @@ -505,15 +522,6 @@ gst_osx_video_sink_init (GstOSXVideoSink * sink) sink->osxwindow = NULL; sink->superview = NULL; sink->osxvideosinkobject = [[GstOSXVideoSinkObject alloc] initWithSink:sink]; -#ifdef RUN_NS_APP_THREAD - g_mutex_init (&sink->loop_thread_lock); - g_cond_init (&sink->loop_thread_cond); -#endif - g_mutex_init (&sink->mrl_check_lock); - g_cond_init (&sink->mrl_check_cond); - sink->mrl_check_done = FALSE; - sink->main_run_loop_running = FALSE; - sink->app_started = FALSE; sink->keep_par = FALSE; } @@ -541,9 +549,6 @@ gst_osx_video_sink_finalize (GObject *object) if (osxvideosink->osxvideosinkobject) [(GstOSXVideoSinkObject*)(osxvideosink->osxvideosinkobject) release]; - g_mutex_clear (&osxvideosink->mrl_check_lock); - g_cond_clear (&osxvideosink->mrl_check_cond); - G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -558,8 +563,11 @@ gst_osx_video_sink_class_init (GstOSXVideoSinkClass * klass) gstelement_class = (GstElementClass *) klass; gstbasesink_class = (GstBaseSinkClass *) klass; - parent_class = g_type_class_ref (GST_TYPE_VIDEO_SINK); + sink_class = klass; + + klass->run_loop_state = GST_OSX_VIDEO_SINK_RUN_LOOP_STATE_UNKNOWN; + klass->ns_app_thread = NULL; gobject_class->set_property = gst_osx_video_sink_set_property; gobject_class->get_property = gst_osx_video_sink_get_property; @@ -675,7 +683,6 @@ gst_osx_video_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle @selector(removeFromSuperview:), (id)nil, YES); } [osxvideosink->superview release]; - } GST_INFO_OBJECT (osxvideosink, "set xwindow id 0x%lx", window_id); @@ -903,7 +910,6 @@ gst_osx_video_sink_get_type (void) [osxwindow->win release]; } } - g_free (osxwindow); } [pool release]; @@ -913,7 +919,6 @@ gst_osx_video_sink_get_type (void) -(void) nsAppThread { NSAutoreleasePool *pool; - GstOSXVideoSink *sink = osxvideosink; /* set the main runloop as the runloop for the current thread. This has the * effect that calling NSApp nextEventMatchingMask:untilDate:inMode:dequeue @@ -931,10 +936,9 @@ gst_osx_video_sink_get_type (void) [NSApplication sharedApplication]; [NSApp finishLaunching]; - g_mutex_lock (&sink->loop_thread_lock); - sink->app_started = TRUE; - g_cond_signal (&sink->loop_thread_cond); - g_mutex_unlock (&sink->loop_thread_lock); + g_mutex_lock (&_run_loop_mutex); + g_cond_signal (&_run_loop_cond); + g_mutex_unlock (&_run_loop_mutex); /* run the loop */ run_ns_app_loop (); @@ -945,9 +949,9 @@ gst_osx_video_sink_get_type (void) -(void) checkMainRunLoop { - g_mutex_lock (&osxvideosink->mrl_check_lock); - g_cond_signal (&osxvideosink->mrl_check_cond); - g_mutex_unlock (&osxvideosink->mrl_check_lock); + g_mutex_lock (&_run_loop_mutex); + g_cond_signal (&_run_loop_cond); + g_mutex_unlock (&_run_loop_mutex); } @end