mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-03-21 17:34:57 -05:00
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.
This commit is contained in:
parent
b6b0531dbc
commit
da28fea2e0
|
|
@ -268,7 +268,8 @@ static inline void populateConditionSelection(QComboBox *list)
|
|||
|
||||
MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionVideo> entryData)
|
||||
: QWidget(parent), _matchDialog(this, entryData.get())
|
||||
: QWidget(parent),
|
||||
_matchDialog(this, entryData.get(), &GetSwitcher()->m)
|
||||
{
|
||||
_videoSelection = new QComboBox();
|
||||
_condition = new QComboBox();
|
||||
|
|
|
|||
|
|
@ -3,12 +3,16 @@
|
|||
#include "opencv-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <condition_variable>
|
||||
|
||||
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<std::mutex> 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QScrollArea>
|
||||
#include <QTimer>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
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};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -156,16 +156,18 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
|
|||
MacroActionSwitchScene temp(nullptr);
|
||||
id = temp.GetId();
|
||||
}
|
||||
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> lock(switcher->m);
|
||||
macro->Actions().erase(macro->Actions().begin() + idx);
|
||||
switcher->abortMacroWait = true;
|
||||
switcher->macroWaitCv.notify_all();
|
||||
macro->UpdateActionIndices();
|
||||
{
|
||||
std::lock_guard<std::mutex> 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);
|
||||
|
|
|
|||
|
|
@ -282,18 +282,20 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
|
|||
id = temp.GetId();
|
||||
logic = LogicType::ROOT_NONE;
|
||||
}
|
||||
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> lock(switcher->m);
|
||||
macro->Conditions().erase(macro->Conditions().begin() + idx);
|
||||
macro->UpdateConditionIndices();
|
||||
{
|
||||
std::lock_guard<std::mutex> 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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user