From 5e60cefd1c4d566a80cb35894d4fdad7e3774367 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Tue, 2 Jun 2020 19:34:15 +0200 Subject: [PATCH 1/9] update current selection on media tab when selecting a different row --- src/advanced-scene-switcher.cpp | 9 ++++++- src/headers/advanced-scene-switcher.hpp | 1 + src/headers/switcher-data-structs.hpp | 6 +++-- src/media-switch.cpp | 34 ++++++++++++++++++++++++- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp index 574497a4..bfa87299 100644 --- a/src/advanced-scene-switcher.cpp +++ b/src/advanced-scene-switcher.cpp @@ -1240,12 +1240,19 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) array_obj, "restriction"); uint64_t time = obs_data_get_int(array_obj, "time"); + string mediaStr = MakeMediaSwitchName(source, scene, + transition, state, + restriction, time) + .toUtf8() + .constData(); + switcher->mediaSwitches.emplace_back( GetWeakSourceByName(scene), GetWeakSourceByName(source), GetWeakTransitionByName(transition), state, restriction, time, - (strcmp(scene, PREVIOUS_SCENE_NAME) == 0)); + (strcmp(scene, PREVIOUS_SCENE_NAME) == 0), + mediaStr); obs_data_release(array_obj); } diff --git a/src/headers/advanced-scene-switcher.hpp b/src/headers/advanced-scene-switcher.hpp index 179130d0..16ddd5be 100644 --- a/src/headers/advanced-scene-switcher.hpp +++ b/src/headers/advanced-scene-switcher.hpp @@ -120,6 +120,7 @@ public slots: void on_fileScenesList_currentRowChanged(int idx); void on_browseButton_3_clicked(); + void on_mediaSwitches_currentRowChanged(int idx); void on_mediaAdd_clicked(); void on_mediaRemove_clicked(); diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp index 26b86e06..23446bed 100644 --- a/src/headers/switcher-data-structs.hpp +++ b/src/headers/switcher-data-structs.hpp @@ -212,18 +212,20 @@ struct MediaSwitch { time_restriction restriction; bool matched; bool usePreviousScene; + std::string mediaSwitchStr; inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_, OBSWeakSource transition_, obs_media_state state_, time_restriction restriction_, uint64_t time_, - bool usePreviousScene_) + bool usePreviousScene_, std::string mediaSwitchStr_) : scene(scene_), source(source_), transition(transition_), state(state_), restriction(restriction_), time(time_), - usePreviousScene(usePreviousScene_) + usePreviousScene(usePreviousScene_), + mediaSwitchStr(mediaSwitchStr_) { } }; diff --git a/src/media-switch.cpp b/src/media-switch.cpp index 07dbb3a0..8545c591 100644 --- a/src/media-switch.cpp +++ b/src/media-switch.cpp @@ -1,6 +1,37 @@ #include #include "headers/advanced-scene-switcher.hpp" +void SceneSwitcher::on_mediaSwitches_currentRowChanged(int idx) +{ + if (loading) + return; + if (idx == -1) + return; + + QListWidgetItem *item = ui->mediaSwitches->item(idx); + + QString mediaSceneStr = item->data(Qt::UserRole).toString(); + + lock_guard lock(switcher->m); + for (auto &s : switcher->mediaSwitches) { + if (mediaSceneStr.compare(s.mediaSwitchStr.c_str()) == 0) { + QString sceneName = GetWeakSourceName(s.scene).c_str(); + QString sourceName = + GetWeakSourceName(s.source).c_str(); + QString transitionName = + GetWeakSourceName(s.transition).c_str(); + ui->mediaScenes->setCurrentText(sceneName); + ui->mediaSources->setCurrentText(sourceName); + ui->mediaTransitions->setCurrentText(transitionName); + ui->mediaStates->setCurrentIndex(s.state); + ui->mediaTimeRestrictions->setCurrentIndex( + s.restriction); + ui->mediaTime->setValue(s.time); + break; + } + } +} + void SceneSwitcher::on_mediaAdd_clicked() { QString sourceName = ui->mediaSources->currentText(); @@ -32,7 +63,8 @@ void SceneSwitcher::on_mediaAdd_clicked() lock_guard lock(switcher->m); switcher->mediaSwitches.emplace_back( scene, source, transition, state, restriction, time, - (sceneName == QString(PREVIOUS_SCENE_NAME))); + (sceneName == QString(PREVIOUS_SCENE_NAME)), + switchText.toUtf8().constData()); } void SceneSwitcher::on_mediaRemove_clicked() From e6a3f98ab79f345c5ef76ea224b0ec7fb4c64c53 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Tue, 2 Jun 2020 20:45:46 +0200 Subject: [PATCH 2/9] use source_id to identify meida sources --- src/advanced-scene-switcher.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp index bfa87299..a37438e1 100644 --- a/src/advanced-scene-switcher.cpp +++ b/src/advanced-scene-switcher.cpp @@ -64,8 +64,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent) auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */ { QComboBox *combo = reinterpret_cast(data); - if (obs_source_media_get_state(source) != - OBS_MEDIA_STATE_NONE) { + if (strcmp(obs_source_get_id(source), "ffmpeg_source") == 0) { const char *name = obs_source_get_name(source); combo->addItem(name); } From 5ab8199e0338ae79620f91c09fe2db0b51c62529 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Tue, 2 Jun 2020 20:53:26 +0200 Subject: [PATCH 3/9] add log on start / stop of switcher thread --- src/advanced-scene-switcher.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp index a37438e1..fe3a7fe6 100644 --- a/src/advanced-scene-switcher.cpp +++ b/src/advanced-scene-switcher.cpp @@ -1392,6 +1392,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) ********************************************************************************/ void SwitcherData::Thread() { + blog(LOG_INFO, "Advanced Scene Switcher started"); //to avoid scene duplication when rapidly switching scene collection this_thread::sleep_for(chrono::seconds(2)); @@ -1483,7 +1484,8 @@ void SwitcherData::Thread() switchScene(scene, transition, lock); } } -endLoop:; +endLoop: + blog(LOG_INFO, "Advanced Scene Switcher stopped"); } void switchScene(OBSWeakSource &scene, OBSWeakSource &transition, From b981a446b6631a8ebce7a7bcd0e5f06363bcf7e9 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Wed, 3 Jun 2020 19:55:06 +0200 Subject: [PATCH 4/9] fix for times switch not saving when using previous scene --- src/headers/switcher-data-structs.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp index 23446bed..bac54fe3 100644 --- a/src/headers/switcher-data-structs.hpp +++ b/src/headers/switcher-data-structs.hpp @@ -442,7 +442,8 @@ struct SwitcherData { for (size_t i = 0; i < timeSwitches.size(); i++) { TimeSwitch &s = timeSwitches[i]; - if (!WeakSourceValid(s.scene) || + if ((!s.usePreviousScene && + !WeakSourceValid(s.scene)) || !WeakSourceValid(s.transition)) timeSwitches.erase(timeSwitches.begin() + i--); } From 5082f5944e476c97deee17ad464de553e91bee6a Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Wed, 3 Jun 2020 19:56:18 +0200 Subject: [PATCH 5/9] prune media switches if invalid --- src/headers/switcher-data-structs.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp index bac54fe3..94a0c3b3 100644 --- a/src/headers/switcher-data-structs.hpp +++ b/src/headers/switcher-data-structs.hpp @@ -453,6 +453,16 @@ struct SwitcherData { !WeakSourceValid(idleData.transition)) { idleData.idleEnable = false; } + + for (size_t i = 0; i < mediaSwitches.size(); i++) { + MediaSwitch &s = mediaSwitches[i]; + if ((!s.usePreviousScene && + !WeakSourceValid(s.scene)) || + !WeakSourceValid(s.source) || + !WeakSourceValid(s.transition)) + mediaSwitches.erase(mediaSwitches.begin() + + i--); + } } inline ~SwitcherData() { Stop(); } }; From 9f03264672827046c689b576ed99e7149815fe39 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Thu, 4 Jun 2020 20:35:36 +0200 Subject: [PATCH 6/9] fix memory leak in check for media switch --- src/media-switch.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/media-switch.cpp b/src/media-switch.cpp index 8545c591..2b392f2c 100644 --- a/src/media-switch.cpp +++ b/src/media-switch.cpp @@ -118,5 +118,6 @@ void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene, transition = mediaSwitch.transition; } mediaSwitch.matched = matched; + obs_source_release(source); } } From 7fef29dafbc351c1c4d2d24c1db49ccac7e178f6 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Sat, 6 Jun 2020 08:59:03 +0200 Subject: [PATCH 7/9] fix media delete button deleting wrong entry the mediaSwitches UI is sorted alphabetically while the switches data strucutre is not the previous implementation of the delete function was just using the index of the currently selected row to delete this index of the switches data structure the new implementation will try to find the correct entry and delete it --- src/media-switch.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/media-switch.cpp b/src/media-switch.cpp index 2b392f2c..92e8767a 100644 --- a/src/media-switch.cpp +++ b/src/media-switch.cpp @@ -73,17 +73,23 @@ void SceneSwitcher::on_mediaRemove_clicked() if (!item) return; - int idx = ui->mediaSwitches->currentRow(); - if (idx == -1) - return; - + string mediaStr = + item->data(Qt::UserRole).toString().toUtf8().constData(); { lock_guard lock(switcher->m); - auto &switches = switcher->mediaSwitches; - switches.erase(switches.begin() + idx); + + for (auto it = switches.begin(); it != switches.end(); ++it) { + auto &s = *it; + + if (s.mediaSwitchStr == mediaStr) { + switches.erase(it); + break; + } + } } - qDeleteAll(ui->mediaSwitches->selectedItems()); + + delete item; } void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene, From f03fca85aa7960b6d9bf7205412f62ea94d141fc Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Sat, 6 Jun 2020 15:14:08 +0200 Subject: [PATCH 8/9] add thread priority option (using QThread) --- forms/advanced-scene-switcher.ui | 9 ++++- src/advanced-scene-switcher.cpp | 33 ++++++++++++---- src/general.cpp | 2 +- src/headers/advanced-scene-switcher.hpp | 1 + src/headers/switcher-data-structs.hpp | 36 ++++++++++++------ src/hotkey.cpp | 6 +-- src/priority.cpp | 50 ++++++++++++++++++------- 7 files changed, 101 insertions(+), 36 deletions(-) diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui index 17cad277..f31dbbf8 100644 --- a/forms/advanced-scene-switcher.ui +++ b/forms/advanced-scene-switcher.ui @@ -348,7 +348,7 @@ - Use thread priority (experimental) + Use thread priority @@ -368,6 +368,13 @@ + + + + (raising the priority higher than "Normal" is usually not recommended) + + + diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp index fe3a7fe6..7177656f 100644 --- a/src/advanced-scene-switcher.cpp +++ b/src/advanced-scene-switcher.cpp @@ -353,7 +353,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent) ui->readPathLineEdit->setDisabled(true); } - if (switcher->th.joinable()) + if (switcher->th && switcher->th->isRunning()) SetStarted(); else SetStopped(); @@ -400,8 +400,17 @@ SceneSwitcher::SceneSwitcher(QWidget *parent) item->setData(Qt::UserRole, text); } - for (std::string p : switcher->threadPrioritiesNamesOrderdByPrio) { - ui->threadPriority->addItem(p.c_str()); + for (int i = 0; i < switcher->threadPriorities.size(); ++i) { + ui->threadPriority->addItem( + switcher->threadPriorities[i].name.c_str()); + ui->threadPriority->setItemData( + i, switcher->threadPriorities[i].description.c_str(), + Qt::ToolTipRole); + if (switcher->threadPriority == + switcher->threadPriorities[i].value) { + ui->threadPriority->setCurrentText( + switcher->threadPriorities[i].name.c_str()); + } } } @@ -882,6 +891,9 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) obs_data_set_int(obj, "priority7", switcher->functionNamesByPriority[7]); + obs_data_set_int(obj, "threadPriority", + switcher->threadPriority); + obs_data_set_obj(save_data, "advanced-scene-switcher", obj); obs_data_array_release(array); @@ -1362,6 +1374,11 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *) (DEFAULT_PRIORITY_7); } + obs_data_set_default_int(obj, "threadPriority", + QThread::NormalPriority); + switcher->threadPriority = + obs_data_get_int(obj, "threadPriority"); + obs_data_array_release(array); obs_data_array_release(screenRegionArray); obs_data_array_release(pauseScenesArray); @@ -1544,19 +1561,21 @@ bool SwitcherData::sceneChangedDuringWait() void SwitcherData::Start() { - if (!th.joinable()) { + if (!(th && th->isRunning())) { stop = false; - switcher->th = thread([]() { switcher->Thread(); }); + switcher->th = QThread::create([]() { switcher->Thread(); }); + switcher->th->start((QThread::Priority)switcher->threadPriority); } } + void SwitcherData::Stop() { - if (th.joinable()) { + if (th && th->isRunning()) { switcher->stop = true; transitionCv.notify_one(); cv.notify_one(); - th.join(); + th->wait(); } } diff --git a/src/general.cpp b/src/general.cpp index 3fe65e72..9bc85203 100644 --- a/src/general.cpp +++ b/src/general.cpp @@ -89,7 +89,7 @@ void SceneSwitcher::SetStopped() void SceneSwitcher::on_toggleStartButton_clicked() { - if (switcher->th.joinable()) + if (switcher->th && switcher->th->isRunning()) { switcher->Stop(); SetStopped(); diff --git a/src/headers/advanced-scene-switcher.hpp b/src/headers/advanced-scene-switcher.hpp index 16ddd5be..e11e548e 100644 --- a/src/headers/advanced-scene-switcher.hpp +++ b/src/headers/advanced-scene-switcher.hpp @@ -130,6 +130,7 @@ public slots: void on_priorityUp_clicked(); void on_priorityDown_clicked(); + void on_threadPriority_currentTextChanged(const QString &text); void updateScreenRegionCursorPos(); diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp index 94a0c3b3..2a12d6ef 100644 --- a/src/headers/switcher-data-structs.hpp +++ b/src/headers/switcher-data-structs.hpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -256,7 +255,7 @@ typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch; * SwitcherData ********************************************************************************/ struct SwitcherData { - thread th; + QThread* th = nullptr; condition_variable cv; mutex m; bool transitionActive = false; @@ -311,18 +310,33 @@ struct SwitcherData { DEFAULT_PRIORITY_3, DEFAULT_PRIORITY_4, DEFAULT_PRIORITY_5, DEFAULT_PRIORITY_6, DEFAULT_PRIORITY_7}; - std::vector threadPrioritiesNamesOrderdByPrio{ - "Lowest", "Low", "Normal", "High", "Highest", "Time critical", + struct ThreadPrio { + std::string name; + std::string description; + uint32_t value; }; - std::map threadPriorities = { - {"Lowest", QThread::LowestPriority}, - {"Low", QThread::LowPriority}, - {"Normal", QThread::NormalPriority}, - {"High", QThread::HighPriority}, - {"Highest", QThread::HighestPriority}, - {"Time critical", QThread::TimeCriticalPriority}, + + std::vector threadPriorities{ + {"Idle", + "scheduled only when no other threads are running (lowest CPU load)", + QThread::IdlePriority}, + {"Lowest", "scheduled less often than LowPriority", + QThread::LowestPriority}, + {"Low", "scheduled less often than NormalPriority", + QThread::LowPriority}, + {"Normal", "the default priority of the operating system", + QThread::NormalPriority}, + {"High", "scheduled more often than NormalPriority", + QThread::HighPriority}, + {"Highest", "scheduled more often than HighPriority", + QThread::HighestPriority}, + {"Time critical", + "scheduled as often as possible (highest CPU load)", + QThread::TimeCriticalPriority}, }; + uint32_t threadPriority = QThread::NormalPriority; + void Thread(); void Start(); void Stop(); diff --git a/src/hotkey.cpp b/src/hotkey.cpp index 924eedbb..f95b5773 100644 --- a/src/hotkey.cpp +++ b/src/hotkey.cpp @@ -8,7 +8,7 @@ void startHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pr if (pressed) { - if (!switcher->th.joinable()) + if (!(switcher->th && switcher->th->isRunning())) switcher->Start(); } @@ -43,7 +43,7 @@ void stopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pre if (pressed) { - if (switcher->th.joinable()) + if (switcher->th && switcher->th->isRunning()) switcher->Stop(); } @@ -78,7 +78,7 @@ void startStopToggleHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotke if (pressed) { - if (switcher->th.joinable()) + if (switcher->th && switcher->th->isRunning()) switcher->Stop(); else switcher->Start(); diff --git a/src/priority.cpp b/src/priority.cpp index 22019b9c..60f5e30e 100644 --- a/src/priority.cpp +++ b/src/priority.cpp @@ -1,44 +1,68 @@ #include #include "headers/advanced-scene-switcher.hpp" +void SceneSwitcher::on_threadPriority_currentTextChanged(const QString &text) +{ + if (loading || ui->threadPriority->count() != switcher->threadPriorities.size()) + return; + + lock_guard lock(switcher->m); + + for (auto p : switcher->threadPriorities) { + if (p.name == text.toUtf8() + .constData()) { + switcher->threadPriority = p.value; + break; + } + } +} + void SceneSwitcher::on_priorityUp_clicked() { int currentIndex = ui->priorityList->currentRow(); - if (currentIndex != -1 && currentIndex != 0) - { - ui->priorityList->insertItem(currentIndex - 1 ,ui->priorityList->takeItem(currentIndex)); - ui->priorityList->setCurrentRow(currentIndex -1); + if (currentIndex != -1 && currentIndex != 0) { + ui->priorityList->insertItem( + currentIndex - 1, + ui->priorityList->takeItem(currentIndex)); + ui->priorityList->setCurrentRow(currentIndex - 1); lock_guard lock(switcher->m); - iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex - 1); + iter_swap(switcher->functionNamesByPriority.begin() + + currentIndex, + switcher->functionNamesByPriority.begin() + + currentIndex - 1); } } void SceneSwitcher::on_priorityDown_clicked() { int currentIndex = ui->priorityList->currentRow(); - if (currentIndex != -1 && currentIndex != ui->priorityList->count() - 1) - { - ui->priorityList->insertItem(currentIndex + 1, ui->priorityList->takeItem(currentIndex)); + if (currentIndex != -1 && + currentIndex != ui->priorityList->count() - 1) { + ui->priorityList->insertItem( + currentIndex + 1, + ui->priorityList->takeItem(currentIndex)); ui->priorityList->setCurrentRow(currentIndex + 1); lock_guard lock(switcher->m); - iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex + 1); + iter_swap(switcher->functionNamesByPriority.begin() + + currentIndex, + switcher->functionNamesByPriority.begin() + + currentIndex + 1); } } bool SwitcherData::prioFuncsValid() { - auto it = std::unique(functionNamesByPriority.begin(), functionNamesByPriority.end()); + auto it = std::unique(functionNamesByPriority.begin(), + functionNamesByPriority.end()); bool wasUnique = (it == functionNamesByPriority.end()); if (!wasUnique) return false; - for (int p : functionNamesByPriority) - { + for (int p : functionNamesByPriority) { if (p < 0 || p > 7) return false; } return true; } - From 98c3131017db23b04d3185599eee0229f72ac9b2 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Sat, 6 Jun 2020 18:51:26 +0200 Subject: [PATCH 9/9] do not use QThread::create there might still be versions of QT in use which do not yet have this functionality (see Linux build fail of f03fca8) --- src/advanced-scene-switcher.cpp | 4 +++- src/headers/switcher-data-structs.hpp | 12 +++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp index 7177656f..cbe89c0b 100644 --- a/src/advanced-scene-switcher.cpp +++ b/src/advanced-scene-switcher.cpp @@ -1563,7 +1563,7 @@ void SwitcherData::Start() { if (!(th && th->isRunning())) { stop = false; - switcher->th = QThread::create([]() { switcher->Thread(); }); + switcher->th = new SwitcherThread(); switcher->th->start((QThread::Priority)switcher->threadPriority); } } @@ -1576,6 +1576,8 @@ void SwitcherData::Stop() transitionCv.notify_one(); cv.notify_one(); th->wait(); + delete th; + th = nullptr; } } diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp index 2a12d6ef..97d5f90b 100644 --- a/src/headers/switcher-data-structs.hpp +++ b/src/headers/switcher-data-structs.hpp @@ -251,11 +251,14 @@ struct TimeSwitch { typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch; +class SwitcherThread; + /******************************************************************************** * SwitcherData ********************************************************************************/ struct SwitcherData { - QThread* th = nullptr; + SwitcherThread *th; + condition_variable cv; mutex m; bool transitionActive = false; @@ -480,3 +483,10 @@ struct SwitcherData { } inline ~SwitcherData() { Stop(); } }; + +extern SwitcherData *switcher; +class SwitcherThread : public QThread { +public: + explicit SwitcherThread(){}; + void run() { switcher->Thread(); }; +};