diff --git a/src/external-macro-modules/opencv/macro-condition-video.cpp b/src/external-macro-modules/opencv/macro-condition-video.cpp index f553b252..602647e0 100644 --- a/src/external-macro-modules/opencv/macro-condition-video.cpp +++ b/src/external-macro-modules/opencv/macro-condition-video.cpp @@ -268,7 +268,8 @@ static inline void populateConditionSelection(QComboBox *list) MacroConditionVideoEdit::MacroConditionVideoEdit( QWidget *parent, std::shared_ptr entryData) - : QWidget(parent), _matchDialog(this, entryData.get()) + : QWidget(parent), + _matchDialog(this, entryData.get(), &GetSwitcher()->m) { _videoSelection = new QComboBox(); _condition = new QComboBox(); diff --git a/src/external-macro-modules/opencv/video-match-dialog.cpp b/src/external-macro-modules/opencv/video-match-dialog.cpp index 830c5ca8..d85bc0dc 100644 --- a/src/external-macro-modules/opencv/video-match-dialog.cpp +++ b/src/external-macro-modules/opencv/video-match-dialog.cpp @@ -3,12 +3,16 @@ #include "opencv-helpers.hpp" #include "utility.hpp" +#include + ShowMatchDialog::ShowMatchDialog(QWidget *parent, - MacroConditionVideo *conditionData) + MacroConditionVideo *conditionData, + std::mutex *mutex) : QDialog(parent), _conditionData(conditionData), _imageLabel(new QLabel), - _scrollArea(new QScrollArea) + _scrollArea(new QScrollArea), + _mtx(mutex) { setWindowTitle("Advanced Scene Switcher"); _statusLabel = new QLabel(obs_module_text( @@ -20,6 +24,16 @@ ShowMatchDialog::ShowMatchDialog(QWidget *parent, layout->addWidget(_statusLabel); layout->addWidget(_scrollArea); setLayout(layout); + + // This is a workaround to handle random segfaults triggered when using: + // QMetaObject::invokeMethod(this, "RedrawImage", -Qt::QueuedConnection, + // Q_ARG(QImage, image)); + // from within CheckForMatchLoop(). + // Even using BlockingQueuedConnection causes deadlocks + _timer.setInterval(500); + QWidget::connect(&_timer, &QTimer::timeout, this, + &ShowMatchDialog::Resize); + _timer.start(); } ShowMatchDialog::~ShowMatchDialog() @@ -43,20 +57,24 @@ void ShowMatchDialog::ShowMatch() _thread = std::thread(&ShowMatchDialog::CheckForMatchLoop, this); } -void ShowMatchDialog::RedrawImage(QImage img) +void ShowMatchDialog::Resize() { - _imageLabel->setPixmap(QPixmap::fromImage(img)); _imageLabel->adjustSize(); } void ShowMatchDialog::CheckForMatchLoop() { + std::condition_variable cv; while (!_stop) { + std::unique_lock lock(*_mtx); auto source = obs_weak_source_get_source( _conditionData->_videoSource); ScreenshotHelper screenshot(source); obs_source_release(source); - std::this_thread::sleep_for(std::chrono::seconds(1)); + cv.wait_for(lock, std::chrono::seconds(1)); + if (_stop) { + return; + } if (!screenshot.done) { _statusLabel->setText(obs_module_text( "AdvSceneSwitcher.condition.video.screenshotFail")); @@ -71,9 +89,7 @@ void ShowMatchDialog::CheckForMatchLoop() continue; } auto image = MarkMatch(screenshot.image); - QMetaObject::invokeMethod(this, "RedrawImage", - Qt::QueuedConnection, - Q_ARG(QImage, image)); + _imageLabel->setPixmap(QPixmap::fromImage(screenshot.image)); } } diff --git a/src/external-macro-modules/opencv/video-match-dialog.hpp b/src/external-macro-modules/opencv/video-match-dialog.hpp index 50274565..0031cee2 100644 --- a/src/external-macro-modules/opencv/video-match-dialog.hpp +++ b/src/external-macro-modules/opencv/video-match-dialog.hpp @@ -3,7 +3,9 @@ #include #include #include +#include #include +#include class MacroConditionVideo; @@ -11,12 +13,13 @@ class ShowMatchDialog : public QDialog { Q_OBJECT public: - ShowMatchDialog(QWidget *parent, MacroConditionVideo *_conditionData); + ShowMatchDialog(QWidget *parent, MacroConditionVideo *_conditionData, + std::mutex *mutex); virtual ~ShowMatchDialog(); void ShowMatch(); private slots: - void RedrawImage(QImage img); + void Resize(); private: void CheckForMatchLoop(); @@ -26,6 +29,8 @@ private: QScrollArea *_scrollArea; QLabel *_statusLabel; QLabel *_imageLabel; + QTimer _timer; + std::mutex *_mtx; std::thread _thread; std::atomic_bool _stop = {false}; }; diff --git a/src/macro-action-edit.cpp b/src/macro-action-edit.cpp index df47f120..1aa783c1 100644 --- a/src/macro-action-edit.cpp +++ b/src/macro-action-edit.cpp @@ -156,16 +156,18 @@ void AdvSceneSwitcher::AddMacroAction(int idx) MacroActionSwitchScene temp(nullptr); id = temp.GetId(); } - std::lock_guard lock(switcher->m); - macro->Actions().emplace(macro->Actions().begin() + idx, - MacroActionFactory::Create(id, macro)); - if (idx - 1 >= 0) { - auto data = obs_data_create(); - macro->Actions().at(idx - 1)->Save(data); - macro->Actions().at(idx)->Load(data); - obs_data_release(data); + { + std::lock_guard lock(switcher->m); + macro->Actions().emplace(macro->Actions().begin() + idx, + MacroActionFactory::Create(id, macro)); + if (idx - 1 >= 0) { + auto data = obs_data_create(); + macro->Actions().at(idx - 1)->Save(data); + macro->Actions().at(idx)->Load(data); + obs_data_release(data); + } + macro->UpdateActionIndices(); } - macro->UpdateActionIndices(); clearLayout(actionsList->ContentLayout(), idx); PopulateMacroActions(*macro, idx); @@ -206,11 +208,13 @@ void AdvSceneSwitcher::RemoveMacroAction(int idx) return; } - std::lock_guard lock(switcher->m); - macro->Actions().erase(macro->Actions().begin() + idx); - switcher->abortMacroWait = true; - switcher->macroWaitCv.notify_all(); - macro->UpdateActionIndices(); + { + std::lock_guard lock(switcher->m); + macro->Actions().erase(macro->Actions().begin() + idx); + switcher->abortMacroWait = true; + switcher->macroWaitCv.notify_all(); + macro->UpdateActionIndices(); + } clearLayout(actionsList->ContentLayout(), idx); PopulateMacroActions(*macro, idx); diff --git a/src/macro-condition-edit.cpp b/src/macro-condition-edit.cpp index 20f4d541..ce1676bf 100644 --- a/src/macro-condition-edit.cpp +++ b/src/macro-condition-edit.cpp @@ -282,18 +282,20 @@ void AdvSceneSwitcher::AddMacroCondition(int idx) id = temp.GetId(); logic = LogicType::ROOT_NONE; } - std::lock_guard lock(switcher->m); - auto cond = macro->Conditions().emplace( - macro->Conditions().begin() + idx, - MacroConditionFactory::Create(id, macro)); - if (idx - 1 >= 0) { - auto data = obs_data_create(); - macro->Conditions().at(idx - 1)->Save(data); - macro->Conditions().at(idx)->Load(data); - obs_data_release(data); + { + std::lock_guard lock(switcher->m); + auto cond = macro->Conditions().emplace( + macro->Conditions().begin() + idx, + MacroConditionFactory::Create(id, macro)); + if (idx - 1 >= 0) { + auto data = obs_data_create(); + macro->Conditions().at(idx - 1)->Save(data); + macro->Conditions().at(idx)->Load(data); + obs_data_release(data); + } + (*cond)->SetLogicType(logic); + macro->UpdateConditionIndices(); } - (*cond)->SetLogicType(logic); - macro->UpdateConditionIndices(); clearLayout(conditionsList->ContentLayout(), idx); PopulateMacroConditions(*macro, idx); @@ -334,13 +336,15 @@ void AdvSceneSwitcher::RemoveMacroCondition(int idx) return; } - std::lock_guard lock(switcher->m); - macro->Conditions().erase(macro->Conditions().begin() + idx); - macro->UpdateConditionIndices(); + { + std::lock_guard lock(switcher->m); + macro->Conditions().erase(macro->Conditions().begin() + idx); + macro->UpdateConditionIndices(); - if (idx == 0 && macro->Conditions().size() > 0) { - auto newRoot = macro->Conditions().at(0); - newRoot->SetLogicType(LogicType::ROOT_NONE); + if (idx == 0 && macro->Conditions().size() > 0) { + auto newRoot = macro->Conditions().at(0); + newRoot->SetLogicType(LogicType::ROOT_NONE); + } } clearLayout(conditionsList->ContentLayout(), idx);