office-gobmx/avmedia
Michael Weghorn 4df2a30c57 tdf#145735 qt avmedia: Don't deadlock with QGstreamerMediaPlayer
While opending a slide with a video worked fine for
me with the qt6 VCL plugin and a local Qt development
build on Debian testing (qtbase as of
8915ae3a75c4a356d94962dd9b31e1458f2a506f,
qtwayland as of deae8b9ce9f551b29ef98d0bb827a8543af2797e,
qtmultimedia as of 235ba5f273fbb7dfed8ba3736e4444a85aee5770),
this resulted in a freeze when using Debian's system-provided
Qt packages instead (libqt6multimedia6:amd64 6.4.2-11+b2).

While the self-compiled Qt dev is using `QFFmpegMediaPlayer`
which asynchronously loads media, the system QtMultimedia
is using `QGstreamerMediaPlayer` (s. frame 37 in below backtrace)
that apparently doesn't use multiple threads.

Therefore, using `Qt::BlockingQueuedConnection` is problematic,
as its documentation [1] says:

> Same as Qt::QueuedConnection, except that the signalling thread blocks
> until the slot returns. This connection must not be used if the receiver
> lives in the signalling thread, or else the application will deadlock.

Use `Qt::AutoConnection` (= 0, the default) instead and specify the
`Qt::SingleShotConnection` flag in addition to ensure the slot
gets called only once:

> This is a flag that can be combined with any one of the above connection
> types, using a bitwise OR. When Qt::SingleShotConnection is set, the
> slot is going to be called only once; the connection will be
> automatically broken when the signal is emitted. This flag was
> introduced in Qt 6.0.

Drop the now no longer needed manual disconnect.

This makes the scenario work with both, the custom-compiled
Qt dev using `QFFmpegMediaPlayer` and the system-provided
Qt 6.4.2 using `QGstreamerMediaPlayer`.

Side note: Unrelated to the issue addressed here, using the
system-provided Qt with `QGstreamerMediaPlayer` results
in a crash when started via the soffice shell script wrapper
with a LibreOffice debug build or when using soffice.bin directly
and manually setting `MALLOC_PERTURB_=153`, which indicates
some memory issue. That could be within Qt, though, haven't
analyzed that further.

