Skip to content

Commit

Permalink
obs-filters: Move NVIDIA filters in their own project
Browse files Browse the repository at this point in the history
This commit does the following:
1. Factor out NVIDIA Audio Effects from Noise Suppression filter.
2. Move NVIDIA Audio Effects to a new filter in a new nv-filters
project.
3. Migrate Noise Suppression filter settings to the new filter when
NVIDIA Audio effects were used.
4. Migrate NVIDIA AI Greenscreen to the new nv-filters project for
easier maintainance of all NVIDIA Maxine effects.

Context:
 Currently, the three NVIDIA Audio Effects (noise suppression, room
echo removal, noise suppression + room echo removal combined) are part
of the noise suppression filter.
Historically, it's because a lot of code was shared between speex,
rnnoise & NVIDIA noise suppression.
But the NVIDIA code has become bulkier & cumbersome due to:
- addition of other effects;
- addition of a deferred loading thread.
The factorisation makes the code very difficult to maintain for
(un)readability reasons.
This will make it easier to add other audio effects, should we wish to.
Developers life will be easier too when debugging.
The code has been reorganized and comments added.
I also added a mutex in the process_fx function to avoid a crash when
swapping effects.

Signed-off-by: pkv <[email protected]>
  • Loading branch information
pkviet committed May 1, 2024
1 parent dfd5798 commit 72e5eb5
Show file tree
Hide file tree
Showing 16 changed files with 1,807 additions and 713 deletions.
123 changes: 72 additions & 51 deletions plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.22...3.25)
option(ENABLE_PLUGINS "Enable building OBS plugins" ON)

if(OBS_CMAKE_VERSION VERSION_GREATER_EQUAL 3.0.0)

if(NOT ENABLE_PLUGINS)
set_property(GLOBAL APPEND PROPERTY OBS_FEATURES_DISABLED "Plugin Support")
return()
Expand All @@ -11,69 +12,88 @@ if(OBS_CMAKE_VERSION VERSION_GREATER_EQUAL 3.0.0)
set_property(GLOBAL APPEND PROPERTY OBS_FEATURES_ENABLED "Plugin Support")

