2023-02-28 01:15:26 +00:00
// AUTOGENERATED COPYRIGHT HEADER START
// Copyright (C) 2021-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
// AUTOGENERATED COPYRIGHT HEADER END
2021-05-01 16:31:13 +00:00
# include "filter-denoising.hpp"
# include "obs/gs/gs-helper.hpp"
# include "plugin.hpp"
# include "util/util-logging.hpp"
2022-08-29 10:29:44 +00:00
# include "warning-disable.hpp"
# include <algorithm>
# include "warning-enable.hpp"
2021-05-01 16:31:13 +00:00
# ifdef _DEBUG
# define ST_PREFIX "<%s> "
# define D_LOG_ERROR(x, ...) P_LOG_ERROR(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
# define D_LOG_WARNING(x, ...) P_LOG_WARN(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
# define D_LOG_INFO(x, ...) P_LOG_INFO(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
# define D_LOG_DEBUG(x, ...) P_LOG_DEBUG(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
# else
# define ST_PREFIX "<filter::video_denoising> "
# define D_LOG_ERROR(...) P_LOG_ERROR(ST_PREFIX __VA_ARGS__)
# define D_LOG_WARNING(...) P_LOG_WARN(ST_PREFIX __VA_ARGS__)
# define D_LOG_INFO(...) P_LOG_INFO(ST_PREFIX __VA_ARGS__)
# define D_LOG_DEBUG(...) P_LOG_DEBUG(ST_PREFIX __VA_ARGS__)
# endif
# define ST_I18N "Filter.Denoising"
# define ST_KEY_PROVIDER "Provider"
# define ST_I18N_PROVIDER ST_I18N "." ST_KEY_PROVIDER
# define ST_I18N_PROVIDER_NVIDIA_DENOISING ST_I18N_PROVIDER ".NVIDIA.Denoising"
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
# define ST_KEY_NVIDIA_DENOISING "NVIDIA.Denoising"
# define ST_I18N_NVIDIA_DENOISING ST_I18N "." ST_KEY_NVIDIA_DENOISING
# define ST_KEY_NVIDIA_DENOISING_STRENGTH "NVIDIA.Denoising.Strength"
# define ST_I18N_NVIDIA_DENOISING_STRENGTH ST_I18N "." ST_KEY_NVIDIA_DENOISING_STRENGTH
# define ST_I18N_NVIDIA_DENOISING_STRENGTH_WEAK ST_I18N_NVIDIA_DENOISING_STRENGTH ".Weak"
# define ST_I18N_NVIDIA_DENOISING_STRENGTH_STRONG ST_I18N_NVIDIA_DENOISING_STRENGTH ".Strong"
# endif
using streamfx : : filter : : denoising : : denoising_factory ;
using streamfx : : filter : : denoising : : denoising_instance ;
using streamfx : : filter : : denoising : : denoising_provider ;
static constexpr std : : string_view HELP_URL = " https://github.com/Xaymar/obs-StreamFX/wiki/Filter-Denoising " ;
static denoising_provider provider_priority [ ] = {
denoising_provider : : NVIDIA_DENOISING ,
} ;
const char * streamfx : : filter : : denoising : : cstring ( denoising_provider provider )
{
switch ( provider ) {
case denoising_provider : : INVALID :
return " N/A " ;
case denoising_provider : : AUTOMATIC :
return D_TRANSLATE ( S_STATE_AUTOMATIC ) ;
case denoising_provider : : NVIDIA_DENOISING :
return D_TRANSLATE ( ST_I18N_PROVIDER_NVIDIA_DENOISING ) ;
default :
throw std : : runtime_error ( " Missing Conversion Entry " ) ;
}
}
std : : string streamfx : : filter : : denoising : : string ( denoising_provider provider )
{
return cstring ( provider ) ;
}
//------------------------------------------------------------------------------
// Instance
//------------------------------------------------------------------------------
denoising_instance : : denoising_instance ( obs_data_t * data , obs_source_t * self )
: obs : : source_instance ( data , self ) ,
2023-05-13 12:35:46 +00:00
_size ( 1 , 1 ) , _provider ( denoising_provider : : INVALID ) , _provider_ui ( denoising_provider : : INVALID ) , _provider_ready ( false ) , _provider_lock ( ) , _provider_task ( ) , _input ( ) , _output ( )
2021-05-01 16:31:13 +00:00
{
2021-10-26 21:38:43 +00:00
D_LOG_DEBUG ( " Initializating... (Addr: 0x% " PRIuPTR " ) " , this ) ;
2021-05-01 16:31:13 +00:00
{
: : streamfx : : obs : : gs : : context gctx ;
// Create the render target for the input buffering.
_input = std : : make_shared < : : streamfx : : obs : : gs : : rendertarget > ( GS_RGBA_UNORM , GS_ZS_NONE ) ;
_input - > render ( 1 , 1 ) ; // Preallocate the RT on the driver and GPU.
_output = _input - > get_texture ( ) ;
2021-10-06 00:13:26 +00:00
// Load the required effect.
2023-05-13 12:35:46 +00:00
_standard_effect = std : : make_shared < : : streamfx : : obs : : gs : : effect > ( : : streamfx : : data_file_path ( " effects/standard.effect " ) ) ;
2021-10-06 00:13:26 +00:00
// Create Samplers
_channel0_sampler = std : : make_shared < : : streamfx : : obs : : gs : : sampler > ( ) ;
_channel0_sampler - > set_filter ( gs_sample_filter : : GS_FILTER_LINEAR ) ;
_channel0_sampler - > set_address_mode_u ( GS_ADDRESS_CLAMP ) ;
_channel0_sampler - > set_address_mode_v ( GS_ADDRESS_CLAMP ) ;
_channel1_sampler = std : : make_shared < : : streamfx : : obs : : gs : : sampler > ( ) ;
_channel1_sampler - > set_filter ( gs_sample_filter : : GS_FILTER_LINEAR ) ;
_channel1_sampler - > set_address_mode_u ( GS_ADDRESS_CLAMP ) ;
_channel1_sampler - > set_address_mode_v ( GS_ADDRESS_CLAMP ) ;
2021-05-01 16:31:13 +00:00
}
if ( data ) {
load ( data ) ;
}
}
denoising_instance : : ~ denoising_instance ( )
{
2021-10-26 21:38:43 +00:00
D_LOG_DEBUG ( " Finalizing... (Addr: 0x% " PRIuPTR " ) " , this ) ;
{ // Unload the underlying effect ASAP.
std : : unique_lock < std : : mutex > ul ( _provider_lock ) ;
// De-queue the underlying task.
if ( _provider_task ) {
streamfx : : threadpool ( ) - > pop ( _provider_task ) ;
_provider_task - > await_completion ( ) ;
_provider_task . reset ( ) ;
}
// TODO: Make this asynchronous.
switch ( _provider ) {
2021-05-01 16:31:13 +00:00
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
2021-10-26 21:38:43 +00:00
case denoising_provider : : NVIDIA_DENOISING :
nvvfx_denoising_unload ( ) ;
break ;
2021-05-01 16:31:13 +00:00
# endif
2021-10-26 21:38:43 +00:00
default :
break ;
}
2021-05-01 16:31:13 +00:00
}
}
void denoising_instance : : load ( obs_data_t * data )
{
update ( data ) ;
}
void denoising_instance : : migrate ( obs_data_t * data , uint64_t version ) { }
void denoising_instance : : update ( obs_data_t * data )
{
// Check if the user changed which Denoising provider we use.
denoising_provider provider = static_cast < denoising_provider > ( obs_data_get_int ( data , ST_KEY_PROVIDER ) ) ;
if ( provider = = denoising_provider : : AUTOMATIC ) {
provider = denoising_factory : : get ( ) - > find_ideal_provider ( ) ;
}
// Check if the provider was changed, and if so switch.
if ( provider ! = _provider ) {
_provider_ui = provider ;
switch_provider ( provider ) ;
}
if ( _provider_ready ) {
std : : unique_lock < std : : mutex > ul ( _provider_lock ) ;
switch ( _provider ) {
2021-10-03 19:45:36 +00:00
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
2021-05-01 16:31:13 +00:00
case denoising_provider : : NVIDIA_DENOISING :
nvvfx_denoising_update ( data ) ;
break ;
# endif
default :
break ;
}
}
}
void streamfx : : filter : : denoising : : denoising_instance : : properties ( obs_properties_t * properties )
{
switch ( _provider_ui ) {
2021-10-03 19:45:36 +00:00
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
2021-05-01 16:31:13 +00:00
case denoising_provider : : NVIDIA_DENOISING :
nvvfx_denoising_properties ( properties ) ;
break ;
# endif
default :
break ;
}
}
uint32_t streamfx : : filter : : denoising : : denoising_instance : : get_width ( )
{
return std : : max < uint32_t > ( _size . first , 1 ) ;
}
uint32_t streamfx : : filter : : denoising : : denoising_instance : : get_height ( )
{
return std : : max < uint32_t > ( _size . second , 1 ) ;
}
void denoising_instance : : video_tick ( float_t time )
{
2021-10-05 20:48:27 +00:00
auto parent = obs_filter_get_parent ( _self ) ;
2021-05-01 16:31:13 +00:00
auto target = obs_filter_get_target ( _self ) ;
auto width = obs_source_get_base_width ( target ) ;
auto height = obs_source_get_base_height ( target ) ;
2021-10-05 20:48:27 +00:00
// Verify that the detected size makes sense.
if ( ( width > 0 ) & & ( height > 0 ) ) {
_size = { width , height } ;
}
2021-05-01 16:31:13 +00:00
// Allow the provider to restrict the size.
if ( target & & _provider_ready ) {
std : : unique_lock < std : : mutex > ul ( _provider_lock ) ;
switch ( _provider ) {
2021-10-03 19:45:36 +00:00
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
2021-05-01 16:31:13 +00:00
case denoising_provider : : NVIDIA_DENOISING :
nvvfx_denoising_size ( ) ;
break ;
# endif
default :
break ;
}
}
_dirty = true ;
}
void denoising_instance : : video_render ( gs_effect_t * effect )
{
auto parent = obs_filter_get_parent ( _self ) ;
auto target = obs_filter_get_target ( _self ) ;
auto width = obs_source_get_base_width ( target ) ;
auto height = obs_source_get_base_height ( target ) ;
vec4 blank = vec4 { 0 , 0 , 0 , 0 } ;
// Ensure we have the bare minimum of valid information.
target = target ? target : parent ;
effect = effect ? effect : obs_get_base_effect ( OBS_EFFECT_DEFAULT ) ;
// Skip the filter if:
// - The Provider isn't ready yet.
// - We don't have a target.
// - The width/height of the next filter in the chain is empty.
if ( ! _provider_ready | | ! target | | ( width = = 0 ) | | ( height = = 0 ) ) {
obs_source_skip_video_filter ( _self ) ;
return ;
}
2023-04-05 16:24:26 +00:00
# if defined(ENABLE_PROFILING) && !defined(D_PLATFORM_MAC) && _DEBUG
2021-05-01 16:31:13 +00:00
: : streamfx : : obs : : gs : : debug_marker profiler0 { : : streamfx : : obs : : gs : : debug_color_source , " StreamFX Denoising " } ;
2023-05-13 12:35:46 +00:00
: : streamfx : : obs : : gs : : debug_marker profiler0_0 { : : streamfx : : obs : : gs : : debug_color_gray , " '%s' on '%s' " , obs_source_get_name ( _self ) , obs_source_get_name ( parent ) } ;
2021-05-01 16:31:13 +00:00
# endif
if ( _dirty ) { // Lock the provider from being changed.
std : : unique_lock < std : : mutex > ul ( _provider_lock ) ;
{ // Allow the provider to restrict the size.
switch ( _provider ) {
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
case denoising_provider : : NVIDIA_DENOISING :
nvvfx_denoising_size ( ) ;
break ;
# endif
default :
_size = { width , height } ;
break ;
}
}
{ // Capture the incoming frame.
2023-04-05 16:24:26 +00:00
# if defined(ENABLE_PROFILING) && !defined(D_PLATFORM_MAC) && _DEBUG
2021-05-01 16:31:13 +00:00
: : streamfx : : obs : : gs : : debug_marker profiler1 { : : streamfx : : obs : : gs : : debug_color_capture , " Capture " } ;
# endif
if ( obs_source_process_filter_begin ( _self , GS_RGBA , OBS_ALLOW_DIRECT_RENDERING ) ) {
auto op = _input - > render ( _size . first , _size . second ) ;
// Matrix
gs_matrix_push ( ) ;
gs_ortho ( 0. , 1. , 0. , 1. , 0. , 1. ) ;
// Clear the buffer
gs_clear ( GS_CLEAR_COLOR | GS_CLEAR_DEPTH , & blank , 0 , 0 ) ;
// Set GPU state
gs_blend_state_push ( ) ;
gs_enable_color ( true , true , true , true ) ;
gs_enable_blending ( false ) ;
gs_enable_depth_test ( false ) ;
gs_enable_stencil_test ( false ) ;
gs_set_cull_mode ( GS_NEITHER ) ;
// Render
2023-04-05 16:24:26 +00:00
# if defined(ENABLE_PROFILING) && !defined(D_PLATFORM_MAC) && _DEBUG
2021-05-01 16:31:13 +00:00
: : streamfx : : obs : : gs : : debug_marker profiler2 { : : streamfx : : obs : : gs : : debug_color_capture , " Storage " } ;
# endif
obs_source_process_filter_end ( _self , obs_get_base_effect ( OBS_EFFECT_DEFAULT ) , 1 , 1 ) ;
// Reset GPU state
gs_blend_state_pop ( ) ;
gs_matrix_pop ( ) ;
} else {
obs_source_skip_video_filter ( _self ) ;
return ;
}
}
try { // Process the captured input with the provider.
2023-04-05 16:24:26 +00:00
# if defined(ENABLE_PROFILING) && !defined(D_PLATFORM_MAC) && _DEBUG
2021-05-01 16:31:13 +00:00
: : streamfx : : obs : : gs : : debug_marker profiler1 { : : streamfx : : obs : : gs : : debug_color_convert , " Process " } ;
# endif
switch ( _provider ) {
2021-10-03 19:45:36 +00:00
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
2021-05-01 16:31:13 +00:00
case denoising_provider : : NVIDIA_DENOISING :
nvvfx_denoising_process ( ) ;
break ;
# endif
default :
_output . reset ( ) ;
break ;
}
} catch ( . . . ) {
obs_source_skip_video_filter ( _self ) ;
return ;
}
if ( ! _output ) {
D_LOG_ERROR ( " Provider '%s' did not return a result. " , cstring ( _provider ) ) ;
obs_source_skip_video_filter ( _self ) ;
return ;
}
2021-10-05 23:32:03 +00:00
// Mark "clean".
2021-05-01 16:31:13 +00:00
_dirty = false ;
2021-10-05 23:32:03 +00:00
// Unlock the provider, as we are no longer doing critical work with it.
2021-05-01 16:31:13 +00:00
}
{ // Draw the result for the next filter to use.
2023-04-05 16:24:26 +00:00
# if defined(ENABLE_PROFILING) && !defined(D_PLATFORM_MAC) && _DEBUG
2021-05-01 16:31:13 +00:00
: : streamfx : : obs : : gs : : debug_marker profiler1 { : : streamfx : : obs : : gs : : debug_color_render , " Render " } ;
# endif
2021-10-22 00:57:03 +00:00
if ( _standard_effect - > has_parameter ( " InputA " , : : streamfx : : obs : : gs : : effect_parameter : : type : : Texture ) ) {
_standard_effect - > get_parameter ( " InputA " ) . set_texture ( _output ) ;
2021-10-06 00:13:26 +00:00
}
2021-10-22 00:57:03 +00:00
if ( _standard_effect - > has_parameter ( " InputB " , : : streamfx : : obs : : gs : : effect_parameter : : type : : Texture ) ) {
_standard_effect - > get_parameter ( " InputB " ) . set_texture ( _input - > get_texture ( ) ) ;
2021-10-06 00:13:26 +00:00
}
while ( gs_effect_loop ( _standard_effect - > get_object ( ) , " RestoreAlpha " ) ) {
2021-05-01 16:31:13 +00:00
gs_draw_sprite ( nullptr , 0 , _size . first , _size . second ) ;
}
}
}
struct switch_provider_data_t {
denoising_provider provider ;
} ;
void streamfx : : filter : : denoising : : denoising_instance : : switch_provider ( denoising_provider provider )
{
std : : unique_lock < std : : mutex > ul ( _provider_lock ) ;
// Safeguard against calls made from unlocked memory.
if ( provider = = _provider ) {
return ;
}
// This doesn't work correctly.
// - Need to allow multiple switches at once because OBS is weird.
// - Doesn't guarantee that the task is properly killed off.
// Log information.
2023-05-13 12:35:46 +00:00
D_LOG_INFO ( " Instance '%s' is switching provider from '%s' to '%s'. " , obs_source_get_name ( _self ) , cstring ( _provider ) , cstring ( provider ) ) ;
2021-05-01 16:31:13 +00:00
2021-10-26 21:38:43 +00:00
// If there is an existing task, attempt to cancel it.
2021-05-01 16:31:13 +00:00
if ( _provider_task ) {
2021-10-26 21:38:43 +00:00
// De-queue it.
2021-05-01 16:31:13 +00:00
streamfx : : threadpool ( ) - > pop ( _provider_task ) ;
2021-10-26 21:38:43 +00:00
// Await the death of the task itself.
_provider_task - > await_completion ( ) ;
// Clear any memory associated with it.
_provider_task . reset ( ) ;
2021-05-01 16:31:13 +00:00
}
2021-10-26 21:38:43 +00:00
// Build data to pass into the task.
2021-05-01 16:31:13 +00:00
auto spd = std : : make_shared < switch_provider_data_t > ( ) ;
spd - > provider = _provider ;
_provider = provider ;
2021-10-26 21:38:43 +00:00
// Then spawn a new task to switch provider.
2023-05-13 12:35:46 +00:00
_provider_task = streamfx : : threadpool ( ) - > push ( std : : bind ( & denoising_instance : : task_switch_provider , this , std : : placeholders : : _1 ) , spd ) ;
2021-05-01 16:31:13 +00:00
}
2022-09-18 16:30:15 +00:00
void streamfx : : filter : : denoising : : denoising_instance : : task_switch_provider ( util : : threadpool : : task_data_t data )
2021-05-01 16:31:13 +00:00
{
std : : shared_ptr < switch_provider_data_t > spd = std : : static_pointer_cast < switch_provider_data_t > ( data ) ;
// 1. Mark the provider as no longer ready.
_provider_ready = false ;
// 2. Lock the provider from being used.
std : : unique_lock < std : : mutex > ul ( _provider_lock ) ;
try {
// 3. Unload the previous provider.
switch ( spd - > provider ) {
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
case denoising_provider : : NVIDIA_DENOISING :
nvvfx_denoising_unload ( ) ;
break ;
# endif
default :
break ;
}
// 4. Load the new provider.
switch ( _provider ) {
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
case denoising_provider : : NVIDIA_DENOISING :
nvvfx_denoising_load ( ) ;
break ;
# endif
default :
break ;
}
// Log information.
2023-05-13 12:35:46 +00:00
D_LOG_INFO ( " Instance '%s' switched provider from '%s' to '%s'. " , obs_source_get_name ( _self ) , cstring ( spd - > provider ) , cstring ( _provider ) ) ;
2021-05-01 16:31:13 +00:00
_provider_ready = true ;
} catch ( std : : exception const & ex ) {
// Log information.
D_LOG_ERROR ( " Instance '%s' failed switching provider with error: %s " , obs_source_get_name ( _self ) , ex . what ( ) ) ;
}
}
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
void streamfx : : filter : : denoising : : denoising_instance : : nvvfx_denoising_load ( )
{
_nvidia_fx = std : : make_shared < : : streamfx : : nvidia : : vfx : : denoising > ( ) ;
}
void streamfx : : filter : : denoising : : denoising_instance : : nvvfx_denoising_unload ( )
{
_nvidia_fx . reset ( ) ;
}
void streamfx : : filter : : denoising : : denoising_instance : : nvvfx_denoising_size ( )
{
if ( ! _nvidia_fx ) {
return ;
}
_nvidia_fx - > size ( _size ) ;
}
void streamfx : : filter : : denoising : : denoising_instance : : nvvfx_denoising_process ( )
{
if ( ! _nvidia_fx ) {
_output = _input - > get_texture ( ) ;
return ;
}
_output = _nvidia_fx - > process ( _input - > get_texture ( ) ) ;
}
void streamfx : : filter : : denoising : : denoising_instance : : nvvfx_denoising_properties ( obs_properties_t * props )
{
obs_properties_t * grp = obs_properties_create ( ) ;
2023-05-13 12:35:46 +00:00
obs_properties_add_group ( props , ST_KEY_NVIDIA_DENOISING , D_TRANSLATE ( ST_I18N_NVIDIA_DENOISING ) , OBS_GROUP_NORMAL , grp ) ;
2021-05-01 16:31:13 +00:00
{
2023-05-13 12:35:46 +00:00
auto p = obs_properties_add_list ( grp , ST_KEY_NVIDIA_DENOISING_STRENGTH , D_TRANSLATE ( ST_I18N_NVIDIA_DENOISING_STRENGTH ) , OBS_COMBO_TYPE_LIST , OBS_COMBO_FORMAT_INT ) ;
2021-05-01 16:31:13 +00:00
obs_property_list_add_int ( p , D_TRANSLATE ( ST_I18N_NVIDIA_DENOISING_STRENGTH_WEAK ) , 0 ) ;
obs_property_list_add_int ( p , D_TRANSLATE ( ST_I18N_NVIDIA_DENOISING_STRENGTH_STRONG ) , 1 ) ;
}
}
void streamfx : : filter : : denoising : : denoising_instance : : nvvfx_denoising_update ( obs_data_t * data )
{
if ( ! _nvidia_fx )
return ;
2023-05-13 12:35:46 +00:00
_nvidia_fx - > set_strength ( static_cast < float > ( obs_data_get_int ( data , ST_KEY_NVIDIA_DENOISING_STRENGTH ) = = 0 ? 0. : 1. ) ) ;
2021-05-01 16:31:13 +00:00
}
# endif
//------------------------------------------------------------------------------
// Factory
//------------------------------------------------------------------------------
denoising_factory : : ~ denoising_factory ( ) { }
denoising_factory : : denoising_factory ( )
{
bool any_available = false ;
// 1. Try and load any configured providers.
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
try {
// Load CVImage and Video Effects SDK.
_nvcuda = : : streamfx : : nvidia : : cuda : : obs : : get ( ) ;
_nvcvi = : : streamfx : : nvidia : : cv : : cv : : get ( ) ;
_nvvfx = : : streamfx : : nvidia : : vfx : : vfx : : get ( ) ;
_nvidia_available = true ;
any_available | = _nvidia_available ;
} catch ( const std : : exception & ex ) {
_nvidia_available = false ;
_nvvfx . reset ( ) ;
_nvcvi . reset ( ) ;
_nvcuda . reset ( ) ;
D_LOG_WARNING ( " Failed to make NVIDIA providers available due to error: %s " , ex . what ( ) ) ;
} catch ( . . . ) {
_nvidia_available = false ;
_nvvfx . reset ( ) ;
_nvcvi . reset ( ) ;
_nvcuda . reset ( ) ;
D_LOG_WARNING ( " Failed to make NVIDIA providers available with unknown error. " , nullptr ) ;
}
# endif
// 2. Check if any of them managed to load at all.
if ( ! any_available ) {
D_LOG_ERROR ( " All supported providers failed to initialize, disabling effect. " , 0 ) ;
return ;
}
// 3. In any other case, register the filter!
2021-10-06 00:33:26 +00:00
_info . id = S_PREFIX " filter-denoising " ;
2021-05-01 16:31:13 +00:00
_info . type = OBS_SOURCE_TYPE_FILTER ;
2021-10-06 00:13:26 +00:00
_info . output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW ;
2021-05-01 16:31:13 +00:00
2022-05-11 03:33:38 +00:00
support_size ( true ) ;
2021-05-01 16:31:13 +00:00
finish_setup ( ) ;
2021-10-06 00:33:26 +00:00
// Proxies
register_proxy ( " streamfx-filter-video-denoising " ) ;
2021-05-01 16:31:13 +00:00
}
const char * denoising_factory : : get_name ( )
{
return D_TRANSLATE ( ST_I18N ) ;
}
void denoising_factory : : get_defaults2 ( obs_data_t * data )
{
obs_data_set_default_int ( data , ST_KEY_PROVIDER , static_cast < int64_t > ( denoising_provider : : AUTOMATIC ) ) ;
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
obs_data_set_default_double ( data , ST_KEY_NVIDIA_DENOISING_STRENGTH , 1. ) ;
# endif
}
static bool modified_provider ( obs_properties_t * props , obs_property_t * , obs_data_t * settings ) noexcept
2022-08-27 11:17:47 +00:00
{
try {
return true ;
} 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 ;
}
2021-05-01 16:31:13 +00:00
}
obs_properties_t * denoising_factory : : get_properties2 ( denoising_instance * data )
{
obs_properties_t * pr = obs_properties_create ( ) ;
# ifdef ENABLE_FRONTEND
{
2023-05-13 12:35:46 +00:00
obs_properties_add_button2 ( pr , S_MANUAL_OPEN , D_TRANSLATE ( S_MANUAL_OPEN ) , denoising_factory : : on_manual_open , nullptr ) ;
2021-05-01 16:31:13 +00:00
}
# endif
if ( data ) {
data - > properties ( pr ) ;
}
{ // Advanced Settings
auto grp = obs_properties_create ( ) ;
obs_properties_add_group ( pr , S_ADVANCED , D_TRANSLATE ( S_ADVANCED ) , OBS_GROUP_NORMAL , grp ) ;
{
2023-05-13 12:35:46 +00:00
auto p = obs_properties_add_list ( grp , ST_KEY_PROVIDER , D_TRANSLATE ( ST_I18N_PROVIDER ) , OBS_COMBO_TYPE_LIST , OBS_COMBO_FORMAT_INT ) ;
2021-05-01 16:31:13 +00:00
obs_property_set_modified_callback ( p , modified_provider ) ;
2023-05-13 12:35:46 +00:00
obs_property_list_add_int ( p , D_TRANSLATE ( S_STATE_AUTOMATIC ) , static_cast < int64_t > ( denoising_provider : : AUTOMATIC ) ) ;
obs_property_list_add_int ( p , D_TRANSLATE ( ST_I18N_PROVIDER_NVIDIA_DENOISING ) , static_cast < int64_t > ( denoising_provider : : NVIDIA_DENOISING ) ) ;
2021-05-01 16:31:13 +00:00
}
}
return pr ;
}
# ifdef ENABLE_FRONTEND
bool denoising_factory : : on_manual_open ( obs_properties_t * props , obs_property_t * property , void * data )
{
streamfx : : open_url ( HELP_URL ) ;
return false ;
}
# endif
bool streamfx : : filter : : denoising : : denoising_factory : : is_provider_available ( denoising_provider provider )
{
switch ( provider ) {
# ifdef ENABLE_FILTER_DENOISING_NVIDIA
case denoising_provider : : NVIDIA_DENOISING :
return _nvidia_available ;
# endif
default :
return false ;
}
}
denoising_provider streamfx : : filter : : denoising : : denoising_factory : : find_ideal_provider ( )
{
for ( auto v : provider_priority ) {
if ( is_provider_available ( v ) ) {
return v ;
break ;
}
}
return denoising_provider : : AUTOMATIC ;
}
std : : shared_ptr < denoising_factory > _video_denoising_factory_instance = nullptr ;
void denoising_factory : : initialize ( )
2022-08-27 11:17:47 +00:00
{
try {
if ( ! _video_denoising_factory_instance )
_video_denoising_factory_instance = std : : make_shared < denoising_factory > ( ) ;
} catch ( const std : : exception & ex ) {
D_LOG_ERROR ( " Failed to initialize due to error: %s " , ex . what ( ) ) ;
} catch ( . . . ) {
D_LOG_ERROR ( " Failed to initialize due to unknown error. " , " " ) ;
}
2021-05-01 16:31:13 +00:00
}
void denoising_factory : : finalize ( )
{
_video_denoising_factory_instance . reset ( ) ;
}
std : : shared_ptr < denoising_factory > denoising_factory : : get ( )
{
return _video_denoising_factory_instance ;
}