osxvideosink: make sure all selectors are performed on the same thread
When we are using a dedicated thread to run the main run loop we must make sure that all selectors are performed on this same thread. For instance if performSelectorOnMainThread is called from the real main thread, it will not go through the message queue and will be executed from the real main thread. By forcing the target thread, we ensure that all functions will be called either from the real main thread when the main run loop is running or from our thread spinning the main loop.
This commit is contained in:
parent
e143c43ef5
commit
5b3d3b0885
@ -49,6 +49,7 @@ struct _GstOSXImage;
|
|||||||
NSTrackingArea *trackingArea;
|
NSTrackingArea *trackingArea;
|
||||||
GstNavigation *navigation;
|
GstNavigation *navigation;
|
||||||
NSRect drawingBounds;
|
NSRect drawingBounds;
|
||||||
|
NSThread *mainThread;
|
||||||
}
|
}
|
||||||
- (void) drawQuad;
|
- (void) drawQuad;
|
||||||
- (void) drawRect: (NSRect) rect;
|
- (void) drawRect: (NSRect) rect;
|
||||||
@ -68,6 +69,7 @@ struct _GstOSXImage;
|
|||||||
- (void) addToSuperview: (NSView *)superview;
|
- (void) addToSuperview: (NSView *)superview;
|
||||||
- (void) removeFromSuperview: (id)unused;
|
- (void) removeFromSuperview: (id)unused;
|
||||||
- (void) setNavigation: (GstNavigation *) nav;
|
- (void) setNavigation: (GstNavigation *) nav;
|
||||||
|
- (void) setMainThread: (NSThread *) thread;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -136,6 +136,7 @@
|
|||||||
userInfo:nil];
|
userInfo:nil];
|
||||||
|
|
||||||
[self addTrackingArea:trackingArea];
|
[self addTrackingArea:trackingArea];
|
||||||
|
mainThread = [NSThread mainThread];
|
||||||
|
|
||||||
[self initTextures];
|
[self initTextures];
|
||||||
return self;
|
return self;
|
||||||
@ -414,6 +415,10 @@
|
|||||||
[self reshape];
|
[self reshape];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) setMainThread: (NSThread *) thread {
|
||||||
|
mainThread = thread;
|
||||||
|
}
|
||||||
|
|
||||||
- (void) haveSuperviewReal:(NSMutableArray *)closure {
|
- (void) haveSuperviewReal:(NSMutableArray *)closure {
|
||||||
BOOL haveSuperview = [self superview] != nil;
|
BOOL haveSuperview = [self superview] != nil;
|
||||||
[closure addObject:[NSNumber numberWithBool:haveSuperview]];
|
[closure addObject:[NSNumber numberWithBool:haveSuperview]];
|
||||||
@ -421,8 +426,9 @@
|
|||||||
|
|
||||||
- (BOOL) haveSuperview {
|
- (BOOL) haveSuperview {
|
||||||
NSMutableArray *closure = [NSMutableArray arrayWithCapacity:1];
|
NSMutableArray *closure = [NSMutableArray arrayWithCapacity:1];
|
||||||
[self performSelectorOnMainThread:@selector(haveSuperviewReal:)
|
[self performSelector:@selector(haveSuperviewReal:)
|
||||||
withObject:(id)closure waitUntilDone:YES];
|
onThread:mainThread
|
||||||
|
withObject:(id)closure waitUntilDone:YES];
|
||||||
|
|
||||||
return [[closure objectAtIndex:0] boolValue];
|
return [[closure objectAtIndex:0] boolValue];
|
||||||
}
|
}
|
||||||
@ -436,8 +442,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) addToSuperview: (NSView *)superview {
|
- (void) addToSuperview: (NSView *)superview {
|
||||||
[self performSelectorOnMainThread:@selector(addToSuperviewReal:)
|
[self performSelector:@selector(addToSuperviewReal:)
|
||||||
withObject:superview waitUntilDone:YES];
|
onThread:mainThread
|
||||||
|
withObject:superview waitUntilDone:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) removeFromSuperview: (id)unused
|
- (void) removeFromSuperview: (id)unused
|
||||||
|
@ -76,7 +76,7 @@ struct _GstOSXVideoSink {
|
|||||||
void *osxvideosinkobject;
|
void *osxvideosinkobject;
|
||||||
NSView *superview;
|
NSView *superview;
|
||||||
#ifdef RUN_NS_APP_THREAD
|
#ifdef RUN_NS_APP_THREAD
|
||||||
GThread *ns_app_thread;
|
NSThread *ns_app_thread;
|
||||||
#else
|
#else
|
||||||
guint cocoa_timeout;
|
guint cocoa_timeout;
|
||||||
gboolean app_started;
|
gboolean app_started;
|
||||||
@ -131,6 +131,9 @@ GType gst_osx_video_sink_get_type(void);
|
|||||||
-(void) resize;
|
-(void) resize;
|
||||||
-(void) destroy;
|
-(void) destroy;
|
||||||
-(void) showFrame: (GstBufferObject*) buf;
|
-(void) showFrame: (GstBufferObject*) buf;
|
||||||
|
#ifdef RUN_NS_APP_THREAD
|
||||||
|
-(void) nsAppThread;
|
||||||
|
#endif
|
||||||
@end
|
@end
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -80,12 +80,13 @@ static GstVideoSinkClass *parent_class = NULL;
|
|||||||
|
|
||||||
/* Helper to trigger calls from the main thread */
|
/* Helper to trigger calls from the main thread */
|
||||||
static void
|
static void
|
||||||
gst_osx_video_sink_call_from_main_thread(NSObject * object, SEL function,
|
gst_osx_video_sink_call_from_main_thread(GstOSXVideoSink *osxvideosink,
|
||||||
NSObject *data, BOOL waitUntilDone)
|
NSObject * object, SEL function, NSObject *data, BOOL waitUntilDone)
|
||||||
{
|
{
|
||||||
|
|
||||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
[object performSelectorOnMainThread:function
|
[object performSelector:function onThread:osxvideosink->ns_app_thread
|
||||||
withObject:data waitUntilDone:waitUntilDone];
|
withObject:data waitUntilDone:waitUntilDone];
|
||||||
[pool release];
|
[pool release];
|
||||||
}
|
}
|
||||||
@ -113,37 +114,6 @@ run_ns_app_loop (void) {
|
|||||||
[pool release];
|
[pool release];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RUN_NS_APP_THREAD
|
|
||||||
static gpointer
|
|
||||||
ns_app_loop_thread (gpointer data)
|
|
||||||
{
|
|
||||||
NSAutoreleasePool *pool;
|
|
||||||
|
|
||||||
/* set the main runloop as the runloop for the current thread. This has the
|
|
||||||
* effect that calling NSApp nextEventMatchingMask:untilDate:inMode:dequeue
|
|
||||||
* runs the main runloop.
|
|
||||||
*/
|
|
||||||
_CFRunLoopSetCurrent(CFRunLoopGetMain());
|
|
||||||
|
|
||||||
/* this is needed to make IsMainThread checks in core foundation work from the
|
|
||||||
* current thread
|
|
||||||
*/
|
|
||||||
_CFMainPThread = pthread_self();
|
|
||||||
|
|
||||||
pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
[NSApplication sharedApplication];
|
|
||||||
[NSApp finishLaunching];
|
|
||||||
|
|
||||||
/* run the loop */
|
|
||||||
run_ns_app_loop ();
|
|
||||||
|
|
||||||
[pool release];
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_osx_video_sink_run_cocoa_loop (GstOSXVideoSink * osxvideosink )
|
gst_osx_video_sink_run_cocoa_loop (GstOSXVideoSink * osxvideosink )
|
||||||
{
|
{
|
||||||
@ -168,8 +138,10 @@ gst_osx_video_sink_run_cocoa_loop (GstOSXVideoSink * osxvideosink )
|
|||||||
|
|
||||||
method_exchangeImplementations(origIsMainThread, ourIsMainThread);
|
method_exchangeImplementations(origIsMainThread, ourIsMainThread);
|
||||||
|
|
||||||
osxvideosink->ns_app_thread = g_thread_new ("GstNSAppThread",
|
osxvideosink->ns_app_thread = [[NSThread alloc]
|
||||||
ns_app_loop_thread, NULL);
|
initWithTarget:osxvideosink->osxvideosinkobject
|
||||||
|
selector:@selector(nsAppThread) object:nil];
|
||||||
|
[osxvideosink->ns_app_thread start];
|
||||||
#else
|
#else
|
||||||
/* assume that there is a GMainLoop and iterate the main runloop from there
|
/* assume that there is a GMainLoop and iterate the main runloop from there
|
||||||
*/
|
*/
|
||||||
@ -227,7 +199,10 @@ gst_osx_video_sink_osxwindow_create (GstOSXVideoSink * osxvideosink, gint width,
|
|||||||
|
|
||||||
GST_INFO_OBJECT (osxvideosink, "'have-ns-view' message sent");
|
GST_INFO_OBJECT (osxvideosink, "'have-ns-view' message sent");
|
||||||
|
|
||||||
|
osxvideosink->ns_app_thread = [NSThread mainThread];
|
||||||
gst_osx_video_sink_run_cocoa_loop (osxvideosink);
|
gst_osx_video_sink_run_cocoa_loop (osxvideosink);
|
||||||
|
[osxwindow->gstview setMainThread:osxvideosink->ns_app_thread];
|
||||||
|
|
||||||
/* check if have-ns-view was handled and osxwindow->gstview was added to a
|
/* check if have-ns-view was handled and osxwindow->gstview was added to a
|
||||||
* superview
|
* superview
|
||||||
*/
|
*/
|
||||||
@ -244,7 +219,7 @@ gst_osx_video_sink_osxwindow_create (GstOSXVideoSink * osxvideosink, gint width,
|
|||||||
* from the main thread
|
* from the main thread
|
||||||
*/
|
*/
|
||||||
GST_INFO_OBJECT (osxvideosink, "we have a superview, adding our view to it");
|
GST_INFO_OBJECT (osxvideosink, "we have a superview, adding our view to it");
|
||||||
gst_osx_video_sink_call_from_main_thread(osxwindow->gstview,
|
gst_osx_video_sink_call_from_main_thread(osxvideosink, osxwindow->gstview,
|
||||||
@selector(addToSuperview:), osxvideosink->superview, NO);
|
@selector(addToSuperview:), osxvideosink->superview, NO);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -255,7 +230,8 @@ gst_osx_video_sink_osxwindow_create (GstOSXVideoSink * osxvideosink, gint width,
|
|||||||
*/
|
*/
|
||||||
GST_INFO_OBJECT (osxvideosink, "no superview");
|
GST_INFO_OBJECT (osxvideosink, "no superview");
|
||||||
} else {
|
} else {
|
||||||
gst_osx_video_sink_call_from_main_thread(osxvideosink->osxvideosinkobject,
|
gst_osx_video_sink_call_from_main_thread(osxvideosink,
|
||||||
|
osxvideosink->osxvideosinkobject,
|
||||||
@selector(createInternalWindow), nil, YES);
|
@selector(createInternalWindow), nil, YES);
|
||||||
GST_INFO_OBJECT (osxvideosink, "No superview, creating an internal window.");
|
GST_INFO_OBJECT (osxvideosink, "No superview, creating an internal window.");
|
||||||
}
|
}
|
||||||
@ -277,8 +253,9 @@ gst_osx_video_sink_osxwindow_destroy (GstOSXVideoSink * osxvideosink)
|
|||||||
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
|
g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink));
|
||||||
pool = [[NSAutoreleasePool alloc] init];
|
pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
gst_osx_video_sink_call_from_main_thread(osxvideosink->osxvideosinkobject,
|
gst_osx_video_sink_call_from_main_thread(osxvideosink,
|
||||||
@selector(destroy), (id) nil, YES);
|
osxvideosink->osxvideosinkobject,
|
||||||
|
@selector(destroy), (id) nil, YES);
|
||||||
gst_osx_video_sink_stop_cocoa_loop (osxvideosink);
|
gst_osx_video_sink_stop_cocoa_loop (osxvideosink);
|
||||||
[pool release];
|
[pool release];
|
||||||
}
|
}
|
||||||
@ -301,7 +278,8 @@ gst_osx_video_sink_osxwindow_resize (GstOSXVideoSink * osxvideosink,
|
|||||||
|
|
||||||
/* Directly resize the underlying view */
|
/* Directly resize the underlying view */
|
||||||
GST_DEBUG_OBJECT (osxvideosink, "Calling setVideoSize on %p", osxwindow->gstview);
|
GST_DEBUG_OBJECT (osxvideosink, "Calling setVideoSize on %p", osxwindow->gstview);
|
||||||
gst_osx_video_sink_call_from_main_thread(object, @selector(resize), (id)nil, YES);
|
gst_osx_video_sink_call_from_main_thread(osxvideosink, object,
|
||||||
|
@selector(resize), (id)nil, YES);
|
||||||
|
|
||||||
[pool release];
|
[pool release];
|
||||||
}
|
}
|
||||||
@ -404,7 +382,8 @@ gst_osx_video_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
|
|||||||
|
|
||||||
GST_DEBUG ("show_frame");
|
GST_DEBUG ("show_frame");
|
||||||
bufferobject = [[GstBufferObject alloc] initWithBuffer:buf];
|
bufferobject = [[GstBufferObject alloc] initWithBuffer:buf];
|
||||||
gst_osx_video_sink_call_from_main_thread(osxvideosink->osxvideosinkobject,
|
gst_osx_video_sink_call_from_main_thread(osxvideosink,
|
||||||
|
osxvideosink->osxvideosinkobject,
|
||||||
@selector(showFrame:), bufferobject, NO);
|
@selector(showFrame:), bufferobject, NO);
|
||||||
[pool release];
|
[pool release];
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
@ -646,7 +625,8 @@ gst_osx_video_sink_set_window_handle (GstXOverlay * overlay, guintptr handle_id)
|
|||||||
if (osxvideosink->superview) {
|
if (osxvideosink->superview) {
|
||||||
GST_INFO_OBJECT (osxvideosink, "old xwindow id %p", osxvideosink->superview);
|
GST_INFO_OBJECT (osxvideosink, "old xwindow id %p", osxvideosink->superview);
|
||||||
if (osxvideosink->osxwindow) {
|
if (osxvideosink->osxwindow) {
|
||||||
gst_osx_video_sink_call_from_main_thread(osxvideosink->osxwindow->gstview,
|
gst_osx_video_sink_call_from_main_thread(osxvideosink,
|
||||||
|
osxvideosink->osxwindow->gstview,
|
||||||
@selector(removeFromSuperview:), (id)nil, YES);
|
@selector(removeFromSuperview:), (id)nil, YES);
|
||||||
}
|
}
|
||||||
[osxvideosink->superview release];
|
[osxvideosink->superview release];
|
||||||
@ -656,7 +636,8 @@ gst_osx_video_sink_set_window_handle (GstXOverlay * overlay, guintptr handle_id)
|
|||||||
GST_INFO_OBJECT (osxvideosink, "set xwindow id 0x%lx", window_id);
|
GST_INFO_OBJECT (osxvideosink, "set xwindow id 0x%lx", window_id);
|
||||||
osxvideosink->superview = [((NSView *) window_id) retain];
|
osxvideosink->superview = [((NSView *) window_id) retain];
|
||||||
if (osxvideosink->osxwindow) {
|
if (osxvideosink->osxwindow) {
|
||||||
gst_osx_video_sink_call_from_main_thread(osxvideosink->osxwindow->gstview,
|
gst_osx_video_sink_call_from_main_thread(osxvideosink,
|
||||||
|
osxvideosink->osxwindow->gstview,
|
||||||
@selector(addToSuperview:), osxvideosink->superview, YES);
|
@selector(addToSuperview:), osxvideosink->superview, YES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -872,6 +853,34 @@ gst_osx_video_sink_get_type (void)
|
|||||||
[pool release];
|
[pool release];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RUN_NS_APP_THREAD
|
||||||
|
-(void) nsAppThread
|
||||||
|
{
|
||||||
|
NSAutoreleasePool *pool;
|
||||||
|
|
||||||
|
/* set the main runloop as the runloop for the current thread. This has the
|
||||||
|
* effect that calling NSApp nextEventMatchingMask:untilDate:inMode:dequeue
|
||||||
|
* runs the main runloop.
|
||||||
|
*/
|
||||||
|
_CFRunLoopSetCurrent(CFRunLoopGetMain());
|
||||||
|
|
||||||
|
/* this is needed to make IsMainThread checks in core foundation work from the
|
||||||
|
* current thread
|
||||||
|
*/
|
||||||
|
_CFMainPThread = pthread_self();
|
||||||
|
|
||||||
|
pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
[NSApplication sharedApplication];
|
||||||
|
[NSApp finishLaunching];
|
||||||
|
|
||||||
|
/* run the loop */
|
||||||
|
run_ns_app_loop ();
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ implementation GstBufferObject
|
@ implementation GstBufferObject
|
||||||
|
Loading…
x
Reference in New Issue
Block a user