obs-StreamFX/source/obs/obs-tools.cpp
Michael Fabian 'Xaymar' Dirks cc9d3486b2 project: Fix Linux support by fixing errors and warnings
With this, GCC 8 and above should now be able to compile the project both in obs-studio and as a standalone install. Some features are currently still not fully supported and require extra work, but the majority of things are supported and work out of the box. Exact feature parity can be looked up here on the wiki: https://github.com/Xaymar/obs-StreamFX/wiki/Platform-Feature-Parity

Related: #119 #98 #30
2020-04-02 20:37:45 +02:00

189 lines
5.7 KiB
C++

/*
* Modern effects for a modern Streamer
* Copyright (C) 2018 Michael Fabian Dirks
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "obs-tools.hpp"
#include <map>
#include <stdexcept>
#include "plugin.hpp"
struct scs_searchdata {
obs_source_t* source;
bool found = false;
std::map<obs_source_t*, bool> visited;
};
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 (...) {
LOG_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 (...) {
LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
return false;
}
static bool scs_contains(scs_searchdata& sd, obs_source_t* source)
{
if (sd.visited.find(source) != sd.visited.end()) {
return false;
} else {
sd.visited.insert({source, true});
}
if (source == sd.source) {
sd.found = true;
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);
}
}
if (sd.found) {
return false;
}
return true;
}
bool 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;
}
extern "C" {
struct _hack_obs_properties;
struct _hack_obs_property {
char* name;
char* desc;
char* long_desc;
void* priv;
enum obs_property_type type;
bool visible;
bool enabled;
struct _hack_obs_properties* parent;
obs_property_modified_t modified;
obs_property_modified2_t modified2;
struct _hack_obs_property* next;
};
struct _hack_obs_properties {
void* param;
void (*destroy)(void* param);
uint32_t flags;
struct _hack_obs_property* first_property;
struct _hack_obs_property** last;
struct _hack_obs_property* parent;
};
}
bool obs::tools::obs_properties_remove_by_name(obs_properties_t* props, const char* name)
{
// Due to a bug in obs_properties_remove_by_name, calling it on the first or last element of a group corrupts the
// obs_properties_t's first and last pointers, which now point at nonsense.
//
// There are two ways to work around this issue for now:
// 1. Add some invisible properties to the beginning and end of the list, ensuring that you never hit the first or
// last element with a obs_properties_remove_by_name.
// 2. Manually adjust the pointers using a dirty hack like in gs::mipmapper.
// I've opted for the 2nd way, at it is way simpler to implement.
// Assume that this is fixed in libobs 24.0.7 or newer.
if (obs_get_version() >= MAKE_SEMANTIC_VERSION(24, 0, 7)) {
::obs_properties_remove_by_name(props, name);
return true;
}
auto rprops = reinterpret_cast<_hack_obs_properties*>(props);
for (_hack_obs_property *el_prev = rprops->first_property, *el_cur = el_prev; el_cur != nullptr;
el_prev = el_cur, el_cur = el_cur->next) {
if (strcmp(el_cur->name, name) == 0) {
// Store some information.
_hack_obs_property* next = el_cur->next;
bool is_first = (rprops->first_property == el_cur);
bool is_last = (rprops->last == &el_cur->next);
bool is_solo = (el_cur == el_prev);
// Call the real one which fixes the element pointer and deallocates the element.
::obs_properties_remove_by_name(props, name);
// Fix up the memory pointers after the element was deleted.
if (is_last) {
if (is_solo) {
rprops->last = &rprops->first_property;
} else {
rprops->last = &el_prev->next;
}
}
if (is_first) {
rprops->first_property = next;
}
// Finally break out as we no longer have to process the properties list.
return true;
}
if (el_cur->type == OBS_PROPERTY_GROUP) {
if (obs::tools::obs_properties_remove_by_name(
obs_property_group_content(reinterpret_cast<obs_property_t*>(el_cur)), name))
return true;
}
}
return false;
}
obs::tools::child_source::child_source(obs_source_t* parent, std::shared_ptr<obs_source_t> child)
: _parent(parent), _child(child)
{
if (!obs_source_add_active_child(_parent, _child.get())) {
throw std::runtime_error("recursion detected");
}
}
obs::tools::child_source::~child_source()
{
obs_source_remove_active_child(_parent, _child.get());
}
std::shared_ptr<obs_source_t> obs::tools::child_source::get()
{
return _child;
}