Bug 489146

Summary: Krita hangs while playing an animation with audio and scrubbing at the same time
Product: [Applications] krita Reporter: YRH <yavn.work>
Component: AnimationAssignee: Krita Bugs <krita-bugs-null>
Status: RESOLVED FIXED    
Severity: normal CC: dimula73
Priority: NOR    
Version: git master (please specify the git hash!)   
Target Milestone: ---   
Platform: Microsoft Windows   
OS: Microsoft Windows   
Latest Commit: Version Fixed In:
Sentry Crash Report:
Attachments: call stack at the time of the freeze

Description YRH 2024-06-24 22:55:38 UTC
Created attachment 170934 [details]
call stack at the time of the freeze

This affects master, 5.2.3, and 5.2.2. Tested in master with commit hash 706cb7d60a66c161028c2f811ac6994016b2a83f.

SUMMARY

If an animation with audio (i.e. using MLT backend) is playing, sometimes scrubbing in the timeline will cause a thread deadlock, which leads to the app being unresponsive (freezing), then crashing (killed by the OS).

Stopping in the debugger at the time of the freeze, I saw this call stack (also attached):

1   NtWaitForMultipleObjects                                                         (x86_64) C:\Windows\System32\ntdll.dll                              0x7ff90fa70af4 
2   WaitForMultipleObjectsEx                                                         (x86_64) C:\Windows\System32\KernelBase.dll                         0x7ff90ce76089 
3   WaitForMultipleObjects                                                           (x86_64) C:\Windows\System32\KernelBase.dll                         0x7ff90ce75f8e 
4   _pthread_wait_for_multiple_objects                                               misc.c                                                         146  0x7ff8ef032e18 
5   do_sema_b_wait_intern                                                            cond.c                                                         647  0x7ff8ef032a80 
6   do_sema_b_wait                                                                   cond.c                                                         606  0x7ff8ef031ecf 
7   pthread_cond_timedwait_impl                                                      cond.c                                                         526  0x7ff8ef032987 
8   mlt_consumer_put_frame                                                           (x86_64) C:\Users\Maciek\krita-dev\_install\bin\libmlt-7.dll        0x7ff86697bfeb 
9   Mlt::PushConsumer::push(Mlt::Frame *)                                            (x86_64) C:\Users\Maciek\krita-dev\_install\bin\libmlt++-7.dll      0x7ff8f70cc4e4 
10  Mlt::PushConsumer::push(Mlt::Frame&)                                             (x86_64) C:\Users\Maciek\krita-dev\_install\bin\libmlt++-7.dll      0x7ff8f70cc50d 
11  KisPlaybackEngineMLT::Private::pushAudio(int)                                    KisPlaybackEngineMLT.cpp                                       160  0x7ff85557acf5 
12  std::__function::__value_func<void (int)>::operator()[abi:v15000](int&&) const   function.h                                                     512  0x7ff8554f3505 
13  std::function<void (int)>::operator()(int) const                                 function.h                                                     1187 0x7ff8554f34ee 
14  KisSignalCompressorWithParam<int>::fakeSlotTimeout()                             kis_signal_compressor_with_param.h                             151  0x7ff8554f34ee 
15  void doActivate<false>(QObject *, int, void * *)                                 qobject.cpp                                                    3931 0x7ff846760cbb 
16  KisSignalCompressor::tryEmitSignalSafely()                                       kis_signal_compressor.cpp                                      199  0x7ff867a43d3e 
17  KisSignalCompressor::start()                                                     kis_signal_compressor.cpp                                      117  0x7ff867a43d36 
18  KisSignalCompressorWithParam<int>::start(int)                                    kis_signal_compressor_with_param.h                             134  0x7ff855578335 
19  KisPlaybackEngineMLT::seek(int, QFlags<SeekOption>)                              KisPlaybackEngineMLT.cpp                                       344  0x7ff855578328 
20  KisTimeBasedItemModel::setHeaderData(int, Qt::Orientation, QVariant const&, int) KisTimeBasedItemModel.cpp                                      332  0x7ff8046ece16 
... <More>                                                                                                                                                              

KA post: https://krita-artists.org/t/testers-wanted-5-2-3-beta1-issues-and-feedback-thread/93122/64?u=yrh

STEPS TO REPRODUCE

Video: https://youtu.be/1157fjYRlYI

1. Open a new document with an animation timeline.
2. Add any audio track (to switch to the MLT engine; the length of the audio shouldn’t matter)
3. Change playback settings to
    start frame 0
    end frame 5000
    FPS 100
4. Hit play
5. As the playback goes on, keep clicking and slightly dragging on the frame numbers to rewind the playback to the clicked frames. Eventually it will freeze due to a deadlock. 

OBSERVED RESULT

The UI becomes unresponsive. Threads deadlocking with the call stack pointing to KisPlaybackEngineMLT::Private::pushAudio(int).

EXPECTED RESULT

Scrubbing works normally and cannot cause a hang/crash.
Comment 1 Dmitry Kazakov 2024-07-21 14:19:16 UTC
Hi, YRH!

Thank you for the detailed report! It seems like setting FPS to 100 was the key factor in reproduction of the race condition causing this bug. 

Now it should be fixed in this patch applied to MLT:
https://invent.kde.org/dkazakov/krita-deps-management/-/commit/c0c8a366d618befa0e65dde87a4aff290945e28a
Comment 2 Dmitry Kazakov 2024-07-21 14:34:16 UTC
Git commit fbfab4555061a496df037c75c47b6e148d456f36 by Dmitry Kazakov.
Committed on 21/07/2024 at 14:33.
Pushed by dkazakov into branch 'krita/5.2'.

[mlt] Fix incorrect usage of get_frame API

When calling activeProducer->get_frame(...), the argument actually
means the "audio track index", not the frame requested. Hence we
should just seek into the position instead of passinf the frame
index as an argument

M  +3    -2    libs/ui/KisPlaybackEngineMLT.cpp

https://invent.kde.org/graphics/krita/-/commit/fbfab4555061a496df037c75c47b6e148d456f36
Comment 3 Dmitry Kazakov 2024-07-21 14:34:40 UTC
Git commit 348aeb8679337c7abec6595185394c05f8dab40b by Dmitry Kazakov.
Committed on 21/07/2024 at 14:15.
Pushed by dkazakov into branch 'master'.

[mlt] Fix incorrect usage of get_frame API

When calling activeProducer->get_frame(...), the argument actually
means the "audio track index", not the frame requested. Hence we
should just seek into the position instead of passinf the frame
index as an argument

M  +3    -2    libs/ui/KisPlaybackEngineMLT.cpp

https://invent.kde.org/graphics/krita/-/commit/348aeb8679337c7abec6595185394c05f8dab40b