mediacodec.dev

Understanding CRF: quality-targeted encoding

What Constant Rate Factor actually does, why it beats fixed bitrates for files, and what the numbers mean in x264, x265, VP9 and AV1.

Updated

Constant Rate Factor is the single most useful encoder setting most developers never learn properly. It answers a different question than bitrate does. A bitrate target says “spend exactly this many bits per second, whatever is on screen.” CRF says “hold this level of visual quality, and spend whatever that costs.”

Why quality targeting wins for files

Video is not uniformly hard to compress. A locked-off interview shot costs almost nothing; a confetti drop or a camera pan across foliage costs a fortune. With a fixed bitrate, the encoder over-spends on the easy scenes and starves the hard ones: you pay for bits you didn’t need and still get artifacts where it hurts.

CRF flips this. The encoder holds perceived quality roughly constant and lets the bitrate float scene by scene. Easy content gets small, hard content gets the bits it needs. For any file you serve on demand (downloads, embedded video, media libraries), this is what you want.

The place CRF does not belong is constrained live streaming. A live encoder feeding a fixed-bandwidth channel must not let bitrate float freely, which is why broadcast and live pipelines use capped or constant bitrate modes instead (often CRF plus a -maxrate/-bufsize cap, a hybrid worth knowing exists).

How the number works

Lower CRF means better quality and bigger files. Higher means smaller and worse. Two details trip people up:

  • The scale is logarithmic-ish. In x264, a change of ±6 roughly halves or doubles the file size. CRF 17 is not “slightly better” than CRF 23: it is about twice the file.
  • Scales differ between codecs. The number is not portable:
Encoder Scale Sane delivery range Common default
x264 (H.264) 0–51 18–23 23
x265 (H.265) 0–51 20–28 28
libvpx-vp9 0–63 15–35 none (must set)
SVT-AV1 0–63 20–40 35

A “CRF 23” VP9 encode is not the quality of a CRF 23 x264 encode: on VP9’s scale that is an extremely high quality setting. When you switch codecs, look up the range again.

Reading the ranges

For x264, the reference points most engineers carry around:

  • CRF 17–18 is “visually lossless”: most viewers cannot tell it from the source at normal playback. Good for masters and archives, heavy for the web.
  • CRF 20–23 is high-quality delivery. The default of 23 is genuinely reasonable for web video.
  • CRF 24–28 is economy territory. Fine on small players; gradients and dark scenes start to give it away on big screens.

One more nuance: CRF interacts with the encoder’s speed setting. A slower x264 preset (or a lower VP9 -cpu-used, or a lower SVT-AV1 -preset) at the same CRF produces a smaller file at the same quality, because the encoder searches harder for savings. CRF picks the destination; the preset decides how efficiently you get there.

Using it

# x264: high-quality web delivery
ffmpeg -i input.mp4 -c:v libx264 -crf 20 -preset slow -c:a copy out.mp4

# VP9: -b:v 0 is REQUIRED for true CRF mode
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 32 -b:v 0 -row-mt 1 -c:a libopus out.webm

# SVT-AV1
ffmpeg -i input.mp4 -c:v libsvtav1 -crf 30 -preset 6 -c:a libopus out.webm

The VP9 flag deserves its warning: without -b:v 0, libvpx treats CRF as a ceiling on a default bitrate target rather than a pure quality target, and quality quietly suffers. It is the most common VP9 mistake on the internet.

You can try these numbers live in the WebM converter: move the CRF slider and watch the explanation track what the value means for your file.

CRF is one of four ways to answer “how many bits does this get?”, and the others matter once a network or a size limit enters the picture. See rate control: CRF, CBR, VBR and two-pass.