From daad792edac851ba79e3f3ee0627832750a95b84 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Mon, 1 Oct 2018 00:54:36 +0200 Subject: [PATCH] filter-blur: Add support for scene as mask input (#14) Adds full support for Scenes as mask input so that you can re-use your overlay scene as a blur input and have the blur follow behind your overlay. Closes #14 --- source/filter-blur.cpp | 76 +++++++++++++++++++++++++++++++++++++++++- source/filter-blur.h | 18 ++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/source/filter-blur.cpp b/source/filter-blur.cpp index c44a1841..8d2c9b8f 100644 --- a/source/filter-blur.cpp +++ b/source/filter-blur.cpp @@ -27,6 +27,7 @@ extern "C" { #pragma warning(push) #pragma warning(disable : 4201) +#include "callback/signal.h" #include "graphics/graphics.h" #include "graphics/matrix4.h" #include "util/platform.h" @@ -353,6 +354,22 @@ obs_properties_t* filter::blur::instance::get_properties() return true; }, p); + factory::get()->enum_scenes([this, p](obs_scene_t* scene) { + struct data { + instance* self; + obs_property_t* prop; + std::string parent_name; + }; + + obs_source_t* scene_source = obs_scene_get_source(scene); + P_LOG_DEBUG(" Instance '%s' adding scene '%s'.", obs_source_get_name(m_source), + obs_source_get_name(scene_source)); + obs_property_list_add_string(p, + std::string(std::string(obs_source_get_name(scene_source)) + " (Scene)").c_str(), + obs_source_get_name(scene_source)); + return true; + }); + /// Shared p = obs_properties_add_color(pr, P_MASK_COLOR, P_TRANSLATE(P_MASK_COLOR)); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_MASK_COLOR))); @@ -454,6 +471,7 @@ void filter::blur::instance::video_tick(float) if (mask.source.name_old != mask.source.name) { try { mask.source.source_texture = std::make_shared(mask.source.name, m_source); + mask.source.is_scene = (obs_scene_from_source(mask.source.source_texture->get_object()) != nullptr); mask.source.name_old = mask.source.name; } catch (...) { P_LOG_ERROR(" Instance '%s' failed to grab source '%s'.", obs_source_get_name(m_source), @@ -684,6 +702,13 @@ void filter::blur::instance::video_render(gs_effect_t* effect) if (source_height == 0) { source_height = baseH; } + if (mask.source.is_scene) { + obs_video_info ovi; + if (obs_get_video_info(&ovi)) { + source_width = ovi.base_width; + source_height = ovi.base_height; + } + } mask.source.texture = mask.source.source_texture->render(source_width, source_height); } @@ -769,9 +794,18 @@ filter::blur::factory::factory() source_info.video_render = video_render; obs_register_source(&source_info); + + auto osi = obs_get_signal_handler(); + signal_handler_connect(osi, "source_create", scene_create_handler, this); + signal_handler_connect(osi, "source_destroy", scene_destroy_handler, this); } -filter::blur::factory::~factory() {} +filter::blur::factory::~factory() +{ + auto osi = obs_get_signal_handler(); + signal_handler_disconnect(osi, "source_create", scene_create_handler, this); + signal_handler_disconnect(osi, "source_destroy", scene_destroy_handler, this); +} void filter::blur::factory::on_list_fill() { @@ -976,6 +1010,28 @@ void filter::blur::factory::video_render(void* inptr, gs_effect_t* effect) reinterpret_cast(inptr)->video_render(effect); } +void filter::blur::factory::scene_create_handler(void* ptr, calldata_t* data) +{ + filter::blur::factory* self = reinterpret_cast(ptr); + obs_source_t* source = nullptr; + calldata_get_ptr(data, "source", &source); + obs_scene_t* scene = obs_scene_from_source(source); + if (scene) { + self->scenes.insert_or_assign(std::string(obs_source_get_name(source)), scene); + } +} + +void filter::blur::factory::scene_destroy_handler(void* ptr, calldata_t* data) +{ + filter::blur::factory* self = reinterpret_cast(ptr); + obs_source_t* source = nullptr; + calldata_get_ptr(data, "source", &source); + obs_scene_t* scene = obs_scene_from_source(source); + if (scene) { + self->scenes.erase(std::string(obs_source_get_name(source))); + } +} + std::shared_ptr filter::blur::factory::get_effect(filter::blur::type type) { return effects.at(type); @@ -996,6 +1052,24 @@ std::shared_ptr filter::blur::factory::get_kernel(filter::blur::typ return kernels.at(type); } +obs_scene_t* filter::blur::factory::get_scene(std::string name) +{ + auto kv = scenes.find(name); + if (kv != scenes.end()) { + return kv->second; + } + return nullptr; +} + +void filter::blur::factory::enum_scenes(std::function fnc) +{ + for (auto kv : scenes) { + if (!fnc(kv.second)) { + break; + } + } +} + static filter::blur::factory* factory_instance = nullptr; void filter::blur::factory::initialize() diff --git a/source/filter-blur.h b/source/filter-blur.h index 540eb5b6..dd555cab 100644 --- a/source/filter-blur.h +++ b/source/filter-blur.h @@ -18,6 +18,7 @@ */ #pragma once +#include #include #include #include @@ -27,6 +28,13 @@ #include "gs-texture.h" #include "plugin.h" +extern "C" { +#pragma warning(push) +#pragma warning(disable : 4201) +#include "callback/signal.h" +#pragma warning(pop) +} + namespace filter { namespace blur { enum type : int64_t { @@ -78,6 +86,7 @@ namespace filter { struct { std::string name_old; std::string name; + bool is_scene; std::shared_ptr source_texture; std::shared_ptr texture; } source; @@ -129,6 +138,8 @@ namespace filter { std::map> effects; std::map> kernels; + std::map scenes; + private: factory(); ~factory(); @@ -157,6 +168,9 @@ namespace filter { static void video_tick(void* source, float delta); static void video_render(void* source, gs_effect_t* effect); + static void scene_create_handler(void* ptr, calldata_t* data); + static void scene_destroy_handler(void* ptr, calldata_t* data); + public: std::shared_ptr get_effect(filter::blur::type type); @@ -166,6 +180,10 @@ namespace filter { std::shared_ptr get_kernel(filter::blur::type type); + obs_scene_t* get_scene(std::string name); + + void enum_scenes(std::function fnc); + public: // Singleton static void initialize(); static void finalize();