Add option to check for and set keyframe interval settings

This commit is contained in:
WarmUpTill
2023-04-25 23:28:01 +02:00
committed by WarmUpTill
parent 20f888b991
commit 8c317c1396
12 changed files with 203 additions and 70 deletions

View File

@@ -219,7 +219,7 @@ AdvSceneSwitcher.condition.stream.state.start="Stream läuft"
AdvSceneSwitcher.condition.stream.state.stop="Stream gestoppt"
AdvSceneSwitcher.condition.stream.state.starting="Stream wird gestartet"
AdvSceneSwitcher.condition.stream.state.stopping="Stream wird gestoppt"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.record="Aufnahme"
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
@@ -438,7 +438,7 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Stream"
AdvSceneSwitcher.action.streaming.type.stop="Stream stoppen"
AdvSceneSwitcher.action.streaming.type.start="Stream starten"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.run="Ausführen"
AdvSceneSwitcher.action.run.arguments="Argumente:"
AdvSceneSwitcher.action.run.addArgument="Argument hinzufügen"

View File

@@ -253,7 +253,8 @@ AdvSceneSwitcher.condition.stream.state.start="Stream running"
AdvSceneSwitcher.condition.stream.state.stop="Stream stopped"
AdvSceneSwitcher.condition.stream.state.starting="Stream starting"
AdvSceneSwitcher.condition.stream.state.stopping="Stream stopping"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.stream.state.keyFrameInterval="Keyframe interval equals"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.record="Recording"
AdvSceneSwitcher.condition.record.state.start="Recording running"
AdvSceneSwitcher.condition.record.state.pause="Recording paused"
@@ -477,7 +478,8 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Streaming"
AdvSceneSwitcher.action.streaming.type.stop="Stop streaming"
AdvSceneSwitcher.action.streaming.type.start="Start streaming"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.streaming.type.keyFrameInterval="Set keyframe interval"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.run="Run"
AdvSceneSwitcher.action.sceneVisibility="Scene item visibility"
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"

View File

@@ -179,7 +179,7 @@ AdvSceneSwitcher.condition.stream.state.start="Transmisión en ejecución"
AdvSceneSwitcher.condition.stream.state.stop="Transmisión detenida"
AdvSceneSwitcher.condition.stream.state.starting="Inicio de transmisión"
AdvSceneSwitcher.condition.stream.state.stopping="Detener transmisión"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.record="Grabación"
AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
@@ -360,7 +360,7 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Transmisión"
AdvSceneSwitcher.action.streaming.type.stop="Detener transmisión"
AdvSceneSwitcher.action.streaming.type.start="Iniciar transmisión"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.run="Ejecutar"
AdvSceneSwitcher.action.run.arguments="Argumentos:"
AdvSceneSwitcher.action.run.addArgument="Agregar argumento"

View File

@@ -144,7 +144,7 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Потоковое вещание"
AdvSceneSwitcher.action.streaming.type.stop="Остановить потоковое вещание"
AdvSceneSwitcher.action.streaming.type.start="Начать потоковое вещание"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.run="Запустить"

View File

@@ -156,7 +156,7 @@ AdvSceneSwitcher.condition.stream.state.start="Yayın çalışıyor"
AdvSceneSwitcher.condition.stream.state.stop="Yayın durdu"
AdvSceneSwitcher.condition.stream.state.starting="Yayın başlıyor"
AdvSceneSwitcher.condition.stream.state.stopping="Yayın duruyor"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.record="Kayıt"
AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
@@ -290,7 +290,7 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Yayın"
AdvSceneSwitcher.action.streaming.type.stop="Yayın durdur"
AdvSceneSwitcher.action.streaming.type.start="Yayın başlat"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.run="Çalıştır"
AdvSceneSwitcher.action.run.arguments="Argümanlar:"
AdvSceneSwitcher.action.run.addArgument="Argüman ekle"

View File

@@ -197,7 +197,7 @@ AdvSceneSwitcher.condition.stream.state.start="推流启动"
AdvSceneSwitcher.condition.stream.state.stop="推流停止"
AdvSceneSwitcher.condition.stream.state.starting="推流启动中"
AdvSceneSwitcher.condition.stream.state.stopping="推流停止中"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.record="录制"
AdvSceneSwitcher.condition.record.state.start="录制运行中"
AdvSceneSwitcher.condition.record.state.pause="录制暂停"
@@ -403,7 +403,7 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="推流"
AdvSceneSwitcher.action.streaming.type.stop="停止推流"
AdvSceneSwitcher.action.streaming.type.start="开始推流"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.run="运行"
AdvSceneSwitcher.action.run.arguments="参数:"
AdvSceneSwitcher.action.run.addArgument="添加参数"

View File

