Add variable support to video condition

This commit is contained in:
WarmUpTill 2022-12-28 16:01:56 +01:00 committed by WarmUpTill
parent 8a2ccef8ec
commit 1fd6f75ee1
13 changed files with 203 additions and 204 deletions

View File

@ -199,7 +199,10 @@ AdvSceneSwitcher.condition.video.patternMatchSuccess="Pattern is highlighted in
AdvSceneSwitcher.condition.video.objectMatchFail="Object was not found!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="Object is highlighted in red"
AdvSceneSwitcher.condition.video.modelLoadFail="Model data could not be loaded!"
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{imagePath}}"
AdvSceneSwitcher.condition.video.type.main="OBS's main output"
AdvSceneSwitcher.condition.video.type.source="Source"
AdvSceneSwitcher.condition.video.type.scene="Scene"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Model data (haar cascade classifier): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum neighbors: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduce CPU load by performing check only every {{throttleCount}} milliseconds"

View File

@ -162,7 +162,7 @@ AdvSceneSwitcher.condition.video.patternMatchSuccess="El patrón está resaltado
AdvSceneSwitcher.condition.video.objectMatchFail="¡No se encontró el objeto!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="El objeto está resaltado en rojo"
AdvSceneSwitcher.condition.video.modelLoadFail="¡No se pudieron cargar los datos del modelo!"
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{imagePath}}"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Datos del modelo (haar cascade classifier): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Mínimo de vecinos: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzca la carga de la CPU realizando una comprobación solo cada {{throttleCount}} milisegundos"

View File

@ -147,7 +147,7 @@ AdvSceneSwitcher.condition.video.screenshotFail="Kaynağın ekran görüntüsü
AdvSceneSwitcher.condition.video.patternMatchFail="Desen bulunamadı!"
AdvSceneSwitcher.condition.video.objectMatchFail="Nesne bulunamadı!"
AdvSceneSwitcher.condition.video.modelLoadFail="Model verileri yüklenemedi!"
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{imagePath}}"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum komşular: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler"

View File

@ -180,7 +180,7 @@ AdvSceneSwitcher.condition.video.patternMatchSuccess="Pattern is highlighted in
AdvSceneSwitcher.condition.video.objectMatchFail="找不到对象!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="Object is highlighted in red"
AdvSceneSwitcher.condition.video.modelLoadFail="无法加载模型数据!"
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{imagePath}}"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="最小区域: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}通过只执行每一次检查来减少CPU负载 {{throttleCount}} 毫秒"

View File

@ -26,9 +26,7 @@ target_sources(
paramerter-wrappers.cpp
paramerter-wrappers.hpp
preview-dialog.cpp
preview-dialog.hpp
video-selection.cpp
video-selection.hpp)
preview-dialog.hpp)
setup_advss_plugin(${PROJECT_NAME})
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")

View File