macro(check_obs_browser)
if((OS_WINDOWS AND CMAKE_GENERATOR_PLATFORM MATCHES "(Win32|x64)")
OR OS_MACOS
OR OS_LINUX)
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/obs-browser/CMakeLists.txt")
message(FATAL_ERROR "Required submodule 'obs-browser' not available.")
else()
if(NOT (OS_WINDOWS AND NOT CMAKE_GENERATOR_PLATFORM MATCHES "(Win32|x64)"))
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/obs-browser/cmake/macos/Info.plist.in")
add_subdirectory(obs-browser)
elseif(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/obs-browser/CMakeLists.txt")
message(FATAL_ERROR "Required submodule 'obs-browser' not available.")
endif()
else()
add_custom_target(obs-browser)
target_disable(obs-browser)
endif()
endmacro()

macro(check_obs_websocket)
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/obs-websocket/CMakeLists.txt")
message(FATAL_ERROR "Required submodule 'obs-websocket' not available.")
else()
add_subdirectory(obs-websocket)
if(OS_WINDOWS
OR OS_MACOS
OR OS_LINUX)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/obs-websocket/cmake/macos/Info.plist.in")
add_subdirectory(obs-websocket)
elseif(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/obs-websocket/CMakeLists.txt")
message(FATAL_ERROR "Required submodule 'obs-websocket' not available.")
endif()
endif()
endmacro()

# Add plugins in alphabetical order to retain order in IDE projects
add_obs_plugin(aja PLATFORMS WINDOWS MACOS LINUX WITH_MESSAGE)
add_obs_plugin(coreaudio-encoder PLATFORMS WINDOWS MACOS)
add_obs_plugin(decklink PLATFORMS WINDOWS MACOS LINUX WITH_MESSAGE)
add_obs_plugin(image-source)
add_obs_plugin(linux-alsa PLATFORMS LINUX FREEBSD OPENBSD)
add_obs_plugin(linux-capture PLATFORMS LINUX FREEBSD OPENBSD)
add_obs_plugin(linux-jack PLATFORMS LINUX FREEBSD OPENBSD)
add_obs_plugin(linux-pipewire PLATFORMS LINUX FREEBSD OPENBSD)
add_obs_plugin(linux-pulseaudio PLATFORMS LINUX FREEBSD OPENBSD)
add_obs_plugin(linux-v4l2 PLATFORMS LINUX FREEBSD OPENBSD)
add_obs_plugin(mac-avcapture PLATFORMS MACOS)
add_obs_plugin(mac-capture PLATFORMS MACOS)
add_obs_plugin(mac-syphon PLATFORMS MACOS)
add_obs_plugin(mac-videotoolbox PLATFORMS MACOS)
add_obs_plugin(mac-virtualcam PLATFORMS MACOS)

add_subdirectory(aja)
if(OS_WINDOWS OR OS_MACOS)
add_subdirectory(coreaudio-encoder)
endif()
if(OS_WINDOWS
OR OS_MACOS
OR OS_LINUX)
add_subdirectory(decklink)
endif()
add_subdirectory(image-source)
if(OS_WINDOWS)
add_subdirectory(nv-filters)
endif()
if(OS_LINUX)
add_subdirectory(linux-alsa)
add_subdirectory(linux-capture)
add_subdirectory(linux-jack)
add_subdirectory(linux-pipewire)
add_subdirectory(linux-pulseaudio)
add_subdirectory(linux-v4l2)
endif()
if(OS_MACOS)
add_subdirectory(mac-avcapture)
add_subdirectory(mac-capture)
add_subdirectory(mac-syphon)
add_subdirectory(mac-videotoolbox)
add_subdirectory(mac-virtualcam)
endif()
check_obs_browser()

add_obs_plugin(obs-ffmpeg)
add_obs_plugin(obs-filters)
add_obs_plugin(obs-libfdk)
add_obs_plugin(obs-outputs)
add_obs_plugin(obs-qsv11 PLATFORMS WINDOWS LINUX)
add_obs_plugin(obs-text PLATFORMS WINDOWS)
add_obs_plugin(obs-transitions)
add_obs_plugin(obs-vst PLATFORMS WINDOWS MACOS LINUX WITH_MESSAGE)
add_obs_plugin(obs-webrtc)

add_subdirectory(obs-ffmpeg)
add_subdirectory(obs-filters)
add_subdirectory(obs-outputs)
if(OS_WINDOWS)
add_subdirectory(obs-qsv11)
add_subdirectory(obs-text)
endif()
add_subdirectory(obs-transitions)
if(OS_WINDOWS
OR OS_MACOS
OR OS_LINUX)
add_subdirectory(obs-vst)
endif()
add_subdirectory(obs-webrtc)
check_obs_websocket()

add_obs_plugin(obs-x264)
add_obs_plugin(oss-audio PLATFORMS FREEBSD OPENBSD)
add_obs_plugin(rtmp-services)
add_obs_plugin(sndio PLATFORMS LINUX FREEBSD OPENBSD)
add_obs_plugin(text-freetype2)
add_obs_plugin(vlc-video WITH_MESSAGE)
add_obs_plugin(win-capture PLATFORMS WINDOWS)
add_obs_plugin(win-dshow PLATFORMS WINDOWS)
add_obs_plugin(win-wasapi PLATFORMS WINDOWS)

add_subdirectory(obs-x264)
add_subdirectory(rtmp-services)
if(OS_LINUX)
add_subdirectory(sndio)
endif()
add_subdirectory(text-freetype2)
if(OS_WINDOWS
OR OS_MACOS
OR OS_LINUX)
add_subdirectory(vlc-video)
endif()
if(OS_WINDOWS)
add_subdirectory(win-capture)
add_subdirectory(win-dshow)
add_subdirectory(win-wasapi)
endif()
return()
endif()

Expand Down Expand Up @@ -101,6 +121,7 @@ if(OS_WINDOWS)
add_subdirectory(obs-text)
add_subdirectory(vlc-video)
add_subdirectory(obs-vst)
add_subdirectory(nv-filters)

check_obs_browser()
elseif(OS_MACOS)
Expand Down
32 changes: 32 additions & 0 deletions plugins/nv-filters/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
cmake_minimum_required(VERSION 3.22...3.25)
if(OS_WINDOWS)
add_library(nv-filters MODULE)
add_library(OBS::nv-filters ALIAS nv-filters)

option(ENABLE_NVAFX "Enable building with NVIDIA Audio Effects SDK (requires redistributable to be installed)" ON)
option(ENABLE_NVVFX "Enable building with NVIDIA Video Effects SDK (requires redistributable to be installed)" ON)

if(ENABLE_NVAFX)
target_enable_feature(nv-filters "NVIDIA Audio FX support" LIBNVAFX_ENABLED HAS_NOISEREDUCTION)
target_sources(nv-filters PRIVATE nvidia-audiofx-filter.c)
else()
target_disable_feature(nv-filters "NVIDIA Audio FX support")
endif()

if(ENABLE_NVVFX)
target_enable_feature(nv-filters "NVIDIA Video FX support" LIBNVVFX_ENABLED)
target_sources(nv-filters PRIVATE nvidia-greenscreen-filter.c)
else()
target_disable_feature(nv-filters "NVIDIA Video FX support")
endif()

configure_file(cmake/windows/obs-module.rc.in nv-filters.rc)
target_sources(nv-filters PRIVATE nv-filters.rc)
target_sources(nv-filters PRIVATE nv-filters.c)

target_link_libraries(nv-filters PRIVATE OBS::libobs $<$<PLATFORM_ID:Windows>:OBS::w32-pthreads>)

# cmake-format: off
set_target_properties_obs(nv-filters PROPERTIES FOLDER plugins PREFIX "")
# cmake-format: on
endif()
24 changes: 24 additions & 0 deletions plugins/nv-filters/cmake/windows/obs-module.rc.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
1 VERSIONINFO
FILEVERSION ${OBS_VERSION_MAJOR},${OBS_VERSION_MINOR},${OBS_VERSION_PATCH},0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "${OBS_COMPANY_NAME}"
VALUE "FileDescription", "NVIDIA A/V Filters"
VALUE "FileVersion", "${OBS_VERSION_CANONICAL}"
VALUE "ProductName", "${OBS_PRODUCT_NAME}"
VALUE "ProductVersion", "${OBS_VERSION_CANONICAL}"
VALUE "Comments", "${OBS_COMMENTS}"
VALUE "LegalCopyright", "${OBS_LEGAL_COPYRIGHT}"
VALUE "InternalName", "nv-filters"
VALUE "OriginalFilename", "nv-filters"
END
END

BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 0x04B0
END
END
95 changes: 95 additions & 0 deletions plugins/nv-filters/data/color.effect
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
float srgb_linear_to_nonlinear_channel(float u)
{
return (u <= 0.0031308) ? (12.92 * u) : ((1.055 * pow(u, 1. / 2.4)) - 0.055);
}

float3 srgb_linear_to_nonlinear(float3 v)
{
return float3(srgb_linear_to_nonlinear_channel(v.r), srgb_linear_to_nonlinear_channel(v.g), srgb_linear_to_nonlinear_channel(v.b));
}

float srgb_nonlinear_to_linear_channel(float u)
{
return (u <= 0.04045) ? (u / 12.92) : pow((u + 0.055) / 1.055, 2.4);
}

float3 srgb_nonlinear_to_linear(float3 v)
{
return float3(srgb_nonlinear_to_linear_channel(v.r), srgb_nonlinear_to_linear_channel(v.g), srgb_nonlinear_to_linear_channel(v.b));
}

float3 rec709_to_rec2020(float3 v)
{
float r = dot(v, float3(0.62740389593469903, 0.32928303837788370, 0.043313065687417225));
float g = dot(v, float3(0.069097289358232075, 0.91954039507545871, 0.011362315566309178));
float b = dot(v, float3(0.016391438875150280, 0.088013307877225749, 0.89559525324762401));
return float3(r, g, b);
}

float3 rec2020_to_rec709(float3 v)
{
float r = dot(v, float3(1.6604910021084345, -0.58764113878854951, -0.072849863319884883));
float g = dot(v, float3(-0.12455047452159074, 1.1328998971259603, -0.0083494226043694768));
float b = dot(v, float3(-0.018150763354905303, -0.10057889800800739, 1.1187296613629127));
return float3(r, g, b);
}

float3 reinhard(float3 rgb)
{
rgb /= rgb + float3(1., 1., 1.);
rgb = saturate(rgb);
rgb = pow(rgb, float3(1. / 2.4, 1. / 2.4, 1. / 2.4));
rgb = srgb_nonlinear_to_linear(rgb);
return rgb;
}

float linear_to_st2084_channel(float x)
{
float c = pow(abs(x), 0.1593017578);
return pow((0.8359375 + 18.8515625 * c) / (1. + 18.6875 * c), 78.84375);
}

float st2084_to_linear_channel(float u)
{
float c = pow(abs(u), 1. / 78.84375);
return pow(abs(max(c - 0.8359375, 0.) / (18.8515625 - 18.6875 * c)), 1. / 0.1593017578);
}

float eetf_0_Lmax(float maxRGB1_pq, float Lw, float Lmax)
{
float Lw_pq = linear_to_st2084_channel(Lw / 10000.);
float E1 = saturate(maxRGB1_pq / Lw_pq); // Ensure normalization in case Lw is a lie
float maxLum = linear_to_st2084_channel(Lmax / 10000.) / Lw_pq;
float KS = (1.5 * maxLum) - 0.5;
float E2 = E1;
if (E1 > KS)
{
float T = (E1 - KS) / (1. - KS);
float Tsquared = T * T;
float Tcubed = Tsquared * T;
float P = (2. * Tcubed - 3. * Tsquared + 1.) * KS + (Tcubed - 2. * Tsquared + T) * (1. - KS) + (-2. * Tcubed + 3. * Tsquared) * maxLum;
E2 = P;
}
float E3 = E2;
float E4 = E3 * Lw_pq;
return E4;
}

float3 maxRGB_eetf_internal(float3 rgb_linear, float maxRGB1_linear, float maxRGB1_pq, float Lw, float Lmax)
{
float maxRGB2_pq = eetf_0_Lmax(maxRGB1_pq, Lw, Lmax);
float maxRGB2_linear = st2084_to_linear_channel(maxRGB2_pq);

// avoid divide-by-zero possibility
maxRGB1_linear = max(6.10352e-5, maxRGB1_linear);

rgb_linear *= maxRGB2_linear / maxRGB1_linear;
return rgb_linear;
}

float3 maxRGB_eetf_linear_to_linear(float3 rgb_linear, float Lw, float Lmax)
{
float maxRGB1_linear = max(max(rgb_linear.r, rgb_linear.g), rgb_linear.b);
float maxRGB1_pq = linear_to_st2084_channel(maxRGB1_linear);
return maxRGB_eetf_internal(rgb_linear, maxRGB1_linear, maxRGB1_pq, Lw, Lmax);
}
16 changes: 16 additions & 0 deletions plugins/nv-filters/data/locale/en-US.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
NoiseSuppress.SuppressLevel="Suppression Level"
NoiseSuppress.Intensity="Suppression Intensity"
NoiseSuppress.Method="Method"
NoiseSuppress.Method.Nvafx.Denoiser="NVIDIA Noise Removal"
NoiseSuppress.Method.Nvafx.Dereverb="NVIDIA Room Echo Removal"
NoiseSuppress.Method.Nvafx.DenoiserPlusDereverb="NVIDIA Noise Removal + Room Echo Removal"
NoiseSuppress.Method.Nvafx.Deprecation="WARNING: Please upgrade both NVIDIA Video & Audio SDK. Your current version of Audio SDK is outdated."
NvidiaGreenscreenFilter="NVIDIA Background Removal"
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."
Greenscreen.Processing="Mask refresh frequency in frames"
Greenscreen.Processing.Hint="This alleviates GPU load by generating a mask every N frames only (2 on default)."
NvidiaAudioFX="NVIDIA Audio Effects"
Loading

0 comments on commit 72e5eb5

Please sign in to comment.