GNOME Bugzilla – Bug 689730
osxvideosink: Blocks the application when setting the pipeline to PLAYING state [multithreading]
Last modified: 2013-07-17 10:20:42 UTC
osxvideosink hangs the application (it actually blocks Glib mainloop) if the pipeline with it was set to PLAYING state outside of the main thread. Deferring that operation to the main thread solves the problem.
Can you attach a patch for that problem?
Not yet, I workarounded the problem deferring the call of gst_element_set_state() to main thread, as I wrote, but I hope to work at it some more as I've already detected the place in code of osxvideosink where the problem raises.
I experimented with this problem a little bit and managed to make NSRunLoop run powered by Glib mainloop (g_timeout_* is used). Sink works fine, video is shown normally, but the remaining problem is that the window is somewhat blocked i.e. the cursor in it is the 'rotating cicle' so one can't neither close or resize it nor input anything inside it using mouse or keyboard. It seems to not processing any input events for unknown reason. As soon as I can fix it, I think, the problem will be solved.
Are you compiling with mmacosx-version-min=10.5? The sink behaves differently (osxvideosink.h): 45 #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_5 46 #ifdef RUN_NS_APP_THREAD 47 #undef RUN_NS_APP_THREAD 48 #endif 49 #endif
Yes, I noticed this conditions but thought it's some experiment code. Compiled with default settings (Mac OS X 10.7 branch), so probably without mmacosx-version-min=10.5. Hope to test it tomorrow. Should I just pass this to ./configure? As for default version, I'm a little bit stuck with this problem of input processing, it seems that just nobody processing input messages as the behaviour very much looks like there's some input queue overrun — the pinwheel appears not at the very beginning but few seconds later. As I said I'm not that much OS X expert so maybe someone could give an advice on this. What I do now is call like this: [[NSRunLoop mainLoop] runMode:NSRunLoopDefaultMode beforeDate:nil] in run_ns_app_loop() before the NSApp code.
So, here's some fresh results: I tried to build osxvideo with RUN_NS_APP_THREAD defined as Andoni suggested to do, and the behaviour was changed: it actually now behaves the same when you set the pipeline to PLAYING state both from main and from separate thread. But: the window blocks user's input just like in my experiment described above. The difference is that in my experiment it happened only for separate thread and here it's all the same for main and separate thread.
Hi Alexey, Can you please attach a test app to reproduce the error? The sink is beeing used correctly in applications that don't integrate with the Cocoa main runloop (like gst-launch-0.10) and others that does, like gst-playback-test. Can you attach some logs too with GST_DEBUG=osxvideosink:5?
Hi, Andoni, Sorry for long delay with the answer. I actually tried to create a test app, but yes, right as you said before, it works quite normally even if pipeline was set to PLAYING in separate thread (I mean, with RUN_NS_APP_THREAD defined). So, it seems that the problem in my application so I'll try to find out what the problem is. The pipeline is quite ordinary, it just uses appsrc as sources and contains two parallel lines for video and audio. So, some of these could make difference.
A good start would be checking that the main run loop is detected as running correctly: http://cgit.freedesktop.org/gstreamer-sdk/gst-plugins-good/tree/sys/osxvideo/osxvideosink.m?h=sdk-0.10.31#n118 you might be blocking the main thread and the conditional wait always time out, even though the main run loop is really running: http://cgit.freedesktop.org/gstreamer-sdk/gst-plugins-good/tree/sys/osxvideo/osxvideosink.m?h=sdk-0.10.31#n144
Andoni, thanks for suggestions. I seem to find a proper test program which reproduces the problem for me (will attach it right now). It actually uses one separate thread with another main loop in it and main thread is not blocked by anything but g_main_loop_run(). I experimented with latest git version of 0.10 branch both with RUN_NS_APP_THREAD defined and without one. Here's also compilation command for me: gcc -I /Library/Frameworks/GStreamer.framework/Headers -I /Library/Frameworks/QtGui.framework/Versions/4/Headers/ -I /Library/Frameworks/QtCore.framework/Versions/4/Headers/ -DTEST_THREADED testprogram_v2.cpp -o testprogram_v2 -L /Library/Frameworks/GStreamer.framework/Libraries/ -lgstreamer-0.10 -lglib-2.0 -lgobject-2.0 So, with -DTEST_THREADED key it hangs when executed, and without it it shows videotestsrc output. Andoni, could you please check if it's proper test case or there's some fault which leads to hang?
Created attachment 233043 [details] Test program reproducing hang problem
I am not able to reproduce this issue, your test app works the same with -DTEST_THREADED and without it
I seem to touch more accurate cause of this problem during the experiments: it seems that gst_osx_video_sink_call_from_main_thread sometimes doesn't work when it's called from thread other than main at some beginning stages. I was able to reproduce in quite a stable way when moved gst_osx_video_sink_osxwindow_create() call from *_change_state() to *_set_caps() function and started gst-launch (no NS_APP_THREAD defined, Mac OS X 10.7.5). And it became stucked. Hope to find out something more tomorrow.
Well, I seem to evaluate the issue: the problem is that gst_osx_video_sink_call_from_main_thread() function blocks when called from non-main thread with waitUntilDone is YES, if the following block: if (!osxvideosink->app_started) { [NSApplication sharedApplication]; [NSApp finishLaunching]; osxvideosink->app_started = TRUE; } wasn't previously called. I tried to move this block to gst_osx_video_sink_osxwindow_create() so that it goes before the first call to gst_osx_video_sink_call_from_main_thread(), it works, but I don't know if this is particularly portable as it's unknown whether gst_osx_video_sink_osxwindow_create() is called from main thread or not. It's written here and there that AppKit methods should be called only single-threaded and _only_ from main thread, so it could potentially lead to some problems. I think, I will create a separate report about it.
This can happen when the NS run loop is not running yet (eg: the sink hasn't prerolled or there isn't any main run loop running). Gtk's main run loop integrates nicely with NS run loop, so replacing g_main_loop_run (loop); with gtk_main(); will make it work.
The patch set in https://bugzilla.gnome.org/show_bug.cgi?id=691419 should probably fix your use case, specially https://bug691419.bugzilla-attachments.gnome.org/attachment.cgi?id=248731
Yes, I noticed that patch, too. Will test it for my couple of cases (test program with g_main_loop_run() and Qt4 application). Am I right that it's generally meant to be compatible with both Glib's main loop and NS run loop?
It only works with the NS run loop, and when it's not found the sink creates its own. Bot Gtk's and Qt's main loop creates a NS run loop, so the sink doesn't need to create one itself, instead GLib's main loop doesn't. But you don't need to use Gtk's main loop here, it should work with glib's one too, sorry for the confusion I have tested with the latest commits and it seems to work now with -DTEST_THREADED using glib's main loop. Can you confirm it?
Thanks for clarification, Andoni. It's clear in case of NS run loop. Is it basically compatible with Glib's main loop, too? I'm a little bit confused with the code of gst_osx_videosink_check_main_run_loop() and gst_osx_video_sink_run_cocoa_loop() (with RUN_NS_APP_THREAD defined) and want to clear it for myself. Is it right that RUN_NS_APP_THREAD is somewhat needed for older versions of OS X and is not necessary for fresh ones? As to test example, I hope to check it tomorrow. Sorry for delay, haven't installed GStreamer-1.0 on OS X yet, so need to finally manage to do it.
Andoni, I actually can confirm that the example works now both with -DTEST_THREADED and without it with your latest commits from git master. Also, I tried an experimental move of gst_osx_video_sink_osxwindow_create () function to *_setcaps() where it was previously blocked gst-launch, and now it works, too. So, I believe that strange threading problem can be considered as solved. The only question I have: how do you think, isn't it better to call [NSApplication sharedApplication] somewhere at the very beginning of work of the element? It could guarantee that NSApplication instance is created and event loop is started before the first calls to objects and gst_osx_video_sink_call_from_main_thread() function. I consulted with my iOS colleagues a little bit and they said it's quite safe to call sharedApplication method from non-main thread.
Ok, so let's close it?