Compare commits

...

6 Commits

Author SHA1 Message Date
WarmUpTill
da28fea2e0 Fix potential freeze or crash with "Show match" dialog
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.
2022-02-26 16:08:55 -08:00
WarmUpTill
b6b0531dbc Fix size ofi new collapsed segments containing ResizingPlainTextEdit 2022-02-26 16:08:55 -08:00
WarmUpTill
2de0a94756 Fix highlight animations never stopping 2022-02-26 16:08:55 -08:00
WarmUpTill
d018740442 Fix potential deadlock in ShowMatchDialog 2022-02-26 16:08:55 -08:00
WarmUpTill
d89f8a7972 Clear pixmap if screenshot creation failed 2022-02-26 16:08:55 -08:00
WarmUpTill
f7a2aa09cb Fix potential crash 2022-02-26 16:08:55 -08:00
15 changed files with 100 additions and 46 deletions

View File

@@ -268,7 +268,8 @@ static inline void populateConditionSelection(QComboBox *list)
MacroConditionVideoEdit::MacroConditionVideoEdit( MacroConditionVideoEdit::MacroConditionVideoEdit(
QWidget *parent, std::shared_ptr<MacroConditionVideo> entryData) QWidget *parent, std::shared_ptr<MacroConditionVideo> entryData)
: QWidget(parent), _matchDialog(this, entryData.get()) : QWidget(parent),
_matchDialog(this, entryData.get(), &GetSwitcher()->m)
{ {
_videoSelection = new QComboBox(); _videoSelection = new QComboBox();
_condition = new QComboBox(); _condition = new QComboBox();

View File

@@ -3,12 +3,16 @@
#include "opencv-helpers.hpp" #include "opencv-helpers.hpp"
#include "utility.hpp" #include "utility.hpp"
#include <condition_variable>
ShowMatchDialog::ShowMatchDialog(QWidget *parent, ShowMatchDialog::ShowMatchDialog(QWidget *parent,
MacroConditionVideo *conditionData) MacroConditionVideo *conditionData,
std::mutex *mutex)
: QDialog(parent), : QDialog(parent),
_conditionData(conditionData), _conditionData(conditionData),
_imageLabel(new QLabel), _imageLabel(new QLabel),
_scrollArea(new QScrollArea) _scrollArea(new QScrollArea),
_mtx(mutex)
{ {
setWindowTitle("Advanced Scene Switcher"); setWindowTitle("Advanced Scene Switcher");
_statusLabel = new QLabel(obs_module_text( _statusLabel = new QLabel(obs_module_text(
@@ -20,6 +24,16 @@ ShowMatchDialog::ShowMatchDialog(QWidget *parent,
layout->addWidget(_statusLabel); layout->addWidget(_statusLabel);
layout->addWidget(_scrollArea); layout->addWidget(_scrollArea);
setLayout(layout); 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() ShowMatchDialog::~ShowMatchDialog()
@@ -43,38 +57,39 @@ void ShowMatchDialog::ShowMatch()
_thread = std::thread(&ShowMatchDialog::CheckForMatchLoop, this); _thread = std::thread(&ShowMatchDialog::CheckForMatchLoop, this);
} }
void ShowMatchDialog::RedrawImage(QImage img) void ShowMatchDialog::Resize()
{ {
_imageLabel->setPixmap(QPixmap::fromImage(img));
_imageLabel->adjustSize(); _imageLabel->adjustSize();
} }
void ShowMatchDialog::CheckForMatchLoop() void ShowMatchDialog::CheckForMatchLoop()
{ {
std::condition_variable cv;
while (!_stop) { while (!_stop) {
std::unique_lock<std::mutex> lock(*_mtx);
auto source = obs_weak_source_get_source( auto source = obs_weak_source_get_source(
_conditionData->_videoSource); _conditionData->_videoSource);
ScreenshotHelper screenshot(source); ScreenshotHelper screenshot(source);
obs_source_release(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) { if (!screenshot.done) {
_statusLabel->setText(obs_module_text( _statusLabel->setText(obs_module_text(
"AdvSceneSwitcher.condition.video.screenshotFail")); "AdvSceneSwitcher.condition.video.screenshotFail"));
_imageLabel->setPixmap(QPixmap());
continue; continue;
} }
if (screenshot.image.width() == 0 || if (screenshot.image.width() == 0 ||
screenshot.image.height() == 0) { screenshot.image.height() == 0) {
_statusLabel->setText(obs_module_text( _statusLabel->setText(obs_module_text(
"AdvSceneSwitcher.condition.video.screenshotEmpty")); "AdvSceneSwitcher.condition.video.screenshotEmpty"));
_imageLabel->setPixmap(QPixmap());
continue; continue;
} }
auto image = MarkMatch(screenshot.image); auto image = MarkMatch(screenshot.image);
if (_stop) { _imageLabel->setPixmap(QPixmap::fromImage(screenshot.image));
return;
}
QMetaObject::invokeMethod(this, "RedrawImage",
Qt::BlockingQueuedConnection,
Q_ARG(QImage, image));
} }
} }

View File

@@ -3,7 +3,9 @@
#include <QDialog> #include <QDialog>
#include <QLabel> #include <QLabel>
#include <QScrollArea> #include <QScrollArea>
#include <QTimer>
#include <thread> #include <thread>
#include <mutex>
class MacroConditionVideo; class MacroConditionVideo;
@@ -11,12 +13,13 @@ class ShowMatchDialog : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
ShowMatchDialog(QWidget *parent, MacroConditionVideo *_conditionData); ShowMatchDialog(QWidget *parent, MacroConditionVideo *_conditionData,
std::mutex *mutex);
virtual ~ShowMatchDialog(); virtual ~ShowMatchDialog();
void ShowMatch(); void ShowMatch();
private slots: private slots:
void RedrawImage(QImage img); void Resize();
private: private:
void CheckForMatchLoop(); void CheckForMatchLoop();
@@ -26,6 +29,8 @@ private:
QScrollArea *_scrollArea; QScrollArea *_scrollArea;
QLabel *_statusLabel; QLabel *_statusLabel;
QLabel *_imageLabel; QLabel *_imageLabel;
QTimer _timer;
std::mutex *_mtx;
std::thread _thread; std::thread _thread;
std::atomic_bool _stop = {false}; std::atomic_bool _stop = {false};
}; };

View File

@@ -156,16 +156,18 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
MacroActionSwitchScene temp(nullptr); MacroActionSwitchScene temp(nullptr);
id = temp.GetId(); id = temp.GetId();
} }
std::lock_guard<std::mutex> lock(switcher->m); {
macro->Actions().emplace(macro->Actions().begin() + idx, std::lock_guard<std::mutex> lock(switcher->m);
MacroActionFactory::Create(id, macro)); macro->Actions().emplace(macro->Actions().begin() + idx,
if (idx - 1 >= 0) { MacroActionFactory::Create(id, macro));
auto data = obs_data_create(); if (idx - 1 >= 0) {
macro->Actions().at(idx - 1)->Save(data); auto data = obs_data_create();
macro->Actions().at(idx)->Load(data); macro->Actions().at(idx - 1)->Save(data);
obs_data_release(data); macro->Actions().at(idx)->Load(data);
obs_data_release(data);
}
macro->UpdateActionIndices();
} }
macro->UpdateActionIndices();
clearLayout(actionsList->ContentLayout(), idx); clearLayout(actionsList->ContentLayout(), idx);
PopulateMacroActions(*macro, idx); PopulateMacroActions(*macro, idx);
@@ -206,11 +208,13 @@ void AdvSceneSwitcher::RemoveMacroAction(int idx)
return; return;
} }
std::lock_guard<std::mutex> lock(switcher->m); {
macro->Actions().erase(macro->Actions().begin() + idx); std::lock_guard<std::mutex> lock(switcher->m);
switcher->abortMacroWait = true; macro->Actions().erase(macro->Actions().begin() + idx);
switcher->macroWaitCv.notify_all(); switcher->abortMacroWait = true;
macro->UpdateActionIndices(); switcher->macroWaitCv.notify_all();
macro->UpdateActionIndices();
}
clearLayout(actionsList->ContentLayout(), idx); clearLayout(actionsList->ContentLayout(), idx);
PopulateMacroActions(*macro, idx); PopulateMacroActions(*macro, idx);

View File

@@ -128,6 +128,9 @@ void MacroActionFileEdit::UpdateEntryData()
_actions->setCurrentIndex(static_cast<int>(_entryData->_action)); _actions->setCurrentIndex(static_cast<int>(_entryData->_action));
_filePath->SetPath(QString::fromStdString(_entryData->_file)); _filePath->SetPath(QString::fromStdString(_entryData->_file));
_text->setPlainText(QString::fromStdString(_entryData->_text)); _text->setPlainText(QString::fromStdString(_entryData->_text));
adjustSize();
updateGeometry();
} }
void MacroActionFileEdit::PathChanged(const QString &text) void MacroActionFileEdit::PathChanged(const QString &text)

