mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 17:20:36 +00:00
osxvideosink: only create the NS app thread for Cocoa once
The helper thread for Cocoa, in case no NS run loop is running, should be started only once and shared across all the instances running
This commit is contained in:
parent
7b69f427f1
commit
213fa3af0d
2 changed files with 66 additions and 61 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue