mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-04-26 00:01:13 -05:00
Fix crash when restoring scene item transition in parallel
This commit is contained in:
parent
03fe7016e4
commit
b030cf0a97
|
|
@ -1,7 +1,10 @@
|
||||||
#include "macro-action-scene-visibility.hpp"
|
#include "macro-action-scene-visibility.hpp"
|
||||||
#include "layout-helpers.hpp"
|
#include "layout-helpers.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
#include "transition-helpers.hpp"
|
#include "transition-helpers.hpp"
|
||||||
|
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
const std::string MacroActionSceneVisibility::id = "scene_visibility";
|
const std::string MacroActionSceneVisibility::id = "scene_visibility";
|
||||||
|
|
@ -24,43 +27,137 @@ const static std::map<MacroActionSceneVisibility::Action, std::string>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
struct TransitionRestoreContext;
|
||||||
|
static std::unordered_map<obs_sceneitem_t *, TransitionRestoreContext *>
|
||||||
|
restoreContexts;
|
||||||
|
static std::mutex restoreMutex;
|
||||||
|
|
||||||
struct TransitionRestoreContext {
|
struct TransitionRestoreContext {
|
||||||
|
public:
|
||||||
obs_sceneitem_t *item;
|
obs_sceneitem_t *item;
|
||||||
bool wasVisible;
|
bool wasVisible;
|
||||||
|
|
||||||
bool restoreTransition;
|
OBSSource originalTransition = nullptr;
|
||||||
OBSSource originalTransition;
|
|
||||||
bool restoreDuration;
|
|
||||||
uint32_t originalDuration;
|
uint32_t originalDuration;
|
||||||
|
|
||||||
|
obs_source_t *transition = nullptr;
|
||||||
signal_handler_t *sh = nullptr;
|
signal_handler_t *sh = nullptr;
|
||||||
|
|
||||||
~TransitionRestoreContext()
|
|
||||||
{
|
|
||||||
if (!sh) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
signal_handler_disconnect(
|
|
||||||
sh, "transition_stop",
|
|
||||||
&TransitionRestoreContext::ResetSceneItemTransition,
|
|
||||||
this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ResetSceneItemTransition(void *param, calldata_t *)
|
|
||||||
{
|
|
||||||
auto *ctx = static_cast<TransitionRestoreContext *>(param);
|
|
||||||
SetSceneItemTransition(ctx->item, ctx->originalTransition,
|
|
||||||
!ctx->wasVisible);
|
|
||||||
|
|
||||||
obs_sceneitem_set_transition_duration(
|
|
||||||
ctx->item, !ctx->wasVisible, ctx->originalDuration);
|
|
||||||
delete ctx;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
static void handleShutdown(enum obs_frontend_event event, void *private_data)
|
||||||
|
{
|
||||||
|
if (event != OBS_FRONTEND_EVENT_EXIT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(restoreMutex);
|
||||||
|
for (const auto &[_, ctx] : restoreContexts) {
|
||||||
|
obs_source_release(ctx->transition);
|
||||||
|
}
|
||||||
|
restoreContexts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setup()
|
||||||
|
{
|
||||||
|
obs_frontend_add_event_callback(handleShutdown, nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupDone = setup();
|
||||||
|
|
||||||
|
static void handleSourceDestroyed(void *param, calldata_t *)
|
||||||
|
{
|
||||||
|
if (OBSIsShuttingDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ctx = static_cast<TransitionRestoreContext *>(param);
|
||||||
|
ctx->sh = nullptr;
|
||||||
|
ctx->originalTransition = nullptr;
|
||||||
|
delete ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resetSceneItemTransition(void *param, calldata_t *)
|
||||||
|
{
|
||||||
|
if (OBSIsShuttingDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ctx = static_cast<TransitionRestoreContext *>(param);
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSceneItemTransition(ctx->item, ctx->originalTransition,
|
||||||
|
!ctx->wasVisible);
|
||||||
|
|
||||||
|
obs_sceneitem_set_transition_duration(ctx->item, !ctx->wasVisible,
|
||||||
|
ctx->originalDuration);
|
||||||
|
|
||||||
|
signal_handler_disconnect(ctx->sh, "transition_stop",
|
||||||
|
resetSceneItemTransition, ctx);
|
||||||
|
signal_handler_disconnect(ctx->sh, "destroy", handleSourceDestroyed,
|
||||||
|
ctx);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(restoreMutex);
|
||||||
|
restoreContexts.erase(ctx->item);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_release(ctx->transition);
|
||||||
|
delete ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void attachRestoreContext(obs_sceneitem_t *item,
|
||||||
|
obs_source_t *transition, bool itemWasVisible,
|
||||||
|
OBSSource originalTransition,
|
||||||
|
uint32_t originalDuration)
|
||||||
|
{
|
||||||
|
signal_handler_t *sh = obs_source_get_signal_handler(transition);
|
||||||
|
if (!sh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(restoreMutex);
|
||||||
|
|
||||||
|
auto ctx = new TransitionRestoreContext{
|
||||||
|
item,
|
||||||
|
itemWasVisible,
|
||||||
|
originalTransition,
|
||||||
|
originalDuration,
|
||||||
|
obs_source_get_ref(transition),
|
||||||
|
sh,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto it = restoreContexts.find(item);
|
||||||
|
if (it != restoreContexts.end()) {
|
||||||
|
auto *oldCtx = it->second;
|
||||||
|
|
||||||
|
signal_handler_disconnect(oldCtx->sh, "transition_stop",
|
||||||
|
resetSceneItemTransition, oldCtx);
|
||||||
|
|
||||||
|
signal_handler_disconnect(oldCtx->sh, "destroy",
|
||||||
|
handleSourceDestroyed, oldCtx);
|
||||||
|
|
||||||
|
ctx->originalTransition = oldCtx->originalTransition;
|
||||||
|
ctx->originalDuration = oldCtx->originalDuration;
|
||||||
|
|
||||||
|
obs_source_release(oldCtx->transition);
|
||||||
|
delete oldCtx;
|
||||||
|
|
||||||
|
restoreContexts.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreContexts[item] = ctx;
|
||||||
|
|
||||||
|
signal_handler_connect(sh, "transition_stop", resetSceneItemTransition,
|
||||||
|
ctx);
|
||||||
|
signal_handler_connect(sh, "destroy", handleSourceDestroyed, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
static void setSceneItemVisibility(obs_sceneitem_t *item,
|
static void setSceneItemVisibility(obs_sceneitem_t *item,
|
||||||
const bool setTransition,
|
const bool setTransition,
|
||||||
const OBSWeakSource &transitionWeak,
|
const OBSWeakSource &transitionWeak,
|
||||||
|
|
@ -76,7 +173,7 @@ static void setSceneItemVisibility(obs_sceneitem_t *item,
|
||||||
const uint32_t currentTransitionDuration =
|
const uint32_t currentTransitionDuration =
|
||||||
obs_sceneitem_get_transition_duration(item, !itemIsVisible);
|
obs_sceneitem_get_transition_duration(item, !itemIsVisible);
|
||||||
|
|
||||||
obs_source_t *privateTransitionSource = nullptr;
|
OBSSource privateTransitionSource = nullptr;
|
||||||
if (setTransition) {
|
if (setTransition) {
|
||||||
privateTransitionSource = SetSceneItemTransition(
|
privateTransitionSource = SetSceneItemTransition(
|
||||||
item, transition, !itemIsVisible);
|
item, transition, !itemIsVisible);
|
||||||
|
|
@ -102,6 +199,10 @@ static void setSceneItemVisibility(obs_sceneitem_t *item,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!setTransition && !setDuration) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!privateTransitionSource) {
|
if (!privateTransitionSource) {
|
||||||
if (setTransition) {
|
if (setTransition) {
|
||||||
SetSceneItemTransition(item, currentTransition,
|
SetSceneItemTransition(item, currentTransition,
|
||||||
|
|
@ -120,17 +221,8 @@ static void setSceneItemVisibility(obs_sceneitem_t *item,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ctx = new TransitionRestoreContext{item,
|
attachRestoreContext(item, privateTransitionSource, itemIsVisible,
|
||||||
itemIsVisible,
|
currentTransition, currentTransitionDuration);
|
||||||
setTransition,
|
|
||||||
currentTransition,
|
|
||||||
setDuration,
|
|
||||||
currentTransitionDuration,
|
|
||||||
sh};
|
|
||||||
|
|
||||||
signal_handler_connect(
|
|
||||||
sh, "transition_stop",
|
|
||||||
&TransitionRestoreContext::ResetSceneItemTransition, ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroActionSceneVisibility::PerformAction()
|
bool MacroActionSceneVisibility::PerformAction()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user