@ -18,7 +18,7 @@ bool MacroConditionVideo::_registered = MacroConditionFactory::Register(
{MacroConditionVideo::Create, MacroConditionVideoEdit::Create,
"AdvSceneSwitcher.condition.video"});
static std::map<VideoCondition, std::string> conditionTypes = {
const static std::map<VideoCondition, std::string> conditionTypes = {
{VideoCondition::MATCH,
"AdvSceneSwitcher.condition.video.condition.match"},
{VideoCondition::DIFFER,
@ -37,6 +37,15 @@ static std::map<VideoCondition, std::string> conditionTypes = {
"AdvSceneSwitcher.condition.video.condition.brightness"},
};
const static std::map<VideoInput::Type, std::string> videoInputTypes = {
{VideoInput::Type::OBS_MAIN_OUTPUT,
"AdvSceneSwitcher.condition.video.type.main"},
{VideoInput::Type::SOURCE,
"AdvSceneSwitcher.condition.video.type.source"},
{VideoInput::Type::SCENE,
"AdvSceneSwitcher.condition.video.type.scene"},
};
cv::CascadeClassifier initObjectCascade(std::string &path)
{
cv::CascadeClassifier cascade;
@ -127,9 +136,6 @@ bool MacroConditionVideo::Load(obs_data_t *obj)
{
MacroCondition::Load(obj);
_video.Load(obj);
if (obs_data_has_user_value(obj, "videoSource")) {
_video.Load(obj, "videoSource");
}
_condition =
static_cast<VideoCondition>(obs_data_get_int(obj, "condition"));
_file = obs_data_get_string(obj, "filePath");
@ -268,6 +274,13 @@ bool MacroConditionVideo::Compare()
return false;
}
static inline void populateVideoInputSelection(QComboBox *list)
{
for (const auto &[_, name] : videoInputTypes) {
list->addItem(obs_module_text(name.c_str()));
}
}
static inline void populateConditionSelection(QComboBox *list)
{
for (auto entry : conditionTypes) {
@ -278,7 +291,10 @@ static inline void populateConditionSelection(QComboBox *list)
MacroConditionVideoEdit::MacroConditionVideoEdit(
QWidget *parent, std::shared_ptr<MacroConditionVideo> entryData)
: QWidget(parent),
_videoSelection(new VideoSelectionWidget(this)),
_videoInputTypes(new QComboBox()),
_scenes(new SceneSelectionWidget(this, true, false, true, true,
true)),
_sources(new SourceSelectionWidget(this, QStringList(), true)),
_condition(new QComboBox()),
_reduceLatency(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.condition.video.reduceLatency"))),
@ -339,10 +355,17 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
_throttleCount->setMaximum(10 * GetSwitcher()->interval);
_throttleCount->setSingleStep(GetSwitcher()->interval);
QWidget::connect(_videoSelection,
SIGNAL(VideoSelectionChange(const VideoSelection &)),
this,
SLOT(VideoSelectionChanged(const VideoSelection &)));
auto sources = GetVideoSourceNames();
sources.sort();
_sources->SetSourceNameList(sources);
QWidget::connect(_videoInputTypes, SIGNAL(currentIndexChanged(int)),
this, SLOT(VideoInputTypeChanged(int)));
QWidget::connect(_sources,
SIGNAL(SourceChanged(const SourceSelection &)), this,
SLOT(SourceChanged(const SourceSelection &)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
SLOT(ConditionChanged(int)));
QWidget::connect(_reduceLatency, SIGNAL(stateChanged(int)), this,
@ -383,20 +406,23 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
SLOT(ShowMatchClicked()));
QWidget::connect(&_previewDialog, SIGNAL(SelectionAreaChanged(QRect)),
this, SLOT(CheckAreaChanged(QRect)));
QWidget::connect(_videoSelection,
SIGNAL(VideoSelectionChange(const VideoSelection &)),
QWidget::connect(this,
SIGNAL(VideoSelectionChanged(const VideoInput &)),
&_previewDialog,
SLOT(VideoSelectionChanged(const VideoSelection &)));
SLOT(VideoSelectionChanged(const VideoInput &)));
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)),
&_previewDialog, SLOT(ConditionChanged(int)));
QWidget::connect(_selectArea, SIGNAL(clicked()), this,
SLOT(SelectAreaClicked()));
populateVideoInputSelection(_videoInputTypes);
populateConditionSelection(_condition);
QHBoxLayout *entryLine1Layout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{videoSources}}", _videoSelection},
{"{{videoInputTypes}}", _videoInputTypes},
{"{{sources}}", _sources},
{"{{scenes}}", _scenes},
{"{{condition}}", _condition},
{"{{reduceLatency}}", _reduceLatency},
{"{{imagePath}}", _imagePath},
@ -499,17 +525,38 @@ void MacroConditionVideoEdit::UpdatePreviewTooltip()
this->setToolTip(html);
}
void MacroConditionVideoEdit::VideoSelectionChanged(const VideoSelection &v)
void MacroConditionVideoEdit::SourceChanged(const SourceSelection &source)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_video = v;
_entryData->ResetLastMatch();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
_entryData->_video.source = source;
HandleVideoInputUpdate();
}
void MacroConditionVideoEdit::SceneChanged(const SceneSelection &scene)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_video.scene = scene;
HandleVideoInputUpdate();
}
void MacroConditionVideoEdit::VideoInputTypeChanged(int type)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_video.type = static_cast<VideoInput::Type>(type);
HandleVideoInputUpdate();
SetWidgetVisibility();
}
void MacroConditionVideoEdit::ConditionChanged(int cond)
@ -741,6 +788,14 @@ void MacroConditionVideoEdit::MinSizeChanged(advss::Size value)
_entryData->_objMatchParameters);
}
void MacroConditionVideoEdit::HandleVideoInputUpdate()
{
_entryData->ResetLastMatch();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
emit VideoSelectionChanged(_entryData->_video);
}
void MacroConditionVideoEdit::MaxSizeChanged(advss::Size value)
{
if (_loading || !_entryData) {
@ -887,6 +942,9 @@ bool needsAreaControls(VideoCondition cond)
void MacroConditionVideoEdit::SetWidgetVisibility()
{
_sources->setVisible(_entryData->_video.type ==
VideoInput::Type::SOURCE);
_scenes->setVisible(_entryData->_video.type == VideoInput::Type::SCENE);
_imagePath->setVisible(requiresFileInput(_entryData->_condition));
_usePatternForChangedCheck->setVisible(
patternControlIsOptional(_entryData->_condition));
@ -930,7 +988,10 @@ void MacroConditionVideoEdit::UpdateEntryData()
return;
}
_videoSelection->SetVideoSelection(_entryData->_video);
_videoInputTypes->setCurrentIndex(
static_cast<int>(_entryData->_video.type));
_scenes->SetScene(_entryData->_video.scene);
_sources->SetSource(_entryData->_video.source);
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
_reduceLatency->setChecked(_entryData->_blockUntilScreenshotDone);
_imagePath->SetPath(QString::fromStdString(_entryData->_file));

View File

@ -1,7 +1,6 @@
#pragma once
#include "opencv-helpers.hpp"
#include "area-selection.hpp"
#include "video-selection.hpp"
#include "preview-dialog.hpp"
#include "paramerter-wrappers.hpp"
@ -40,7 +39,7 @@ public:
void ResetLastMatch() { _lastMatchResult = false; }
double GetCurrentBrightness() const { return _currentBrigthness; }
VideoSelection _video;
VideoInput _video;
VideoCondition _condition = VideoCondition::MATCH;
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");
// Enabling this will reduce matching latency, but slow down the
@ -97,7 +96,9 @@ public:
void UpdatePreviewTooltip();
private slots:
void VideoSelectionChanged(const VideoSelection &);
void VideoInputTypeChanged(int);
void SourceChanged(const SourceSelection &);
void SceneChanged(const SceneSelection &);
void ConditionChanged(int cond);
void ReduceLatencyChanged(int value);
@ -127,10 +128,16 @@ private slots:
void UpdateCurrentBrightness();
signals:
void VideoSelectionChanged(const VideoInput &);
void HeaderInfoChanged(const QString &);
protected:
VideoSelectionWidget *_videoSelection;
private:
void SetWidgetVisibility();
void HandleVideoInputUpdate();
QComboBox *_videoInputTypes;
SceneSelectionWidget *_scenes;
SourceSelectionWidget *_sources;
QComboBox *_condition;
QCheckBox *_reduceLatency;
@ -166,11 +173,8 @@ protected:
QPushButton *_showMatch;
PreviewDialog _previewDialog;
std::shared_ptr<MacroConditionVideo> _entryData;
private:
QTimer _updateBrightnessTimer;
void SetWidgetVisibility();
std::shared_ptr<MacroConditionVideo> _entryData;
bool _loading = true;
};

View File

@ -110,3 +110,81 @@ bool AreaParamters::Load(obs_data_t *obj)
obs_data_release(data);
return true;
}
bool VideoInput::Save(obs_data_t *obj) const
{
auto data = obs_data_create();
obs_data_set_int(data, "type", static_cast<int>(type));
source.Save(data);
scene.Save(data);
obs_data_set_obj(obj, "videoInputData", data);
obs_data_release(data);
return true;
}
bool VideoInput::Load(obs_data_t *obj)
{
// TODO: Remove this fallback in a future version
if (obs_data_has_user_value(obj, "videoType")) {
enum class VideoSelectionType {
SOURCE,
OBS_MAIN,
};
auto oldType = static_cast<VideoSelectionType>(
obs_data_get_int(obj, "videoType"));
if (oldType == VideoSelectionType::SOURCE) {
type = Type::SOURCE;
auto name = obs_data_get_string(obj, "video");
source.SetSource(GetWeakSourceByName(name));
} else {
type = Type::OBS_MAIN_OUTPUT;
}
return true;
}
auto data = obs_data_get_obj(obj, "videoInputData");
type = static_cast<Type>(obs_data_get_int(data, "type"));
source.Load(data);
scene.Load(data);
obs_data_release(data);
return true;
}
std::string VideoInput::ToString(bool resolve) const
{
switch (type) {
case VideoInput::Type::OBS_MAIN_OUTPUT:
return obs_module_text("AdvSceneSwitcher.OBSVideoOutput");
case VideoInput::Type::SOURCE:
return source.ToString(resolve);
case VideoInput::Type::SCENE:
return scene.ToString(resolve);
}
return "";
}
bool VideoInput::ValidSelection() const
{
switch (type) {
case VideoInput::Type::OBS_MAIN_OUTPUT:
return true;
case VideoInput::Type::SOURCE:
return !!source.GetSource();
case VideoInput::Type::SCENE:
return !!scene.GetScene();
}
return false;
}
OBSWeakSource VideoInput::GetVideo() const
{
switch (type) {
case VideoInput::Type::OBS_MAIN_OUTPUT:
return nullptr;
case VideoInput::Type::SOURCE:
return source.GetSource();
case VideoInput::Type::SCENE:
return scene.GetScene();
}
return nullptr;
}

