FFmpeg encoding settings compared
Compare every FFmpeg encoding setting that changes output size, measured on one file: preset, CRF, tune, keyframe interval, pixel format, threads and scaler.
There are perhaps a dozen FFmpeg settings that meaningfully change what comes out of an encode, and most guides describe all of them without measuring any. This one measures all of them, on the same file, so the numbers compare.
Short version, ranked by how much each setting moves the output:
- Codec — up to 66% fewer bytes at matched quality
- Keyframe interval — up to 6.1x, and 35% for the common HLS setting
-tune— up to 121% for one word- CRF — about 20% per 3 points
- Preset — 6.6x across the full range, non-monotonic in the middle
- Pixel format — 5% and a lot of compatibility
- Scaler flag — 66% between best and worst, and free in time
Everything below came from a real job. 106 encodes on one 5-second 1280x720 source, run through a live API, with the exact commands and costs recorded.
The settings that cost the most
Keyframe interval is the biggest lever after codec
A keyframe is a complete picture; every other frame stores only what changed. So the interval decides how often the encoder throws away its compression and starts again, and it compounds.
| Variant | Encode | Size | Cost |
|---|---|---|---|
| -g 12 (0.4s) | 836 ms | 778.7 KB | $0.0024 |
| -g 30 (1s) | 939 ms | 584.6 KB | $0.0024 |
| -g 60 (2s) | 960 ms | 504.6 KB | $0.0024 |
| -g 250 (default) | 945 ms | 433.0 KB | $0.0024 |
| all keyframes | 446 ms fastest | 2661.4 KB | $0.0039 |
Encoding every frame as a keyframe produced 2,661 KB against the default’s 433 KB. The 1-second GOP that HLS guides recommend costs 35% more bytes than x264’s default, and a 2-second GOP costs 17%.
Encode time barely moves across the range, so this is a pure bandwidth decision. For streaming, 2 seconds is usually right. For a download, the default is free money. Full detail in FFmpeg keyframe interval compared.
-tune is the most expensive single word
| Variant | Encode | Size | Cost |
|---|---|---|---|
| no tune | 912 ms fastest | 433.0 KB | $0.0025 |
| film | 1502 ms | 446.6 KB | $0.0030 |
| animation | 2045 ms | 404.9 KB | $0.0036 |
| grain | 1133 ms | 450.0 KB | $0.0026 |
| stillimage | 959 ms | 536.6 KB | $0.0023 |
| fastdecode | 982 ms | 725.7 KB | $0.0024 |
| zerolatency | 1444 ms | 955.5 KB | $0.0029 |
-tune zerolatency produced 121% more bytes. It disables lookahead, B-frames and frame threading so the encoder never holds a frame back, and every one of those exists to improve compression. -tune fastdecode costs 68% for the same reason.
Neither flag is misnamed. The trap is that “tune for low latency” reads like a scheduling hint and behaves like a doubled bitrate. If your pipeline already buffers seconds of HLS segments, you have accepted the latency and are paying for nothing. Detail in FFmpeg tune presets compared.
CRF is the cheapest decision available
| Variant | Encode | Size | Cost |
|---|---|---|---|
| CRF 18 | 2216 ms | 665.8 KB | $0.0038 |
| CRF 20 | 1938 ms | 551.9 KB | $0.0036 |
| CRF 23 | 982 ms | 433.0 KB | $0.0025 |
| CRF 26 | 2384 ms | 338.1 KB | $0.0038 |
| CRF 28 | 967 ms | 282.5 KB | $0.0025 |
| CRF 30 | 1200 ms | 233.8 KB | $0.0026 |
| CRF 32 | 854 ms fastest | 186.8 KB | $0.0023 |
About 20% of the remaining bytes per 3 points, across a range from CRF 18 to 32 that spans 3.6x in file size. And encode time does not track CRF at all, so raising it is close to a pure saving.
If you are on the default 23, moving to 26 removes 22% of your bytes for a difference most viewers will not see on typical content. Detail in FFmpeg CRF explained and measured.
The settings people get wrong
Preset ordering is not what you think
| Variant | Encode | Size | Cost |
|---|---|---|---|
| ultrafast | 238 ms fastest | 2185.1 KB | $0.0029 |
| superfast | 388 ms | 732.2 KB | $0.0024 |
| veryfast | 542 ms | 388.4 KB | $0.0021 |
| faster | 737 ms | 440.0 KB | $0.0022 |
| fast | 985 ms | 463.1 KB | $0.0025 |
| medium | 1912 ms | 433.0 KB | $0.0039 |
| slow | 2450 ms | 422.8 KB | $0.0040 |
| slower | 2685 ms | 358.6 KB | $0.0041 |
| veryslow | 4635 ms | 329.5 KB | $0.0062 |
The ends behave as advertised: ultrafast produced 6.6x the bytes of veryslow. The middle does not. veryfast produced a smaller file than faster, fast, medium and slow.
That is not a bug. CRF targets constant quality, so a slower preset is free to spend the bytes it saves on detail it previously discarded. Size at fixed CRF is emergent, not a dial. The same inversion appears in SVT-AV1 presets compared, where preset 12 beat preset 10 on both size and speed.
The practical rule: pick a preset by measuring your own content, and do not assume slower means smaller. FFmpeg x264 presets compared has the full curve.
The pixel format that breaks Safari
| Variant | Encode | Size | Cost |
|---|---|---|---|
| yuv420p | 899 ms fastest | 433.0 KB | $0.0024 |
| yuv422p | 1152 ms | 475.0 KB | $0.0026 |
| yuv444p | 1487 ms | 456.7 KB | $0.0031 |
| yuv420p10le | 1257 ms | 467.9 KB | $0.0029 |
yuv420p was both the smallest and the fastest. yuv444p cost 65% more encode time for 5% more bytes and is rejected by a large amount of hardware.
If a video plays in Chrome and not in Safari or QuickTime, this is almost always why: a filter somewhere in the chain output a higher-chroma or RGB format and nothing converted back. Ending a delivery chain with format=yuv420p costs nothing when the format is already right. Detail in FFmpeg yuv420p vs yuv444p.
One caution from that sweep: yuv422p produced more bytes than yuv444p, which is not what subsampling arithmetic predicts. Do not reason about output size from chroma volume.
The scaler flag is free, so use a good one
| Variant | Encode | Size | Cost |
|---|---|---|---|
| neighbor | 653 ms | 394.0 KB | $0.0022 |
| bilinear | 636 ms fastest | 236.9 KB | $0.0035 |
| bicubic (default) | 649 ms | 265.3 KB | $0.0022 |
| lanczos | 645 ms | 272.5 KB | $0.0024 |
| spline | 641 ms | 268.8 KB | $0.0020 |
Five algorithms landed within 17 ms of each other while output size varied 66%. Scaling is a per-pixel filter pass and encoding is a search problem, so the encoder dominates completely.
Nearest-neighbor is the expensive one, at 49% more bytes than bicubic, because its hard stair-stepped edges are high-frequency detail the codec then pays to describe. That generalises: any filter that adds artificial sharpness costs you encoder bytes.
And smaller is not better here. Bilinear won on bytes because it is blurriest. The useful cluster is bicubic, spline and lanczos, within 3% of each other. Detail in FFmpeg lanczos vs bicubic scaling.
Rate control: quality, bitrate, or both
| Variant | Encode | Size | Cost |
|---|---|---|---|
| CRF 23 (quality) | 1596 ms | 433.0 KB | $0.0031 |
| 700k ABR | 948 ms fastest | 483.0 KB | $0.0023 |
| 700k capped VBV | 1074 ms | 428.1 KB | $0.0025 |
| CRF 23 capped VBV | 1602 ms | 417.0 KB | $0.0030 |
Single-pass ABR at 700k delivered 483 KB where the arithmetic predicts 437.5 KB, overshooting its own target by 10.4%. It aims without knowing what is coming, so it corrects as it goes.
CRF with a VBV cap produced the smallest file of the four. That combination is the one most people never reach for and usually the right one: quality drives the encode and the cap only intervenes on the hardest passages.
-crf 23 -maxrate 900k -bufsize 1400kNote that -maxrate without -bufsize does almost nothing, because the default window is large enough that the ceiling rarely binds. That pairing is one of the most commonly half-configured things in FFmpeg. Detail in FFmpeg CRF vs bitrate.
Threads, and why your benchmarks disagree
| Variant | Encode | Size | Cost |
|---|---|---|---|
| 1 thread | 3644 ms | 387.8 KB | $0.0053 |
| 2 threads | 2122 ms | 387.9 KB | $0.0036 |
| 4 threads | 1510 ms | 387.7 KB | $0.0029 |
| 8 threads | 1220 ms | 387.2 KB | $0.0026 |
| auto (0) | 1033 ms fastest | 433.0 KB | $0.0024 |
Eight threads was 2.99x faster than one, not 8x. Encoding has genuinely serial parts, so the curve flattens and four threads captures most of the benefit.
The more useful finding is about measurement. With -threads pinned, repeated runs landed within 1.4% to 8.9%. On auto, the identical command ranged 918 to 1,699 ms, an 85% spread, because x264 sizes itself to whatever the machine has free.
That variance was large enough to invalidate a claim we had already published, which is documented in FFmpeg benchmark variance. If your FFmpeg timings wander between runs, pin the threads before concluding anything.
What to actually set
For web delivery, the combination that sits near the knee of every curve measured here:
ffmpeg -i input.mp4 \ -c:v libx264 -crf 23 -preset medium -g 60 \ -vf "scale=1280:-2:flags=lanczos,format=yuv420p" \ -c:a aac -b:a 128k \ -movflags +faststart \ output.mp4Every element is there for a measured reason. CRF 23 is the quality anchor, -g 60 is a 2-second GOP at 30fps costing 17% rather than 35%, lanczos is free, format=yuv420p prevents the Safari failure, and +faststart is what lets a browser begin playing before the file finishes downloading.
For archival, drop -g 60, raise the preset, and consider a modern codec: AV1 vs H.264 VMAF compared measured AV1 delivering 20 more VMAF points at the same file size.
For live, -tune zerolatency is finally correct, and the 121% is the price of the thing you are actually buying.
How these numbers were produced
Every figure came from a job executed against a live API on one fixed source: a 5-second 1280x720 H.264 clip, audio stripped so the video numbers are clean. The sweeps behind this page total 106 encodes.
Two properties of that data are worth knowing before you use it:
Sizes are exact and repeatable. The same command produced byte-identical output on all ten runs we checked, 443,351 bytes every time. Any size comparison here would reproduce.
Timings are a single sample unless stated. The threads and SVT-AV1 sweeps were repeated with pinned threads and report medians; everything else is one run. Treat a timing difference under about 2x as noise.
That asymmetry is why this page leads with size on every setting and only makes a speed claim where the gap is large or the sweep was repeated.
Where this stops
One clip, one resolution, one content type. Grain and motion change encoder behaviour more than almost anything else, and a static screencast or a high-motion sports clip will move several of these numbers.
What should travel is the ordering and the mechanisms: keyframes are expensive, zerolatency disables compression features by design, CRF trades size against quality and nothing else, and any filter that adds artificial detail costs bytes downstream.
What this costs to run
Every sweep on this page was a real job billed at a real price. Across the last 425 FFmpeg jobs on this account the median was $0.0025 and every one came in under a cent, which is what makes a page like this affordable to produce rather than a marketing exercise.
FFmpeg API pricing compared works that full distribution through six services and shows where per-GB, per-command and per-compute billing invert against each other. Before any of it, though, comes the cheaper step: validating the input with ffprobe costs a flat $0.0010 and stops you paying for encodes that were always going to fail.
Two more measurements sit under this page. How long video transcoding takes shows that the encode is the fastest step in the pipeline, at a median of 861 ms against a 3,626 ms wait to start. How to compress video to a target size covers what it takes to hit a size and a quality target at once, measured across 667 probe encodes.
Frequently asked questions
Which FFmpeg setting has the biggest effect on file size?
Codec choice first, then keyframe interval. Encoding every frame as a keyframe produced 6.1x the bytes of x264's default interval at the same quality setting, which is a larger swing than preset, tune or pixel format.
What are the best FFmpeg settings for web video?
libx264 at CRF 23 to 26, preset medium, a 2-second keyframe interval, format=yuv420p and -movflags +faststart. That combination plays everywhere, streams without a full download, and sits near the knee of every cost curve measured here.
Does a slower FFmpeg preset always produce a smaller file?
No. At a fixed CRF the encoder targets quality, so size is emergent. We measured veryfast producing a smaller file than faster, fast, medium and slow, and the same non-monotonicity appears in SVT-AV1's presets.
How many threads should FFmpeg use?
Four captures most of the benefit. One to four threads gave a 2.41x speedup and going to eight only reached 2.99x, so the returns fall off sharply past four.
Why do my FFmpeg benchmarks give different times each run?
Default threading. With -threads pinned our repeats landed within 1.4% to 8.9%; on auto the identical command ranged 918 to 1,699 ms. Pin the thread count before drawing any timing conclusion.
