mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-24 12:25:11 +00:00
d47ab0570f
This class and template should be used to reduce the code clutter from repeatedly doing the same thing. It requires OBS v24.0 or newer since the get_properties2 and get_defaults2 API were fully implemented with it.
447 lines
16 KiB
C++
447 lines
16 KiB
C++
/*
|
|
* Modern effects for a modern Streamer
|
|
* Copyright (C) 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
|
|
*/
|
|
|
|
#ifndef STREAMEFFECTS_SOURCE_FACTORY_HPP
|
|
#define STREAMEFFECTS_SOURCE_FACTORY_HPP
|
|
|
|
#pragma once
|
|
#include "plugin.hpp"
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4201)
|
|
#endif
|
|
#include <obs-source.h>
|
|
#include <obs.h>
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
namespace obs {
|
|
template<class _factory, typename _instance>
|
|
class source_factory {
|
|
protected:
|
|
obs_source_info _info = {};
|
|
|
|
public:
|
|
source_factory()
|
|
{
|
|
_info.type_data = this;
|
|
|
|
_info.get_name = _get_name;
|
|
_info.create = _create;
|
|
_info.destroy = _destroy;
|
|
_info.get_defaults2 = _get_defaults2;
|
|
_info.get_properties2 = _get_properties2;
|
|
|
|
_info.get_width = _get_width;
|
|
_info.get_height = _get_height;
|
|
_info.update = _update;
|
|
_info.activate = _activate;
|
|
_info.deactivate = _deactivate;
|
|
_info.show = _show;
|
|
_info.hide = _hide;
|
|
_info.video_tick = _video_tick;
|
|
_info.video_render = _video_render;
|
|
_info.filter_video = _filter_video;
|
|
_info.filter_audio = _filter_audio;
|
|
_info.enum_active_sources = _enum_active_sources;
|
|
_info.save = _save;
|
|
_info.load = _load;
|
|
_info.mouse_click = _mouse_click;
|
|
_info.mouse_move = _mouse_move;
|
|
_info.mouse_wheel = _mouse_wheel;
|
|
_info.focus = _focus;
|
|
_info.key_click = _key_click;
|
|
_info.filter_remove = _filter_remove;
|
|
_info.audio_render = _audio_render;
|
|
_info.enum_all_sources = _enum_all_sources;
|
|
_info.transition_start = _transition_start;
|
|
_info.transition_stop = _transition_stop;
|
|
_info.audio_mix = _audio_mix;
|
|
}
|
|
virtual ~source_factory() {}
|
|
|
|
private /* Factory */:
|
|
static const char* _get_name(void* type_data) noexcept try {
|
|
return reinterpret_cast<_factory*>(type_data)->get_name();
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
return nullptr;
|
|
} catch (...) {
|
|
P_LOG_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) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
return nullptr;
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
return nullptr;
|
|
}
|
|
|
|
static void _get_defaults2(void* type_data, obs_data_t* settings) noexcept try {
|
|
reinterpret_cast<_factory*>(type_data)->get_defaults2(settings);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static obs_properties_t* _get_properties2(void* data, void* type_data) noexcept try {
|
|
return reinterpret_cast<_factory*>(type_data)->get_properties2(reinterpret_cast<_instance*>(data));
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
return nullptr;
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
return nullptr;
|
|
}
|
|
|
|
private /* Instance */:
|
|
static void _destroy(void* data) noexcept try {
|
|
delete reinterpret_cast<_instance*>(data);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static uint32_t _get_width(void* data) noexcept try {
|
|
return reinterpret_cast<_instance*>(data)->get_width();
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
return 0;
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t _get_height(void* data) noexcept try {
|
|
return reinterpret_cast<_instance*>(data)->get_height();
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
return 0;
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
return 0;
|
|
}
|
|
|
|
static void _update(void* data, obs_data_t* settings) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->update(settings);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _activate(void* data) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->activate();
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _deactivate(void* data) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->deactivate();
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _show(void* data) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->show();
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _hide(void* data) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->hide();
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _video_tick(void* data, float seconds) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->video_tick(seconds);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _video_render(void* data, gs_effect_t* effect) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->video_render(effect);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static struct obs_source_frame* _filter_video(void* data, struct obs_source_frame* frame) noexcept try {
|
|
return reinterpret_cast<_instance*>(data)->filter_video(frame);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
return frame;
|
|
} catch (...) {
|
|
P_LOG_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 {
|
|
return reinterpret_cast<_instance*>(data)->filter_audio(frame);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
return frame;
|
|
} catch (...) {
|
|
P_LOG_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 {
|
|
reinterpret_cast<_instance*>(data)->enum_active_sources(enum_callback, param);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _save(void* data, obs_data_t* settings) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->save(settings);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _load(void* data, obs_data_t* settings) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->load(settings);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_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 {
|
|
reinterpret_cast<_instance*>(data)->mouse_click(event, type, mouse_up, click_count);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_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 {
|
|
reinterpret_cast<_instance*>(data)->mouse_move(event, mouse_leave);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_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 {
|
|
reinterpret_cast<_instance*>(data)->mouse_wheel(event, x_delta, y_delta);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _focus(void* data, bool focus) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->focus(focus);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_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 {
|
|
reinterpret_cast<_instance*>(data)->key_click(event, key_up);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _filter_remove(void* data, obs_source_t* source) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->filter_remove(source);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static bool _audio_render(void* data, uint64_t* ts_out, struct obs_source_audio_mix* audio_output,
|
|
uint32_t mixers, size_t channels, size_t sample_rate) noexcept try {
|
|
return reinterpret_cast<_instance*>(data)->audio_render(ts_out, audio_output, mixers, channels,
|
|
sample_rate);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
return false;
|
|
} catch (...) {
|
|
P_LOG_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 {
|
|
reinterpret_cast<_instance*>(data)->enum_all_sources(enum_callback, param);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _transition_start(void* data) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->transition_start();
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static void _transition_stop(void* data) noexcept try {
|
|
reinterpret_cast<_instance*>(data)->transition_stop();
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
}
|
|
|
|
static bool _audio_mix(void* data, uint64_t* ts_out, struct audio_output_data* audio_output, size_t channels,
|
|
size_t sample_rate) noexcept try {
|
|
return reinterpret_cast<_instance*>(data)->audio_mix(ts_out, audio_output, channels, sample_rate);
|
|
} catch (const std::exception& ex) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
|
return false;
|
|
} catch (...) {
|
|
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
|
return false;
|
|
}
|
|
|
|
public:
|
|
virtual const char* get_name()
|
|
{
|
|
return "Not Implemented Yet";
|
|
}
|
|
|
|
virtual void* create(obs_data_t* settings, obs_source_t* source)
|
|
{
|
|
return reinterpret_cast<void*>(new _instance(settings, source));
|
|
}
|
|
|
|
virtual void get_defaults2(obs_data_t* data) {}
|
|
|
|
virtual obs_properties_t* get_properties2(_instance* data)
|
|
{
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
class source_instance {
|
|
protected:
|
|
obs_source_t* _self;
|
|
|
|
public:
|
|
source_instance(obs_data_t* settings, obs_source_t* source) : _self(source) {}
|
|
virtual ~source_instance(){};
|
|
|
|
virtual uint32_t get_width()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
virtual uint32_t get_height()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
virtual void update(obs_data_t* settings) {}
|
|
|
|
virtual void activate() {}
|
|
|
|
virtual void deactivate() {}
|
|
|
|
virtual void show() {}
|
|
|
|
virtual void hide() {}
|
|
|
|
virtual void video_tick(float 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;
|
|
}
|
|
|
|
virtual void enum_active_sources(obs_source_enum_proc_t enum_callback, void* param) {}
|
|
|
|
virtual void save(obs_data_t* settings) {}
|
|
|
|
virtual void load(obs_data_t* settings) {}
|
|
|
|
virtual void mouse_click(const struct obs_mouse_event* event, int32_t type, bool mouse_up, uint32_t click_count)
|
|
{}
|
|
|
|
virtual void mouse_move(const struct obs_mouse_event* event, bool mouse_leave) {}
|
|
|
|
virtual void mouse_wheel(const struct obs_mouse_event* event, int x_delta, int y_delta) {}
|
|
|
|
virtual void focus(bool focus) {}
|
|
|
|
virtual void key_click(const struct obs_key_event* event, bool key_up) {}
|
|
|
|
virtual void filter_remove(obs_source_t* source) {}
|
|
|
|
virtual bool audio_render(uint64_t* ts_out, struct obs_source_audio_mix* audio_output, uint32_t mixers,
|
|
size_t channels, size_t sample_rate)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
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, size_t channels,
|
|
size_t sample_rate)
|
|
{
|
|
return false;
|
|
}
|
|
};
|
|
|
|
} // namespace obs
|
|
|
|
#endif
|