FFmpeg MicroSign Up
ffmpegvideo-encodingcrfcompressionapi

Pick the Right FFmpeg CRF: libx264 + libx265 Reference

·Javid Jamae·9 min read
Pick the Right FFmpeg CRF: libx264 + libx265 Reference

Every video encoder faces the same tradeoff: quality versus file size. CRF, short for Constant Rate Factor, is how FFmpeg lets you control that tradeoff with a single number.

Quick answer: for H.264 (libx264), use CRF 23 for general use, 18 for archive, and 25 to 27 for web and mobile. Lower CRF means better quality and a bigger file, and every +6 roughly halves the size.

Most guides tell you to "just use CRF 23." That is fine for a quick test, but the same CRF means very different things depending on your codec, your footage, and where the video is headed. This page is the quick reference: what CRF does, the value and preset to use for each codec, and how to choose in a few seconds.

Last verified 2026-06-23: the commands here run on FFmpeg 7.1 and later, and the API examples match the live FFmpeg Micro API.

Skip the FFmpeg install. Run any of the encodes below through one API call, with no codecs to compile and no servers to manage. Get a free API key

See the quality difference

<CRFComparisonWidget />

Drag the slider or pick a CRF value to compare the same frame at different settings. File size and bitrate update with each one. The detail holds up well from CRF 18 to 28, softens by 33, and shows obvious compression by 38, while the file shrinks by more than 10x across the range.

Estimate your output size

<CRFSizeEstimator />

CRF and preset quick reference

Codec (encoder)Default CRFArchiveGeneralWebMobilePreset to start
H.264 (libx264)2318232527medium
H.265 (libx265)2823283032medium
AV1 (SVT-AV1)3525354045preset 6
VP9 (libvpx-vp9)3124313540use -b:v 0

Lower CRF means higher quality and a larger file. Higher CRF means a smaller file with more visible compression. Start at the General value for your codec, watch one output, then nudge up or down from there.

What CRF actually controls

CRF targets a consistent level of perceptual quality across the whole video and lets the bitrate float to hit it. Simple scenes (static shots, flat color) get fewer bits. Complex scenes (fast motion, fine detail, film grain) get more. The result looks consistent to your eye even though the bitrate changes frame to frame.

That is different from the other two rate-control modes:

  • CRF sets a quality target; the encoder picks the bitrate. File size varies with the footage.
  • Bitrate (-b:v) sets a size target; the encoder fits the quality into it. Quality varies with the footage.
  • QP fixes compression per frame with no rate control. You rarely want this outside testing.

Because CRF follows the footage, the same number produces very different files. CRF 23 on a talking-head clip might be 500 MB; CRF 23 on a fast action scene might be 2 GB. That is expected, not a bug.

H.264 with libx264 (the safe default)

H.264 plays on every browser, phone, and TV, so it is where most people should start. This encodes to H.264 at CRF 23 with a balanced preset:

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

Skip the FFmpeg install. Here is that exact encode as one API call:

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

Get a free API key and run it. No FFmpeg install, no codec builds, no machine pinned for minutes.

A few numbers worth memorizing for libx264:

  • Range: 0 (lossless) to 51 (worst). Default is 23.
  • Sane range for delivery: 18 to 28.
  • Visually lossless: about 17 to 18.
  • Every +6 to CRF roughly halves the file size. So CRF 17 is about double CRF 23, and CRF 29 is about half.

The preset controls how hard the encoder works, not the quality target. A slower preset produces a smaller file at the same CRF but takes longer. From fastest to slowest, the presets are: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, and veryslow.

  • medium is the default and a good balance.
  • Use fast or veryfast when speed matters more than size.
  • Use slow for final renders where you want every byte.

H.265 with libx265

H.265 is more efficient than H.264, so it makes noticeably smaller files at the same quality. Its default is CRF 28, which lands close to H.264 at CRF 23.

ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset medium -tag:v hvc1 output.mp4

The common rule is "H.265 CRF is about H.264 CRF plus 5 or 6." It holds for typical footage but breaks down with heavy grain, very low bitrates, or different presets. Start at 28 if you are used to 23 in H.264, compare one output, and adjust by a point or two. The -tag:v hvc1 flag keeps the file playable in Safari and QuickTime.

