mediacodec.dev

Rate control: CRF, CBR, VBR and two-pass

The four ways to tell an encoder how many bits to spend, what each one guarantees, and which job each belongs in.

Updated

Every encoder has to answer one question a few thousand times a second: how many bits does this frame get? Rate control is the policy that answers it, and picking the wrong policy is why some files are twice the size they need to be and others fall apart in the one shot that mattered.

There are only four answers worth knowing.

Constant quality (CRF)

You name a quality level. The encoder spends whatever each scene costs to hold it, and the bitrate moves around freely. Cheap scenes get small, expensive scenes get the bits they need.

This is the right default for anything you store and serve as a file, and it is covered on its own page: Understanding CRF.

What CRF does not give you is a predictable file size. You find out how big the export is when it finishes. For a video library that is fine. For a 30-second spot that must fit under 4 MB, it is a problem.

Constant bitrate (CBR)

You name a bitrate and the encoder hits it, continuously, whatever is on screen. Simple scenes get padded; hard scenes get starved.

CBR wastes bits by construction, and nobody uses it for files. It exists because some channels genuinely cannot cope with a stream that surges: fixed broadcast pipes, satellite links, and live streaming to a service that has told you its ceiling. When the pipe is the constraint rather than the disk, predictability beats efficiency.

Average bitrate (VBR / ABR), and two-pass

You name an average, and the encoder varies around it, aiming to land on your target across the whole file. In one pass it is guessing as it goes, and it guesses badly at the start because it has not seen the ending yet.

Two-pass fixes the guessing. The first pass encodes and throws the output away, keeping only a log of how complex each part of the video turned out to be. The second pass encodes for real, now knowing where the expensive scenes are, and distributes the budget accordingly.

ffmpeg -i in.mp4 -c:v libx264 -b:v 3000k -pass 1 -an -f null /dev/null
ffmpeg -i in.mp4 -c:v libx264 -b:v 3000k -pass 2 -c:a aac -b:a 128k out.mp4

Two-pass earns its extra encode when you have a real size target. If you do not, it is strictly worse than CRF: you have spent double the CPU to hit a number you did not care about, and quality will still swing around more than a CRF encode of the same size.

Capped quality (CRF plus a ceiling)

The hybrid, and the one most streaming pipelines actually run. You set a quality target as usual, then add a cap so the bitrate cannot spike past what a client’s connection can absorb:

ffmpeg -i in.mp4 -c:v libx264 -crf 22 -maxrate 4M -bufsize 8M -c:a copy out.mp4

Most of the file behaves like CRF and stays efficient. Only the scenes that would have blown past 4 Mbps get held back. -bufsize is the part people skip and should not: it is the size of the imaginary buffer the cap is measured over. A large bufsize allows longer surges above the cap; a small one enforces it tightly and costs quality. Two seconds of -maxrate is the usual starting point, which is where the 4M/8M pairing above comes from.

This is the mode to use for each rung of an adaptive streaming ladder, where every rendition has a bitrate it is not allowed to exceed but there is no reason to waste bits when the content is easy.

Choosing

Mode You specify Size predictable Quality predictable Use for
CRF Quality No Yes Files, libraries, anything on demand
Capped CRF Quality + ceiling Roughly Yes Streaming ladders, bandwidth-constrained delivery
Two-pass VBR Average bitrate Yes No Hard size limits
CBR Exact bitrate Yes No Live, fixed-capacity channels

The short version: reach for CRF, add a cap when a network is involved, use two-pass only when a number in a spec has to be met, and use CBR only when something downstream refuses to accept anything else.

One thing that is not rate control

The encoder preset is a separate dial and people conflate the two. Rate control decides how many bits to spend. The preset decides how hard the encoder works to spend them well. A slower preset at the same CRF gives you a smaller file at the same quality; a slower preset at the same bitrate gives you better quality at the same size. Either way it changes the deal, not the target. The WebM builder exposes both so you can watch the flags change as you move them.

Once you know roughly which bitrate a rendition will sit at, the bandwidth calculator will tell you what serving it costs.