diff --git a/source/sources/source-mirror.cpp b/source/sources/source-mirror.cpp index 6dd4c39..2c64096 100644 --- a/source/sources/source-mirror.cpp +++ b/source/sources/source-mirror.cpp @@ -50,55 +50,10 @@ using namespace source; -void mirror::mirror_instance::release() -{ - _source_item.reset(); - if (_source) { - _source->events.rename.clear(); - _source->events.audio_data.clear(); - } - _source.reset(); - _source_name.clear(); -} - -void mirror::mirror_instance::acquire(std::string source_name) -{ - using namespace std::placeholders; - - // Try and get source by name. - std::shared_ptr source = std::shared_ptr( - obs_get_source_by_name(source_name.c_str()), [](obs_source_t* ref) { obs_source_release(ref); }); - if (!source) { // If we failed, just exit early. - return; - } else if (source.get() == _self) { // Otherwise, if we somehow found self, also early exit. - return; - } - - // We seem to have a true link to a source, let's add it to our rendering. - obs_sceneitem_t* item = obs_scene_add(obs_scene_from_source(_scene.get()), source.get()); - if (!item) { // Can't add this source to our scene, probably due to one or more issues with it. - return; - } - - // It seems everything has worked out, so let's update our state. - _source = std::make_shared(source.get(), true, true); - _source_name = obs_source_get_name(source.get()); - _source_item = std::shared_ptr(item, [](obs_sceneitem_t* ref) { obs_sceneitem_remove(ref); }); - - // And let's hook up all our events too. - _source->events.rename.add(std::bind(&mirror::mirror_instance::on_source_rename, this, _1, _2, _3)); - if ((obs_source_get_output_flags(this->_source->get()) & OBS_SOURCE_AUDIO) != 0) - _source->events.audio_data.add(std::bind(&mirror::mirror_instance::on_audio_data, this, _1, _2, _3)); -} - mirror::mirror_instance::mirror_instance(obs_data_t* settings, obs_source_t* self) - : obs::source_instance(settings, self), _source(), _source_name(), _audio_enabled(), _audio_layout(), - _audio_kill_thread(), _audio_have_output() + : obs::source_instance(settings, self), _source(), _audio_enabled(), _audio_layout(), _audio_kill_thread(), + _audio_have_output() { - // Create Internal Scene - _scene = std::shared_ptr(obs_scene_get_source(obs_scene_create_private("")), - [](obs_source_t* ref) { obs_source_release(ref); }); - // Spawn Audio Thread _audio_thread = std::thread(std::bind(&mirror::mirror_instance::audio_output_cb, this)); @@ -115,19 +70,16 @@ mirror::mirror_instance::~mirror_instance() if (_audio_thread.joinable()) { _audio_thread.join(); } - - // Delete Internal Scene - _scene.reset(); } uint32_t mirror::mirror_instance::get_width() { - return _source_size.first; + return obs_source_get_width(_source.get()); } uint32_t mirror::mirror_instance::get_height() { - return _source_size.second; + return obs_source_get_height(_source.get()); } static void convert_config(obs_data_t* data) @@ -150,97 +102,87 @@ void mirror::mirror_instance::update(obs_data_t* data) { convert_config(data); - if (this->_source_name != obs_data_get_string(data, ST_SOURCE)) { - // Mirrored source was changed, release and reacquire. - release(); - - // Acquire the new source. - acquire(obs_data_get_string(data, ST_SOURCE)); - } + // Acquire new source. + acquire(obs_data_get_string(data, ST_SOURCE)); // Audio - this->_audio_enabled = obs_data_get_bool(data, ST_SOURCE_AUDIO); - this->_audio_layout = static_cast(obs_data_get_int(data, ST_SOURCE_AUDIO_LAYOUT)); + _audio_enabled = obs_data_get_bool(data, ST_SOURCE_AUDIO); + _audio_layout = static_cast(obs_data_get_int(data, ST_SOURCE_AUDIO_LAYOUT)); } void mirror::mirror_instance::load(obs_data_t* data) { - this->update(data); + update(data); } void mirror::mirror_instance::save(obs_data_t* data) { if (_source) { - obs_data_set_string(data, ST_SOURCE, obs_source_get_name(_source->get())); - } -} - -void mirror::mirror_instance::video_tick(float time) -{ - if (_source && ((obs_source_get_output_flags(_source->get()) & OBS_SOURCE_VIDEO) != 0)) { - _source_size.first = _source->width(); - _source_size.second = _source->height(); + obs_data_set_string(data, ST_SOURCE, obs_source_get_name(_source.get())); } else { - _source_size.first = 0; - _source_size.second = 0; - } - - if (_source_item && ((obs_source_get_output_flags(_source->get()) & OBS_SOURCE_VIDEO) != 0)) { - obs_transform_info info; - - /// Position, Rotation, Scale, Alignment, Bounding Box - vec2_set(&info.pos, 0, 0); - info.rot = 0; - vec2_set(&info.scale, 1., 1.); - info.alignment = OBS_ALIGN_LEFT | OBS_ALIGN_TOP; - vec2_set(&info.bounds, static_cast(_source_size.first), static_cast(_source_size.second)); - - info.bounds_alignment = 0; - info.bounds_type = OBS_BOUNDS_STRETCH; - - obs_sceneitem_set_info(_source_item.get(), &info); - obs_sceneitem_force_update_transform(_source_item.get()); - obs_sceneitem_set_scale_filter(_source_item.get(), OBS_SCALE_DISABLE); + obs_data_unset_user_value(data, ST_SOURCE); } } +void source::mirror::mirror_instance::show() +{ + _visible = obs_source_showing(_self); +} + +void source::mirror::mirror_instance::hide() +{ + _visible = obs_source_showing(_self); +} + +void source::mirror::mirror_instance::activate() +{ + _active = obs_source_active(_self); +} + +void source::mirror::mirror_instance::deactivate() +{ + _active = obs_source_active(_self); +} + +void mirror::mirror_instance::video_tick(float time) {} + void mirror::mirror_instance::video_render(gs_effect_t* effect) { - if (!_source || !_source_item) + if (!_source) return; - if ((obs_source_get_output_flags(_source->get()) & OBS_SOURCE_VIDEO) == 0) + if ((obs_source_get_output_flags(_source.get()) & OBS_SOURCE_VIDEO) == 0) return; - obs_source_video_render(_scene.get()); + obs_source_video_render(_source.get()); } void mirror::mirror_instance::audio_output_cb() noexcept try { - std::unique_lock ulock(this->_audio_lock_outputter); + std::unique_lock ulock(_audio_lock_outputter); - while (!this->_audio_kill_thread) { - this->_audio_notify.wait(ulock, [this]() { return this->_audio_have_output || this->_audio_kill_thread; }); + while (!_audio_kill_thread) { + _audio_notify.wait(ulock, [this]() { return _audio_have_output || _audio_kill_thread; }); - if (this->_audio_have_output) { // Get used audio element + if (_audio_have_output) { // Get used audio element std::shared_ptr mad; { - std::lock_guard capture_lock(this->_audio_lock_capturer); + std::lock_guard capture_lock(_audio_lock_capturer); if (_audio_data_queue.size() > 0) { mad = _audio_data_queue.front(); _audio_data_queue.pop(); } if (_audio_data_queue.size() == 0) { - this->_audio_have_output = false; + _audio_have_output = false; } } if (mad) { ulock.unlock(); - obs_source_output_audio(this->_self, &mad->audio); + obs_source_output_audio(_self, &mad->audio); ulock.lock(); { - std::lock_guard capture_lock(this->_audio_lock_capturer); + std::lock_guard capture_lock(_audio_lock_capturer); _audio_data_free_queue.push(mad); } } @@ -252,34 +194,63 @@ try { LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); } -void mirror::mirror_instance::enum_active_sources(obs_source_enum_proc_t enum_callback, void* param) +void mirror::mirror_instance::enum_active_sources(obs_source_enum_proc_t cb, void* ptr) { - /* if (_scene) { - enum_callback(_self, _scene.get(), param); - }*/ - if (_source) { - enum_callback(_self, _source->get(), param); - } + if (!_source || !_active) + return; + cb(_self, _source.get(), ptr); } -void mirror::mirror_instance::enum_all_sources(obs_source_enum_proc_t enum_callback, void* param) +void source::mirror::mirror_instance::enum_all_sources(obs_source_enum_proc_t cb, void* ptr) { - /* if (_scene) { - enum_callback(_self, _scene.get(), param); - }*/ - if (_source) { - enum_callback(_self, _source->get(), param); - } + if (!_source) + return; + + cb(_self, _source.get(), ptr); } -void mirror::mirror_instance::on_source_rename(obs::deprecated_source* source, std::string, std::string) +void mirror::mirror_instance::acquire(std::string source_name) +try { + // Find source by name if possible. + std::shared_ptr source = + std::shared_ptr{obs_get_source_by_name(source_name.c_str()), obs::obs_source_deleter}; + if ((!source) || (source.get() == _self)) { // If we failed, just exit early. + return; + } + + // Everything went well, store. + _source_child = std::make_shared(_self, source); + _source = source; + + // Listen to the rename event to update our own settings. + _signal_rename = std::make_shared("rename", _source); + _signal_rename->event.add( + std::bind(&source::mirror::mirror_instance::on_rename, this, std::placeholders::_1, std::placeholders::_2)); + + // Listen to any audio the source spews out. + _signal_audio = std::make_shared(_source); + _signal_audio->event.add(std::bind(&source::mirror::mirror_instance::on_audio, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)); +} catch (...) { + release(); +} + +void mirror::mirror_instance::release() +{ + _signal_audio.reset(); + _signal_rename.reset(); + _source_child.reset(); + _source.reset(); +} + +void source::mirror::mirror_instance::on_rename(std::shared_ptr, calldata*) { obs_source_save(_self); } -void mirror::mirror_instance::on_audio_data(obs::deprecated_source*, const audio_data* audio, bool) +void source::mirror::mirror_instance::on_audio(std::shared_ptr, const audio_data* audio, bool) { - if (!this->_audio_enabled) { + if (!_audio_enabled) { return; } @@ -294,7 +265,7 @@ void mirror::mirror_instance::on_audio_data(obs::deprecated_source*, const audio std::shared_ptr mad; { // Get free audio data element. - std::lock_guard capture_lock(this->_audio_lock_capturer); + std::lock_guard capture_lock(_audio_lock_capturer); if (_audio_data_free_queue.size() > 0) { mad = _audio_data_free_queue.front(); _audio_data_free_queue.pop(); @@ -324,23 +295,23 @@ void mirror::mirror_instance::on_audio_data(obs::deprecated_source*, const audio mad->audio.frames = audio->frames; mad->audio.timestamp = audio->timestamp; mad->audio.samples_per_sec = aoi->samples_per_sec; - if (this->_audio_layout != SPEAKERS_UNKNOWN) { - mad->audio.speakers = this->_audio_layout; + if (_audio_layout != SPEAKERS_UNKNOWN) { + mad->audio.speakers = _audio_layout; } else { mad->audio.speakers = aoi->speakers; } } { // Push used audio data element. - std::lock_guard capture_lock(this->_audio_lock_capturer); + std::lock_guard capture_lock(_audio_lock_capturer); _audio_data_queue.push(mad); } { // Signal other side. - std::lock_guard output_lock(this->_audio_lock_outputter); - this->_audio_have_output = true; + std::lock_guard output_lock(_audio_lock_outputter); + _audio_have_output = true; } - this->_audio_notify.notify_all(); + _audio_notify.notify_all(); } std::shared_ptr mirror::mirror_factory::factory_instance; @@ -349,9 +320,11 @@ mirror::mirror_factory::mirror_factory() { _info.id = "obs-stream-effects-source-mirror"; _info.type = OBS_SOURCE_TYPE_INPUT; - _info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_AUDIO; + _info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW | OBS_SOURCE_AUDIO; set_have_active_child_sources(true); + set_have_child_sources(true); + set_visibility_tracking_enabled(true); finish_setup(); } diff --git a/source/sources/source-mirror.hpp b/source/sources/source-mirror.hpp index 45000fb..b7fdc59 100644 --- a/source/sources/source-mirror.hpp +++ b/source/sources/source-mirror.hpp @@ -27,8 +27,10 @@ #include "gfx/gfx-source-texture.hpp" #include "obs/gs/gs-rendertarget.hpp" #include "obs/gs/gs-sampler.hpp" +#include "obs/obs-signal-handler.hpp" #include "obs/obs-source-factory.hpp" #include "obs/obs-source.hpp" +#include "obs/obs-tools.hpp" #include "plugin.hpp" // OBS @@ -48,12 +50,14 @@ namespace source::mirror { }; class mirror_instance : public obs::source_instance { - // Source - std::shared_ptr _source; - std::string _source_name; + bool _visible; + bool _active; - // Cached Data - std::pair _source_size; + // Source + std::shared_ptr _source; + std::shared_ptr _source_child; + std::shared_ptr _signal_rename; + std::shared_ptr _signal_audio; // Audio bool _audio_enabled; @@ -67,14 +71,6 @@ namespace source::mirror { std::queue> _audio_data_queue; std::queue> _audio_data_free_queue; - // Scene - std::shared_ptr _scene; - std::shared_ptr _source_item; - - private: - void release(); - void acquire(std::string source_name); - public: mirror_instance(obs_data_t* settings, obs_source_t* self); virtual ~mirror_instance(); @@ -86,16 +82,26 @@ namespace source::mirror { virtual void load(obs_data_t*) override; virtual void save(obs_data_t*) override; + virtual void show() override; + virtual void hide() override; + + virtual void activate() override; + virtual void deactivate() override; + virtual void video_tick(float) override; virtual void video_render(gs_effect_t*) override; virtual void enum_active_sources(obs_source_enum_proc_t, void*) override; virtual void enum_all_sources(obs_source_enum_proc_t, void*) override; + private: + void acquire(std::string source_name); + void release(); + void audio_output_cb() noexcept; - void on_source_rename(obs::deprecated_source* source, std::string new_name, std::string old_name); - void on_audio_data(obs::deprecated_source* source, const audio_data* audio, bool muted); + void on_rename(std::shared_ptr, calldata*); + void on_audio(std::shared_ptr, const struct audio_data*, bool); }; class mirror_factory : public obs::source_factory {