Backtrace of deadlock:

    1 syscall syscall.S 38 0x7f40a83249f9
    2 QSemaphore::acquire(int) 0x7f40948714e2
    3 ?? 0x7f409477fede
    4 QVideoSink::videoFrameChanged(QVideoFrame const&) const 0x7f4095195376
    5 ?? 0x7f405c219f5c
    6 ?? 0x7f405c21a25b
    7 QApplicationPrivate::notify_helper(QObject *, QEvent *) 0x7f4093782d62
    8 QCoreApplication::notifyInternal2(QObject *, QEvent *) 0x7f40947356d8
    9 QCoreApplicationPrivate::sendPostedEvents(QObject *, int, QThreadData *) 0x7f40947358b7
    10 ?? 0x7f4094925257
    11 ?? 0x7f409ab0de3f
    12 ?? 0x7f409ab0fec7
    13 g_main_context_iteration 0x7f409ab104e0
    14 QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) 0x7f4094922f60
    15 QtInstance::ImplYield QtInstance.cxx 455 0x7f4094e534e0
    16 QtInstance::DoYield QtInstance.cxx 464 0x7f4094e568a5
    17 ImplYield svapp.cxx 384 0x7f409f3c48cc
    18 Scheduler::ProcessEventsToIdle svapp.cxx 419 0x7f409f3c4bc8
    19 avmedia::qt::QtFrameGrabber::grabFrame QtFrameGrabber.cxx 106 0x7f405cac5524
    20 non-virtual thunk to avmedia::qt::QtFrameGrabber::grabFrame(double) 0x7f405cac564e
    21 avmedia::MediaWindow::grabFrame mediawindow.cxx 385 0x7f40a03e41ad
    22 SdrMediaObj::getSnapshot() const::$_0::operator()(com::sun::uno::Reference<com::sun::media::XPlayer> const&) const svdomedia.cxx 195 0x7f40a249e5b5
    23 std::__invoke_impl<void, SdrMediaObj::getSnapshot() const::$_0&, com::sun::uno::Reference<com::sun::media::XPlayer> const&>(std::__invoke_other, SdrMediaObj::getSnapshot() const::$_0&, com::sun::uno::Reference<com::sun::media::XPlayer> const&) invoke.h 61 0x7f40a249e52d
    24 std::__invoke_r<void, SdrMediaObj::getSnapshot() const::$_0&, com::sun::uno::Reference<com::sun::media::XPlayer> const&>(SdrMediaObj::getSnapshot() const::$_0&, com::sun::uno::Reference<com::sun::media::XPlayer> const&) invoke.h 111 0x7f40a249e4dd
    25 std::_Function_handler<void (com::sun::uno::Reference<com::sun::media::XPlayer> const&), SdrMediaObj::getSnapshot() const::$_0>::_M_invoke(std::_Any_data const&, com::sun::uno::Reference<com::sun::media::XPlayer> const&) std_function.h 290 0x7f40a249e345
    26 std::function<void (com::sun::uno::Reference<com::sun::media::XPlayer> const&)>::operator()(com::sun::uno::Reference<com::sun::media::XPlayer> const&) const std_function.h 591 0x7f40a03e96cd
    27 avmedia::PlayerListener::callPlayerWindowSizeAvailable mediawindow.hxx 76 0x7f40a03e6bf1
    28 avmedia::PlayerListener::preferredPlayerWindowSizeAvailable mediawindow.cxx 496 0x7f40a03e5055
    29 avmedia::qt::QtPlayer::notifyListeners QtPlayer.cxx 395 0x7f405cacfd53
    30 avmedia::qt::QtPlayer::notifyIfReady QtPlayer.cxx 326 0x7f405cacfb42
    31 QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QMediaPlayer::MediaStatus>, void, void (avmedia::qt::QtPlayer:: *)(QMediaPlayer::MediaStatus)>::call qobjectdefs_impl.h 135 0x7f405cad477b
    32 QtPrivate::FunctionPointer<void (avmedia::qt::QtPlayer:: *)(QMediaPlayer::MediaStatus)>::call<QtPrivate::List<QMediaPlayer::MediaStatus>, void> qobjectdefs_impl.h 172 0x7f405cad46cd
    33 QtPrivate::QSlotObject<void (avmedia::qt::QtPlayer:: *)(QMediaPlayer::MediaStatus), QtPrivate::List<QMediaPlayer::MediaStatus>, void>::impl qobjectdefs_impl.h 383 0x7f405cad4612
    34 ?? 0x7f409477fbbe
    35 QMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus) 0x7f4095184a05
    36 ?? 0x7f405c210740
    37 non-virtual thunk to QGstreamerMediaPlayer::processBusMessage(QGstreamerMessage const&) 0x7f405c2009f7
    38 ?? 0x7f405c21aa94
    39 QObject::event(QEvent *) 0x7f40947723e0
    40 QApplicationPrivate::notify_helper(QObject *, QEvent *) 0x7f4093782d62
    41 QCoreApplication::notifyInternal2(QObject *, QEvent *) 0x7f40947356d8
    42 QCoreApplicationPrivate::sendPostedEvents(QObject *, int, QThreadData *) 0x7f40947358b7
    43 ?? 0x7f4094925257
    44 ?? 0x7f409ab0de3f
    45 ?? 0x7f409ab0fec7
    46 g_main_context_iteration 0x7f409ab104e0
    47 QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) 0x7f4094922f60
    48 QtInstance::ImplYield QtInstance.cxx 455 0x7f4094e534e0
    49 QtInstance::DoYield QtInstance.cxx 464 0x7f4094e568a5
    50 ImplYield svapp.cxx 384 0x7f409f3c48cc
    51 Scheduler::ProcessEventsToIdle svapp.cxx 419 0x7f409f3c4bc8
    52 avmedia::qt::QtFrameGrabber::grabFrame QtFrameGrabber.cxx 106 0x7f405cac5524
    53 non-virtual thunk to avmedia::qt::QtFrameGrabber::grabFrame(double) 0x7f405cac564e
    54 avmedia::MediaWindow::grabFrame mediawindow.cxx 385 0x7f40a03e41ad
    55 SdrMediaObj::getSnapshot() const::$_0::operator()(com::sun::uno::Reference<com::sun::media::XPlayer> const&) const svdomedia.cxx 195 0x7f40a249e5b5
    56 std::__invoke_impl<void, SdrMediaObj::getSnapshot() const::$_0&, com::sun::uno::Reference<com::sun::media::XPlayer> const&>(std::__invoke_other, SdrMediaObj::getSnapshot() const::$_0&, com::sun::uno::Reference<com::sun::media::XPlayer> const&) invoke.h 61 0x7f40a249e52d
    57 std::__invoke_r<void, SdrMediaObj::getSnapshot() const::$_0&, com::sun::uno::Reference<com::sun::media::XPlayer> const&>(SdrMediaObj::getSnapshot() const::$_0&, com::sun::uno::Reference<com::sun::media::XPlayer> const&) invoke.h 111 0x7f40a249e4dd
    58 std::_Function_handler<void (com::sun::uno::Reference<com::sun::media::XPlayer> const&), SdrMediaObj::getSnapshot() const::$_0>::_M_invoke(std::_Any_data const&, com::sun::uno::Reference<com::sun::media::XPlayer> const&) std_function.h 290 0x7f40a249e345
    59 std::function<void (com::sun::uno::Reference<com::sun::media::XPlayer> const&)>::operator()(com::sun::uno::Reference<com::sun::media::XPlayer> const&) const std_function.h 591 0x7f40a03e96cd
    60 avmedia::PlayerListener::callPlayerWindowSizeAvailable mediawindow.hxx 76 0x7f40a03e6bf1
    61 avmedia::PlayerListener::preferredPlayerWindowSizeAvailable mediawindow.cxx 496 0x7f40a03e5055
    62 avmedia::qt::QtPlayer::notifyListeners QtPlayer.cxx 395 0x7f405cacfd53
    63 avmedia::qt::QtPlayer::notifyIfReady QtPlayer.cxx 326 0x7f405cacfb42
    64 QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QMediaPlayer::MediaStatus>, void, void (avmedia::qt::QtPlayer:: *)(QMediaPlayer::MediaStatus)>::call qobjectdefs_impl.h 135 0x7f405cad477b
    65 QtPrivate::FunctionPointer<void (avmedia::qt::QtPlayer:: *)(QMediaPlayer::MediaStatus)>::call<QtPrivate::List<QMediaPlayer::MediaStatus>, void> qobjectdefs_impl.h 172 0x7f405cad46cd
    66 QtPrivate::QSlotObject<void (avmedia::qt::QtPlayer:: *)(QMediaPlayer::MediaStatus), QtPrivate::List<QMediaPlayer::MediaStatus>, void>::impl qobjectdefs_impl.h 383 0x7f405cad4612

