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
This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2018-10-01 00:54:36 +02:00
parent 382a217f06
commit daad792eda
2 changed files with 93 additions and 1 deletions

View File

@ -27,6 +27,7 @@
extern "C" { extern "C" {
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4201) #pragma warning(disable : 4201)
#include "callback/signal.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"
#include "graphics/matrix4.h" #include "graphics/matrix4.h"
#include "util/platform.h" #include "util/platform.h"
@ -353,6 +354,22 @@ obs_properties_t* filter::blur::instance::get_properties()
return true; return true;
}, },
p); 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("<filter-blur> 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 /// Shared
p = obs_properties_add_color(pr, P_MASK_COLOR, P_TRANSLATE(P_MASK_COLOR)); 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))); 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) { if (mask.source.name_old != mask.source.name) {
try { try {
mask.source.source_texture = std::make_shared<gfx::source_texture>(mask.source.name, m_source); mask.source.source_texture = std::make_shared<gfx::source_texture>(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; mask.source.name_old = mask.source.name;
} catch (...) { } catch (...) {
P_LOG_ERROR("<filter-blur> Instance '%s' failed to grab source '%s'.", obs_source_get_name(m_source), P_LOG_ERROR("<filter-blur> 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) { if (source_height == 0) {
source_height = baseH; 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); 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; source_info.video_render = video_render;
obs_register_source(&source_info); 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() 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<filter::blur::instance*>(inptr)->video_render(effect); reinterpret_cast<filter::blur::instance*>(inptr)->video_render(effect);
} }
void filter::blur::factory::scene_create_handler(void* ptr, calldata_t* data)
{
filter::blur::factory* self = reinterpret_cast<filter::blur::factory*>(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<filter::blur::factory*>(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<gs::effect> filter::blur::factory::get_effect(filter::blur::type type) std::shared_ptr<gs::effect> filter::blur::factory::get_effect(filter::blur::type type)
{ {
return effects.at(type); return effects.at(type);
@ -996,6 +1052,24 @@ std::shared_ptr<gs::texture> filter::blur::factory::get_kernel(filter::blur::typ
return kernels.at(type); 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<bool(obs_scene_t*)> fnc)
{
for (auto kv : scenes) {
if (!fnc(kv.second)) {
break;
}
}
}
static filter::blur::factory* factory_instance = nullptr; static filter::blur::factory* factory_instance = nullptr;
void filter::blur::factory::initialize() void filter::blur::factory::initialize()

View File

@ -18,6 +18,7 @@
*/ */
#pragma once #pragma once
#include <functional>
#include <list> #include <list>
#include <map> #include <map>
#include <memory> #include <memory>
@ -27,6 +28,13 @@
#include "gs-texture.h" #include "gs-texture.h"
#include "plugin.h" #include "plugin.h"
extern "C" {
#pragma warning(push)
#pragma warning(disable : 4201)
#include "callback/signal.h"
#pragma warning(pop)
}
namespace filter { namespace filter {
namespace blur { namespace blur {
enum type : int64_t { enum type : int64_t {
@ -78,6 +86,7 @@ namespace filter {
struct { struct {
std::string name_old; std::string name_old;
std::string name; std::string name;
bool is_scene;
std::shared_ptr<gfx::source_texture> source_texture; std::shared_ptr<gfx::source_texture> source_texture;
std::shared_ptr<gs::texture> texture; std::shared_ptr<gs::texture> texture;
} source; } source;
@ -129,6 +138,8 @@ namespace filter {
std::map<filter::blur::type, std::shared_ptr<gs::effect>> effects; std::map<filter::blur::type, std::shared_ptr<gs::effect>> effects;
std::map<filter::blur::type, std::shared_ptr<gs::texture>> kernels; std::map<filter::blur::type, std::shared_ptr<gs::texture>> kernels;
std::map<std::string, obs_scene_t*> scenes;
private: private:
factory(); factory();
~factory(); ~factory();
@ -157,6 +168,9 @@ namespace filter {
static void video_tick(void* source, float delta); static void video_tick(void* source, float delta);
static void video_render(void* source, gs_effect_t* effect); 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: public:
std::shared_ptr<gs::effect> get_effect(filter::blur::type type); std::shared_ptr<gs::effect> get_effect(filter::blur::type type);
@ -166,6 +180,10 @@ namespace filter {
std::shared_ptr<gs::texture> get_kernel(filter::blur::type type); std::shared_ptr<gs::texture> get_kernel(filter::blur::type type);
obs_scene_t* get_scene(std::string name);
void enum_scenes(std::function<bool(obs_scene_t*)> fnc);
public: // Singleton public: // Singleton
static void initialize(); static void initialize();
static void finalize(); static void finalize();