Add option to reduce video matching latency

This commit is contained in:
WarmUpTill 2022-09-10 16:48:01 +02:00 committed by WarmUpTill
parent b2585ae176
commit 75cdd3c80d
6 changed files with 78 additions and 8 deletions

View File

@ -151,6 +151,8 @@ AdvSceneSwitcher.condition.video.condition.object="contains object"
AdvSceneSwitcher.condition.video.askFileAction="Do you want to use an existing file or create a screenshot of the currently selected source?"
AdvSceneSwitcher.condition.video.askFileAction.file="Use existing file"
AdvSceneSwitcher.condition.video.askFileAction.screenshot="Create screenshot"
AdvSceneSwitcher.condition.video.reduceLatency="Reduce matching latency"
AdvSceneSwitcher.condition.video.reduceLatency.tooltip="Enabling will reduce the matching latency, but will slow down the condition checks of all macros overall."
AdvSceneSwitcher.condition.video.usePatternForChangedCheck="Use pattern matching"
AdvSceneSwitcher.condition.video.usePatternForChangedCheck.tooltip="This will allow you to control how much the image has to change for the condition to be true."
AdvSceneSwitcher.condition.video.patternThreshold="Threshold: "

View File

@ -24,7 +24,7 @@ void MacroActionScreenshot::CustomScreenshot()
{
auto s = obs_weak_source_get_source(_source);
_screenshot.~ScreenshotHelper();
new (&_screenshot) ScreenshotHelper(s, true, _path);
new (&_screenshot) ScreenshotHelper(s, false, 0, true, _path);
obs_source_release(s);
}

View File