View File

@@ -153,6 +153,9 @@ void MacroActionFilterEdit::UpdateEntryData()
GetWeakSourceName(_entryData->_filter).c_str()); GetWeakSourceName(_entryData->_filter).c_str());
_settings->setPlainText(QString::fromStdString(_entryData->_settings)); _settings->setPlainText(QString::fromStdString(_entryData->_settings));
SetWidgetVisibility(_entryData->_action == FilterAction::SETTINGS); SetWidgetVisibility(_entryData->_action == FilterAction::SETTINGS);
adjustSize();
updateGeometry();
} }
void MacroActionFilterEdit::SourceChanged(const QString &text) void MacroActionFilterEdit::SourceChanged(const QString &text)

View File

@@ -161,6 +161,9 @@ void MacroActionSceneTransformEdit::UpdateEntryData()
_scenes->SetScene(_entryData->_scene); _scenes->SetScene(_entryData->_scene);
_sources->SetSceneItem(_entryData->_source); _sources->SetSceneItem(_entryData->_source);
_settings->setPlainText(formatJsonString(_entryData->GetSettings())); _settings->setPlainText(formatJsonString(_entryData->GetSettings()));
adjustSize();
updateGeometry();
} }
void MacroActionSceneTransformEdit::SceneChanged(const SceneSelection &s) void MacroActionSceneTransformEdit::SceneChanged(const SceneSelection &s)