[1] https://doc.qt.io/qt-6/qt.html#ConnectionType-enum

Change-Id: Ia8bfd19b0c0c4f970a5eb200c2a0b45784ef25fd
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169036
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-06-18 05:27:53 +02:00
..
inc
source tdf#145735 qt avmedia: Don't deadlock with QGstreamerMediaPlayer 2024-06-18 05:27:53 +02:00
util
AllLangMoTarget_avmedia.mk
CustomTarget_avmediaqt6_moc.mk tdf#145735 qt avmedia: Implement frame grabber 2024-05-31 09:24:01 +02:00
IwyuFilter_avmedia.yaml
Library_avmedia.mk
Library_avmediagst.mk
Library_avmediagtk.mk
Library_avmediaMacAVF.mk
Library_avmediaqt6.mk tdf#145735 qt avmedia: Implement frame grabber 2024-05-31 09:24:01 +02:00
Library_avmediawin.mk
Makefile
Module_avmedia.mk tdf#145735 avmedia qt: Use QtMultimedia for Qt 6 media playback 2024-05-21 17:28:04 +02:00
README.md

Audio / video Media Implementation.

Provides per-platform implementations of multimedia functionality. Currently no stream API is provided, only a URI based one, so streaming has to be wrapped around it via temp files.

Also provides (in source/framework/mediacontrol.cxx) an implementation of the graphical media playback control that appears in the toolbar / mediaobject bar when media is selected under the .uno:AVMediaToolBox item.

avmedia / gstreamer

The avmedia component is implementation of manager service defined in offapi/com/sun/star/media/. Radek has added implementation based on gstreamer so that we can add audio and video files into impress presentation on Linux with gstreamer.

The implementation is pretty straightforward, sometimes it has problems when gstreamer installation is incomplete.

In the beginning the media files were not embedded, Thorsten added support for that later.

Future Works

it might be worthwhile to revamp the avmedia UI.