From e3c7b13d6fdb0be43c5a729bfed88ff09549b298 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Wed, 11 May 2022 05:33:38 +0200 Subject: [PATCH] obs/source-factory: Add support for OBS Studio 27.x Also improves the functionality logic slightly to be more in line with real behavior. --- source/filters/filter-autoframing.cpp | 2 +- source/filters/filter-blur.cpp | 2 +- source/filters/filter-color-grade.cpp | 2 +- source/filters/filter-denoising.cpp | 2 +- source/filters/filter-displacement.cpp | 2 +- source/filters/filter-dynamic-mask.cpp | 10 +- source/filters/filter-sdf-effects.cpp | 2 +- source/filters/filter-shader.cpp | 4 +- source/filters/filter-transform.cpp | 2 +- source/filters/filter-upscaling.cpp | 2 +- source/filters/filter-virtual-greenscreen.cpp | 2 +- source/obs/obs-source-factory.hpp | 1252 ++++++++++------- source/sources/source-mirror.cpp | 4 +- source/sources/source-shader.cpp | 4 +- source/transitions/transition-shader.cpp | 2 +- 15 files changed, 803 insertions(+), 491 deletions(-) diff --git a/source/filters/filter-autoframing.cpp b/source/filters/filter-autoframing.cpp index c86e1d14..5150c454 100644 --- a/source/filters/filter-autoframing.cpp +++ b/source/filters/filter-autoframing.cpp @@ -1086,7 +1086,7 @@ autoframing_factory::autoframing_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO; - set_resolution_enabled(true); + support_size(true); finish_setup(); // Register proxy identifiers. diff --git a/source/filters/filter-blur.cpp b/source/filters/filter-blur.cpp index 253ae683..b4f249c1 100644 --- a/source/filters/filter-blur.cpp +++ b/source/filters/filter-blur.cpp @@ -604,7 +604,7 @@ blur_factory::blur_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO; - set_resolution_enabled(false); + support_size(false); finish_setup(); register_proxy("obs-stream-effects-filter-blur"); } diff --git a/source/filters/filter-color-grade.cpp b/source/filters/filter-color-grade.cpp index d11093b3..dacb778c 100644 --- a/source/filters/filter-color-grade.cpp +++ b/source/filters/filter-color-grade.cpp @@ -584,7 +584,7 @@ color_grade_factory::color_grade_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO; - set_resolution_enabled(false); + support_size(false); finish_setup(); register_proxy("obs-stream-effects-filter-color-grade"); } diff --git a/source/filters/filter-denoising.cpp b/source/filters/filter-denoising.cpp index 670ffe06..3ff8c142 100644 --- a/source/filters/filter-denoising.cpp +++ b/source/filters/filter-denoising.cpp @@ -550,7 +550,7 @@ denoising_factory::denoising_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW; - set_resolution_enabled(true); + support_size(true); finish_setup(); // Proxies diff --git a/source/filters/filter-displacement.cpp b/source/filters/filter-displacement.cpp index 063130e0..64a28f86 100644 --- a/source/filters/filter-displacement.cpp +++ b/source/filters/filter-displacement.cpp @@ -150,7 +150,7 @@ displacement_factory::displacement_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW | OBS_SOURCE_DEPRECATED | OBS_SOURCE_CAP_DISABLED; - set_resolution_enabled(false); + support_size(false); finish_setup(); register_proxy("obs-stream-effects-filter-displacement"); } diff --git a/source/filters/filter-dynamic-mask.cpp b/source/filters/filter-dynamic-mask.cpp index fbc0956b..ca1b79ec 100644 --- a/source/filters/filter-dynamic-mask.cpp +++ b/source/filters/filter-dynamic-mask.cpp @@ -455,11 +455,11 @@ dynamic_mask_factory::dynamic_mask_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW; - set_have_active_child_sources(true); - set_have_child_sources(true); - set_resolution_enabled(false); - set_activity_tracking_enabled(true); - set_visibility_tracking_enabled(true); + support_active_child_sources(true); + support_child_sources(true); + support_size(false); + support_activity_tracking(true); + support_visibility_tracking(true); finish_setup(); register_proxy("obs-stream-effects-filter-dynamic-mask"); } diff --git a/source/filters/filter-sdf-effects.cpp b/source/filters/filter-sdf-effects.cpp index 8bfe1467..9d7877fa 100644 --- a/source/filters/filter-sdf-effects.cpp +++ b/source/filters/filter-sdf-effects.cpp @@ -570,7 +570,7 @@ sdf_effects_factory::sdf_effects_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO; - set_resolution_enabled(false); + support_size(false); finish_setup(); register_proxy("obs-stream-effects-filter-sdf-effects"); } diff --git a/source/filters/filter-shader.cpp b/source/filters/filter-shader.cpp index 7a191e5d..d47a8587 100644 --- a/source/filters/filter-shader.cpp +++ b/source/filters/filter-shader.cpp @@ -179,8 +179,8 @@ shader_factory::shader_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO; - set_activity_tracking_enabled(true); - set_visibility_tracking_enabled(true); + support_activity_tracking(true); + support_visibility_tracking(true); finish_setup(); register_proxy("obs-stream-effects-filter-shader"); } diff --git a/source/filters/filter-transform.cpp b/source/filters/filter-transform.cpp index 1ea1ea99..d06f655b 100644 --- a/source/filters/filter-transform.cpp +++ b/source/filters/filter-transform.cpp @@ -597,7 +597,7 @@ transform_factory::transform_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO; - set_resolution_enabled(false); + support_size(false); finish_setup(); register_proxy("obs-stream-effects-filter-transform"); } diff --git a/source/filters/filter-upscaling.cpp b/source/filters/filter-upscaling.cpp index 7829654f..d9ba6290 100644 --- a/source/filters/filter-upscaling.cpp +++ b/source/filters/filter-upscaling.cpp @@ -550,7 +550,7 @@ upscaling_factory::upscaling_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW /*| OBS_SOURCE_SRGB*/; - set_resolution_enabled(true); + support_size(true); finish_setup(); // Proxies diff --git a/source/filters/filter-virtual-greenscreen.cpp b/source/filters/filter-virtual-greenscreen.cpp index cf9640b9..b46b8108 100644 --- a/source/filters/filter-virtual-greenscreen.cpp +++ b/source/filters/filter-virtual-greenscreen.cpp @@ -554,7 +554,7 @@ virtual_greenscreen_factory::virtual_greenscreen_factory() _info.type = OBS_SOURCE_TYPE_FILTER; _info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW /*| OBS_SOURCE_SRGB*/; - set_resolution_enabled(true); + support_size(true); finish_setup(); } diff --git a/source/obs/obs-source-factory.hpp b/source/obs/obs-source-factory.hpp index 474b36b6..736d761a 100644 --- a/source/obs/obs-source-factory.hpp +++ b/source/obs/obs-source-factory.hpp @@ -19,7 +19,7 @@ #pragma once #include "common.hpp" -#include "plugin.hpp" +#include "obs-source.hpp" namespace streamfx::obs { template @@ -30,9 +30,10 @@ namespace streamfx::obs { std::set _proxy_names; public: - source_factory() + source_factory(obs_source_type type = OBS_SOURCE_TYPE_INPUT) { _info.type_data = this; + _info.type = type; _info.get_name = _get_name; _info.create = _create; @@ -43,126 +44,84 @@ namespace streamfx::obs { _info.update = _update; _info.save = _save; _info.filter_remove = _filter_remove; - - set_resolution_enabled(true); - set_activity_tracking_enabled(false); - set_visibility_tracking_enabled(false); - set_input_enabled(false); - set_have_child_sources(false); } virtual ~source_factory() {} protected: - void set_resolution_enabled(bool v) - { - if (v) { - _info.get_width = _get_width; - _info.get_height = _get_height; - } else { - _info.get_width = nullptr; - _info.get_height = nullptr; - } - } - - void set_activity_tracking_enabled(bool v) - { - if (v) { - _info.activate = _activate; - _info.deactivate = _deactivate; - } else { - _info.activate = nullptr; - _info.deactivate = nullptr; - } - } - - void set_visibility_tracking_enabled(bool v) - { - if (v) { - _info.show = _show; - _info.hide = _hide; - } else { - _info.show = nullptr; - _info.hide = nullptr; - } - } - - void set_input_enabled(bool v) - { - if (v) { - _info.mouse_click = _mouse_click; - _info.mouse_move = _mouse_move; - _info.mouse_wheel = _mouse_wheel; - _info.focus = _focus; - _info.key_click = _key_click; - } else { - _info.mouse_click = nullptr; - _info.mouse_move = nullptr; - _info.mouse_wheel = nullptr; - _info.focus = nullptr; - _info.key_click = nullptr; - } - } - - void set_have_child_sources(bool v) - { - if (v) { - _info.enum_all_sources = _enum_all_sources; - } else { - _info.enum_all_sources = nullptr; - } - } - - void set_have_active_child_sources(bool v) - { - if (v) { - _info.enum_active_sources = _enum_active_sources; - } else { - _info.enum_active_sources = nullptr; - } - } - void finish_setup() { - if (_info.output_flags & OBS_SOURCE_INTERACTION) { - set_input_enabled(true); - } else { - set_input_enabled(false); - } - + // Adjust options by type: + // - Transitions if (_info.type == OBS_SOURCE_TYPE_TRANSITION) { - set_resolution_enabled(false); + // Transitions don't have size. + support_size(false); + + // Transitions are also composite, video and custom draw, but never async. + _info.output_flags |= OBS_SOURCE_COMPOSITE | OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW; + _info.output_flags &= ~(OBS_SOURCE_ASYNC); + + // Transition controls. _info.transition_start = _transition_start; _info.transition_stop = _transition_stop; - _info.audio_render = _audio_render; - _info.video_tick = _video_tick; - _info.video_render = _video_render; - } else if (_info.type == OBS_SOURCE_TYPE_FILTER) { - switch (_info.output_flags & OBS_SOURCE_ASYNC_VIDEO) { - case OBS_SOURCE_ASYNC_VIDEO: - _info.filter_video = _filter_video; - break; - case OBS_SOURCE_VIDEO: + + // Transitions are always synchronous video. + _info.video_tick = _video_tick; + _info.video_render = _video_render; + } + // - Filter + if (_info.type == OBS_SOURCE_TYPE_FILTER) { + support_interaction(false); + + // If this is a video filter, require one of two code paths. + uint32_t av = (_info.output_flags & OBS_SOURCE_ASYNC_VIDEO); + if (av == OBS_SOURCE_VIDEO) { _info.video_tick = _video_tick; _info.video_render = _video_render_filter; - break; + } else if (av == OBS_SOURCE_ASYNC_VIDEO) { + _info.video_tick = _video_tick; + _info.filter_video = _filter_video; } - if ((_info.output_flags & OBS_SOURCE_AUDIO) != 0) { + + // If this is an audio filter + if ((_info.output_flags & OBS_SOURCE_AUDIO) == OBS_SOURCE_AUDIO) { _info.filter_audio = _filter_audio; - if ((_info.output_flags & OBS_SOURCE_COMPOSITE) != 0) { - _info.audio_render = _audio_render; - } } - } else { - if ((_info.output_flags & OBS_SOURCE_ASYNC_VIDEO) != 0) { - if ((_info.output_flags & OBS_SOURCE_ASYNC) == 0) { - set_resolution_enabled(true); - } + } + // - Input + if (_info.type == OBS_SOURCE_TYPE_INPUT) { + uint32_t av = (_info.output_flags & OBS_SOURCE_ASYNC_VIDEO); + if (av == OBS_SOURCE_VIDEO) { _info.video_tick = _video_tick; _info.video_render = _video_render; + support_size(true); + } else if (av == OBS_SOURCE_ASYNC_VIDEO) { + _info.video_tick = _video_tick; + support_size(false); } - if ((_info.output_flags & OBS_SOURCE_COMPOSITE) != 0) { - _info.audio_render = _audio_render; + } + + // Does the source have the composite audio flag? + if ((_info.output_flags & OBS_SOURCE_COMPOSITE) == OBS_SOURCE_COMPOSITE) { + // Does it also have some invalid flags? + if ((_info.output_flags & OBS_SOURCE_AUDIO) == OBS_SOURCE_AUDIO) { + throw std::runtime_error("Composite sources may not be audio sources."); } + if ((_info.output_flags & OBS_SOURCE_ASYNC) == OBS_SOURCE_ASYNC) { + throw std::runtime_error("Composite sources may not be asynchronous."); + } + // If not allow the assignment of audio_render. + _info.audio_render = _audio_render; + } + + // Does the source have the submix audio flag? (Internal to libOBS?) + if ((_info.output_flags & OBS_SOURCE_SUBMIX) == OBS_SOURCE_SUBMIX) { + if ((_info.output_flags & OBS_SOURCE_AUDIO) == OBS_SOURCE_AUDIO) { + throw std::runtime_error("Composite sources may not be audio sources."); + } + if ((_info.output_flags & OBS_SOURCE_COMPOSITE) == OBS_SOURCE_COMPOSITE) { + throw std::runtime_error("Submix sources may not be composite."); + } + _info.audio_mix = _audio_mix; } obs_register_source(&_info); @@ -184,354 +143,665 @@ namespace streamfx::obs { private /* Factory */: static const char* _get_name(void* type_data) noexcept - try { - if (type_data) - return reinterpret_cast<_factory*>(type_data)->get_name(); - return nullptr; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return nullptr; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return nullptr; + { + try { + if (type_data) + return reinterpret_cast<_factory*>(type_data)->get_name(); + return nullptr; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return nullptr; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return nullptr; + } } static void* _create(obs_data_t* settings, obs_source_t* source) noexcept - try { - return reinterpret_cast<_factory*>(obs_source_get_type_data(source))->create(settings, source); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return nullptr; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return nullptr; + { + try { + return reinterpret_cast<_factory*>(obs_source_get_type_data(source))->create(settings, source); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return nullptr; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return nullptr; + } } static void _get_defaults2(void* type_data, obs_data_t* settings) noexcept - try { - if (type_data) - reinterpret_cast<_factory*>(type_data)->get_defaults2(settings); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + { + try { + if (type_data) + reinterpret_cast<_factory*>(type_data)->get_defaults2(settings); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } } static obs_properties_t* _get_properties2(void* data, void* type_data) noexcept - try { - if (type_data) - return reinterpret_cast<_factory*>(type_data)->get_properties2(reinterpret_cast<_instance*>(data)); - return nullptr; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return nullptr; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return nullptr; + { + try { + if (type_data) + return reinterpret_cast<_factory*>(type_data)->get_properties2(reinterpret_cast<_instance*>(data)); + return nullptr; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return nullptr; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return nullptr; + } } private /* Instance */: static void _destroy(void* data) noexcept - try { - if (data) - delete reinterpret_cast<_instance*>(data); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static uint32_t _get_width(void* data) noexcept - try { - if (data) - return reinterpret_cast<_instance*>(data)->get_width(); - return 0; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return 0; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return 0; - } - - static uint32_t _get_height(void* data) noexcept - try { - if (data) - return reinterpret_cast<_instance*>(data)->get_height(); - return 0; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return 0; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return 0; - } - - static void _activate(void* data) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->activate(); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _deactivate(void* data) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->deactivate(); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _show(void* data) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->show(); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _hide(void* data) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->hide(); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _video_tick(void* data, float seconds) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->video_tick(seconds); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _video_render(void* data, gs_effect_t* effect) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->video_render(effect); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _video_render_filter(void* data, gs_effect_t* effect) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->video_render(effect); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - obs_source_skip_video_filter(reinterpret_cast<_instance*>(data)->get()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - obs_source_skip_video_filter(reinterpret_cast<_instance*>(data)->get()); - } - - static struct obs_source_frame* _filter_video(void* data, struct obs_source_frame* frame) noexcept - try { - if (data) - return reinterpret_cast<_instance*>(data)->filter_video(frame); - return frame; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return frame; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return frame; - } - - static struct obs_audio_data* _filter_audio(void* data, struct obs_audio_data* frame) noexcept - try { - if (data) - return reinterpret_cast<_instance*>(data)->filter_audio(frame); - return frame; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return frame; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return frame; - } - - static void _enum_active_sources(void* data, obs_source_enum_proc_t enum_callback, void* param) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->enum_active_sources(enum_callback, param); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _load(void* data, obs_data_t* settings) noexcept - try { - auto priv = reinterpret_cast<_instance*>(data); - if (priv) { - uint64_t version = static_cast(obs_data_get_int(settings, S_VERSION)); - priv->migrate(settings, version); - obs_data_set_int(settings, S_VERSION, static_cast(STREAMFX_VERSION)); - obs_data_set_string(settings, S_COMMIT, STREAMFX_COMMIT); - priv->load(settings); + { + try { + if (data) + delete reinterpret_cast<_instance*>(data); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); } - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _update(void* data, obs_data_t* settings) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->update(settings); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _save(void* data, obs_data_t* settings) noexcept - try { - if (data) { - reinterpret_cast<_instance*>(data)->save(settings); - obs_data_set_int(settings, S_VERSION, static_cast(STREAMFX_VERSION)); - obs_data_set_string(settings, S_COMMIT, STREAMFX_COMMIT); - } - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _mouse_click(void* data, const struct obs_mouse_event* event, int32_t type, bool mouse_up, - uint32_t click_count) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->mouse_click(event, type, mouse_up, click_count); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _mouse_move(void* data, const struct obs_mouse_event* event, bool mouse_leave) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->mouse_move(event, mouse_leave); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _mouse_wheel(void* data, const struct obs_mouse_event* event, int x_delta, int y_delta) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->mouse_wheel(event, x_delta, y_delta); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _focus(void* data, bool focus) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->focus(focus); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _key_click(void* data, const struct obs_key_event* event, bool key_up) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->key_click(event, key_up); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); } static void _filter_remove(void* data, obs_source_t* source) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->filter_remove(source); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + { + try { + if (data) + reinterpret_cast<_instance*>(data)->filter_remove(source); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + public /* Instance > Video */: + static void _video_tick(void* data, float seconds) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->video_tick(seconds); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _video_render(void* data, gs_effect_t* effect) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->video_render(effect); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _video_render_filter(void* data, gs_effect_t* effect) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->video_render(effect); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + obs_source_skip_video_filter(reinterpret_cast<_instance*>(data)->get()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + obs_source_skip_video_filter(reinterpret_cast<_instance*>(data)->get()); + } + } + + static struct obs_source_frame* _filter_video(void* data, struct obs_source_frame* frame) noexcept + { + try { + if (data) + return reinterpret_cast<_instance*>(data)->filter_video(frame); + return frame; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return frame; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return frame; + } + } + + public /* Instance > Audio */: + static struct obs_audio_data* _filter_audio(void* data, struct obs_audio_data* frame) noexcept + { + try { + if (data) + return reinterpret_cast<_instance*>(data)->filter_audio(frame); + return frame; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return frame; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return frame; + } } static bool _audio_render(void* data, uint64_t* ts_out, struct obs_source_audio_mix* audio_output, uint32_t mixers, std::size_t channels, std::size_t sample_rate) noexcept - try { - if (data) - return reinterpret_cast<_instance*>(data)->audio_render(ts_out, audio_output, mixers, channels, - sample_rate); - return false; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return false; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return false; - } - - static void _enum_all_sources(void* data, obs_source_enum_proc_t enum_callback, void* param) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->enum_all_sources(enum_callback, param); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _transition_start(void* data) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->transition_start(); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - } - - static void _transition_stop(void* data) noexcept - try { - if (data) - reinterpret_cast<_instance*>(data)->transition_stop(); - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + { + try { + if (data) + return reinterpret_cast<_instance*>(data)->audio_render(ts_out, audio_output, mixers, channels, + sample_rate); + return false; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return false; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return false; + } } static bool _audio_mix(void* data, uint64_t* ts_out, struct audio_output_data* audio_output, std::size_t channels, std::size_t sample_rate) noexcept - try { - if (data) - return reinterpret_cast<_instance*>(data)->audio_mix(ts_out, audio_output, channels, sample_rate); - return false; - } catch (const std::exception& ex) { - DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); - return false; - } catch (...) { - DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); - return false; + { + try { + if (data) + return reinterpret_cast<_instance*>(data)->audio_mix(ts_out, audio_output, channels, sample_rate); + return false; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return false; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return false; + } + } + + public /* Instance > Transition */: + static void _transition_start(void* data) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->transition_start(); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _transition_stop(void* data) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->transition_stop(); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + public /* Instance > Resolution */: + void support_size(bool v) + { + if (v) { + _info.get_width = _get_width; + _info.get_height = _get_height; + } else { + _info.get_width = nullptr; + _info.get_height = nullptr; + } + } + + static uint32_t _get_width(void* data) noexcept + { + try { + if (data) + return reinterpret_cast<_instance*>(data)->get_width(); + return 0; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return 0; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return 0; + } + } + + static uint32_t _get_height(void* data) noexcept + { + try { + if (data) + return reinterpret_cast<_instance*>(data)->get_height(); + return 0; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return 0; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return 0; + } + } + + public /* Instance > Children */: + void support_active_child_sources(bool v) + { + if (v) { + _info.enum_active_sources = _enum_active_sources; + } else { + _info.enum_active_sources = nullptr; + } + } + + static void _enum_active_sources(void* data, obs_source_enum_proc_t enum_callback, void* param) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->enum_active_sources(enum_callback, param); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + void support_child_sources(bool v) + { + if (v) { + _info.enum_all_sources = _enum_all_sources; + } else { + _info.enum_all_sources = nullptr; + } + } + + static void _enum_all_sources(void* data, obs_source_enum_proc_t enum_callback, void* param) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->enum_all_sources(enum_callback, param); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + public /* Instance > Configuration */: + static void _load(void* data, obs_data_t* settings) noexcept + { + try { + auto priv = reinterpret_cast<_instance*>(data); + if (priv) { + uint64_t version = static_cast(obs_data_get_int(settings, S_VERSION)); + priv->migrate(settings, version); + obs_data_set_int(settings, S_VERSION, static_cast(STREAMFX_VERSION)); + obs_data_set_string(settings, S_COMMIT, STREAMFX_COMMIT); + priv->load(settings); + } + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _update(void* data, obs_data_t* settings) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->update(settings); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _save(void* data, obs_data_t* settings) noexcept + { + try { + if (data) { + reinterpret_cast<_instance*>(data)->save(settings); + obs_data_set_int(settings, S_VERSION, static_cast(STREAMFX_VERSION)); + obs_data_set_string(settings, S_COMMIT, STREAMFX_COMMIT); + } + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + public /* Instance > Activity Tracking */: + void support_activity_tracking(bool v) + { + if (v) { + _info.activate = _activate; + _info.deactivate = _deactivate; + } else { + _info.activate = nullptr; + _info.deactivate = nullptr; + } + } + + static void _activate(void* data) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->activate(); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _deactivate(void* data) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->deactivate(); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + public /* Instance > Visibility Tracking */: + void support_visibility_tracking(bool v) + { + if (v) { + _info.show = _show; + _info.hide = _hide; + } else { + _info.show = nullptr; + _info.hide = nullptr; + } + } + + static void _show(void* data) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->show(); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _hide(void* data) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->hide(); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + public /* Instance > Interaction */: + void support_interaction(bool v) + { + if (v) { + _info.output_flags |= (OBS_SOURCE_INTERACTION); + _info.mouse_click = _mouse_click; + _info.mouse_move = _mouse_move; + _info.mouse_wheel = _mouse_wheel; + _info.focus = _focus; + _info.key_click = _key_click; + } else { + _info.output_flags &= ~(OBS_SOURCE_INTERACTION); + _info.mouse_click = nullptr; + _info.mouse_move = nullptr; + _info.mouse_wheel = nullptr; + _info.focus = nullptr; + _info.key_click = nullptr; + } + } + + static void _mouse_click(void* data, const obs_mouse_event* event, int32_t type, bool mouse_up, + uint32_t click_count) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->mouse_click(event, type, mouse_up, click_count); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _mouse_move(void* data, const obs_mouse_event* event, bool mouse_leave) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->mouse_move(event, mouse_leave); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _mouse_wheel(void* data, const obs_mouse_event* event, int x_delta, int y_delta) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->mouse_wheel(event, x_delta, y_delta); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _focus(void* data, bool focus) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->focus(focus); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _key_click(void* data, const obs_key_event* event, bool key_up) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->key_click(event, key_up); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + public /* Instance > Media Controls */: + void support_media_controls(bool v) + { + if (v) { + _info.output_flags |= (OBS_SOURCE_CONTROLLABLE_MEDIA); + _info.media_play_pause = _media_play_pause; + _info.media_restart = _media_restart; + _info.media_stop = _media_stop; + _info.media_next = _media_next; + _info.media_previous = _media_previous; + _info.media_get_duration = _media_get_duration; + _info.media_get_time = _media_get_time; + _info.media_set_time = _media_set_time; + _info.media_get_state = _media_get_state; + } else { + _info.output_flags &= ~(OBS_SOURCE_CONTROLLABLE_MEDIA); + _info.media_play_pause = nullptr; + _info.media_restart = nullptr; + _info.media_stop = nullptr; + _info.media_next = nullptr; + _info.media_previous = nullptr; + _info.media_get_duration = nullptr; + _info.media_get_time = nullptr; + _info.media_set_time = nullptr; + _info.media_get_state = nullptr; + } + } + + static void _media_play_pause(void* data, bool pause) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->media_play_pause(pause); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _media_restart(void* data) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->media_restart(); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _media_stop(void* data) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->media_stop(); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _media_next(void* data) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->media_next(); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static void _media_previous(void* data) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->media_previous(); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static int64_t _media_get_duration(void* data) noexcept + { + try { + if (data) + return reinterpret_cast<_instance*>(data)->media_get_duration(); + return 0; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return 0; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return 0; + } + } + + static int64_t _media_get_time(void* data) noexcept + { + try { + if (data) + return reinterpret_cast<_instance*>(data)->media_get_time(); + return 0; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return 0; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return 0; + } + } + + static void _media_set_time(void* data, int64_t milliseconds) noexcept + { + try { + if (data) + reinterpret_cast<_instance*>(data)->media_set_time(milliseconds); + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + } + } + + static obs_media_state _media_get_state(void* data) noexcept + { + try { + if (data) + return reinterpret_cast<_instance*>(data)->media_get_state(); + return OBS_MEDIA_STATE_NONE; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return OBS_MEDIA_STATE_NONE; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return OBS_MEDIA_STATE_NONE; + } + } + + public /* Instance > Missing Files */: + void support_missing_files(bool v) + { + if (v) { + _info.missing_files = _missing_files; + } else { + _info.missing_files = nullptr; + } + } + + static obs_missing_files_t* _missing_files(void* data) + { + try { + if (data) + return reinterpret_cast<_instance*>(data)->missing_files(); + return nullptr; + } catch (const std::exception& ex) { + DLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what()); + return nullptr; + } catch (...) { + DLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); + return nullptr; + } } public: @@ -555,17 +825,53 @@ namespace streamfx::obs { class source_instance { protected: - obs_source_t* _self; + ::streamfx::obs::source _self; public: - source_instance(obs_data_t* settings, obs_source_t* source) : _self(source) {} + source_instance(obs_data_t* settings, obs_source_t* source) : _self(source, false, false) {} virtual ~source_instance(){}; - virtual obs_source_t* get() + virtual ::streamfx::obs::source get() { return _self; } + virtual void filter_remove(obs_source_t* source) {} + + public /* Instance > Video */: + virtual void video_tick(float_t seconds) {} + + virtual void video_render(gs_effect_t* effect) {} + + virtual struct obs_source_frame* filter_video(struct obs_source_frame* frame) + { + return frame; + } + + public /* Instance > Audio */: + virtual struct obs_audio_data* filter_audio(struct obs_audio_data* audio) + { + return audio; + } + + virtual bool audio_render(uint64_t* ts_out, struct obs_source_audio_mix* audio_output, uint32_t mixers, + std::size_t channels, std::size_t sample_rate) + { + return false; + } + + virtual bool audio_mix(uint64_t* ts_out, struct audio_output_data* audio_output, std::size_t channels, + std::size_t sample_rate) + { + return false; + } + + public /* Instance > Transition */: + virtual void transition_start() {} + + virtual void transition_stop() {} + + public /* Instance > Resolution */: virtual uint32_t get_width() { return 0; @@ -576,30 +882,12 @@ namespace streamfx::obs { return 0; } - virtual void activate() {} - - virtual void deactivate() {} - - virtual void show() {} - - virtual void hide() {} - - virtual void video_tick(float_t seconds) {} - - virtual void video_render(gs_effect_t* effect) {} - - virtual struct obs_source_frame* filter_video(struct obs_source_frame* frame) - { - return frame; - } - - virtual struct obs_audio_data* filter_audio(struct obs_audio_data* audio) - { - return audio; - } - + public /* Instance > Children */: virtual void enum_active_sources(obs_source_enum_proc_t enum_callback, void* param) {} + virtual void enum_all_sources(obs_source_enum_proc_t enum_callback, void* param) {} + + public /* Instance > Configuration */: virtual void load(obs_data_t* settings) {} virtual void migrate(obs_data_t* settings, uint64_t version) {} @@ -608,36 +896,60 @@ namespace streamfx::obs { virtual void save(obs_data_t* settings) {} - virtual void mouse_click(const struct obs_mouse_event* event, int32_t type, bool mouse_up, uint32_t click_count) - {} + public /* Instance > Activity Tracking */: + virtual void activate() {} - virtual void mouse_move(const struct obs_mouse_event* event, bool mouse_leave) {} + virtual void deactivate() {} - virtual void mouse_wheel(const struct obs_mouse_event* event, int32_t x_delta, int32_t y_delta) {} + public /* Instance > Visibility Tracking */: + virtual void show() {} + + virtual void hide() {} + + public /* Instance > Interaction */: + virtual void mouse_click(const obs_mouse_event* event, int32_t type, bool mouse_up, uint32_t click_count) {} + + virtual void mouse_move(const obs_mouse_event* event, bool mouse_leave) {} + + virtual void mouse_wheel(const obs_mouse_event* event, int32_t x_delta, int32_t y_delta) {} virtual void focus(bool focus) {} - virtual void key_click(const struct obs_key_event* event, bool key_up) {} + virtual void key_click(const obs_key_event* event, bool key_up) {} - virtual void filter_remove(obs_source_t* source) {} + public /* Media Controls */: + virtual void media_play_pause(bool pause){}; - virtual bool audio_render(uint64_t* ts_out, struct obs_source_audio_mix* audio_output, uint32_t mixers, - std::size_t channels, std::size_t sample_rate) + virtual void media_restart(){}; + + virtual void media_stop(){}; + + virtual void media_next(){}; + + virtual void media_previous(){}; + + virtual int64_t media_get_duration() { - return false; + return 0; } - virtual void enum_all_sources(obs_source_enum_proc_t enum_callback, void* param) {} - - virtual void transition_start() {} - - virtual void transition_stop() {} - - virtual bool audio_mix(uint64_t* ts_out, struct audio_output_data* audio_output, std::size_t channels, - std::size_t sample_rate) + virtual int64_t media_get_time() { - return false; + return 0; } + + virtual void media_set_time(int64_t milliseconds) {} + + virtual obs_media_state media_get_state() + { + return OBS_MEDIA_STATE_NONE; + } + + public /* Missing Files */: + virtual obs_missing_files_t* missing_files() + { + return nullptr; + }; }; } // namespace streamfx::obs diff --git a/source/sources/source-mirror.cpp b/source/sources/source-mirror.cpp index 8a4e2fe3..86b452cd 100644 --- a/source/sources/source-mirror.cpp +++ b/source/sources/source-mirror.cpp @@ -296,8 +296,8 @@ mirror_factory::mirror_factory() _info.type = OBS_SOURCE_TYPE_INPUT; _info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW | OBS_SOURCE_AUDIO; - set_have_active_child_sources(true); - set_have_child_sources(true); + support_active_child_sources(true); + support_child_sources(true); finish_setup(); register_proxy("obs-stream-effects-source-mirror"); } diff --git a/source/sources/source-shader.cpp b/source/sources/source-shader.cpp index d0bd5b3c..c8098e37 100644 --- a/source/sources/source-shader.cpp +++ b/source/sources/source-shader.cpp @@ -132,8 +132,8 @@ shader_factory::shader_factory() _info.type = OBS_SOURCE_TYPE_INPUT; _info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW; - set_activity_tracking_enabled(true); - set_visibility_tracking_enabled(true); + support_activity_tracking(true); + support_visibility_tracking(true); finish_setup(); register_proxy("obs-stream-effects-source-shader"); } diff --git a/source/transitions/transition-shader.cpp b/source/transitions/transition-shader.cpp index 49c2cf45..0dad6de8 100644 --- a/source/transitions/transition-shader.cpp +++ b/source/transitions/transition-shader.cpp @@ -145,7 +145,7 @@ shader_factory::shader_factory() _info.type = OBS_SOURCE_TYPE_TRANSITION; _info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW; - //set_activity_tracking_enabled(true); // Handled via transition start/stop + //support_activity_tracking(true); // Handled via transition start/stop finish_setup(); register_proxy("obs-stream-effects-transition-shader"); }