View File

@@ -12,7 +12,7 @@ bool MacroActionSequence::_registered = MacroActionFactory::Register(
int getNextUnpausedMacroIdx(std::vector<MacroRef> &macros, int startIdx) int getNextUnpausedMacroIdx(std::vector<MacroRef> &macros, int startIdx)
{ {
for (; (int)macros.size() > startIdx; ++startIdx) { for (; (int)macros.size() > startIdx; ++startIdx) {
if (!macros[startIdx]->Paused()) { if (macros[startIdx].get() && !macros[startIdx]->Paused()) {
return startIdx; return startIdx;
} }
} }

View File

@@ -141,6 +141,9 @@ void MacroActionSourceEdit::UpdateEntryData()
GetWeakSourceName(_entryData->_source).c_str()); GetWeakSourceName(_entryData->_source).c_str());
_settings->setPlainText(QString::fromStdString(_entryData->_settings)); _settings->setPlainText(QString::fromStdString(_entryData->_settings));
SetWidgetVisibility(_entryData->_action == SourceAction::SETTINGS); SetWidgetVisibility(_entryData->_action == SourceAction::SETTINGS);
adjustSize();
updateGeometry();
} }
void MacroActionSourceEdit::SourceChanged(const QString &text) void MacroActionSourceEdit::SourceChanged(const QString &text)

View File