View File

@ -2,6 +2,8 @@
#include "opencv-helpers.hpp"
#include "area-selection.hpp"
#include <source-selection.hpp>
#include <scene-selection.hpp>
#include <obs.hpp>
#include <obs-module.h>
@ -16,6 +18,25 @@ enum class VideoCondition {
BRIGHTNESS,
};
class VideoInput {
public:
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string ToString(bool resolve = false) const;
bool ValidSelection() const;
OBSWeakSource GetVideo() const;
enum class Type {
OBS_MAIN_OUTPUT,
SOURCE,
SCENE,
};
Type type = Type::OBS_MAIN_OUTPUT;
SourceSelection source;
SceneSelection scene;
};
class PatternMatchParameters {
public:
bool Save(obs_data_t *obj) const;

View File

@ -143,7 +143,7 @@ void PreviewDialog::ObjDetectParamtersChanged(const ObjDetectParamerts &params)
_objDetectParams = params;
}
void PreviewDialog::VideoSelectionChanged(const VideoSelection &video)
void PreviewDialog::VideoSelectionChanged(const VideoInput &video)
{
std::unique_lock<std::mutex> lock(_mtx);
_video = video;

View File

@ -1,5 +1,4 @@
#pragma once
#include "video-selection.hpp"
#include "paramerter-wrappers.hpp"
#include <QDialog>
@ -28,7 +27,7 @@ public:
public slots:
void PatternMatchParamtersChanged(const PatternMatchParameters &);
void ObjDetectParamtersChanged(const ObjDetectParamerts &);
void VideoSelectionChanged(const VideoSelection &);
void VideoSelectionChanged(const VideoInput &);
void AreaParamtersChanged(const AreaParamters &);
void ConditionChanged(int cond);
private slots:
@ -46,7 +45,7 @@ private:
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
VideoSelection _video;
VideoInput _video;
PatternMatchParameters _patternMatchParams;
PatternImageData _patternImageData;
ObjDetectParamerts _objDetectParams;

View File

@ -1,122 +0,0 @@
#include "video-selection.hpp"
#include "utility.hpp"
void VideoSelection::Save(obs_data_t *obj, const char *name,
const char *typeName) const
{
obs_data_set_int(obj, typeName, static_cast<int>(_type));
switch (_type) {
case VideoSelectionType::SOURCE:
obs_data_set_string(obj, name,
GetWeakSourceName(_source).c_str());
break;
default:
break;
}
}
void VideoSelection::Load(obs_data_t *obj, const char *name,
const char *typeName)
{
_type = static_cast<VideoSelectionType>(
obs_data_get_int(obj, typeName));
auto target = obs_data_get_string(obj, name);
switch (_type) {
case VideoSelectionType::SOURCE:
_source = GetWeakSourceByName(target);
break;
case VideoSelectionType::OBS_MAIN:
_source = nullptr;
break;
default:
break;
}
}
OBSWeakSource VideoSelection::GetVideo() const
{
if (_type == VideoSelectionType::SOURCE) {
return _source;
}
return nullptr;
}
std::string VideoSelection::ToString() const
{
switch (_type) {
case VideoSelectionType::SOURCE:
return GetWeakSourceName(_source);
case VideoSelectionType::OBS_MAIN:
return obs_module_text("AdvSceneSwitcher.OBSVideoOutput");
default:
break;
}
return "";
}
bool VideoSelection::ValidSelection() const
{
return _type == VideoSelectionType::OBS_MAIN || !!_source;
}
VideoSelectionWidget::VideoSelectionWidget(QWidget *parent, bool addOBSVideoOut)
: QComboBox(parent)
{
setDuplicatesEnabled(true);
populateVideoSelection(this, addOBSVideoOut);
QWidget::connect(this, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SelectionChanged(const QString &)));
}
void VideoSelectionWidget::SetVideoSelection(VideoSelection &t)
{
int idx;
switch (t.GetType()) {
case VideoSelectionType::SOURCE:
setCurrentText(QString::fromStdString(t.ToString()));
break;
case VideoSelectionType::OBS_MAIN:
idx = findText(QString::fromStdString(obs_module_text(
obs_module_text("AdvSceneSwitcher.OBSVideoOutput"))));
if (idx != -1) {
setCurrentIndex(idx);
}
break;
default:
setCurrentIndex(0);
break;
}
}
static bool isFirstEntry(QComboBox *l, QString name, int idx)
{
for (int i = 0; i < l->count(); i++) {
if (l->itemText(i) == name) {
return idx == i;
}
}
return false;
}
bool VideoSelectionWidget::IsOBSVideoOutSelected(const QString &name)
{
if (name == QString::fromStdString(obs_module_text(
"AdvSceneSwitcher.OBSVideoOutput"))) {
return isFirstEntry(this, name, currentIndex());
}
return false;
}
void VideoSelectionWidget::SelectionChanged(const QString &name)
{
VideoSelection t;
if (IsOBSVideoOutSelected(name)) {
t._type = VideoSelectionType::OBS_MAIN;
} else {
auto source = GetWeakSourceByQString(name);
t._type = VideoSelectionType::SOURCE;
t._source = source;
}
emit VideoSelectionChange(t);
}

View File

@ -1,43 +0,0 @@
#pragma once
#include <QComboBox>
#include <obs-module.h>
#include <obs.hpp>
enum class VideoSelectionType {
SOURCE,
OBS_MAIN,
};
class VideoSelection {
public:
void Save(obs_data_t *obj, const char *name = "video",
const char *typeName = "videoType") const;
void Load(obs_data_t *obj, const char *name = "video",
const char *typeName = "videoType");
VideoSelectionType GetType() const { return _type; }
OBSWeakSource GetVideo() const;
std::string ToString() const;
bool ValidSelection() const;
private:
OBSWeakSource _source;
VideoSelectionType _type = VideoSelectionType::SOURCE;
friend class VideoSelectionWidget;
};
class VideoSelectionWidget : public QComboBox {
Q_OBJECT
public:
VideoSelectionWidget(QWidget *parent, bool addOBSVideoOut = true);
void SetVideoSelection(VideoSelection &);
signals:
void VideoSelectionChange(const VideoSelection &);
private slots:
void SelectionChanged(const QString &name);
private:
bool IsOBSVideoOutSelected(const QString &name);
};