@@ -1,6 +1,8 @@
#include "macro-action-streaming.hpp"
#include "utility.hpp"
#include <util/config-file.h>
namespace advss {
const std::string MacroActionStream::id = "streaming";
@@ -10,15 +12,32 @@ bool MacroActionStream::_registered = MacroActionFactory::Register(
{MacroActionStream::Create, MacroActionStreamEdit::Create,
"AdvSceneSwitcher.action.streaming"});
const static std::map<StreamAction, std::string> actionTypes = {
{StreamAction::STOP, "AdvSceneSwitcher.action.streaming.type.stop"},
{StreamAction::START, "AdvSceneSwitcher.action.streaming.type.start"},
const static std::map<MacroActionStream::Action, std::string> actionTypes = {
{MacroActionStream::Action::STOP,
"AdvSceneSwitcher.action.streaming.type.stop"},
{MacroActionStream::Action::START,
"AdvSceneSwitcher.action.streaming.type.start"},
{MacroActionStream::Action::KEYFRAME_INTERVAL,
"AdvSceneSwitcher.action.streaming.type.keyFrameInterval"},
};
constexpr int streamStartCooldown = 5;
std::chrono::high_resolution_clock::time_point MacroActionStream::s_lastAttempt =
std::chrono::high_resolution_clock::now();
void MacroActionStream::SetKeyFrameInterval()
{
const auto configPath = GetPathInProfileDir("streamEncoder.json");
obs_data_t *settings =
obs_data_create_from_json_file_safe(configPath.c_str(), "bak");
obs_data_set_int(settings, "keyint_sec", _keyFrameInterval);
if (settings) {
obs_data_save_json_safe(settings, configPath.c_str(), "tmp",
"bak");
obs_data_release(settings);
}
}
bool MacroActionStream::CooldownDurationReached()
{
auto timePassed = std::chrono::duration_cast<std::chrono::seconds>(
@@ -29,12 +48,12 @@ bool MacroActionStream::CooldownDurationReached()
bool MacroActionStream::PerformAction()
{
switch (_action) {
case StreamAction::STOP:
case Action::STOP:
if (obs_frontend_streaming_active()) {
obs_frontend_streaming_stop();
}
break;
case StreamAction::START:
case Action::START:
if (!obs_frontend_streaming_active() &&
CooldownDurationReached()) {
obs_frontend_streaming_start();
@@ -42,6 +61,9 @@ bool MacroActionStream::PerformAction()
std::chrono::high_resolution_clock::now();
}
break;
case Action::KEYFRAME_INTERVAL:
SetKeyFrameInterval();
break;
default:
break;
}
@@ -63,13 +85,15 @@ bool MacroActionStream::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
obs_data_set_int(obj, "action", static_cast<int>(_action));
_keyFrameInterval.Save(obj, "keyFrameInterval");
return true;
}
bool MacroActionStream::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_action = static_cast<StreamAction>(obs_data_get_int(obj, "action"));
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
_keyFrameInterval.Load(obj, "keyFrameInterval");
return true;
}
@@ -82,21 +106,28 @@ static inline void populateActionSelection(QComboBox *list)
MacroActionStreamEdit::MacroActionStreamEdit(
QWidget *parent, std::shared_ptr<MacroActionStream> entryData)
: QWidget(parent)
: QWidget(parent),
_actions(new QComboBox()),
_keyFrameInterval(new VariableSpinBox())
{
_actions = new QComboBox();
_keyFrameInterval->setMinimum(0);
_keyFrameInterval->setMaximum(25);
populateActionSelection(_actions);
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int)));
QWidget::connect(
_keyFrameInterval,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this,
SLOT(KeyFrameIntervalChanged(const NumberVariable<int> &)));
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{actions}}", _actions},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.streaming.entry"),
mainLayout, widgetPlaceholders);
mainLayout,
{{"{{actions}}", _actions},
{"{{keyFrameInterval}}", _keyFrameInterval}});
setLayout(mainLayout);
_entryData = entryData;
@@ -110,6 +141,30 @@ void MacroActionStreamEdit::UpdateEntryData()
return;
}
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
_keyFrameInterval->SetValue(_entryData->_keyFrameInterval);
SetWidgetVisiblity();
}
void MacroActionStreamEdit::KeyFrameIntervalChanged(
const NumberVariable<int> &value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_keyFrameInterval = value;
}
void MacroActionStreamEdit::SetWidgetVisiblity()
{
if (!_entryData) {
return;
}
_keyFrameInterval->setVisible(
_entryData->_action ==
MacroActionStream::Action::KEYFRAME_INTERVAL);
}
void MacroActionStreamEdit::ActionChanged(int value)
@@ -119,7 +174,8 @@ void MacroActionStreamEdit::ActionChanged(int value)
}
auto lock = LockContext();
_entryData->_action = static_cast<StreamAction>(value);
_entryData->_action = static_cast<MacroActionStream::Action>(value);
SetWidgetVisiblity();
}
} // namespace advss

