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.

Share

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:

  1. Codec — up to 66% fewer bytes at matched quality
  2. Keyframe interval — up to 6.1x, and 35% for the common HLS setting
  3. -tune — up to 121% for one word
  4. CRF — about 20% per 3 points
  5. Preset — 6.6x across the full range, non-monotonic in the middle
  6. Pixel format — 5% and a lot of compatibility
  7. 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.

Keyframe interval
What does a shorter keyframe interval cost, and what does it buy?
Held constant: libx264 CRF 23 preset medium, same source, audio stripped
Bar chart. Keyframe interval. Encode time and output size for each variant, each metric scaled to its own maximum.
VariantEncodeSizeCost
-g 12 (0.4s)836 ms778.7 KB$0.0024
-g 30 (1s)939 ms584.6 KB$0.0024
-g 60 (2s)960 ms504.6 KB$0.0024
-g 250 (default)945 ms433.0 KB$0.0024
all keyframes446 ms fastest2661.4 KB$0.0039
Measured 2026-08-20 on the Rendobar API. Encode time is the FFmpeg step alone, separated from download and upload. 5 of 5 runs succeeded. Sizes are exact and repeatable. Timings are a single sample and vary up to 2x run to run, so treat small differences as noise. Why.

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

x264 tune presets
What does -tune actually change, and does it cost anything?
Held constant: libx264 CRF 23 preset medium, same source, audio stripped
Bar chart. x264 tune presets. Encode time and output size for each variant, each metric scaled to its own maximum.
VariantEncodeSizeCost
no tune912 ms fastest433.0 KB$0.0025
film1502 ms446.6 KB$0.0030
animation2045 ms404.9 KB$0.0036
grain1133 ms450.0 KB$0.0026
stillimage959 ms536.6 KB$0.0023
fastdecode982 ms725.7 KB$0.0024
zerolatency1444 ms955.5 KB$0.0029
Measured 2026-08-20 on the Rendobar API. Encode time is the FFmpeg step alone, separated from download and upload. 7 of 7 runs succeeded. Sizes are exact and repeatable. Timings are a single sample and vary up to 2x run to run, so treat small differences as noise. Why.

-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

x264 CRF
What does each step of CRF actually cost in bytes?
Held constant: libx264, preset medium, 5 seconds of the same source
Bar chart. x264 CRF. Encode time and output size for each variant, each metric scaled to its own maximum.
VariantEncodeSizeCost
CRF 182216 ms665.8 KB$0.0038
CRF 201938 ms551.9 KB$0.0036
CRF 23982 ms433.0 KB$0.0025
CRF 262384 ms338.1 KB$0.0038
CRF 28967 ms282.5 KB$0.0025
CRF 301200 ms233.8 KB$0.0026
CRF 32854 ms fastest186.8 KB$0.0023
Measured 2026-08-20 on the Rendobar API. Encode time is the FFmpeg step alone, separated from download and upload. 7 of 7 runs succeeded. Sizes are exact and repeatable. Timings are a single sample and vary up to 2x run to run, so treat small differences as noise. Why.

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

x264 presets
Is a slower x264 preset worth the extra encode time?
Held constant: libx264, CRF 23, 5 seconds of the same 1280x720 source
Bar chart. x264 presets. Encode time and output size for each variant, each metric scaled to its own maximum.
VariantEncodeSizeCost
ultrafast238 ms fastest2185.1 KB$0.0029
superfast388 ms732.2 KB$0.0024
veryfast542 ms388.4 KB$0.0021
faster737 ms440.0 KB$0.0022
fast985 ms463.1 KB$0.0025
medium1912 ms433.0 KB$0.0039
slow2450 ms422.8 KB$0.0040
slower2685 ms358.6 KB$0.0041
veryslow4635 ms329.5 KB$0.0062
Measured 2026-08-20 on the Rendobar API. Encode time is the FFmpeg step alone, separated from download and upload. 9 of 9 runs succeeded. Sizes are exact and repeatable. Timings are a single sample and vary up to 2x run to run, so treat small differences as noise. Why.

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

Pixel formats
What does chroma subsampling cost in bytes and compatibility?
Held constant: libx264 CRF 23 preset medium, same source, audio stripped
Bar chart. Pixel formats. Encode time and output size for each variant, each metric scaled to its own maximum.
VariantEncodeSizeCost
yuv420p899 ms fastest433.0 KB$0.0024
yuv422p1152 ms475.0 KB$0.0026
yuv444p1487 ms456.7 KB$0.0031
yuv420p10le1257 ms467.9 KB$0.0029
Measured 2026-08-20 on the Rendobar API. Encode time is the FFmpeg step alone, separated from download and upload. 4 of 4 runs succeeded. Sizes are exact and repeatable. Timings are a single sample and vary up to 2x run to run, so treat small differences as noise. Why.

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

Scaling algorithms
Does the scaling flag matter, and what does the good one cost?
Held constant: 720p down to 480p, libx264 CRF 23 preset medium, audio stripped
Bar chart. Scaling algorithms. Encode time and output size for each variant, each metric scaled to its own maximum.
VariantEncodeSizeCost
neighbor653 ms394.0 KB$0.0022
bilinear636 ms fastest236.9 KB$0.0035
bicubic (default)649 ms265.3 KB$0.0022
lanczos645 ms272.5 KB$0.0024
spline641 ms268.8 KB$0.0020
Measured 2026-08-20 on the Rendobar API. Encode time is the FFmpeg step alone, separated from download and upload. 5 of 5 runs succeeded. Sizes are exact and repeatable. Timings are a single sample and vary up to 2x run to run, so treat small differences as noise. Why.

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

CRF against target bitrate
Should you ask for a quality or ask for a bitrate?
Held constant: libx264 preset medium, same source, audio stripped
Bar chart. CRF against target bitrate. Encode time and output size for each variant, each metric scaled to its own maximum.
VariantEncodeSizeCost
CRF 23 (quality)1596 ms433.0 KB$0.0031
700k ABR948 ms fastest483.0 KB$0.0023
700k capped VBV1074 ms428.1 KB$0.0025
CRF 23 capped VBV1602 ms417.0 KB$0.0030
Measured 2026-08-20 on the Rendobar API. Encode time is the FFmpeg step alone, separated from download and upload. 4 of 4 runs succeeded. Sizes are exact and repeatable. Timings are a single sample and vary up to 2x run to run, so treat small differences as noise. Why.

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.

Terminal window
-crf 23 -maxrate 900k -bufsize 1400k

Note 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

Thread count
Where does adding encoder threads stop helping?
Held constant: libx264 CRF 23 preset medium, same source, audio stripped
Bar chart. Thread count. Encode time and output size for each variant, each metric scaled to its own maximum.
VariantEncodeSizeCost
1 thread3644 ms387.8 KB$0.0053
2 threads2122 ms387.9 KB$0.0036
4 threads1510 ms387.7 KB$0.0029
8 threads1220 ms387.2 KB$0.0026
auto (0)1033 ms fastest433.0 KB$0.0024
Measured 2026-08-20 on the Rendobar API. Encode time is the FFmpeg step alone, separated from download and upload. 5 of 5 runs succeeded. Sizes are exact and repeatable. Timings are a single sample and vary up to 2x run to run, so treat small differences as noise. Why.

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:

Terminal window
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.mp4

Every 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.

Sources

Tags #ffmpeg#x264#encoding#benchmarks#guide
All posts
Share
  1. How to compress video to a target size Guides for the video API
  2. FFmpeg API pricing compared Guides for the video API
  3. How to burn subtitles into a video Guides for the video API