An enhanced fork of FFmpeg n7.1.5 focused on modern hardware: multi-CCD CPUs, any-vendor GPUs, and NPUs. Same LGPL/GPL license as upstream.
| Area | What it adds | Key option |
|---|---|---|
| CPU / threads | CCD/NUMA-aware thread pinning for chiplet CPUs | -numa_aware |
| GPU | Vendor-neutral compute dispatch (Vulkan/OpenCL/D3D12) | -gpu_backend, *_gpu filters |
| HW transcode | NVENC/NVDEC + QSV + AMF hardware encode/decode, full-GPU pipeline | -c:v h264_nvenc, -hwaccel cuda |
| NPU / ML | ONNX Runtime backend with DirectML offload | dnn_backend=onnxruntime:execution_provider=directml |
The build ships with vendor hardware encoders and decoders so the GPU's dedicated video engines do the encode/decode work instead of the CPU.
| Vendor | Decoders | Encoders | Scale filter |
|---|---|---|---|
| NVIDIA | *_cuvid, *_nvdec hwaccel |
h264_nvenc, hevc_nvenc, av1_nvenc |
scale_npp |
| Intel | *_qsv |
h264_qsv, hevc_qsv, av1_qsv |
scale_qsv, vpp_qsv |
| AMD | (d3d11va) | h264_amf, hevc_amf, av1_amf |
— |
# Simple: GPU encode (CPU decodes, NVENC encodes)
ffmpeg -i in.mp4 -c:v h264_nvenc -preset p7 out.mp4
# Full-GPU pipeline: NVDEC decodes -> scale_npp scales -> NVENC encodes,
# the frame never leaves the GPU (no CPU<->GPU copy).
ffmpeg -threads 1 -hwaccel cuda -hwaccel_output_format cuda -i in.mp4 \
-vf scale_npp=1920:1080 -c:v h264_nvenc -preset p7 out.mp4Measured on RTX 4090 (4K source):
| Job | CPU libx264 |
h264_nvenc |
Full-GPU pipeline |
|---|---|---|---|
| 4K → 4K (quality preset) | 0.95× realtime (29 fps) | 2.81× (85 fps) | — |
| 4K → 1080p downscale | — | — | 7.28× (220 fps) |
Important —
-threads 1with-hwaccel cuda: this fork raises the automatic frame-thread cap to 64 (see §1). NVDEC allocates a decode surface per thread and fails above 32 surfaces (CUDA_ERROR_INVALID_VALUE). When hardware-decoding, the GPU does the decode, so CPU threads add nothing — pass-threads 1to keep the surface count in range. (CPU-only decode is unaffected.)
A common instinct is to run many transcode jobs in parallel for throughput. Whether that helps depends entirely on the encoder:
Measured on RTX 4090 (4K → 1080p scale_npp + h264_nvenc), aggregate fps:
| Concurrent jobs | 1 | 2 | 4 | 6 | 8 |
|---|---|---|---|---|---|
| Aggregate fps | 201 | 226 | 233 | 234 | 236 |
A single NVENC job already saturates the GPU's encode engine — running 8 in
parallel raises throughput by only ~17 % while consuming 8× the VRAM and encode
sessions. Hardware encoders should be run serially. CPU encoders
(libx264/libx265) are the opposite: throughput scales with cores, so they
should be run in parallel (and benefit from the CCD pinning in §1).
tools/batch_transcode.sh encodes this rule — it auto-detects the encoder and
runs hardware jobs serially, CPU jobs in parallel:
# GPU: serial (engine-bound)
FFMPEG=./ffmpeg.exe tools/batch_transcode.sh -i in/ -o out/ -c h264_nvenc -a "-preset p5 -cq 26"
# CPU: parallel across CCDs
FFMPEG=./ffmpeg.exe tools/batch_transcode.sh -i in/ -o out/ -c libx264 -a "-preset medium -crf 20" -j 8The build includes av1_nvenc (and hevc_nvenc). On an Ada GPU (RTX 4090)
these are faster than h264_nvenc and produce substantially smaller files at
the same quality.
Measured — Big Buck Bunny 1080p, NVENC -preset p6, quality = VMAF
(libvmaf, model v0.6.1) vs the source:
| Bitrate | H.264 VMAF | HEVC VMAF | AV1 VMAF |
|---|---|---|---|
| ~1 Mbps | 65.6 | 74.9 | 78.1 |
| ~2 Mbps | 81.4 | 85.6 | 87.8 |
| ~4 Mbps | 89.9 | 91.9 | 92.9 |
| ~8 Mbps | 94.2 | 95.3 | 95.7 |
Bitrate needed for the same quality (log-interpolated from the table):
| Target | H.264 | HEVC | AV1 |
|---|---|---|---|
| VMAF 85 | baseline | −29 % | −39 % |
| VMAF 90 | baseline | −20 % | −34 % |
So av1_nvenc reaches the same perceptual quality as h264_nvenc at roughly
one-third less bitrate — biggest at low bitrates, where it matters most.
# AV1 at a quality target (CQ), hardware speed:
ffmpeg -i in.mp4 -c:v av1_nvenc -preset p6 -rc vbr -cq 28 -c:a copy out.mp4Gains here use the hardware encoder. Re-verified on live-action content (Xiph
foreman, 720p) the advantage is larger, not smaller: AV1 reaches VMAF 93 at ~1 Mbps where H.264 needs ~2 Mbps — roughly −50 % bitrate at equal quality (vs −34 % on the animated clip). So the animation numbers are conservative; AV1 helps most on the detailed, high-motion footage H.264 struggles with.
Decoding AV1: the build includes libdav1d (VideoLAN's AV1 decoder), so AV1 decodes natively in software — no hardware decoder required.
libdav1dis the default AV1 decoder;av1_cuvid(NVDEC) andav1_qsvremain available for hardware decode. (FFmpeg's built-inav1decoder is incomplete and is not used.)
The build also includes the SVT-AV1 software encoder (libsvtav1). Hardware
and software AV1 sit at opposite ends of the speed/quality curve.
Measured — 1080p, same target bitrate, VMAF vs. source (RTX 4090 / Ryzen 9950X):
| Encoder | Preset | 2 Mbps VMAF | 4 Mbps VMAF | Speed |
|---|---|---|---|---|
av1_nvenc (HW) |
p5 | 88.5 | 93.3 | 10.5× |
libsvtav1 (SW) |
10 (fast) | 88.2 | — | 7.8× |
libsvtav1 (SW) |
6 (quality) | 93.1 | 95.6 | 2.9× |
Reading the table:
- For speed / realtime →
av1_nvenc. The hardware engine runs ~10× realtime at any bitrate; nothing software matches it. - For maximum compression →
libsvtav1 -preset 6. It reaches VMAF 93 at 2 Mbps whereav1_nvencneeds ~4 Mbps — roughly half the bitrate at equal quality — but at ~⅓ the speed. - Fast software (
-preset 10) is the worst of both: slower than hardware with no quality gain. The real choice is HW for speed vs SW preset 6 for quality.
# fastest (hardware):
ffmpeg -i in.mp4 -c:v av1_nvenc -preset p5 -b:v 2M out.mp4
# smallest at equal quality (software, ~3.6x slower):
ffmpeg -i in.mp4 -c:v libsvtav1 -preset 6 -b:v 2M out.mp4Combining the quality and speed measurements above (1080p, RTX 4090, NVENC):
| Encoder | Bitrate vs H.264¹ | Encode speed² | Pick when |
|---|---|---|---|
h264_nvenc |
baseline | 8.4× | maximum device compatibility |
hevc_nvenc |
−20 % | 5.7× | smaller files, broad HW HEVC support |
av1_nvenc |
−34 % | 9.6× | AV1 playback available (newest, best) |
¹ Bitrate for equal quality (VMAF 90), from the AV1 efficiency table above. ² Realtime multiple at preset p6, 4 Mbps.
On Ada, av1_nvenc is both the most efficient and the fastest of the three —
the obvious default wherever AV1 decode is supported (browsers, recent TVs/phones).
hevc_nvenc is the middle ground for hardware that lacks AV1; h264_nvenc remains
the universal-compatibility baseline.
Instead of guessing a CRF/CQ, let the tool find the smallest-file setting that still meets a quality target. It binary-searches the quality parameter, measuring each step with this build's libvmaf, and reports (optionally producing) the encode.
FFMPEG=./ffmpeg.exe python tools/vmaf_tune.py -i in.mp4 -o out.mp4 \
--encoder av1_nvenc --target-vmaf 93 --preset p6It returns the largest q whose VMAF ≥ target (smallest file meeting quality).
Example on Xiph foreman 720p, av1_nvenc, target VMAF 93: it picked -cq 40
(≈1.07 Mbps) — vs the naive high-quality -cq 20 at ≈9 Mbps for the same
perceptual quality, an 8.5× smaller file. Works with av1_nvenc/hevc_nvenc/
h264_nvenc (-cq) and libsvtav1/libx264/libx265 (-crf); a short
--sample-seconds keeps the search fast, then -o does the full-length encode.
Pins frame/slice worker threads to a single CCD (L3 cache domain) so each worker's working set stays in one cache — a measurable win on chiplet CPUs such as AMD Ryzen 9000.
# auto (default): on when >1 CCD is detected
ffmpeg -i in.mp4 -c:v libx264 -threads 0 out.mp4
# force on / off (for A/B benchmarking)
ffmpeg -numa_aware 1 -i in.mp4 ... out.mp4
ffmpeg -numa_aware 0 -i in.mp4 ... out.mp4-v verbose prints the detected topology:
CPU topology: 2 CCD(s), 16 physical cores, 32 logical CPUs, SMT=2
CCD 0: 8 cores, 16 threads, L3=32768KB, mask=0x000000000000ffff
CCD 1: 8 cores, 16 threads, L3=32768KB, mask=0x00000000ffff0000
A <base>_gpu filter name resolves at runtime to the best available backend
variant (_vulkan / _opencl), so the same command line works on NVIDIA,
AMD and Intel GPUs.
# auto-pick backend (priority: vulkan > opencl > d3d12)
ffmpeg -init_hw_device vulkan=vk -filter_hw_device vk -i in.mp4 \
-vf "format=nv12,hwupload,scale_gpu=w=1920:h=1080,hwdownload,format=nv12" out.mp4
# force a backend
ffmpeg -gpu_backend opencl -i in.mp4 -vf "...,avgblur_gpu=sizeX=5,..." out.mp4Available meta-filters: scale_gpu, avgblur_gpu, transpose_gpu,
overlay_gpu, nlmeans_gpu (resolve where a backend variant exists).
For super-resolution / denoise, prefer the bundled npuscale tool (in this repo). The in-graph
dnn_backend=onnxruntimeroute below works, but FFmpeg's DNN framework spawns a thread per inference and limits optimization. npuscale pipes raw frames to/from stock ffmpeg and drives ONNX Runtime + DirectML directly, so it gets full control — worker pool, IoBinding, FP16, tiling, and temporal (multi-frame) models — and is faster. Use the in-fork backend only when you need the DNN step inside a single ffmpeg filter graph (e.g.dnn_detectside-data).
Run DNN filters on the ONNX Runtime, optionally offloaded to an NPU/GPU via the DirectML execution provider.
# generic frame processing on the NPU
ffmpeg -i in.mp4 -vf \
"format=rgb24,dnn_processing=dnn_backend=onnxruntime:model=model.onnx:execution_provider=directml" \
out.mp4
# NPU super-resolution
ffmpeg -i in.mp4 -vf \
"format=yuv420p,sr=dnn_backend=onnxruntime:model=sr.onnx:execution_provider=directml" \
out.mp4Filters supporting dnn_backend=onnxruntime: dnn_processing, sr, derain, dnn_detect.
Pipelined inference: add async=1 to run inference on background threads and
nireq=N (default 2) to keep several frames in flight, overlapping inference
with decode/encode. Example:
dnn_processing=dnn_backend=onnxruntime:model=m.onnx:execution_provider=directml:async=1:nireq=4
Execution providers: cpu (always), directml (NPU/GPU, Windows),
cuda. Verify NPU usage in Task Manager → Performance → NPU.
A prebuilt, self-contained Windows x64 package with a DirectML-enabled ONNX Runtime (plus test models and benchmark scripts) is attached to the latest release.
See INSTALL.md for the standard FFmpeg build. Extra options introduced by this fork:
--enable-libonnxruntime # ONNX Runtime DNN backend (DirectML auto-detected)
GPU compute uses the usual --enable-vulkan / --enable-opencl
(--enable-libshaderc for Vulkan compute filters). CCD affinity has no extra
dependency.
One command: from the repo root in an MSYS2 ucrt64 shell, run
./tools/build.sh(full/personal) or./tools/build.sh --redistributable(GPL build, drops fdk-aac/libnpp). It installs deps, auto-detects the CUDA path, configures, verifies the License line, and builds.--dry-runprints the exact./configurecommand. The manual steps below are what it automates.
Install dependencies first:
pacman -S --needed \
mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-nasm make diffutils pkgconf \
mingw-w64-ucrt-x86_64-x264 mingw-w64-ucrt-x86_64-libass mingw-w64-ucrt-x86_64-fdk-aac \
mingw-w64-ucrt-x86_64-shaderc mingw-w64-ucrt-x86_64-vulkan-headers mingw-w64-ucrt-x86_64-vulkan-loader \
mingw-w64-ucrt-x86_64-opencl-headers mingw-w64-ucrt-x86_64-opencl-icd \
mingw-w64-ucrt-x86_64-ffnvcodec-headers mingw-w64-ucrt-x86_64-libvpl mingw-w64-ucrt-x86_64-amf-headers \
mingw-w64-ucrt-x86_64-vmaf mingw-w64-ucrt-x86_64-svt-av1 mingw-w64-ucrt-x86_64-dav1dFor NVIDIA NPP (scale_npp, GPU-resident scaling) you also need the CUDA
Toolkit installed (provides the NPP libraries); the configure below points at
CUDA 12.6 via the 8.3 short path (spaces in Program Files break the linker).
Configure with all features enabled:
export TMP=/tmp TEMP=/tmp TMPDIR=/tmp # required on Windows
./configure \
--cc=gcc \
--enable-gpl --enable-nonfree \
--enable-libx264 --enable-libass --enable-libfdk-aac \
--enable-libonnxruntime --enable-libvmaf --enable-libsvtav1 --enable-libdav1d \
--enable-vulkan --enable-libshaderc --enable-opencl \
--enable-ffnvcodec --enable-cuvid --enable-nvenc --enable-nvdec \
--enable-libvpl --enable-amf --enable-libnpp \
--extra-cflags=-I/c/PROGRA~1/NVIDIA~2/CUDA/v12.6/include \
--extra-ldflags=-L/c/PROGRA~1/NVIDIA~2/CUDA/v12.6/lib/x64 \
--enable-protocol=file,pipe,data \
--enable-demuxer=mov,matroska,avi,mpegts,rawvideo,flv,ogg,wav,mp3,aac,flac,yuv4mpegpipe \
--enable-muxer=mp4,matroska,avi,mpegts,rawvideo,ogg,null,flv,mp3,adts,flac,wav \
--enable-decoder=h264,hevc,vp8,vp9,av1,mpeg4,aac,mp3,ac3,opus,vorbis,flac,pcm_s16le,rawvideo,wrapped_avframe,ass,ssa,libdav1d,h264_cuvid,hevc_cuvid,av1_cuvid,vp9_cuvid,h264_qsv,hevc_qsv,av1_qsv \
--enable-encoder=libx264,libfdk_aac,aac,rawvideo,wrapped_avframe,mpeg4,mp3,h264_nvenc,hevc_nvenc,av1_nvenc,h264_qsv,hevc_qsv,av1_qsv,h264_amf,hevc_amf,av1_amf,libsvtav1 \
--enable-hwaccel=h264_nvdec,hevc_nvdec,av1_nvdec,vp9_nvdec,h264_d3d11va,hevc_d3d11va,av1_d3d11va \
--enable-filter=scale,format,ass,subtitles,amix,aresample,amerge,volume,aformat,overlay,crop,pad,vflip,hflip,transpose,rotate,trim,atrim,concat,split,asplit,fps,setpts,null,anull,dnn_processing,sr,derain,dnn_detect,scale_npp,scale_qsv,vpp_qsv,hwupload,hwupload_cuda,hwdownload,psnr,ssim,xpsnr,libvmaf \
--enable-filter=avgblur_vulkan,scale_vulkan,transpose_vulkan,overlay_vulkan,nlmeans_vulkan \
--enable-indev=lavfi \
--disable-doc
make -j$(nproc)This produces an ffmpeg.exe with H.264 (libx264), AAC (libfdk_aac), ASS subtitles,
audio mixing (amix), Vulkan/OpenCL GPU filters, NVENC/NVDEC + QSV + AMF hardware
transcode with a full-GPU scale_npp pipeline, and ONNX Runtime NPU inference all
in one binary.
CUDA filters that require
nvcc(scale_cuda,overlay_cuda,yadif_cuda) are not enabled here — they need--enable-cuda-nvcc, which on MSYS2 pulls in the MSVC host compiler and complicates the build.scale_nppcovers GPU-resident scaling withoutnvcc.
The recipe above uses --enable-nonfree (for fdk-aac) and libnpp
(scale_npp). FFmpeg's configure flags both as nonfree, so it prints
"License: nonfree and unredistributable" — that binary is fine for personal
use but cannot be legally redistributed.
To build a GPL‑redistributable binary (for publishing prebuilt downloads), drop the three nonfree pieces:
| Remove | Replace with |
|---|---|
--enable-nonfree |
(just --enable-gpl) |
--enable-libfdk-aac + libfdk_aac encoder |
the native aac encoder (already enabled) |
--enable-libnpp + scale_npp filter |
scale_vulkan (or scale_cuda with --enable-cuda-nvcc) for GPU scaling |
Everything else — NVENC/NVDEC, QSV, AMF, SVT‑AV1, libdav1d, libvmaf, libx264,
ONNX Runtime, Vulkan/OpenCL filters — stays. Configure then prints
"License: GPL version 2 or later" and the binary is redistributable.
(The only functional losses are fdk-aac, marginally better than native aac, and
the scale_npp GPU scaler — use scale_vulkan for a vendor‑neutral GPU scale.)
For full details of every change, see CHANGES.md.