AV1 and VP9

AV1 gives the best compression but encodes slowly. SVT-AV1 is the practical encoder for most workflows:

ffmpeg -i input.mp4 -c:v libsvtav1 -crf 35 -preset 6 -c:a libopus output.mp4

VP9 needs one extra flag. Without -b:v 0 it runs in a constrained mode that ignores your CRF:

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

Handling real inputs

Real footage is rarely a clean local MP4. A few patterns that come up constantly:

Encode straight from a URL

The API takes a URL as the input, so you do not have to download the file first:

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

Strip or keep the audio

Drop the audio with -an, or keep it as-is without re-encoding using -c:a copy:

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

A different input codec or container

CRF cares about the output encoder, not the input. A HEVC MOV and an H.264 MP4 both use the same -c:v libx264 -crf 23; only the input path changes.

When the request is wrong

If the request is malformed, the API returns a 400 with a plain error message instead of silently producing a broken file:

{ "error": "Missing required fields: inputs, outputFormat" }

When CRF is the wrong tool

CRF is the right default when you care about quality and have no hard size or bitrate limit. Reach for bitrate mode instead when you do:

GoalUseWhy
Archive or masterCRF 18 to 23Quality matters more than size
Social uploadCRF 23 to 28The platform re-encodes anyway
Adaptive streaming (HLS/DASH)Target bitrate ladderEach rendition needs a predictable bitrate
Live streamingCBR or capped VBRReal-time cannot ride CRF bitrate spikes
Exact file sizeTwo-pass bitrateCRF output size is unpredictable

CRF on your laptop vs through the API

The CRF math is the same either way. What differs is everything around it.

On your laptopThrough the FFmpeg Micro API
Install FFmpeg and the right codec builds (libx265, SVT-AV1, libvpx)One POST, nothing to install
Write a shell loop to process each fileOne request per file, or batch them
Your CPU is pinned for minutes per encodeRuns on our hardware, many in parallel
Manage temp files, storage, and cleanupGet a download URL back when it finishes

The same request drops straight into an automation tool, so you can trigger encodes from n8n or Make, or read the full request format in the FFmpeg API reference.

Get a free API key and encode your first video in under a minute.

Common mistakes

Using -c copy with CRF. Stream copy skips re-encoding, so CRF is ignored. You have to name a video encoder:

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

Leaving out -c:v. FFmpeg then picks a default encoder that may not be the one you expect. Always name it.

Expecting CRF on hardware encoders. CRF is a software-encoder setting. Hardware encoders use their own flags: NVENC uses -cq, QuickSync uses -global_quality, VideoToolbox uses -q:v.

Forgetting -b:v 0 on VP9. Without it, VP9 caps the bitrate and your CRF does not behave the way you set it.

FAQ

What CRF should I use for YouTube?

CRF 18 to 21 for H.264, or 23 to 25 for H.265. YouTube re-encodes every upload, so feeding it high quality gives the re-encode more to work with.

Can I use CRF for live streaming?

No. Live needs a predictable, bounded bitrate. Use CBR or a VBV-capped VBR instead.

Does CRF change the audio?

No. CRF only affects video. Set audio separately with -c:a and -b:a, for example -c:a aac -b:a 128k.

How do I choose between H.264 and H.265?

Use H.264 for the widest playback and faster encodes. Use H.265 when you want 40 to 50 percent smaller files and your players support it.

Want this without managing any of it? Get a free FFmpeg Micro API key and run your first encode from the terminal:

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

FFmpeg Micro runs the same FFmpeg you would install locally, so every command on this page works through the API.

Weighing a hosted option? See our comparison of the best FFmpeg API services to line up pricing, flexibility, and automation support before you pick one.

About Javid Jamae

Founder at FFmpeg Micro

Founder of FFmpeg Micro. Software engineer and author building media automation tools; previously engineering leadership across multiple startups.

video APIsautomationdeveloper tools

Process video at scale with one API call

No servers to run, no FFmpeg to install. Call it from your code, from n8n, Make, and Zapier, or from your AI agents. Free tier included.

Sign up free