obs/tools: Replace scene_contains_source
As the recursion checking code is somewhat broken in libOBS, we need something to prevent accidental recursion from occurring. While the alternative fix is to simply make all of libOBS support recursion, unfortunately that endeavor would be too large for a single person to take on.
This commit is contained in:
parent
e3c7b13d6f
commit
39548e760d
|
@ -19,67 +19,96 @@
|
|||
|
||||
#include "obs-tools.hpp"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include "obs-source.hpp"
|
||||
#include "obs-weak-source.hpp"
|
||||
#include "plugin.hpp"
|
||||
|
||||
struct scs_searchdata {
|
||||
obs_source_t* source;
|
||||
bool found = false;
|
||||
std::map<obs_source_t*, bool> visited;
|
||||
struct __sfs_data {
|
||||
std::set<::streamfx::obs::weak_source> sources;
|
||||
};
|
||||
|
||||
static bool scs_contains(scs_searchdata& sd, obs_source_t* source);
|
||||
|
||||
static void scs_enum_active_cb(obs_source_t*, obs_source_t* child, void* searchdata) noexcept
|
||||
try {
|
||||
scs_searchdata& sd = reinterpret_cast<scs_searchdata&>(*reinterpret_cast<scs_searchdata*>(searchdata));
|
||||
scs_contains(sd, child);
|
||||
} catch (...) {
|
||||
DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
}
|
||||
|
||||
static bool scs_enum_items_cb(obs_scene_t*, obs_sceneitem_t* item, void* searchdata) noexcept
|
||||
try {
|
||||
scs_searchdata& sd = reinterpret_cast<scs_searchdata&>(*reinterpret_cast<scs_searchdata*>(searchdata));
|
||||
obs_source_t* source = obs_sceneitem_get_source(item);
|
||||
return scs_contains(sd, source);
|
||||
} catch (...) {
|
||||
DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool scs_contains(scs_searchdata& sd, obs_source_t* source)
|
||||
void __source_find_source_enumerate(obs_source_t* haystack, __sfs_data* cbd)
|
||||
{
|
||||
if (sd.visited.find(source) != sd.visited.end()) {
|
||||
return false;
|
||||
} else {
|
||||
sd.visited.insert({source, true});
|
||||
auto tp = obs_source_get_type(haystack);
|
||||
|
||||
// Check if this source is already present in the set.
|
||||
::streamfx::obs::weak_source weak_child{haystack};
|
||||
if (!weak_child || (cbd->sources.find(weak_child) != cbd->sources.end())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (source == sd.source) {
|
||||
sd.found = true;
|
||||
// If it was not in the list, add it now.
|
||||
cbd->sources.insert(weak_child);
|
||||
|
||||
// Enumerate direct reference tree.
|
||||
obs_source_enum_full_tree(
|
||||
haystack,
|
||||
[](obs_source_t* parent, obs_source_t* child, void* param) {
|
||||
try {
|
||||
__source_find_source_enumerate(child, reinterpret_cast<__sfs_data*>(param));
|
||||
} catch (...) {
|
||||
}
|
||||
},
|
||||
cbd);
|
||||
|
||||
switch (tp) {
|
||||
case OBS_SOURCE_TYPE_SCENE: {
|
||||
obs_scene_enum_items(
|
||||
obs_scene_from_source(haystack),
|
||||
[](obs_scene_t* scene, obs_sceneitem_t* item, void* param) {
|
||||
try {
|
||||
__sfs_data* cbd = reinterpret_cast<__sfs_data*>(param);
|
||||
__source_find_source_enumerate(obs_sceneitem_get_source(item), cbd);
|
||||
return true;
|
||||
} else {
|
||||
if (strcmp(obs_source_get_id(source), "scene")) {
|
||||
obs_scene_t* nscene = obs_scene_from_source(source);
|
||||
obs_scene_enum_items(nscene, scs_enum_items_cb, &sd);
|
||||
} else {
|
||||
obs_source_enum_active_sources(source, scs_enum_active_cb, &sd);
|
||||
} catch (...) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
cbd);
|
||||
}
|
||||
#if __cplusplus >= 201700L
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
case OBS_SOURCE_TYPE_INPUT: {
|
||||
// Enumerate filter tree.
|
||||
obs_source_enum_filters(
|
||||
haystack,
|
||||
[](obs_source_t* parent, obs_source_t* child, void* param) {
|
||||
try {
|
||||
__sfs_data* cbd = reinterpret_cast<__sfs_data*>(param);
|
||||
__source_find_source_enumerate(child, cbd);
|
||||
} catch (...) {
|
||||
}
|
||||
},
|
||||
cbd);
|
||||
}
|
||||
#if __cplusplus >= 201700L
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sd.found) {
|
||||
return false;
|
||||
bool streamfx::obs::tools::source_find_source(::streamfx::obs::source haystack, ::streamfx::obs::source needle)
|
||||
{
|
||||
__sfs_data cbd = {};
|
||||
try {
|
||||
__source_find_source_enumerate(haystack.get(), &cbd);
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
for (auto weak_source : cbd.sources) {
|
||||
if (!weak_source)
|
||||
continue;
|
||||
|
||||
if (weak_source == needle)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool streamfx::obs::tools::scene_contains_source(obs_scene_t* scene, obs_source_t* source)
|
||||
{
|
||||
scs_searchdata sd;
|
||||
sd.source = source;
|
||||
obs_scene_enum_items(scene, scs_enum_items_cb, &sd);
|
||||
return sd.found;
|
||||
return false;
|
||||
}
|
||||
|
||||
streamfx::obs::tools::child_source::child_source(obs_source_t* parent, std::shared_ptr<obs_source_t> child)
|
||||
|
|
|
@ -19,10 +19,11 @@
|
|||
|
||||
#pragma once
|
||||
#include "common.hpp"
|
||||
#include "obs-source.hpp"
|
||||
|
||||
namespace streamfx::obs {
|
||||
namespace tools {
|
||||
bool scene_contains_source(obs_scene_t* scene, obs_source_t* source);
|
||||
bool source_find_source(::streamfx::obs::source haystack, ::streamfx::obs::source needle);
|
||||
|
||||
class child_source {
|
||||
obs_source_t* _parent;
|
||||
|
|
Loading…
Reference in New Issue