-
-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
obs-filters: Move NVIDIA filters in their own project
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
Showing
17 changed files
with
1,747 additions
and
673 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
Nvafx="NVIDIA Audio Effects" | ||
Nvafx.SuppressLevel="Suppression Level" | ||
Nvafx.Intensity="Suppression Intensity" | ||
Nvafx.Method="Method" | ||
Nvafx.Method.Denoiser="NVIDIA Noise Removal" | ||
Nvafx.Method.Dereverb="NVIDIA Room Echo Removal" | ||
Nvafx.Method.DenoiserPlusDereverb="NVIDIA Noise Removal + Room Echo Removal" | ||
Nvafx.OutdatedSDK="WARNING: Please upgrade both NVIDIA Video & Audio SDK. Your current version of Audio SDK is outdated." | ||
Nvvfx.Method.Greenscreen="NVIDIA Background Removal" | ||
Nvvfx.Method.Greenscreen.Mode="Mode" | ||
Nvvfx.Method.Greenscreen.Quality="Quality (higher GPU usage, better quality)" | ||
Nvvfx.Method.Greenscreen.Performance="Performance (lower GPU usage, good quality)" | ||
Nvvfx.Method.Greenscreen.Threshold="Threshold" | ||
Nvvfx.OutdatedSDK="WARNING: Please upgrade both NVIDIA Video & Audio SDK. Your current version of Video SDK is outdated." | ||
Nvvfx.Method.Greenscreen.Processing="Mask refresh frequency in frames" | ||
Nvvfx.Method.Greenscreen.Processing.Hint="This alleviates GPU load by generating a mask every N frames only (2 on default)." | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
#include "color.effect" | ||
|
||
uniform float4x4 ViewProj; | ||
uniform texture2d image; | ||
uniform float multiplier; | ||
|
||
uniform texture2d mask; | ||
uniform float threshold; | ||
|
||
sampler_state texSampler { | ||
Filter = Linear; | ||
AddressU = Clamp; | ||
AddressV = Clamp; | ||
}; | ||
|
||
struct VertData { | ||
float4 pos : POSITION; | ||
float2 uv : TEXCOORD0; | ||
}; | ||
|
||
struct VertInOut { | ||
float2 uv : TEXCOORD0; | ||
float4 pos : POSITION; | ||
}; | ||
|
||
struct FragData { | ||
float2 uv : TEXCOORD0; | ||
}; | ||
|
||
struct FragPos { | ||
float4 pos : POSITION; | ||
}; | ||
|
||
VertInOut VSDefault(VertData v_in) | ||
{ | ||
VertInOut v_out; | ||
v_out.uv = v_in.uv; | ||
v_out.pos = mul(float4(v_in.pos.xyz, 1.), ViewProj); | ||
return v_out; | ||
} | ||
|
||
FragPos VSConvertUnorm(uint id : VERTEXID) | ||
{ | ||
float idHigh = float(id >> 1); | ||
float idLow = float(id & uint(1)); | ||
|
||
float x = idHigh * 4.0 - 1.0; | ||
float y = idLow * 4.0 - 1.0; | ||
|
||
FragPos vert_out; | ||
vert_out.pos = float4(x, y, 0.0, 1.0); | ||
return vert_out; | ||
} | ||
|
||
float4 Mask(FragData f_in) | ||
{ | ||
float4 rgba = image.Sample(texSampler, f_in.uv); | ||
rgba *= smoothstep(threshold - 0.1,threshold,mask.Sample(texSampler, f_in.uv).a); | ||
return rgba; | ||
} | ||
|
||
float4 PSMask(FragData f_in) : TARGET | ||
{ | ||
float4 rgba = Mask(f_in); | ||
return rgba; | ||
} | ||
|
||
float4 PSMaskMultiply(FragData f_in) : TARGET | ||
{ | ||
float4 rgba = Mask(f_in); | ||
rgba.rgb *= multiplier; | ||
return rgba; | ||
} | ||
|
||
float4 PSMaskTonemap(FragData f_in) : TARGET | ||
{ | ||
float4 rgba = Mask(f_in); | ||
rgba.rgb = rec709_to_rec2020(rgba.rgb); | ||
rgba.rgb = reinhard(rgba.rgb); | ||
rgba.rgb = rec2020_to_rec709(rgba.rgb); | ||
return rgba; | ||
} | ||
|
||
float4 PSMaskMultiplyTonemap(FragData f_in) : TARGET | ||
{ | ||
float4 rgba = Mask(f_in); | ||
rgba.rgb *= multiplier; | ||
rgba.rgb = rec709_to_rec2020(rgba.rgb); | ||
rgba.rgb = reinhard(rgba.rgb); | ||
rgba.rgb = rec2020_to_rec709(rgba.rgb); | ||
return rgba; | ||
} | ||
|
||
float4 PSConvertUnorm(FragPos f_in) : TARGET | ||
{ | ||
float4 rgba = image.Load(int3(f_in.pos.xy, 0)); | ||
rgba.rgb = srgb_linear_to_nonlinear(rgba.rgb); | ||
return rgba; | ||
} | ||
|
||
float4 PSConvertUnormTonemap(FragPos f_in) : TARGET | ||
{ | ||
float4 rgba = image.Load(int3(f_in.pos.xy, 0)); | ||
rgba.rgb = rec709_to_rec2020(rgba.rgb); | ||
rgba.rgb = reinhard(rgba.rgb); | ||
rgba.rgb = rec2020_to_rec709(rgba.rgb); | ||
rgba.rgb = srgb_linear_to_nonlinear(rgba.rgb); | ||
return rgba; | ||
} | ||
|
||
float4 PSConvertUnormMultiplyTonemap(FragPos f_in) : TARGET | ||
{ | ||
float4 rgba = image.Load(int3(f_in.pos.xy, 0)); | ||
rgba.rgb *= multiplier; | ||
rgba.rgb = rec709_to_rec2020(rgba.rgb); | ||
rgba.rgb = reinhard(rgba.rgb); | ||
rgba.rgb = rec2020_to_rec709(rgba.rgb); | ||
rgba.rgb = srgb_linear_to_nonlinear(rgba.rgb); | ||
return rgba; | ||
} | ||
|
||
technique Draw | ||
{ | ||
pass | ||
{ | ||
vertex_shader = VSDefault(v_in); | ||
pixel_shader = PSMask(f_in); | ||
} | ||
} | ||
|
||
technique DrawMultiply | ||
{ | ||
pass | ||
{ | ||
vertex_shader = VSDefault(v_in); | ||
pixel_shader = PSMaskMultiply(f_in); | ||
} | ||
} | ||
|
||
technique DrawTonemap | ||
{ | ||
pass | ||
{ | ||
vertex_shader = VSDefault(v_in); | ||
pixel_shader = PSMaskTonemap(f_in); | ||
} | ||
} | ||
|
||
technique DrawMultiplyTonemap | ||
{ | ||
pass | ||
{ | ||
vertex_shader = VSDefault(v_in); | ||
pixel_shader = PSMaskMultiplyTonemap(f_in); | ||
} | ||
} | ||
|
||
technique ConvertUnorm | ||
{ | ||
pass | ||
{ | ||
vertex_shader = VSConvertUnorm(id); | ||
pixel_shader = PSConvertUnorm(f_in); | ||
} | ||
} | ||
|
||
technique ConvertUnormTonemap | ||
{ | ||
pass | ||
{ | ||
vertex_shader = VSConvertUnorm(id); | ||
pixel_shader = PSConvertUnormTonemap(f_in); | ||
} | ||
} | ||
|
||
technique ConvertUnormMultiplyTonemap | ||
{ | ||
pass | ||
{ | ||
vertex_shader = VSConvertUnorm(id); | ||
pixel_shader = PSConvertUnormMultiplyTonemap(f_in); | ||
} | ||
} |
Oops, something went wrong.