Glad to hear you found something that works for you!
Since you got me down the rabbit hole of denoisers, I figured I would share my research results with anyone who’s interested.
ffmpeg has six denoisers built-in that I was able to find, which I’ve listed below along with their transcoding speeds on a 1080p source video using a four-core laptop computer. I wrote scripts that used a variety of settings with each denoiser to make sure I was seeing the best each one had to offer.
atadenoise (20 fps) - by averaging pixels across frames, it reduces contrast of noise areas to make them less obvious as opposed to using a specialized algorithm to smooth the noise away; this reduces overall image contrast; filter also darkens the overall output
dctdnoiz (1.6 fps) - creates beautiful detail on a still image, but randomizes the noise across frames so much that it actually makes the noise look worse during playback, plus it darkens the output
nlmeans (0.6 fps) - darkens the output, but sometimes has redeeming qualities (more on this later)
hqdn3d (21 fps) - color neutral which is good, but the output looks smeary to me where it loses a lot of fine detail in hair strands and wood grain
owdenoise (0.3 fps) - color neutral wavelet denoiser with stunningly good results on high-res sources
vaguedenoiser (7.6 fps) - another color neutral wavelet denoiser whose output looks identical to owdenoise, but its processing speed is 25x faster; tried every combination of threshold and nsteps, and found the default settings of 2/6 to consistently produce the closest-to-real-life results
I tested the denoisers on videos I took with my own mirrorless camera, meaning I remember what the scene looked like in real life. In one video, there happened to be a guy in a black business dress shirt made of silk or satin or something with a sheen to it, but the sheen wasn’t coming through due to the noise of the original footage. The wavelet-based denoisers were the only ones to remove and smooth the noise such that the fabric regained the smooth sheen you would expect from silk. To my eye, it bumped up the realism of the video an entire notch to see fabric actually look like fabric. The rest of the frame also dropped to zero dancing noise. It turned the video into a still photograph when nothing was moving. I didn’t realize until this experiment that even a tiny amount of dancing noise can seriously detract from the realism of a video, and that a sense of immersion can be restored by getting rid of it. Obviously, vaguedenoiser is my new weapon of choice.
So, about nlmeans… I found a radical difference between the ffmpeg version and the HandBrake version. I think HandBrake wins on every metric. nlmeans in ffmpeg actually makes video look worse (blockier) if the resolution is 1080p or above, or if the video comes from an excellent camera that has little noise to begin with. nlmeans in ffmpeg also can’t be used as a finishing step because it darkens the output, which destroys any color grading that happened before it. But I found two places where nlmeans in ffmpeg outshined the other ffmpeg denoisers: low-resolution video, and very-high-noise video. nlmeans does great at restoring a VHS capture, which I sense from the author’s web site was one of the original design goals. Secondly, in my tests, nlmeans did better than the other ffmpeg denoisers on high-resolution high-noise videos, which in my case meant a smartphone video in low light using digital zoom. Given these two specialized cases where nlmeans performed well, I could see a workflow where I used nlmeans to create denoised intermediates, then color graded the intermediates to fix the darkened output. Running nlmeans on a noisy source then adding it to the timeline and running vaguedenoiser on the total project did not cause any harm in my tests. But for best results, I think HandBrake is still the way to go where nlmeans is involved.
For my purposes, I think I will stick to vaguedenoiser because it’s beautiful on 1080p and 4K, and it is easily added to my existing ffmpeg filter chain when I do my finishing steps. I don’t have to create an intermediate to pass off to HandBrake this way. However, if I came across a particularly noisy source video, I would probably run it through HandBrake before adding it to my Shotcut project to get the same benefits Andrew noticed.
Good luck to everyone, whatever you use.