@ -82,6 +82,10 @@ bool MacroConditionVideo::CheckCondition()
return _lastMatchResult;
}
if (_blockUntilScreenshotDone) {
GetScreenshot(true);
}
if (_screenshotData.done) {
match = Compare();
_lastMatchResult = match;
@ -94,7 +98,7 @@ bool MacroConditionVideo::CheckCondition()
match = _lastMatchResult;
}
if (_getNextScreenshot) {
if (!_blockUntilScreenshotDone && _getNextScreenshot) {
GetScreenshot();
}
return match;
@ -106,6 +110,8 @@ bool MacroConditionVideo::Save(obs_data_t *obj)
_video.Save(obj);
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
obs_data_set_string(obj, "filePath", _file.c_str());
obs_data_set_bool(obj, "blockUntilScreenshotDone",
_blockUntilScreenshotDone);
obs_data_set_bool(obj, "usePatternForChangedCheck",
_usePatternForChangedCheck);
obs_data_set_double(obj, "threshold", _patternThreshold);
@ -143,6 +149,8 @@ bool MacroConditionVideo::Load(obs_data_t *obj)
_condition =
static_cast<VideoCondition>(obs_data_get_int(obj, "condition"));
_file = obs_data_get_string(obj, "filePath");
_blockUntilScreenshotDone =
obs_data_get_bool(obj, "blockUntilScreenshotDone");
_usePatternForChangedCheck =
obs_data_get_bool(obj, "usePatternForChangedCheck");
_patternThreshold = obs_data_get_double(obj, "threshold");
@ -186,11 +194,12 @@ std::string MacroConditionVideo::GetShortDesc()
return _video.ToString();
}
void MacroConditionVideo::GetScreenshot()
void MacroConditionVideo::GetScreenshot(bool blocking)
{
auto source = obs_weak_source_get_source(_video.GetVideo());
_screenshotData.~ScreenshotHelper();
new (&_screenshotData) ScreenshotHelper(source);
new (&_screenshotData)
ScreenshotHelper(source, blocking, GetSwitcher()->interval);
obs_source_release(source);
_getNextScreenshot = false;
}
@ -287,6 +296,8 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
: QWidget(parent),
_videoSelection(new VideoSelectionWidget(this)),
_condition(new QComboBox()),
_reduceLatency(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.condition.video.reduceLatency"))),
_usePatternForChangedCheck(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.condition.video.usePatternForChangedCheck"))),
_imagePath(new FileSelection()),
@ -326,6 +337,8 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
"AdvSceneSwitcher.condition.video.showMatch"))),
_previewDialog(this, entryData.get(), &GetSwitcher()->m)
{
_reduceLatency->setToolTip(obs_module_text(
"AdvSceneSwitcher.condition.video.reduceLatency.tooltip"));
_imagePath->Button()->disconnect();
_usePatternForChangedCheck->setToolTip(obs_module_text(
"AdvSceneSwitcher.condition.video.usePatternForChangedCheck.tooltip"));
@ -341,6 +354,8 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
SLOT(VideoSelectionChanged(const VideoSelection &)));
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
SLOT(ConditionChanged(int)));
QWidget::connect(_reduceLatency, SIGNAL(stateChanged(int)), this,
SLOT(ReduceLatencyChanged(int)));
QWidget::connect(_imagePath, SIGNAL(PathChanged(const QString &)), this,
SLOT(ImagePathChanged(const QString &)));
QWidget::connect(_imagePath->Button(), SIGNAL(clicked()), this,
@ -383,6 +398,7 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{videoSources}}", _videoSelection},
{"{{condition}}", _condition},
{"{{reduceLatency}}", _reduceLatency},
{"{{imagePath}}", _imagePath},
{"{{minNeighbors}}", _minNeighbors},
{"{{minSize}}", _minSize},
@ -442,6 +458,7 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
mainLayout->addLayout(_sizeLayout);
mainLayout->addLayout(_throttleControlLayout);
mainLayout->addLayout(_checkAreaControlLayout);
mainLayout->addWidget(_reduceLatency);
mainLayout->addLayout(showMatchLayout);
setLayout(mainLayout);
@ -635,6 +652,16 @@ void MacroConditionVideoEdit::PatternThresholdChanged(double value)
_entryData->_patternThreshold = value;
}
void MacroConditionVideoEdit::ReduceLatencyChanged(int value)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_blockUntilScreenshotDone = value;
}
void MacroConditionVideoEdit::UseAlphaAsMaskChanged(int value)
{
if (_loading || !_entryData) {
@ -851,6 +878,7 @@ void MacroConditionVideoEdit::UpdateEntryData()
_videoSelection->SetVideoSelection(_entryData->_video);
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
_reduceLatency->setChecked(_entryData->_blockUntilScreenshotDone);
_imagePath->SetPath(QString::fromStdString(_entryData->_file));
_usePatternForChangedCheck->setChecked(
_entryData->_usePatternForChangedCheck);

View File

@ -40,7 +40,7 @@ public:
{
return std::make_shared<MacroConditionVideo>(m);
}
void GetScreenshot();
void GetScreenshot(bool blocking = false);
bool LoadImageFromFile();
bool LoadModelData(std::string &path);
std::string GetModelDataPath() { return _modelDataPath; }
@ -49,6 +49,13 @@ public:
VideoSelection _video;
VideoCondition _condition = VideoCondition::MATCH;
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");
// Enabling this will reduce matching latency, but slow down the
// the condition checks of all macros overall.
//
// If not set the screenshot will be gathered in one interval and
// checked in the next one.
// If set both operations will happen in the same interval.
bool _blockUntilScreenshotDone = false;
bool _useAlphaAsMask = false;
bool _usePatternForChangedCheck = false;
PatternMatchData _patternData;
@ -107,8 +114,11 @@ public:
private slots:
void VideoSelectionChanged(const VideoSelection &);
void ConditionChanged(int cond);
void ReduceLatencyChanged(int value);
void ImagePathChanged(const QString &text);
void ImageBrowseButtonClicked();
void UsePatternForChangedCheckChanged(int value);
void PatternThresholdChanged(double);
void UseAlphaAsMaskChanged(int value);
@ -134,8 +144,11 @@ protected:
VideoSelectionWidget *_videoSelection;
QComboBox *_condition;
QCheckBox *_reduceLatency;
QCheckBox *_usePatternForChangedCheck;
FileSelection *_imagePath;
ThresholdSlider *_patternThreshold;
QCheckBox *_useAlphaAsMask;

View File

@ -1,16 +1,35 @@
#include "screenshot-helper.hpp"
#include "advanced-scene-switcher.hpp"
#include <chrono>
static void ScreenshotTick(void *param, float);
ScreenshotHelper::ScreenshotHelper(obs_source_t *source, bool saveToFile,
ScreenshotHelper::ScreenshotHelper(obs_source_t *source, bool blocking,
int timeout, bool saveToFile,
std::string path)
: weakSource(OBSGetWeakRef(source)),
_blocking(blocking),
_saveToFile(saveToFile),
_path(path)
{
std::unique_lock<std::mutex> lock(_mutex);
_initDone = true;
obs_add_tick_callback(ScreenshotTick, this);
if (_blocking) {
auto res =
_cv.wait_for(lock, std::chrono::milliseconds(timeout));
if (res == std::cv_status::timeout) {
if (source) {
blog(LOG_WARNING,
"Failed to get screenshot in time for source %s",
obs_source_get_name(source));
} else {
blog(LOG_WARNING,
"Failed to get screenshot in time");
}
}
}
}
ScreenshotHelper::~ScreenshotHelper()
@ -104,6 +123,8 @@ void ScreenshotHelper::MarkDone()
{
time = std::chrono::high_resolution_clock::now();
done = true;
std::unique_lock<std::mutex> lock(_mutex);
_cv.notify_all();
}
void ScreenshotHelper::WriteToFile()
@ -148,8 +169,8 @@ static void ScreenshotTick(void *param, float)
break;
case STAGE_COPY_AND_SAVE:
data->Copy();
data->MarkDone();
data->WriteToFile();
data->MarkDone();
obs_remove_tick_callback(ScreenshotTick, data);
break;

View File

@ -4,11 +4,14 @@
#include <QImage>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
class ScreenshotHelper {
public:
ScreenshotHelper() = default;
ScreenshotHelper(obs_source_t *source, bool saveToFile = false,
ScreenshotHelper(obs_source_t *source, bool blocking = false,
int timeout = 1000, bool saveToFile = false,
std::string path = "");
ScreenshotHelper &operator=(const ScreenshotHelper &) = delete;
ScreenshotHelper(const ScreenshotHelper &) = delete;
@ -34,7 +37,10 @@ public:
private:
bool _initDone = false;
bool _blocking = false;
std::thread _saveThread;
bool _saveToFile = false;
std::string _path = "";
std::mutex _mutex;
std::condition_variable _cv;
};