mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-05-13 15:59:41 -05:00
Merge 5feff07134 into 873e073eb6
This commit is contained in:
commit
1e2f51c916
|
|
@ -856,6 +856,7 @@ AdvSceneSwitcher.condition.streamDeck.stopListen="Stop listening"
|
|||
AdvSceneSwitcher.condition.streamDeck.pluginDownload="<html><head/><body><p>The Stream Deck plugin can be found <a href=\"https://github.com/WarmUpTill/advanced-scene-switcher-streamdeck-plugin/releases\"><span style=\" text-decoration: underline; color:#268bd2;\">here on GitHub</span></a>.</p></body></html>"
|
||||
AdvSceneSwitcher.condition.gameCapture="Game capture"
|
||||
AdvSceneSwitcher.condition.gameCapture.entry="{{sources}}hooked a game."
|
||||
|
||||
AdvSceneSwitcher.condition.screenshot="Screenshot"
|
||||
AdvSceneSwitcher.condition.screenshot.entry="A screenshot was taken"
|
||||
AdvSceneSwitcher.condition.mqtt="MQTT"
|
||||
|
|
@ -2538,6 +2539,9 @@ AdvSceneSwitcher.selectDisplay="--select display--"
|
|||
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
|
||||
AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB"
|
||||
|
||||
AdvSceneSwitcher.keepSourceActive="Keep source active"
|
||||
AdvSceneSwitcher.keepSourceActive.help="When a source is not visible in the active scene it becomes inactive, which can cause it to stop producing output (e.g. video frames or game capture hooks).\nEnabling this option forces the source to remain active at all times, ensuring it continues to produce output even when not displayed.\n\nNote: Keeping a source permanently active may increase CPU and GPU usage, as the source continues to run even when not shown."
|
||||
|
||||
AdvSceneSwitcher.settings.suffix.type.invalid=" (Invalid)"
|
||||
AdvSceneSwitcher.settings.suffix.type.bool=" (Bool)"
|
||||
AdvSceneSwitcher.settings.suffix.type.int=" (Int)"
|
||||
|
|
|
|||
|
|
@ -162,4 +162,47 @@ bool IsMediaSource(obs_source_t *source)
|
|||
return (flags & OBS_SOURCE_CONTROLLABLE_MEDIA) != 0;
|
||||
}
|
||||
|
||||
SourceActiveKeeper::~SourceActiveKeeper()
|
||||
{
|
||||
ReleaseRef();
|
||||
}
|
||||
|
||||
void SourceActiveKeeper::SetActive(bool active)
|
||||
{
|
||||
if (_active == active) {
|
||||
return;
|
||||
}
|
||||
_active = active;
|
||||
if (_active) {
|
||||
AcquireRef();
|
||||
} else {
|
||||
ReleaseRef();
|
||||
}
|
||||
}
|
||||
|
||||
void SourceActiveKeeper::SetSource(obs_source_t *source)
|
||||
{
|
||||
if (_source == source) {
|
||||
return;
|
||||
}
|
||||
ReleaseRef();
|
||||
_source = source;
|
||||
AcquireRef();
|
||||
}
|
||||
|
||||
void SourceActiveKeeper::AcquireRef()
|
||||
{
|
||||
if (_active && _source) {
|
||||
obs_source_inc_active(_source);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceActiveKeeper::ReleaseRef()
|
||||
{
|
||||
if (_active && _source) {
|
||||
obs_source_dec_active(_source);
|
||||
_source = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
|
|
@ -20,4 +20,25 @@ EXPORT OBSWeakSource GetWeakFilterByQString(OBSWeakSource source,
|
|||
EXPORT int GetSceneItemCount(const OBSWeakSource &);
|
||||
EXPORT bool IsMediaSource(obs_source_t *source);
|
||||
|
||||
// RAII helper that keeps an OBS source active (via obs_source_inc_active /
|
||||
// obs_source_dec_active) for as long as the keeper is enabled.
|
||||
class EXPORT SourceActiveKeeper {
|
||||
public:
|
||||
SourceActiveKeeper() = default;
|
||||
~SourceActiveKeeper();
|
||||
|
||||
SourceActiveKeeper(const SourceActiveKeeper &) = delete;
|
||||
SourceActiveKeeper &operator=(const SourceActiveKeeper &) = delete;
|
||||
|
||||
void SetActive(bool active);
|
||||
void SetSource(obs_source_t *source);
|
||||
|
||||
private:
|
||||
void AcquireRef();
|
||||
void ReleaseRef();
|
||||
|
||||
OBSSource _source;
|
||||
bool _active = false;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ bool MacroConditionGameCapture::CheckCondition()
|
|||
return false;
|
||||
}
|
||||
|
||||
_activeKeeper.SetActive(_keepActive);
|
||||
|
||||
std::lock_guard<std::mutex> lock(_mtx);
|
||||
if (_hooked) {
|
||||
SetTempVarValue("title", _title);
|
||||
|
|
@ -38,6 +40,7 @@ bool MacroConditionGameCapture::Save(obs_data_t *obj) const
|
|||
{
|
||||
MacroCondition::Save(obj);
|
||||
_source.Save(obj);
|
||||
obs_data_set_bool(obj, "keepActive", _keepActive);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -45,6 +48,7 @@ bool MacroConditionGameCapture::Load(obs_data_t *obj)
|
|||
{
|
||||
MacroCondition::Load(obj);
|
||||
_source.Load(obj);
|
||||
_keepActive = obs_data_get_bool(obj, "keepActive");
|
||||
SetupSignalHandler(OBSGetStrongRef(_source.GetSource()));
|
||||
return true;
|
||||
}
|
||||
|
|
@ -111,6 +115,9 @@ void MacroConditionGameCapture::SetupSignalHandler(obs_source_t *source)
|
|||
_unhookSignal = OBSSignal(sh, "unhooked", UnhookedSignalReceived, this);
|
||||
_lastSource = source;
|
||||
|
||||
_activeKeeper.SetActive(_keepActive);
|
||||
_activeKeeper.SetSource(source);
|
||||
|
||||
SetupInitialState(source);
|
||||
}
|
||||
|
||||
|
|
@ -164,17 +171,33 @@ MacroConditionGameCaptureEdit::MacroConditionGameCaptureEdit(
|
|||
QWidget *parent, std::shared_ptr<MacroConditionGameCapture> entryData)
|
||||
: QWidget(parent),
|
||||
_sources(new SourceSelectionWidget(this, getGameCaptureSourcesList,
|
||||
true))
|
||||
true)),
|
||||
_keepActive(new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.keepSourceActive"), this)),
|
||||
_keepActiveHelp(new HelpIcon(
|
||||
obs_module_text("AdvSceneSwitcher.keepSourceActive.help"),
|
||||
this))
|
||||
{
|
||||
QWidget::connect(_sources,
|
||||
SIGNAL(SourceChanged(const SourceSelection &)), this,
|
||||
SLOT(SourceChanged(const SourceSelection &)));
|
||||
QWidget::connect(_keepActive, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(KeepActiveChanged(int)));
|
||||
|
||||
auto layout = new QHBoxLayout;
|
||||
auto entryLayout = new QHBoxLayout;
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.condition.gameCapture.entry"),
|
||||
layout, {{"{{sources}}", _sources}});
|
||||
setLayout(layout);
|
||||
entryLayout, {{"{{sources}}", _sources}});
|
||||
|
||||
auto keepActiveLayout = new QHBoxLayout;
|
||||
keepActiveLayout->addWidget(_keepActive);
|
||||
keepActiveLayout->addWidget(_keepActiveHelp);
|
||||
keepActiveLayout->addStretch();
|
||||
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entryLayout);
|
||||
mainLayout->addLayout(keepActiveLayout);
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
|
|
@ -187,9 +210,16 @@ void MacroConditionGameCaptureEdit::SourceChanged(const SourceSelection &source)
|
|||
_entryData->_source = source;
|
||||
}
|
||||
|
||||
void MacroConditionGameCaptureEdit::KeepActiveChanged(int state)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_keepActive = state;
|
||||
}
|
||||
|
||||
void MacroConditionGameCaptureEdit::UpdateEntryData()
|
||||
{
|
||||
_sources->SetSource(_entryData->_source);
|
||||
_keepActive->setChecked(_entryData->_keepActive);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
#pragma once
|
||||
#include "help-icon.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
#include "source-selection.hpp"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
|
||||
namespace advss {
|
||||
|
||||
|
|
@ -20,6 +23,7 @@ public:
|
|||
}
|
||||
|
||||
SourceSelection _source;
|
||||
bool _keepActive = false;
|
||||
|
||||
private:
|
||||
static void HookedSignalReceived(void *data, calldata_t *);
|
||||
|
|
@ -31,6 +35,7 @@ private:
|
|||
void GetCalldataInfo(calldata_t *cd);
|
||||
|
||||
obs_source_t *_lastSource = nullptr;
|
||||
SourceActiveKeeper _activeKeeper;
|
||||
OBSSignal _hookSignal;
|
||||
OBSSignal _unhookSignal;
|
||||
|
||||
|
|
@ -63,9 +68,12 @@ public:
|
|||
|
||||
private slots:
|
||||
void SourceChanged(const SourceSelection &);
|
||||
void KeepActiveChanged(int);
|
||||
|
||||
private:
|
||||
SourceSelectionWidget *_sources;
|
||||
QCheckBox *_keepActive;
|
||||
HelpIcon *_keepActiveHelp;
|
||||
std::shared_ptr<MacroConditionGameCapture> _entryData;
|
||||
|
||||
bool _loading = true;
|
||||
|
|
|
|||
|
|
@ -118,12 +118,28 @@ MacroConditionVideo::MacroConditionVideo(Macro *m)
|
|||
{
|
||||
}
|
||||
|
||||
void MacroConditionVideo::UpdateActiveKeeper()
|
||||
{
|
||||
_activeKeeper.SetActive(_keepActive);
|
||||
if (_video.type == VideoInput::Type::OBS_MAIN_OUTPUT) {
|
||||
return;
|
||||
}
|
||||
auto videoSource = _video.GetVideo();
|
||||
if (videoSource == _lastActiveKeeperSource) {
|
||||
return;
|
||||
}
|
||||
_lastActiveKeeperSource = videoSource;
|
||||
_activeKeeper.SetSource(OBSGetStrongRef(videoSource));
|
||||
}
|
||||
|
||||
bool MacroConditionVideo::CheckCondition()
|
||||
{
|
||||
if (!_video.ValidSelection()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UpdateActiveKeeper();
|
||||
|
||||
bool match = false;
|
||||
if (CheckShouldBeSkipped()) {
|
||||
return _lastMatchResult;
|
||||
|
|
@ -159,6 +175,7 @@ bool MacroConditionVideo::Save(obs_data_t *obj) const
|
|||
{
|
||||
MacroCondition::Save(obj);
|
||||
_video.Save(obj);
|
||||
obs_data_set_bool(obj, "keepActive", _keepActive);
|
||||
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",
|
||||
|
|
@ -178,6 +195,7 @@ bool MacroConditionVideo::Load(obs_data_t *obj)
|
|||
{
|
||||
MacroCondition::Load(obj);
|
||||
_video.Load(obj);
|
||||
_keepActive = obs_data_get_bool(obj, "keepActive");
|
||||
SetCondition(static_cast<VideoCondition>(
|
||||
obs_data_get_int(obj, "condition")));
|
||||
_file = obs_data_get_string(obj, "filePath");
|
||||
|
|
@ -1233,7 +1251,12 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
|||
_area(new AreaEdit(this, &_previewDialog, entryData)),
|
||||
_throttleControlLayout(new QHBoxLayout),
|
||||
_throttleEnable(new QCheckBox()),
|
||||
_throttleCount(new QSpinBox())
|
||||
_throttleCount(new QSpinBox()),
|
||||
_keepActive(new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.keepSourceActive"))),
|
||||
_keepActiveHelp(new HelpIcon(
|
||||
obs_module_text("AdvSceneSwitcher.keepSourceActive.help"),
|
||||
this))
|
||||
{
|
||||
_reduceLatency->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.reduceLatency.tooltip"));
|
||||
|
|
@ -1290,6 +1313,8 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
|||
SLOT(ThrottleEnableChanged(int)));
|
||||
QWidget::connect(_throttleCount, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(ThrottleCountChanged(int)));
|
||||
QWidget::connect(_keepActive, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(KeepActiveChanged(int)));
|
||||
QWidget::connect(_showMatch, SIGNAL(clicked()), this,
|
||||
SLOT(ShowMatchClicked()));
|
||||
QWidget::connect(this,
|
||||
|
|
@ -1334,6 +1359,11 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
|||
"AdvSceneSwitcher.condition.video.layout.throttle"),
|
||||
_throttleControlLayout, widgetPlaceholders);
|
||||
|
||||
QHBoxLayout *keepActiveLayout = new QHBoxLayout;
|
||||
keepActiveLayout->addWidget(_keepActive);
|
||||
keepActiveLayout->addWidget(_keepActiveHelp);
|
||||
keepActiveLayout->addStretch();
|
||||
|
||||
QHBoxLayout *showMatchLayout = new QHBoxLayout;
|
||||
showMatchLayout->addWidget(_showMatch);
|
||||
showMatchLayout->addStretch();
|
||||
|
|
@ -1349,6 +1379,7 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
|||
mainLayout->addWidget(_color);
|
||||
mainLayout->addLayout(_throttleControlLayout);
|
||||
mainLayout->addWidget(_area);
|
||||
mainLayout->addLayout(keepActiveLayout);
|
||||
mainLayout->addWidget(_reduceLatency);
|
||||
mainLayout->addLayout(showMatchLayout);
|
||||
setLayout(mainLayout);
|
||||
|
|
@ -1569,6 +1600,12 @@ void MacroConditionVideoEdit::ThrottleCountChanged(int value)
|
|||
_entryData->_throttleCount = value / GetIntervalValue();
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::KeepActiveChanged(int value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_keepActive = value;
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::ShowMatchClicked()
|
||||
{
|
||||
_previewDialog.show();
|
||||
|
|
@ -1634,6 +1671,11 @@ void MacroConditionVideoEdit::SetWidgetVisibility()
|
|||
needsThrottleControls(_entryData->GetCondition()));
|
||||
_area->setVisible(needsAreaControls(_entryData->GetCondition()));
|
||||
|
||||
const bool sourceOrScene = _entryData->_video.type !=
|
||||
VideoInput::Type::OBS_MAIN_OUTPUT;
|
||||
_keepActive->setVisible(sourceOrScene);
|
||||
_keepActiveHelp->setVisible(sourceOrScene);
|
||||
|
||||
if (_entryData->GetCondition() == VideoCondition::HAS_CHANGED ||
|
||||
_entryData->GetCondition() == VideoCondition::HAS_NOT_CHANGED) {
|
||||
_patternThreshold->setVisible(
|
||||
|
|
@ -1700,6 +1742,7 @@ void MacroConditionVideoEdit::UpdateEntryData()
|
|||
_throttleEnable->setChecked(_entryData->_throttleEnabled);
|
||||
_throttleCount->setValue(_entryData->_throttleCount *
|
||||
GetIntervalValue());
|
||||
_keepActive->setChecked(_entryData->_keepActive);
|
||||
UpdatePreviewTooltip();
|
||||
SetupPreviewDialogParams();
|
||||
SetWidgetVisibility();
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@
|
|||
#include "parameter-wrappers.hpp"
|
||||
#include "preview-dialog.hpp"
|
||||
|
||||
#include <help-icon.hpp>
|
||||
#include <macro-condition-edit.hpp>
|
||||
#include <file-selection.hpp>
|
||||
#include <screenshot-helper.hpp>
|
||||
#include <slider-spinbox.hpp>
|
||||
#include <source-helpers.hpp>
|
||||
#include <variable-line-edit.hpp>
|
||||
#include <variable-text-edit.hpp>
|
||||
|
||||
|
|
@ -53,6 +55,7 @@ public:
|
|||
void SetupTempVars();
|
||||
|
||||
VideoInput _video;
|
||||
bool _keepActive = false;
|
||||
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.
|
||||
|
|
@ -80,6 +83,7 @@ signals:
|
|||
|
||||
private:
|
||||
bool FileInputIsUpToDate() const;
|
||||
void UpdateActiveKeeper();
|
||||
|
||||
bool OutputChanged();
|
||||
bool ScreenshotContainsPattern();
|
||||
|
|
@ -92,6 +96,8 @@ private:
|
|||
|
||||
VideoCondition _condition = VideoCondition::MATCH;
|
||||
|
||||
SourceActiveKeeper _activeKeeper;
|
||||
OBSWeakSource _lastActiveKeeperSource;
|
||||
bool _getNextScreenshot = true;
|
||||
Screenshot _screenshotData;
|
||||
QImage _matchImage;
|
||||
|
|
@ -285,6 +291,7 @@ private slots:
|
|||
void ThrottleEnableChanged(int value);
|
||||
void ThrottleCountChanged(int value);
|
||||
void ShowMatchClicked();
|
||||
void KeepActiveChanged(int value);
|
||||
|
||||
void SetWidgetVisibility();
|
||||
void Resize();
|
||||
|
|
@ -326,6 +333,9 @@ private:
|
|||
QCheckBox *_throttleEnable;
|
||||
QSpinBox *_throttleCount;
|
||||
|
||||
QCheckBox *_keepActive;
|
||||
HelpIcon *_keepActiveHelp;
|
||||
|
||||
std::shared_ptr<MacroConditionVideo> _entryData;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user