Skip to content

Instantly share code, notes, and snippets.

@myfreeer
Last active January 19, 2025 09:23
Show Gist options
  • Save myfreeer/d744c445aa71c0eeb165ca39cf6c0511 to your computer and use it in GitHub Desktop.
Save myfreeer/d744c445aa71c0eeb165ca39cf6c0511 to your computer and use it in GitHub Desktop.
mpv user-script to cycle between lavfi's denoise filters, tested over mpv 0.25.0-58-g99cef59fc
-- settings
-- key_binding: press the key specified below
-- to cycle between denoise filters below,
-- set it to nil to disable the binding
local key_binding = "n"
-- key_binding_reverse cycle between denoise filters below
-- in reverse order, set it to nil to disable the binding,
-- set it to a single-char string to enable
local key_binding_reverse = nil
-- denoisers: specify names of denoise libavfilter filters
-- from `mpv --vf=lavfi=help` command
-- where the last 3 filters (dctdnoiz, owdenoise, nlmeans)
-- are too slow to be used in playback
local denoisers = {
"removegrain"
,"atadenoise"
,"hqdn3d"
,"vaguedenoiser"
-- ,"dctdnoiz"
-- ,"owdenoise"
-- ,"nlmeans"
}
local denoiser_count = #denoisers
local filter_index = 0
local script_name = mp.get_script_name()
local denoise_label = string.format("%s-denoise", script_name)
-- from https://github.com/mpv-player/mpv/blob/39e04e929483847a3e0722d86d53f69837ed99db/TOOLS/lua/autocrop.lua
function del_filter_if_present(label)
-- necessary because mp.command('vf del @label:filter') raises an
-- error if the filter doesn't exist
local vfs = mp.get_property_native("vf")
for i,vf in pairs(vfs) do
if vf["label"] == label then
table.remove(vfs, i)
mp.set_property_native("vf", vfs)
return true
end
end
return false
end
function cycle_denoise()
if not del_filter_if_present(denoise_label) then
filter_index = 0
end
filter_index = filter_index + 1
if filter_index > denoiser_count then
mp.osd_message("denoise filters removed", osd_time)
return
end
-- insert the filter
mp.command(
string.format(
'vf add @%s:lavfi=graph="%s"',
denoise_label, denoisers[filter_index]
)
)
end
function cycle_denoise_reverse()
if not del_filter_if_present(denoise_label) then
filter_index = denoiser_count
else
filter_index = filter_index - 1
end
if filter_index < 1 then
mp.osd_message("denoise filters removed", osd_time)
return
end
-- insert the filter
mp.command(
string.format(
'vf add @%s:lavfi=graph="%s"',
denoise_label, denoisers[filter_index]
)
)
end
if key_binding then
mp.add_key_binding(key_binding, "denoise", cycle_denoise)
end
if key_binding_reverse then
mp.add_key_binding(key_binding_reverse, "denoise-reverse", cycle_denoise_reverse)
end
@geextahslex
Copy link

@myfreeer The noise is most of the time present in the lows 0-60srgb. When it's affecting the whole image, it blurrs the mids and highlights with no reason. Is it possible to limit the affected range of the video filter (srgb0-60)? This would be very usefull. It would keep details in the highlights, like faces etc.

@myfreeer
Copy link
Author

myfreeer commented May 2, 2024

@myfreeer The noise is most of the time present in the lows 0-60srgb. When it's affecting the whole image, it blurrs the mids and highlights with no reason. Is it possible to limit the affected range of the video filter (srgb0-60)? This would be very usefull. It would keep details in the highlights, like faces etc.

@geextahslex The filters referenced by this script is ffmpeg filters, check the docs for detailed usage of filters, or maybe try VapourSynth filter if your build includes it.

@geextahslex
Copy link

Hi, I try to limit the effect of lavfi atadenoise to a specific srgb threshold but I have no idea how to make this "work"
this would be the ffmpeg command

-vf "split [original][denoised];
[denoised] atadenoise [denoised_out];
[original] lutyuv='u=128:v=128' [gray];
[gray][denoised_out]
blend=all_expr='if(between(A,0,25),B,if(between(A,25,35),B+(35-A)*(B-A)/10,A))'"

So how to put this inside mpv? ^^'

@myfreeer
Copy link
Author

@geextahslex
So how to put this inside mpv? ^^'

See CONFIGURATION FILES, using this can make mpv load specified options on startup.

@geextahslex
Copy link

@myfreeer yeah I already fixed that, no worries mate :)

@veganomy
Copy link

veganomy commented Jan 13, 2025

How to use this script ? Kept the file in my scripts directory. What next ?

PS: I use no-input-default-bindings and have my own bindings through input.conf

@myfreeer
Copy link
Author

How to use this script ? Kept the file in my scripts directory. What next ?

PS: I use no-input-default-bindings and have my own bindings through input.conf

Edit the key binding here, and press it when the player is active.

Have not tested how no-input-default-bindings affects this.

@veganomy
Copy link

@myfreeer That is exactly why I asked. Doesn't work with no-input-default-bindings

@myfreeer
Copy link
Author

@myfreeer That is exactly why I asked. Doesn't work with no-input-default-bindings

@veganomy You'll need to change mp.add_key_binding to mp.add_forced_key_binding in line 89 and 93 according to the doc

@veganomy
Copy link

veganomy commented Jan 19, 2025

Why not just use forced function in your script? Like what's the point of preventing the bindings from users who do no-input-default-bindings ? Like I don't even use n binding and the script doesn't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment