FFmpeg CRF vs bitrate

Compare constant quality against target bitrate in FFmpeg. ABR overshot its own target by 10 percent, and CRF with a VBV cap produced the smallest file.

Share

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.

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.

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: if you are sizing storage from bitrate times duration, add margin. Nominal bitrate is a request, not a receipt.

Capped CRF won

ModeSize
CRF 23 + VBV cap417.0 KB
700k + VBV cap428.1 KB
CRF 23433.0 KB
700k ABR483.0 KB
Terminal window
-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.

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.

Frequently asked questions

Should I use CRF or a target bitrate?

Usually neither on its own. CRF with a VBV cap produced the smallest file of the four options we measured, and it gives quality-driven encoding with a ceiling that protects a player's buffer.

Why did my file miss its bitrate target?

Single-pass ABR aims at a target without knowing what is coming, so it corrects as it goes. We measured 700k ABR delivering 483 KB where the arithmetic predicts 437.5 KB, 10.4% over.

What does -bufsize do?

It sets the window over which -maxrate is measured. Setting -maxrate without -bufsize does almost nothing, because the default window is large enough that the ceiling rarely binds.

How do I hit an exact file size?

Two-pass ABR or a target-size search. No CRF mode can promise a size, because CRF is a promise about quality and the bytes follow the content.

Sources

Tags #ffmpeg#x264#streaming#encoding#benchmarks
All posts
Share
  1. Opus vs AAC vs MP3 vs FLAC Engineering blog
  2. AV1 vs H.264 VMAF compared Engineering blog
  3. AV1 vs VP9 vs HEVC vs H.264 Engineering blog