View File

@@ -1,5 +1,6 @@
#pragma once
#include "macro-action-edit.hpp"
#include "variable-spinbox.hpp"
#include <QDoubleSpinBox>
#include <QComboBox>
@@ -8,11 +9,6 @@
namespace advss {
enum class StreamAction {
STOP,
START,
};
class MacroActionStream : public MacroAction {
public:
MacroActionStream(Macro *m) : MacroAction(m) {}
@@ -26,9 +22,16 @@ public:
return std::make_shared<MacroActionStream>(m);
}
StreamAction _action = StreamAction::STOP;
enum class Action {
STOP,
START,
KEYFRAME_INTERVAL,
};
Action _action = Action::STOP;
NumberVariable<int> _keyFrameInterval = 0;
private:
void SetKeyFrameInterval();
bool CooldownDurationReached();
static std::chrono::high_resolution_clock::time_point s_lastAttempt;
@@ -54,12 +57,16 @@ public:
private slots:
void ActionChanged(int value);
void KeyFrameIntervalChanged(const NumberVariable<int> &);
protected:
QComboBox *_actions;
VariableSpinBox *_keyFrameInterval;
std::shared_ptr<MacroActionStream> _entryData;
private:
void SetWidgetVisiblity();
QHBoxLayout *_mainLayout;
bool _loading = true;
};

View File

@@ -11,36 +11,56 @@ bool MacroConditionStream::_registered = MacroConditionFactory::Register(
{MacroConditionStream::Create, MacroConditionStreamEdit::Create,
"AdvSceneSwitcher.condition.stream"});
static std::map<StreamState, std::string> streamStates = {
{StreamState::STOP, "AdvSceneSwitcher.condition.stream.state.stop"},
{StreamState::START, "AdvSceneSwitcher.condition.stream.state.start"},
{StreamState::STARTING,
static std::map<MacroConditionStream::Condition, std::string> streamStates = {
{MacroConditionStream::Condition::STOP,
"AdvSceneSwitcher.condition.stream.state.stop"},
{MacroConditionStream::Condition::START,
"AdvSceneSwitcher.condition.stream.state.start"},
{MacroConditionStream::Condition::STARTING,
"AdvSceneSwitcher.condition.stream.state.starting"},
{StreamState::STOPPING,
{MacroConditionStream::Condition::STOPPING,
"AdvSceneSwitcher.condition.stream.state.stopping"},
{MacroConditionStream::Condition::KEYFRAME_INTERVAL,
"AdvSceneSwitcher.condition.stream.state.keyFrameInterval"},
};
int MacroConditionStream::GetKeyFrameInterval()
{
const auto configPath = GetPathInProfileDir("streamEncoder.json");
obs_data_t *settings =
obs_data_create_from_json_file_safe(configPath.c_str(), "bak");
if (!settings) {
return -1;
}
int ret = obs_data_get_int(settings, "keyint_sec");
obs_data_release(settings);
return ret;
}
bool MacroConditionStream::CheckCondition()
{
bool stateMatch = false;
bool match = false;
bool streamStarting = switcher->lastStreamStartingTime !=
_lastStreamStartingTime;
bool streamStopping = switcher->lastStreamStoppingTime !=
_lastStreamStoppingTime;
switch (_streamState) {
case StreamState::STOP:
stateMatch = !obs_frontend_streaming_active();
switch (_condition) {
case Condition::STOP:
match = !obs_frontend_streaming_active();
break;
case StreamState::START:
stateMatch = obs_frontend_streaming_active();
case Condition::START:
match = obs_frontend_streaming_active();
break;
case StreamState::STARTING:
stateMatch = streamStarting;
case Condition::STARTING:
match = streamStarting;
break;
case StreamState::STOPPING:
stateMatch = streamStopping;
case Condition::STOPPING:
match = streamStopping;
break;
case Condition::KEYFRAME_INTERVAL:
match = GetKeyFrameInterval() == _keyFrameInterval;
break;
default:
break;
@@ -52,20 +72,22 @@ bool MacroConditionStream::CheckCondition()
if (streamStopping) {
_lastStreamStoppingTime = switcher->lastStreamStoppingTime;
}
return stateMatch;
return match;
}
bool MacroConditionStream::Save(obs_data_t *obj) const
{
MacroCondition::Save(obj);
obs_data_set_int(obj, "state", static_cast<int>(_streamState));
obs_data_set_int(obj, "state", static_cast<int>(_condition));
_keyFrameInterval.Save(obj, "keyFrameInterval");
return true;
}
bool MacroConditionStream::Load(obs_data_t *obj)
{
MacroCondition::Load(obj);
_streamState = static_cast<StreamState>(obs_data_get_int(obj, "state"));
_condition = static_cast<Condition>(obs_data_get_int(obj, "state"));
_keyFrameInterval.Load(obj, "keyFrameInterval");
return true;
}
@@ -78,23 +100,28 @@ static inline void populateStateSelection(QComboBox *list)
MacroConditionStreamEdit::MacroConditionStreamEdit(
QWidget *parent, std::shared_ptr<MacroConditionStream> entryData)
: QWidget(parent)
: QWidget(parent),
_streamState(new QComboBox()),
_keyFrameInterval(new VariableSpinBox())
{
_streamState = new QComboBox();
QWidget::connect(_streamState, SIGNAL(currentIndexChanged(int)), this,
SLOT(StateChanged(int)));
_keyFrameInterval->setMinimum(0);
_keyFrameInterval->setMaximum(25);
populateStateSelection(_streamState);
QWidget::connect(_streamState, SIGNAL(currentIndexChanged(int)), this,
SLOT(StateChanged(int)));
QWidget::connect(
_keyFrameInterval,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this,
SLOT(KeyFrameIntervalChanged(const NumberVariable<int> &)));
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{streamState}}", _streamState},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.stream.entry"),
mainLayout, widgetPlaceholders);
mainLayout,
{{"{{streamState}}", _streamState},
{"{{keyFrameInterval}}", _keyFrameInterval}});
setLayout(mainLayout);
_entryData = entryData;
@@ -109,7 +136,20 @@ void MacroConditionStreamEdit::StateChanged(int value)
}
auto lock = LockContext();
_entryData->_streamState = static_cast<StreamState>(value);
_entryData->_condition =
static_cast<MacroConditionStream::Condition>(value);
SetWidgetVisiblity();
}
void MacroConditionStreamEdit::KeyFrameIntervalChanged(
const NumberVariable<int> &value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_keyFrameInterval = value;
}
void MacroConditionStreamEdit::UpdateEntryData()
@@ -118,8 +158,19 @@ void MacroConditionStreamEdit::UpdateEntryData()
return;
}
_streamState->setCurrentIndex(
static_cast<int>(_entryData->_streamState));
_streamState->setCurrentIndex(static_cast<int>(_entryData->_condition));
_keyFrameInterval->SetValue(_entryData->_keyFrameInterval);
SetWidgetVisiblity();
}
void MacroConditionStreamEdit::SetWidgetVisiblity()
{
if (!_entryData) {
return;
}
_keyFrameInterval->setVisible(
_entryData->_condition ==
MacroConditionStream::Condition::KEYFRAME_INTERVAL);
}
} // namespace advss

