DEV Community

Javid Jamae
Javid Jamae

Posted on • Originally published at ffmpeg-micro.com

How to Encode Video with H.264 (libx264) Using FFmpeg

Originally published at ffmpeg-micro.com

H.264 is still the default video codec on the internet. YouTube, Vimeo, Zoom, most browsers, every phone made since 2010. If you're encoding video with FFmpeg and need maximum compatibility, libx264 is the encoder you want.

The trick is picking the right CRF and preset values. Get them wrong and you'll either waste storage on an oversized file or ship a blocky mess your users will notice.

TL;DR

For most web video: -c:v libx264 -crf 23 -preset medium. That's the default for a reason. If you need smaller files, bump CRF to 26-28. If you need higher quality, drop it to 18-20. Slower presets produce smaller files at the same quality but take longer.

What CRF and Preset Do

CRF (Constant Rate Factor) controls quality. It tells FFmpeg "make every frame look this good" and lets the bitrate float to hit that target. Low CRF means high quality and big files. High CRF means lower quality and smaller files.

The libx264 CRF scale runs from 0 (lossless) to 51 (worst). The default is 23.

Preset controls encoding speed. A slower preset spends more CPU time finding better compression, which produces a smaller file at the same quality level. It doesn't improve visual quality. It improves efficiency.

These two settings work independently. CRF picks the quality. Preset picks how efficiently the encoder reaches that quality.

The Basic libx264 Command

ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output.mp4
Enter fullscreen mode Exit fullscreen mode

What each flag does:

  • -c:v libx264 selects the H.264 encoder
  • -crf 23 sets quality (lower = better, default 23)
  • -preset medium balances encode speed and compression (default)
  • -c:a aac -b:a 128k re-encodes audio to AAC at 128kbps

If your input already has AAC audio and you don't want to re-encode it, use -c:a copy instead.

CRF Values by Use Case

Use Case CRF Range File Size vs Default When to Use
Lossless archival 0 10-50x larger Source preservation. Not for delivery.
Visually lossless 17-18 ~2x larger Master copies, professional editing, archival with compression.
High quality delivery 20-22 ~1.3x larger Streaming to large screens, paid video content.
General purpose 23 (default) baseline Web video, social media, most applications.
Smaller files 26-28 ~50% smaller Bandwidth-constrained delivery, batch processing.
Preview / thumbnails 30-35 ~70-80% smaller Quick previews, quality doesn't matter much.

A useful rule: every +6 CRF roughly halves the file size. CRF 23 to CRF 29 cuts your file roughly in half. CRF 23 to CRF 17 roughly doubles it.

Don't go above CRF 30 for anything users will actually watch. Compression artifacts become obvious fast.

Preset Speed vs Compression

Preset Encode Speed File Size (same CRF) Best For
ultrafast ~15x faster ~40-50% larger Testing, live previews, CI pipelines
veryfast ~8x faster ~25% larger Real-time or near-real-time use cases
faster ~5x faster ~15% larger Batch jobs where speed matters
fast ~3x faster ~10% larger Good balance for high-volume pipelines
medium 1x (baseline) baseline General use (default)
slow ~0.5x ~5% smaller Final renders, content you'll serve repeatedly
slower ~0.25x ~8-10% smaller High-value content worth the wait
veryslow ~0.1x ~10-15% smaller Archival. Rarely worth it in practice.

For automation pipelines, medium or fast is usually the right call. Going from medium to veryslow saves maybe 10-15% on file size but takes 10x longer. That math only works if you're encoding once and serving millions of times.

H.264 Profile and Level

libx264 supports three profiles that control which encoding features are used:

  • Baseline - no B-frames, no CABAC. Maximum device compatibility (older phones, embedded players). Worst compression.
  • Main - adds B-frames and CABAC. Good compression, broad compatibility. Still plays on most hardware from 2012+.
  • High - full feature set. Best compression. Default for libx264 and what you should use unless you have a specific device constraint.
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -profile:v high -level 4.1 output.mp4
Enter fullscreen mode Exit fullscreen mode

Level 4.1 supports up to 1080p at 30fps or 720p at 60fps. For 4K, use level 5.1. Most developers don't need to set these manually. libx264 picks sensible defaults based on resolution.

Encoding H.264 via API

If you don't want to install FFmpeg locally or manage encoding infrastructure, you can run the same libx264 command through the FFmpeg Micro API. Same flags, same output. No server to maintain.

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

The API returns a job ID immediately:

{
  "id": "trc_abc123",
  "status": "queued",
  "outputFormat": "mp4",
  "createdAt": "2026-06-17T10:00:00.000Z"
}
Enter fullscreen mode Exit fullscreen mode

Poll GET /v1/transcodes/trc_abc123 until the status is completed, then download the output. FFmpeg Micro handles the infrastructure, codec dependencies, and scaling. You get the same libx264 output without compiling FFmpeg or provisioning servers.

Free tier includes 100 processing minutes. No credit card required.

Common Pitfalls

Using CRF with -b:v at the same time. These are conflicting rate control modes. CRF targets constant quality (variable bitrate). -b:v targets constant bitrate. Pick one. If you set both, -b:v wins and CRF gets ignored.

Forgetting the audio codec. If your input has audio in a format incompatible with MP4 (like Vorbis or PCM), FFmpeg will fail or produce a broken file. Always specify -c:a aac or -c:a copy.

Using GPU encoder flags with libx264. NVENC and VideoToolbox are different encoders with different flag sets. -crf doesn't work with NVENC (use -qp instead). If you see "Option crf not found," you're probably using h264_nvenc instead of libx264.

Assuming CRF values are the same across codecs. CRF 23 in libx264 produces different quality than CRF 23 in libx265 or libvpx-vp9. Each codec has its own scale. For H.264, the default is 23. For H.265, it's 28. They produce roughly equivalent quality at those defaults.

FAQ

What CRF value should I use for YouTube uploads?
CRF 18-20. YouTube re-encodes everything, so uploading a higher quality source gives the re-encoder more to work with. Uploading at CRF 28 means YouTube is compressing already-compressed video, which makes the final result worse.

Is libx264 the same as H.264?
H.264 is the codec standard (also called AVC). libx264 is the open-source software encoder that implements that standard. When you run -c:v libx264 in FFmpeg, you're encoding H.264 video using the x264 encoder.

Should I use H.264 or H.265 for web video?
H.264 if you need maximum compatibility (older browsers, older devices, email players). H.265 if your audience is on modern devices and you want 30-50% smaller files. For a detailed H.265 guide, see our libx265 CRF and preset guide.

Can I use two-pass encoding instead of CRF?
Yes. Two-pass targets a specific file size (constant bitrate). CRF targets constant quality (variable file size). Use CRF when quality matters more than file size. Use two-pass when you have a strict size budget.

What's the difference between -c:v libx264 and -c:v h264_nvenc?
libx264 is CPU-based and produces the best compression at any given quality level. h264_nvenc uses NVIDIA GPU hardware and is much faster but produces larger files at the same perceived quality. For batch pipelines where speed matters more than file size, NVENC wins. For quality-sensitive encoding, libx264 wins.

Last verified: 2026-06-17 against FFmpeg 7.x and FFmpeg Micro API v1

Top comments (0)