@@ -282,18 +282,20 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
id = temp.GetId(); id = temp.GetId();
logic = LogicType::ROOT_NONE; logic = LogicType::ROOT_NONE;
} }
std::lock_guard<std::mutex> lock(switcher->m); {
auto cond = macro->Conditions().emplace( std::lock_guard<std::mutex> lock(switcher->m);
macro->Conditions().begin() + idx, auto cond = macro->Conditions().emplace(
MacroConditionFactory::Create(id, macro)); macro->Conditions().begin() + idx,
if (idx - 1 >= 0) { MacroConditionFactory::Create(id, macro));
auto data = obs_data_create(); if (idx - 1 >= 0) {
macro->Conditions().at(idx - 1)->Save(data); auto data = obs_data_create();
macro->Conditions().at(idx)->Load(data); macro->Conditions().at(idx - 1)->Save(data);
obs_data_release(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); clearLayout(conditionsList->ContentLayout(), idx);
PopulateMacroConditions(*macro, idx); PopulateMacroConditions(*macro, idx);
@@ -334,13 +336,15 @@ void AdvSceneSwitcher::RemoveMacroCondition(int idx)
return; return;
} }
std::lock_guard<std::mutex> lock(switcher->m); {
macro->Conditions().erase(macro->Conditions().begin() + idx); std::lock_guard<std::mutex> lock(switcher->m);
macro->UpdateConditionIndices(); macro->Conditions().erase(macro->Conditions().begin() + idx);
macro->UpdateConditionIndices();
if (idx == 0 && macro->Conditions().size() > 0) { if (idx == 0 && macro->Conditions().size() > 0) {
auto newRoot = macro->Conditions().at(0); auto newRoot = macro->Conditions().at(0);
newRoot->SetLogicType(LogicType::ROOT_NONE); newRoot->SetLogicType(LogicType::ROOT_NONE);
}
} }
clearLayout(conditionsList->ContentLayout(), idx); clearLayout(conditionsList->ContentLayout(), idx);

View File

@@ -208,6 +208,9 @@ void MacroConditionFileEdit::UpdateEntryData()
_useRegex->setChecked(_entryData->_useRegex); _useRegex->setChecked(_entryData->_useRegex);
_checkModificationDate->setChecked(_entryData->_useTime); _checkModificationDate->setChecked(_entryData->_useTime);
_checkFileContent->setChecked(_entryData->_onlyMatchIfChanged); _checkFileContent->setChecked(_entryData->_onlyMatchIfChanged);
adjustSize();
updateGeometry();
} }
void MacroConditionFileEdit::FileTypeChanged(int index) void MacroConditionFileEdit::FileTypeChanged(int index)

View File

@@ -247,4 +247,7 @@ void MacroConditionFilterEdit::UpdateEntryData()
_regex->setChecked(_entryData->_regex); _regex->setChecked(_entryData->_regex);
SetSettingsSelectionVisible(_entryData->_condition == SetSettingsSelectionVisible(_entryData->_condition ==
FilterCondition::SETTINGS); FilterCondition::SETTINGS);
adjustSize();
updateGeometry();
} }

View File

@@ -134,6 +134,9 @@ void MacroConditionSceneTransformEdit::UpdateEntryData()
_sources->SetSceneItem(_entryData->_source); _sources->SetSceneItem(_entryData->_source);
_regex->setChecked(_entryData->_regex); _regex->setChecked(_entryData->_regex);
_settings->setPlainText(QString::fromStdString(_entryData->_settings)); _settings->setPlainText(QString::fromStdString(_entryData->_settings));
adjustSize();
updateGeometry();
} }
void MacroConditionSceneTransformEdit::SceneChanged(const SceneSelection &s) void MacroConditionSceneTransformEdit::SceneChanged(const SceneSelection &s)

View File

@@ -221,4 +221,7 @@ void MacroConditionSourceEdit::UpdateEntryData()
_regex->setChecked(_entryData->_regex); _regex->setChecked(_entryData->_regex);
SetSettingsSelectionVisible(_entryData->_condition == SetSettingsSelectionVisible(_entryData->_condition ==
SourceCondition::SETTINGS); SourceCondition::SETTINGS);
adjustSize();
updateGeometry();
} }

View File

@@ -912,6 +912,7 @@ QMetaObject::Connection PulseWidget(QWidget *widget, QColor startColor,
[animation] { [animation] {
animation->start(); animation->start();
}); });
timer->setSingleShot(true);
timer->start(1000); timer->start(1000);
}); });
animation->start(); animation->start();