View File

@@ -1,18 +1,12 @@
#pragma once
#include "macro-condition-edit.hpp"
#include "variable-spinbox.hpp"
#include <QWidget>
#include <QComboBox>
namespace advss {
enum class StreamState {
STOP,
START,
STARTING,
STOPPING,
};
class MacroConditionStream : public MacroCondition {
public:
MacroConditionStream(Macro *m) : MacroCondition(m) {}
@@ -25,9 +19,19 @@ public:
return std::make_shared<MacroConditionStream>(m);
}
StreamState _streamState = StreamState::STOP;
enum class Condition {
STOP,
START,
STARTING,
STOPPING,
KEYFRAME_INTERVAL,
};
Condition _condition = Condition::STOP;
NumberVariable<int> _keyFrameInterval = 0;
private:
int GetKeyFrameInterval();
std::chrono::high_resolution_clock::time_point _lastStreamStartingTime{};
std::chrono::high_resolution_clock::time_point _lastStreamStoppingTime{};
@@ -53,12 +57,16 @@ public:
private slots:
void StateChanged(int value);
void KeyFrameIntervalChanged(const NumberVariable<int> &);
protected:
QComboBox *_streamState;
VariableSpinBox *_keyFrameInterval;
std::shared_ptr<MacroConditionStream> _entryData;
private:
void SetWidgetVisiblity();
bool _loading = true;
};

View File

@@ -1120,4 +1120,12 @@ QString GetDefaultSettingsSaveLocation()
timestamp.toString("yyyy.MM.dd.hh.mm.ss");
}
std::string GetPathInProfileDir(const char *filePath)
{
auto path = obs_frontend_get_current_profile_path();
std::string result(path);
bfree(path);
return result + "/" + filePath;
}
} // namespace advss

View File

@@ -117,6 +117,7 @@ std::pair<int, int> GetCursorPos();
void ReplaceAll(std::string &str, const std::string &from,
const std::string &to);
QString GetDefaultSettingsSaveLocation();
std::string GetPathInProfileDir(const char *filePath);
/* Legacy helpers */