diff --git a/CMakeLists.txt b/CMakeLists.txt index 151be8c4..f9ab34ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -305,6 +305,8 @@ SET(PROJECT_PRIVATE "${PROJECT_SOURCE_DIR}/source/util-memory.cpp" "${PROJECT_SOURCE_DIR}/source/obs-source.hpp" "${PROJECT_SOURCE_DIR}/source/obs-source.cpp" + "${PROJECT_SOURCE_DIR}/source/obs-source-tracker.hpp" + "${PROJECT_SOURCE_DIR}/source/obs-source-tracker.cpp" ) source_group("Data Files\\Locale" FILES ${PROJECT_DATA_LOCALE}) diff --git a/source/obs-source-tracker.cpp b/source/obs-source-tracker.cpp new file mode 100644 index 00000000..0657c6c7 --- /dev/null +++ b/source/obs-source-tracker.cpp @@ -0,0 +1,164 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017-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-source-tracker.hpp" + +static std::shared_ptr source_tracker_instance; + +void obs::source_tracker::source_create_handler(void* ptr, calldata_t* data) +{ + obs::source_tracker* self = reinterpret_cast(ptr); + + obs_source_t* target = nullptr; + calldata_get_ptr(data, "source", &target); + + if (!target) { + return; + } + + const char* name = obs_source_get_name(target); + if (!name) { + // Do not track unnamed sources. + return; + } + + obs_weak_source_t* weak = obs_source_get_weak_source(target); + if (!weak) { + return; + } + + + self->source_map.insert({std::string(name), weak}); +} + +void obs::source_tracker::source_destroy_handler(void* ptr, calldata_t* data) +{ + obs::source_tracker* self = reinterpret_cast(ptr); + + obs_source_t* target = nullptr; + calldata_get_ptr(data, "source", &target); + + if (!target) { + return; + } + + const char* name = obs_source_get_name(target); + if (!name) { + // Not tracking unnamed sources. + return; + } + + auto found = self->source_map.find(std::string(name)); + if (found == self->source_map.end()) { + return; + } + + obs_weak_source_release(found->second); + self->source_map.erase(found); +} + +void obs::source_tracker::initialize() +{ + source_tracker_instance = std::make_shared(); +} + +void obs::source_tracker::finalize() +{ + source_tracker_instance.reset(); +} + +std::shared_ptr obs::source_tracker::get() +{ + return source_tracker_instance; +} + +obs::source_tracker::source_tracker() +{ + auto osi = obs_get_signal_handler(); + signal_handler_connect(osi, "source_create", &source_create_handler, this); + signal_handler_connect(osi, "source_destroy", &source_destroy_handler, this); +} + +obs::source_tracker::~source_tracker() +{ + auto osi = obs_get_signal_handler(); + if (osi) { + signal_handler_disconnect(osi, "source_create", &source_create_handler, this); + signal_handler_disconnect(osi, "source_destroy", &source_destroy_handler, this); + } + + for (auto kv : this->source_map) { + obs_weak_source_release(kv.second); + } + this->source_map.clear(); +} + +void obs::source_tracker::enumerate(enumerate_cb_t ecb, filter_cb_t fcb) { + // Need func-local copy, otherwise we risk corruption if a new source is created or destroyed. + auto source_map_copy = this->source_map; + for (auto kv : this->source_map) { + obs_source_t* source = obs_weak_source_get_source(kv.second); + if (!source) { + continue; + } + + if (fcb) { + if (fcb(kv.first, source)) { + obs_source_release(source); + continue; + } + } + + if (ecb) { + if (ecb(kv.first, source)) { + obs_source_release(source); + break; + } + } + + obs_source_release(source); + } +} + +bool obs::source_tracker::filter_sources(std::string name, obs_source_t* source) +{ + return (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT); +} + +bool obs::source_tracker::filter_audio_sources(std::string name, obs_source_t* source) +{ + uint32_t flags = obs_source_get_flags(source); + return !(flags & OBS_SOURCE_AUDIO) || (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT); +} + +bool obs::source_tracker::filter_video_sources(std::string name, obs_source_t* source) +{ + uint32_t flags = obs_source_get_flags(source); + return !(flags & OBS_SOURCE_VIDEO) || (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT); +} + +bool obs::source_tracker::filter_transitions(std::string name, obs_source_t* source) +{ + return (obs_source_get_type(source) != OBS_SOURCE_TYPE_TRANSITION); +} + +bool obs::source_tracker::filter_scenes(std::string name, obs_source_t* source) +{ + return (obs_source_get_type(source) != OBS_SOURCE_TYPE_SCENE); +} diff --git a/source/obs-source-tracker.hpp b/source/obs-source-tracker.hpp new file mode 100644 index 00000000..8c07b684 --- /dev/null +++ b/source/obs-source-tracker.hpp @@ -0,0 +1,81 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017-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 + */ + +#pragma once +#include +#include +#include + +// OBS +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4201) +#endif +#include +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace obs { + class source_tracker { + friend class std::_Ref_count_obj; + + std::map source_map; + + static void source_create_handler(void* ptr, calldata_t* data); + static void source_destroy_handler(void* ptr, calldata_t* data); + + public: // Singleton + static void initialize(); + static void finalize(); + static std::shared_ptr get(); + + private: + source_tracker(); + ~source_tracker(); + + public: + // Callback function for enumerating sources. + // + // @param std::string Name of the Source + // @param obs_source_t* Source + // @return true to abort enumeration, false to keep going. + typedef std::function enumerate_cb_t; + + // Filter function for enumerating sources. + // + // @param std::string Name of the Source + // @param obs_source_t* Source + // @return true to skip, false to pass along. + typedef std::function filter_cb_t; + + //! Enumerate all tracked sources + // + // @param enumerate_cb The function called for each tracked source. + // @param filter_cb Filter function to narrow down results. + void enumerate(enumerate_cb_t enumerate_cb, filter_cb_t filter_cb = nullptr); + + public: + static bool filter_sources(std::string name, obs_source_t* source); + static bool filter_audio_sources(std::string name, obs_source_t* source); + static bool filter_video_sources(std::string name, obs_source_t* source); + static bool filter_transitions(std::string name, obs_source_t* source); + static bool filter_scenes(std::string name, obs_source_t* source); + }; +} // namespace obs diff --git a/source/plugin.cpp b/source/plugin.cpp index ed572e2e..56203fc4 100644 --- a/source/plugin.cpp +++ b/source/plugin.cpp @@ -22,6 +22,7 @@ #include "filter-displacement.hpp" #include "filter-shape.hpp" #include "filter-transform.hpp" +#include "obs-source-tracker.hpp" std::list> initializerFunctions; std::list> finalizerFunctions; @@ -30,6 +31,7 @@ MODULE_EXPORT bool obs_module_load(void) { P_LOG_INFO("Loading Version %u.%u.%u (Build %u)", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH, PROJECT_VERSION_TWEAK); + obs::source_tracker::initialize(); for (auto func : initializerFunctions) { func(); } @@ -43,6 +45,7 @@ MODULE_EXPORT void obs_module_unload(void) for (auto func : finalizerFunctions) { func(); } + obs::source_tracker::finalize(); } #ifdef _WIN32