# FFmpeg CRF vs bitrate

Canonical: https://rendobar.com/blog/crf-vs-bitrate-measured/
Author: Abdelrahman Essawy
Published: 2026-08-20
Updated: 2026-08-20

---

## Key takeaways

- 700k ABR delivered 483.0 KB where the arithmetic predicts 437.5 KB, overshooting its own target by 10.4%.
- CRF 23 with a VBV cap produced the smallest file of all four at 417.0 KB, beating plain CRF's 433.0 KB and plain ABR's 483.0 KB.
- Capped CRF is the option most people never reach for and it is usually the right one: quality-driven, with a ceiling that keeps a player's buffer safe.
- Plain ABR is the worst of both. It does not guarantee quality, and on this clip it did not hit its bitrate either.
- A bitrate target is a promise about the average, not the peak. Without -maxrate and -bufsize nothing bounds the spikes.

Every encoding guide eventually asks you to choose between constant quality and
a bitrate target. The interesting answer is that you do not have to.

Short version. **CRF with a VBV cap produced the smallest file of the four**, and
plain ABR overshot its own bitrate target by 10%. If you are picking between CRF
and bitrate you are picking between the two worse options.

## ABR missed its own target

`-b:v 700k` on a 5-second clip should produce about **437.5 KB**. It produced
**483.0 KB**, which is **10.4% over**.

That is not a bug. `-b:v` on a single pass is a target the encoder aims at
without knowing what is coming, so it corrects as it goes and lands near rather
than on. Two-pass ABR exists precisely to fix this: the first pass measures the
whole file, the second spends the budget with full knowledge.

The practical consequence is the same one from
[Opus vs AAC vs MP3 vs FLAC](/blog/audio-codecs-measured/): **if you are sizing storage
from bitrate times duration, add margin.** Nominal bitrate is a request, not a
receipt.

## Capped CRF won

| Mode | Size |
|---|---:|
| CRF 23 + VBV cap | **417.0 KB** |
| 700k + VBV cap | 428.1 KB |
| CRF 23 | 433.0 KB |
| 700k ABR | 483.0 KB |

```bash
-crf 23 -maxrate 900k -bufsize 1400k
```

This says: encode to a constant quality of 23, but never let the bitrate exceed
900 kbps over a 1,400 kbit window. Quality drives the encode, and the cap only
intervenes on the hardest passages.

It is the best of both. Plain CRF gives you consistent quality with unbounded
peaks, which can stall a player on a complex scene. Plain ABR gives you a
predictable average with no quality floor, so simple scenes waste bits and hard
scenes fall apart. Capped CRF gives you quality with a ceiling.

That it also produced the smallest file here is a bonus rather than the point,
and on other content it will not always be smallest. The reason to use it is the
bounded peak.

## What the cap numbers mean

`-maxrate` is the ceiling. `-bufsize` is the window that ceiling is measured
over, and it is the argument people omit or copy without understanding.

A large `bufsize` lets the encoder average over a long stretch, so it can spend
heavily on a hard scene and recover later. A small one forces it to stay near the
cap moment to moment, which is stricter and hurts quality more.

The usual starting point is `bufsize` at one to two times `maxrate`, which is
what we used at 900k and 1400k. For live streaming, smaller is safer because the
player has less buffer to absorb a spike.

**Setting `-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 common half-configured flags in FFmpeg.

## Which to actually use

**Download or archive**: plain CRF. Peaks do not matter when nothing is
streaming, and you get consistent quality for the fewest bytes.

**Streaming, ABR ladder, anything with a player buffer**: capped CRF. You want
quality-driven encoding with a ceiling that respects the buffer.

**A hard file-size limit**: two-pass ABR, or a target-size search. Neither CRF
form can promise a size, because CRF is a promise about quality and the bytes
fall where they fall.

**Plain single-pass ABR**: rarely. It is the option that guarantees neither the
quality nor, as measured here, the bitrate.

## Where this stops

One 5-second 1280x720 clip, libx264 preset medium, audio stripped. Sizes are
exact and repeatable; the timing column is a single sample on auto threading and
should not be read closely, for
reasons covered in [FFmpeg benchmark variance](/blog/measurement-noise-ffmpeg-benchmarks/).

A 5-second clip is also short for rate control to show its character. VBV
behaviour matters most over minutes, where the encoder has real scene changes to
budget across, and a clip this length barely exercises the buffer model.

Rate control is one of seven settings measured on this same source. The rest are in [FFmpeg encoding settings compared](/blog/ffmpeg-encoding-settings/).
