diff --git a/plugins/obs-filters/data/locale/en-US.ini b/plugins/obs-filters/data/locale/en-US.ini index 62cbaff9f..1ee2caace 100644 --- a/plugins/obs-filters/data/locale/en-US.ini +++ b/plugins/obs-filters/data/locale/en-US.ini @@ -124,6 +124,7 @@ Greenscreen.Mode="Mode" Greenscreen.Quality="Quality (higher GPU usage, better quality)" Greenscreen.Performance="Performance (lower GPU usage, good quality)" Greenscreen.Threshold="Threshold" +Greenscreen.Deprecation="WARNING: Please upgrade both NVIDIA Video & Audio SDK. Your current version of Video SDK is outdated." Upward.Compressor="Upward Compressor" 3BandEq="3-Band Equalizer" 3BandEq.low="Low" diff --git a/plugins/obs-filters/nvidia-greenscreen-filter.c b/plugins/obs-filters/nvidia-greenscreen-filter.c index 34bf928c4..8a5e9e258 100644 --- a/plugins/obs-filters/nvidia-greenscreen-filter.c +++ b/plugins/obs-filters/nvidia-greenscreen-filter.c @@ -6,9 +6,9 @@ #include "nvvfx-load.h" /* -------------------------------------------------------- */ -#define do_log(level, format, ...) \ - blog(level, \ - "[NVIDIA RTX AI Greenscreen (Background removal): '%s'] " format, \ +#define do_log(level, format, ...) \ + blog(level, \ + "[NVIDIA AI Greenscreen (Background removal): '%s'] " format, \ obs_source_get_name(filter->context), ##__VA_ARGS__) #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) @@ -33,8 +33,10 @@ #define TEXT_MODE_QUALITY MT_("Greenscreen.Quality") #define TEXT_MODE_PERF MT_("Greenscreen.Performance") #define TEXT_MODE_THRESHOLD MT_("Greenscreen.Threshold") +#define TEXT_DEPRECATION MT_("Greenscreen.Deprecation") bool nvvfx_loaded = false; +bool nvvfx_new_sdk = false; struct nv_greenscreen_data { obs_source_t *context; bool images_allocated; @@ -54,6 +56,7 @@ struct nv_greenscreen_data { NvCVImage *A_dst_img; // mask img on GPU NvCVImage *dst_img; // mask texture NvCVImage *stage; // planar stage img used for transfer to texture + unsigned int version; /* alpha mask effect */ gs_effect_t *effect; @@ -445,13 +448,15 @@ static void *nv_greenscreen_filter_create(obs_data_t *settings, nv_greenscreen_filter_destroy(filter); return NULL; } - /* log sdk version */ - unsigned int version; - if (NvVFX_GetVersion(&version) == NVCV_SUCCESS) { - uint8_t major = (version >> 24) & 0xff; - uint8_t minor = (version >> 16) & 0x00ff; - uint8_t build = (version >> 8) & 0x0000ff; - info("RTX VIDEO FX version: %i.%i.%i", major, minor, build); + /* check sdk version */ + if (NvVFX_GetVersion(&filter->version) == NVCV_SUCCESS) { + uint8_t major = (filter->version >> 24) & 0xff; + uint8_t minor = (filter->version >> 16) & 0x00ff; + uint8_t build = (filter->version >> 8) & 0x0000ff; + uint8_t revision = (filter->version >> 0) & 0x000000ff; + // sanity check + nvvfx_new_sdk = filter->version >= (MIN_VFX_SDK_VERSION) && + nvvfx_new_sdk; } /* 3. Load alpha mask effect. */ @@ -486,6 +491,7 @@ static void *nv_greenscreen_filter_create(obs_data_t *settings, static obs_properties_t *nv_greenscreen_filter_properties(void *data) { + struct nv_greenscreen_data *filter = (struct nv_greenscreen_data *)data; obs_properties_t *props = obs_properties_create(); obs_property_t *mode = obs_properties_add_list(props, S_MODE, TEXT_MODE, OBS_COMBO_TYPE_LIST, @@ -494,8 +500,14 @@ static obs_properties_t *nv_greenscreen_filter_properties(void *data) obs_property_list_add_int(mode, TEXT_MODE_PERF, S_MODE_PERF); obs_property_t *threshold = obs_properties_add_float_slider( props, S_THRESHOLDFX, TEXT_MODE_THRESHOLD, 0, 1, 0.05); + unsigned int version = get_lib_version(); + if (version < (MIN_VFX_SDK_VERSION)) { + obs_property_t *warning = obs_properties_add_text( + props, "deprecation", NULL, OBS_TEXT_INFO); + obs_property_text_set_info_type(warning, OBS_TEXT_INFO_WARNING); + obs_property_set_long_description(warning, TEXT_DEPRECATION); + } - UNUSED_PARAMETER(data); return props; } @@ -815,20 +827,33 @@ static void nv_greenscreen_filter_render(void *data, gs_effect_t *effect) bool load_nvvfx(void) { + bool old_sdk_loaded = false; + unsigned int version = get_lib_version(); + uint8_t major = (version >> 24) & 0xff; + uint8_t minor = (version >> 16) & 0x00ff; + uint8_t build = (version >> 8) & 0x0000ff; + uint8_t revision = (version >> 0) & 0x000000ff; + blog(LOG_INFO, + "[NVIDIA VIDEO FX]: NVIDIA VIDEO FX version: %i.%i.%i.%i", major, + minor, build, revision); + if (version < (MIN_VFX_SDK_VERSION)) { + blog(LOG_INFO, + "[NVIDIA VIDEO FX]: NVIDIA VIDEO Effects SDK is outdated; please update both audio & video SDK."); + } if (!load_nv_vfx_libs()) { blog(LOG_INFO, - "[NVIDIA RTX VIDEO FX]: FX disabled, redistributable not found."); + "[NVIDIA VIDEO FX]: FX disabled, redistributable not found or could not be loaded."); return false; } -#define LOAD_SYM_FROM_LIB(sym, lib, dll) \ - if (!(sym = (sym##_t)GetProcAddress(lib, #sym))) { \ - DWORD err = GetLastError(); \ - printf("[NVIDIA RTX VIDEO FX]: Couldn't load " #sym \ - " from " dll ": %lu (0x%lx)", \ - err, err); \ - release_nv_vfx(); \ - goto unload_everything; \ +#define LOAD_SYM_FROM_LIB(sym, lib, dll) \ + if (!(sym = (sym##_t)GetProcAddress(lib, #sym))) { \ + DWORD err = GetLastError(); \ + printf("[NVIDIA VIDEO FX]: Couldn't load " #sym " from " dll \ + ": %lu (0x%lx)", \ + err, err); \ + release_nv_vfx(); \ + goto unload_everything; \ } #define LOAD_SYM(sym) LOAD_SYM_FROM_LIB(sym, nv_videofx, "NVVideoEffects.dll") @@ -857,6 +882,7 @@ bool load_nvvfx(void) LOAD_SYM(NvVFX_Load); LOAD_SYM(NvVFX_CudaStreamCreate); LOAD_SYM(NvVFX_CudaStreamDestroy); + old_sdk_loaded = true; #undef LOAD_SYM #define LOAD_SYM(sym) LOAD_SYM_FROM_LIB(sym, nv_cvimage, "NVCVImage.dll") LOAD_SYM(NvCV_GetErrorStringFromCode); @@ -900,20 +926,22 @@ bool load_nvvfx(void) if (err != NVCV_SUCCESS) { if (err == NVCV_ERR_UNSUPPORTEDGPU) { blog(LOG_INFO, - "[NVIDIA RTX VIDEO FX]: disabled, unsupported GPU"); + "[NVIDIA VIDEO FX]: disabled, unsupported GPU"); } else { - blog(LOG_ERROR, - "[NVIDIA RTX VIDEO FX]: disabled, error %i", err); + blog(LOG_ERROR, "[NVIDIA VIDEO FX]: disabled, error %i", + err); } goto unload_everything; } NvVFX_DestroyEffect(h); nvvfx_loaded = true; - blog(LOG_INFO, "[NVIDIA RTX VIDEO FX]: enabled, redistributable found"); + blog(LOG_INFO, "[NVIDIA VIDEO FX]: enabled, redistributable found"); return true; unload_everything: nvvfx_loaded = false; + blog(LOG_INFO, + "[NVIDIA VIDEO FX]: disabled, redistributable not found"); release_nv_vfx(); return false; } diff --git a/plugins/obs-filters/nvvfx-load.h b/plugins/obs-filters/nvvfx-load.h index 47bf5fff1..4feb5afc6 100644 --- a/plugins/obs-filters/nvvfx-load.h +++ b/plugins/obs-filters/nvvfx-load.h @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -38,7 +39,7 @@ extern "C" { #define CUDARTAPI #ifdef LIBNVVFX_ENABLED -// allows for future loading of a second fx +#define MIN_VFX_SDK_VERSION 0 << 24 | 7 << 16 | 1 << 8 | 0 << 0 static HMODULE nv_videofx = NULL; static HMODULE nv_cvimage = NULL; static HMODULE nv_cudart = NULL; @@ -139,8 +140,14 @@ typedef enum NvCV_Status { #define NVVFX_CUDA_STREAM "CudaStream" //!< The CUDA stream to use #define NVVFX_CUDA_GRAPH "CudaGraph" //!< Enable CUDA graph to use #define NVVFX_INFO "Info" //!< Get info about the effects -#define NVVFX_SCALE "Scale" //!< Scale factor -#define NVVFX_STRENGTH "Strength" //!< Strength for different filters +#define NVVFX_MAX_INPUT_WIDTH \ + "MaxInputWidth" //!< Maximum width of the input supported +#define NVVFX_MAX_INPUT_HEIGHT \ + "MaxInputHeight" //!< Maximum height of the input supported +#define NVVFX_MAX_NUMBER_STREAMS \ + "MaxNumberStreams" //!< Maximum number of concurrent input streams +#define NVVFX_SCALE "Scale" //!< Scale factor +#define NVVFX_STRENGTH "Strength" //!< Strength for different filters #define NVVFX_STRENGTH_LEVELS "StrengthLevels" //!< Number of strength levels #define NVVFX_MODE "Mode" //!< Mode for different filters #define NVVFX_TEMPORAL "Temporal" //!< Temporal mode: 0=image, 1=video @@ -149,6 +156,8 @@ typedef enum NvCV_Status { #define NVVFX_MODEL_BATCH "ModelBatch" #define NVVFX_STATE "State" //!< State variable #define NVVFX_STATE_SIZE "StateSize" //!< Number of bytes needed to store state +#define NVVFX_STATE_COUNT \ + "NumStateObjects" //!< Number of active state object handles //! The format of pixels in an image. typedef enum NvCVImage_PixelFormat { @@ -324,6 +333,8 @@ typedef struct CUstream_st *CUstream; typedef const char *NvVFX_EffectSelector; typedef const char *NvVFX_ParameterSelector; typedef void *NvVFX_Handle; +/* requires sdk version >= 0.7.0 */ +typedef void *NvVFX_StateObjectHandle; /* nvvfx functions */ typedef NvCV_Status NvVFX_API (*NvVFX_GetVersion_t)(unsigned int *version); @@ -346,6 +357,11 @@ typedef NvCV_Status unsigned long long val); typedef NvCV_Status NvVFX_API (*NvVFX_SetObject_t)( NvVFX_Handle effect, NvVFX_ParameterSelector param_name, void *ptr); +/* requires sdk version >= 0.7.0 */ +typedef NvCV_Status NvVFX_API (*NvVFX_SetStateObjectHandleArray_t)( + NvVFX_Handle effect, NvVFX_ParameterSelector param_name, + NvVFX_StateObjectHandle *handle); +/* ----------------------------- */ typedef NvCV_Status NvVFX_API (*NvVFX_SetCudaStream_t)(NvVFX_Handle effect, NvVFX_ParameterSelector param_name, @@ -387,6 +403,17 @@ typedef NvCV_Status NvVFX_API (*NvVFX_Load_t)(NvVFX_Handle effect); typedef NvCV_Status NvVFX_API (*NvVFX_CudaStreamCreate_t)(CUstream *stream); typedef NvCV_Status NvVFX_API (*NvVFX_CudaStreamDestroy_t)(CUstream stream); +/* requires sdk version >= 0.7.0 */ +typedef NvCV_Status + NvVFX_API (*NvVFX_AllocateState_t)(NvVFX_Handle effect, + NvVFX_StateObjectHandle *handle); +typedef NvCV_Status + NvVFX_API (*NvVFX_DeallocateState_t)(NvVFX_Handle effect, + NvVFX_StateObjectHandle handle); +typedef NvCV_Status + NvVFX_API (*NvVFX_ResetState_t)(NvVFX_Handle effect, + NvVFX_StateObjectHandle handle); + /* NvCVImage functions */ typedef NvCV_Status NvCV_API (*NvCVImage_Init_t)( NvCVImage *im, unsigned width, unsigned height, int pitch, void *pixels, @@ -643,6 +670,12 @@ static NvVFX_Load_t NvVFX_Load = NULL; static NvVFX_CudaStreamCreate_t NvVFX_CudaStreamCreate = NULL; static NvVFX_CudaStreamDestroy_t NvVFX_CudaStreamDestroy = NULL; +/* nvvfx sdk >= 0.7.0 */ +static NvVFX_SetStateObjectHandleArray_t NvVFX_SetStateObjectHandleArray = NULL; +static NvVFX_AllocateState_t NvVFX_AllocateState = NULL; +static NvVFX_DeallocateState_t NvVFX_DeallocateState = NULL; +static NvVFX_ResetState_t NvVFX_ResetState = NULL; + /*nvcvimage */ static NvCVImage_Init_t NvCVImage_Init = NULL; static NvCVImage_InitView_t NvCVImage_InitView = NULL; @@ -707,6 +740,10 @@ static inline void release_nv_vfx() NvVFX_SetString = NULL; NvVFX_SetU32 = NULL; NvVFX_SetU64 = NULL; + NvVFX_SetStateObjectHandleArray = NULL; + NvVFX_AllocateState = NULL; + NvVFX_DeallocateState = NULL; + NvVFX_ResetState = NULL; if (nv_videofx) { FreeLibrary(nv_videofx); nv_videofx = NULL; @@ -761,8 +798,7 @@ static inline void nvvfx_get_sdk_path(char *buffer, const size_t len) size_t max_len = sizeof(path) / sizeof(char); snprintf(buffer, max_len, - "%s\\NVIDIA Corporation\\NVIDIA Video Effects\\", - path); + "%s\\NVIDIA Corporation\\NVIDIA Video Effects", path); } } @@ -771,6 +807,7 @@ static inline bool load_nv_vfx_libs() char fullPath[MAX_PATH]; nvvfx_get_sdk_path(fullPath, MAX_PATH); SetDllDirectoryA(fullPath); + nv_videofx = LoadLibrary(L"NVVideoEffects.dll"); nv_cvimage = LoadLibrary(L"NVCVImage.dll"); nv_cudart = LoadLibrary(L"cudart64_110.dll"); @@ -778,6 +815,18 @@ static inline bool load_nv_vfx_libs() return !!nv_videofx && !!nv_cvimage && !!nv_cudart; } +static unsigned int get_lib_version(void) +{ + char path[MAX_PATH]; + nvvfx_get_sdk_path(path, sizeof(path)); + + SetDllDirectoryA(path); + struct win_version_info nto_ver = {0}; + get_dll_ver(L"NVVideoEffects.dll", &nto_ver); + unsigned int version = nto_ver.major << 24 | nto_ver.minor << 16 | + nto_ver.build << 8 | nto_ver.revis << 0; + return version; +} #endif #ifdef __cplusplus