Denoise HD Video with FFmpeg nlmeans on Multi-Core

This article explains how to use the nlmeans (Non-Local Means) filter in FFmpeg to remove noise and grain from high-definition (HD) video. Because nlmeans is a highly effective but computationally expensive spatial denoising filter, we will focus on optimization techniques and command configurations that maximize multi-core processor performance to speed up render times.


Understanding the nlmeans Filter

The nlmeans filter works by finding and averaging similar pixel patches across a search window. While this process preserves edges and fine details much better than simple blur filters, processing 1080p or 4K video using default settings can be incredibly slow.

To run this efficiently on a multi-core CPU, you must balance the algorithm’s search parameters and leverage FFmpeg’s multi-threading capabilities.

The Basic nlmeans Command

The basic syntax for applying the nlmeans filter is:

ffmpeg -i input.mp4 -vf "nlmeans=s=1.0:p=7:r=15" -c:v libx264 -crf 18 output.mp4

Optimizing Parameters for Speed on HD Video

For HD video, the default patch and research sizes are often too demanding. You can significantly reduce processing time with minimal loss in visual quality by adjusting these parameters:

ffmpeg -i input.mp4 -vf "nlmeans=s=1.5:p=5:r=11" -c:v libx264 output.mp4

Maximizing Multi-Core Processor Usage

FFmpeg automatically attempts to multi-thread video decoding, filtering, and encoding, but you can explicitly force optimized threading behavior to ensure all CPU cores are saturated.

1. Enable Global Threading

Use the -threads option to tell FFmpeg to use all available CPU threads for both the filtering pipeline and the encoder:

ffmpeg -i input.mp4 -vf "nlmeans=s=1.0:p=5:r=11" -threads 0 -c:v libx264 -preset slow output.mp4

Setting -threads 0 forces FFmpeg to automatically spawn the optimal number of threads based on your processor’s logical core count.

2. Specify Filter Threads

You can specifically allocate CPU threads to the filter graph itself by using the -filter_threads flag. This is highly beneficial when running heavy filters like nlmeans:

ffmpeg -i input.mp4 -filter_threads 8 -vf "nlmeans=s=1.0:p=5:r=11" -c:v libx264 output.mp4

Replace 8 with the number of physical cores or logical threads you wish to dedicate solely to the denoising process.

3. Segmented parallel processing (Advanced)

If your CPU has a high core count (e.g., 16+ cores), a single FFmpeg process using nlmeans might still underutilize your system due to internal filtering bottlenecks. To fully saturate a high-end processor, you can split your video into segments, process them simultaneously in parallel, and concatenate them:

# Process segment 1 on threads 0-7
ffmpeg -ss 00:00:00 -t 00:05:00 -i input.mp4 -vf "nlmeans" -threads 8 part1.mp4

# Process segment 2 on threads 8-15
ffmpeg -ss 00:05:00 -t 00:10:00 -i input.mp4 -vf "nlmeans" -threads 8 part2.mp4

Using these optimization strategies ensures you achieve high-quality, detail-preserving denoising on HD video without stalling your post-production workflow.