ffmpegvideo-encodingcrfcompressionapi

FFmpeg CRF Explained: Quality vs File Size Guide

·Javid Jamae·6 min read
FFmpeg CRF Explained: Quality vs File Size Guide

Every video encoder faces the same tradeoff: quality vs. file size. CRF (Constant Rate Factor) is how FFmpeg lets you control that tradeoff with a single number.

Most guides say "just use CRF 23." That's fine for a quick transcode, but CRF 23 means completely different things depending on your codec, your content, and where you're delivering. This guide covers what CRF actually does, how the scale works across codecs, and how to pick the right value.

What Is CRF in FFmpeg?

CRF is a rate control mode that targets consistent perceptual quality across an entire video, letting the bitrate float as needed. Simple scenes (static shots, solid colors) get fewer bits. Complex scenes (fast motion, fine detail) get more bits. The result is a file where quality looks consistent to your eyes, even though the bitrate varies frame to frame.

ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4

Lower CRF always means higher quality and larger files. CRF 0 is mathematically lossless (and produces enormous files). The default for libx264 is 23.

CRF Scale by Codec

CRF values aren't universal. Each codec has its own scale, and the same number produces different quality levels.

CodecEncoderCRF RangeDefaultVisually LosslessGood BalanceSmall File
H.264libx2640-512317-1820-2328-30
H.265/HEVClibx2650-512820-2224-2832-35
VP9libvpx-vp90-633115-2025-3135-40
AV1libaom-av10-633220-2528-3238-45

CRF 23 in H.264 is not the same quality as CRF 23 in H.265. H.265 is a more efficient encoder, so its default is CRF 28 to produce roughly comparable quality.

A useful rule of thumb for H.264: every +6 CRF roughly halves the file size. Going from CRF 23 to 17 will roughly double your file. Going from 23 to 29 will cut it in half.

CRF Examples for Each Codec

H.264 (most common):

ffmpeg -i input.mp4 -c:v libx264 -crf 20 -preset medium -c:a aac -b:a 192k output.mp4

H.265/HEVC (better compression, slower):

ffmpeg -i input.mp4 -c:v libx265 -crf 24 -preset medium -c:a aac -b:a 192k output_hevc.mp4

VP9 (WebM format, used by YouTube internally):

ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus output.webm

VP9 requires -b:v 0 alongside CRF. Without it, the encoder applies a default bitrate cap that overrides your CRF setting. This trips up a lot of people.

AV1 (best compression, slowest encoding):

ffmpeg -i input.mp4 -c:v libaom-av1 -crf 30 -cpu-used 4 -c:a libopus output.mkv

How Preset Interacts with CRF

CRF controls quality. Preset controls how hard the encoder works to hit that quality at the smallest file size. They're independent settings, but they interact.

ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset slow output.mp4

Presets for libx264, from fastest to smallest output: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow.

At the same CRF value, a slower preset produces a smaller file with identical visual quality. The tradeoff is encoding time. medium (the default) or slow gives the best balance for most workflows.

CRF vs CBR vs VBR

ModeHow It WorksBest For
CRFConsistent quality, variable bitrateDownloads, on-demand streaming
CBRFixed bitrate throughoutLive streaming, hard bandwidth limits
VBRAverage bitrate with a ceilingStreaming platforms, predictable file sizes

CRF is the best default for most developers. Consistent quality without guessing at bitrate numbers.

CBR is for live streaming or hard bandwidth constraints. Quality varies, but bitrate stays predictable:

ffmpeg -i input.mp4 -c:v libx264 -b:v 4000k -maxrate 4000k -bufsize 8000k output.mp4

VBR (two-pass) gives you a target file size with smart bit allocation. Takes twice as long:

ffmpeg -i input.mp4 -c:v libx264 -b:v 4000k -pass 1 -f null /dev/null
ffmpeg -i input.mp4 -c:v libx264 -b:v 4000k -pass 2 output.mp4

Recommended CRF by Use Case

  • Archiving source footage: CRF 17-18 (H.264) or CRF 20-22 (H.265). Near-lossless, file size doesn't matter.
  • YouTube/social media: CRF 18-20 (H.264). YouTube re-encodes everything, so give it the best source you can.
  • Web delivery: CRF 23-25 (H.264) or CRF 28-30 (H.265). Good quality, reasonable file sizes.
  • Mobile-first: CRF 26-28 (H.264). Smaller screens forgive compression artifacts.
  • Thumbnails and previews: CRF 30-35. Small and disposable. Save the bytes.

Common CRF Pitfalls

**Forgetting -b:v 0 with VP9.** VP9 ignores your CRF and uses a default bitrate cap instead. Always add -b:v 0 when using CRF with libvpx-vp9.

Comparing CRF across codecs. CRF 23 in H.264 produces different quality than CRF 23 in H.265. Use the table above when switching codecs.

Using CRF 0 for "best quality." CRF 0 is lossless and creates enormous files. CRF 17-18 is visually indistinguishable from lossless for H.264, at a fraction of the size.

Using CRF with the FFmpeg Micro API

If you're processing video programmatically, FFmpeg Micro's API handles CRF through a simple preset mode and an advanced mode for raw FFmpeg options.

Preset mode maps quality names to CRF values (high = CRF 18, medium = CRF 23, low = CRF 28):

curl -X POST "https://www.ffmpeg-micro.com/v1/transcodes" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [{"url": "https://storage.example.com/video.mp4"}],
    "outputFormat": "mp4",
    "preset": {"quality": "high", "resolution": "1080p"}
  }'

Advanced mode lets you set any CRF value directly:

curl -X POST "https://www.ffmpeg-micro.com/v1/transcodes" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [{"url": "https://storage.example.com/video.mp4"}],
    "outputFormat": "mp4",
    "options": [
      {"option": "-c:v", "argument": "libx264"},
      {"option": "-crf", "argument": "20"},
      {"option": "-preset", "argument": "slow"}
    ]
  }'

Full flexibility without managing servers or installing FFmpeg. Get an API key from the FFmpeg Micro docs and start processing video in minutes.

Frequently Asked Questions

What CRF should I use for H.264?

CRF 23 is the default and works for most cases. For archiving or YouTube uploads, drop to CRF 18-20. For web delivery or mobile, use CRF 26-28. Visually lossless starts around CRF 17-18.

Does CRF 18 in H.265 equal CRF 18 in H.264?

No. H.265 is more efficient, so CRF 18 in H.265 produces higher quality than CRF 18 in H.264. The rough H.265 equivalent of H.264's CRF 23 is around CRF 28.

Can I use CRF with hardware encoding (NVENC, QSV)?

Hardware encoders use a different parameter called CQ (Constant Quality) instead of CRF. The flag is -cq or -qp, not -crf. Similar concept, different implementation.

Why is VP9 ignoring my CRF setting?

Add -b:v 0. VP9 in FFmpeg applies a default bitrate cap even when CRF is set. Removing the cap with -b:v 0 lets CRF control quality exclusively.

What's the difference between CRF and QP?

CRF adjusts quality per-frame based on scene complexity. QP (Quantization Parameter) applies the same quantization to every frame. CRF produces more consistent perceived quality across the video.

About Javid Jamae

Founder & CEO at FFmpeg Micro

Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.

Software EngineeringVideo ProcessingFFmpegCloud ArchitectureAPI DesignAutomation

Ready to process videos at scale?

Start using FFmpeg Micro's simple API today. No infrastructure required.

Get Started Free