FFmpeg Video Compression: Best Practices Guide
Master FFmpeg video compression with this deep technical guide covering CRF, presets, two-pass encoding, codec comparison, resolution scaling, and real-world scenarios.

FFmpeg video compression comes down to balancing three knobs — CRF (quality), preset (speed), and codec (efficiency). This deep guide covers everything from CRF math to two-pass encoding, H.264 vs H.265 vs AV1 benchmarks, and real-world scenarios (web, social, archival, HLS). Every command in this guide is copy-paste ready.
Test compression settings in your browser before scripting them — drop a clip, pick CRF / preset, download the result.
Understanding CRF (Constant Rate Factor)
CRF is the most important setting for quality-based video compression. It tells the encoder to target a consistent visual quality level, letting the bitrate vary as needed. Lower CRF = higher quality = larger file. Higher CRF = lower quality = smaller file.
CRF Values for H.264 (libx264)
ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4
The CRF scale for H.264 ranges from 0 (lossless) to 51 (worst quality). Here's what different values produce:
| CRF | Quality Level | Typical Use Case | File Size (relative to CRF 23) |
|---|---|---|---|
| 0 | Lossless | Archival, editing masters | 10-50x larger |
| 14 | Near-lossless | Professional post-production | 4-6x larger |
| 18 | Visually lossless | High-quality delivery, streaming premium | 2-3x larger |
| 20 | Excellent | High-quality web video | 1.5-2x larger |
| 23 | Good (default) | General purpose, web delivery | 1x (baseline) |
| 26 | Acceptable | Social media, mobile delivery | 0.5-0.7x |
| 28 | Moderate | Bandwidth-constrained delivery | 0.3-0.5x |
| 32 | Low | Previews, thumbnails | 0.15-0.25x |
| 40 | Very low | Extreme compression (barely watchable) | 0.05-0.1x |
| 51 | Worst | Never use this | Tiny |
The sweet spot for most use cases is CRF 18-28. Below 18, you're spending bits on quality differences most viewers can't perceive. Above 28, artifacts become clearly visible.
CRF Values for H.265 (libx265)
H.265 achieves the same visual quality at roughly 40-50% lower bitrate than H.264. However, the CRF scale shifts: CRF 28 in H.265 is approximately equivalent to CRF 23 in H.264.
ffmpeg -i input.mp4 -c:v libx265 -crf 28 output.mp4
| CRF (H.265) | Equivalent H.264 CRF | Quality Level |
|---|---|---|
| 18 | ~14 | Near-lossless |
| 22 | ~18 | Visually lossless |
| 24 | ~20 | Excellent |
| 28 | ~23 | Good (default) |
| 32 | ~26 | Acceptable |
| 36 | ~30 | Low |
How to Choose the Right CRF
A practical approach:
- Start with the default (23 for H.264, 28 for H.265)
- Watch the output — is the quality acceptable?
- Adjust by 2-4 points in either direction
- A/B test — encode the same complex scene at two CRF values and compare
The scenes that reveal compression artifacts most are: fast motion, fine textures (grass, fabric), gradients (sky, fog), and dark scenes with subtle detail. For a beginner-friendly introduction, see our guide to compressing video with FFmpeg.
Encoding Presets: Speed vs Quality
FFmpeg's preset parameter controls how much CPU time the encoder spends optimizing compression. Slower presets achieve better compression (smaller files at the same quality) at the cost of longer encoding times.
H.264 Preset Benchmark
All tests below use CRF 23 with a 1080p 60fps source video (2 minutes):
| Preset | Encoding Time | File Size | Quality (VMAF) |
|---|---|---|---|
| ultrafast | 15s | 85 MB | 92.1 |
| superfast | 22s | 62 MB | 93.8 |
| veryfast | 30s | 48 MB | 94.5 |
| faster | 40s | 42 MB | 95.0 |
| fast | 52s | 38 MB | 95.3 |
| medium | 70s | 35 MB | 95.5 |
| slow | 120s | 33 MB | 95.7 |
| slower | 210s | 31 MB | 95.8 |
| veryslow | 450s | 30 MB | 95.9 |
| placebo | 1800s | 29.5 MB | 95.9 |
Key observations:
mediumis the default and the sweet spot for most workflows- Going from
mediumtoslowsaves ~6% file size but takes 70% longer - Going from
mediumtoveryslowsaves ~14% but takes 6.4x longer placebooffers virtually no improvement oververyslow— never use itultrafastproduces files 2.4x larger thanmedium— avoid for final delivery
# Good default for most use cases
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium output.mp4
# When encoding time matters more than file size
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset fast output.mp4
# When file size matters more than encoding time
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset slow output.mp4
H.265 Preset Behavior
H.265 presets follow the same naming convention but encoding is significantly slower at each tier:
| Preset | H.264 Time | H.265 Time | H.265 File Size |
|---|---|---|---|
| fast | 52s | 180s | 25 MB |
| medium | 70s | 300s | 22 MB |
| slow | 120s | 600s | 20 MB |
H.265 encoding takes roughly 3-5x longer than H.264 at the same preset, but produces 30-40% smaller files at equivalent quality.
Two-Pass Encoding
Two-pass encoding gives you precise control over output bitrate, which is essential when you need to hit a specific file size target (e.g., "this video must be under 50MB").
How It Works
- Pass 1: FFmpeg analyzes the video and creates a log file with complexity data
- Pass 2: FFmpeg uses the log to distribute bits optimally — more bits for complex scenes, fewer for simple ones
Basic Two-Pass Command
# Pass 1 — analyze (output is discarded)
ffmpeg -i input.mp4 -c:v libx264 -b:v 4M -pass 1 -f null /dev/null
# Pass 2 — encode using analysis data
ffmpeg -i input.mp4 -c:v libx264 -b:v 4M -pass 2 output.mp4
Calculating Target Bitrate
To fit a video into a target file size:
Video bitrate = (Target file size in bits - Audio size in bits) / Duration in seconds
Example: 10-minute video, 100MB target, 128kbps audio:
Audio size = 128,000 bps × 600s = 76,800,000 bits = 9.6 MB
Video bitrate = (100 MB - 9.6 MB) × 8,000,000 / 600 = 1,205,333 bps ≈ 1.2 Mbps
ffmpeg -i input.mp4 -c:v libx264 -b:v 1200k -pass 1 -c:a aac -b:a 128k -f null /dev/null
ffmpeg -i input.mp4 -c:v libx264 -b:v 1200k -pass 2 -c:a aac -b:a 128k output.mp4
CRF vs Two-Pass: When to Use Which
| Approach | Best For | Control |
|---|---|---|
| CRF | Consistent quality, unknown file size | Quality-focused |
| Two-pass | Target file size or bitrate | Size-focused |
| CRF + maxrate | Quality with bitrate ceiling | Streaming |
For streaming with a bitrate ceiling:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -maxrate 4M -bufsize 8M output.mp4
This targets CRF 23 quality but caps the bitrate at 4 Mbps — useful for streaming where bandwidth is limited.
Codec Comparison: H.264 vs H.265 vs VP9 vs AV1
Choosing the right codec is a tradeoff between compression efficiency, encoding speed, and playback compatibility.
Compression Efficiency
At equivalent visual quality (VMAF 95), relative file sizes:
| Codec | Relative File Size | Compression vs H.264 |
|---|---|---|
| H.264 (libx264) | 100% | Baseline |
| H.265 (libx265) | 55-65% | 35-45% smaller |
| VP9 (libvpx-vp9) | 55-65% | 35-45% smaller |
| AV1 (libaom-av1) | 40-50% | 50-60% smaller |
Encoding Speed
Relative encoding time for a 1080p 60fps source at equivalent quality:
| Codec | Encoding Time (relative) | Notes |
|---|---|---|
| H.264 | 1x | Fast, well-optimized |
| H.265 | 3-5x | Significantly slower |
| VP9 | 5-10x | Very slow (single-threaded by default) |
| AV1 (libaom) | 20-50x | Extremely slow |
| AV1 (SVT-AV1) | 3-8x | Much faster AV1 implementation |
Playback Compatibility (2026)
| Codec | Browsers | Mobile | Smart TVs | Hardware Decode |
|---|---|---|---|---|
| H.264 | 99%+ | 99%+ | 99%+ | Universal |
| H.265 | Safari, Edge (partial) | iOS, Android 5+ | Most modern | Common |
| VP9 | Chrome, Firefox, Edge | Android 5+ | Limited | Growing |
| AV1 | Chrome, Firefox, Edge, Safari 17+ | Flagship phones | Limited | Emerging |
Practical Commands
# H.264 — maximum compatibility
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output.mp4
# H.265 — 40% smaller, good mobile support
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset medium -c:a aac -b:a 128k output.mp4
# VP9 — royalty-free, good for web
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -row-mt 1 -c:a libopus -b:a 128k output.webm
# AV1 (SVT-AV1) — best compression, modern devices
ffmpeg -i input.mp4 -c:v libsvtav1 -crf 30 -preset 6 -c:a libopus -b:a 128k output.mp4
Which Codec to Choose
| Scenario | Recommended Codec | Why |
|---|---|---|
| Maximum compatibility | H.264 | Plays everywhere |
| Bandwidth savings, Apple ecosystem | H.265 | Good compression, iOS/macOS native |
| Web-first, royalty-free | VP9 | Chrome/Firefox support, no licensing fees |
| Future-proof, best compression | AV1 (SVT-AV1) | 50%+ savings, growing support |
| Mixed audience | H.264 with H.265/AV1 fallback | Serve best codec per device |
For more details on switching between container formats, see our video format conversion guide.
Resolution Scaling Best Practices
Downscaling video properly involves more than just changing the resolution.
Common Target Resolutions
| Name | Resolution | Typical Bitrate (H.264) | Typical Bitrate (H.265) |
|---|---|---|---|
| 4K UHD | 3840x2160 | 15-30 Mbps | 8-15 Mbps |
| 1440p | 2560x1440 | 8-15 Mbps | 4-8 Mbps |
| 1080p Full HD | 1920x1080 | 4-8 Mbps | 2-4 Mbps |
| 720p HD | 1280x720 | 2-4 Mbps | 1-2 Mbps |
| 480p SD | 854x480 | 1-2 Mbps | 0.5-1 Mbps |
| 360p | 640x360 | 0.5-1 Mbps | 0.3-0.5 Mbps |
Scaling with Aspect Ratio Preservation
Always use -1 for one dimension to maintain the aspect ratio, and use -2 to ensure the value is divisible by 2 (required for most codecs):
# Scale to 720p width, auto-calculate height (divisible by 2)
ffmpeg -i input.mp4 -vf "scale=1280:-2" -c:v libx264 -crf 23 output.mp4
# Scale to 1080 height, auto-calculate width
ffmpeg -i input.mp4 -vf "scale=-2:1080" -c:v libx264 -crf 23 output.mp4
Scaling Filter Quality
FFmpeg offers multiple scaling algorithms. The default (bilinear) is fine for most cases, but for best quality downscaling, use Lanczos:
# High-quality downscale with Lanczos
ffmpeg -i input.mp4 -vf "scale=1280:720:flags=lanczos" -c:v libx264 -crf 23 output.mp4
| Algorithm | Speed | Downscale Quality | Best For |
|---|---|---|---|
| fast_bilinear | Fastest | Low | Real-time processing |
| bilinear | Fast | Moderate | Default, general use |
| bicubic | Medium | Good | Moderate quality needs |
| lanczos | Slower | Best | Final delivery, quality-critical |
| spline | Slower | Excellent | Alternative to Lanczos |
Don't Upscale
As a general rule, never upscale video. Encoding a 720p source as 1080p wastes bandwidth without adding real detail. If you must upscale, keep it minimal and use Lanczos:
# If you must upscale (avoid when possible)
ffmpeg -i input_720p.mp4 -vf "scale=1920:1080:flags=lanczos" -c:v libx264 -crf 20 output.mp4
Audio Compression
Audio is often overlooked in video compression workflows, but optimizing it can save significant bandwidth.
Recommended Audio Settings
| Use Case | Codec | Bitrate | Command |
|---|---|---|---|
| General web video | AAC | 128 kbps | -c:a aac -b:a 128k |
| High-quality video | AAC | 192 kbps | -c:a aac -b:a 192k |
| Music-focused content | AAC | 256 kbps | -c:a aac -b:a 256k |
| WebM/VP9 video | Opus | 128 kbps | -c:a libopus -b:a 128k |
| Podcast/speech | AAC | 64 kbps | -c:a aac -b:a 64k |
| Podcast/speech (Opus) | Opus | 48 kbps | -c:a libopus -b:a 48k |
Normalizing Audio Loudness
Inconsistent audio levels across videos is a common problem. FFmpeg's loudnorm filter normalizes to broadcast standards:
# Normalize to -16 LUFS (standard for streaming)
ffmpeg -i input.mp4 -c:v copy -af "loudnorm=I=-16:TP=-1.5:LRA=11" -c:a aac -b:a 128k output.mp4
Stripping Audio
If you don't need audio at all:
ffmpeg -i input.mp4 -an -c:v libx264 -crf 23 output.mp4
Copying Audio Without Re-encoding
If the audio is already in a suitable format:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a copy output.mp4
Real-World Compression Scenarios
Web Delivery (General Purpose)
The most common scenario — compressing video for embedding on websites:
ffmpeg -i input.mp4 \
-c:v libx264 -crf 23 -preset medium \
-vf "scale=1920:1080:flags=lanczos" \
-c:a aac -b:a 128k \
-movflags +faststart \
output.mp4
Key details:
-movflags +faststartmoves metadata to the beginning of the file, enabling progressive playback (essential for web)- CRF 23 provides a good balance of quality and size
- AAC 128k is sufficient for most web content
Social Media Optimization
Platforms like Twitter/X, Instagram, and TikTok have specific requirements:
# Optimized for social platforms (H.264, AAC, fast start)
ffmpeg -i input.mp4 \
-c:v libx264 -crf 23 -preset medium \
-profile:v high -level:v 4.0 \
-pix_fmt yuv420p \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2" \
-c:a aac -b:a 128k -ar 44100 \
-movflags +faststart \
output.mp4
-profile:v high -level:v 4.0ensures broad compatibility-pix_fmt yuv420pguarantees playback on all devices- The
scale+padfilter creates a 9:16 vertical video with letterboxing
Archival (Maximum Quality, Minimum Loss)
For long-term storage where file size is less important:
ffmpeg -i input.mp4 \
-c:v libx264 -crf 16 -preset slow \
-c:a flac \
output.mkv
- CRF 16 preserves virtually all visual detail
- FLAC audio is lossless
- MKV container supports more codecs than MP4
Streaming (Adaptive Bitrate with HLS)
Generating multiple quality levels for adaptive streaming:
ffmpeg -i input.mp4 \
-map 0:v -map 0:a -map 0:v -map 0:a -map 0:v -map 0:a \
-c:v libx264 -crf 22 \
-c:a aac -b:a 128k \
-var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" \
-b:v:0 5M -maxrate:v:0 5.5M -bufsize:v:0 10M -s:v:0 1920x1080 \
-b:v:1 2.5M -maxrate:v:1 2.75M -bufsize:v:1 5M -s:v:1 1280x720 \
-b:v:2 1M -maxrate:v:2 1.1M -bufsize:v:2 2M -s:v:2 854x480 \
-f hls -hls_time 6 -hls_list_size 0 \
-master_pl_name master.m3u8 \
stream_%v/playlist.m3u8
Batch Compression Script
For processing an entire directory of videos:
#!/bin/bash
# 批量压缩目录下所有视频
for f in *.mp4; do
ffmpeg -i "$f" \
-c:v libx264 -crf 23 -preset medium \
-c:a aac -b:a 128k \
-movflags +faststart \
"compressed_${f}"
done
Cloud Compression with FFHub
All the commands in this guide work directly with FFHub.io — just send them via API:
# Compress a video in the cloud (no local FFmpeg needed)
curl -X POST https://api.ffhub.io/v1/tasks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "ffmpeg -i https://example.com/input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k -movflags +faststart output.mp4"
}'
This offloads the CPU-intensive encoding work to the cloud, keeping your local machine or server free. Particularly useful for batch video transcoding or when running FFmpeg on your application server would impact performance.
Quick Reference Cheat Sheet
One-Liner Commands
# Good default compression
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac -b:a 128k -movflags +faststart output.mp4
# Aggressive compression (smaller file)
ffmpeg -i input.mp4 -c:v libx264 -crf 28 -preset fast -c:a aac -b:a 96k output.mp4
# High-quality compression (larger file)
ffmpeg -i input.mp4 -c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k output.mp4
# Maximum compression with H.265
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset medium -c:a aac -b:a 128k output.mp4
# Future-proof with AV1
ffmpeg -i input.mp4 -c:v libsvtav1 -crf 30 -preset 6 -c:a libopus -b:a 128k output.mp4
Decision Tree
- Need maximum compatibility? Use H.264
- Need smaller files? Use H.265 (Apple/mobile) or VP9 (web)
- Need smallest files and have time? Use AV1
- Need specific file size? Use two-pass encoding
- Need consistent quality? Use CRF
- Processing many files? Use
fastorveryfastpreset - Processing one important file? Use
slowpreset
Conclusion
Effective video compression comes down to understanding and balancing three factors: quality (CRF), speed (preset), and file size (codec choice). Start with the defaults — CRF 23, medium preset, H.264 — and adjust based on your specific requirements. Test with your actual content, because compression behavior varies dramatically between talking-head videos and action sequences.
The commands in this guide are standard FFmpeg — they'll work on your local machine, on any server, or through a cloud service like FFHub. Master these fundamentals and you'll handle any video compression challenge that comes your way.
Validate a CRF / preset / codec combo on a real clip before wiring it into your pipeline. Same FFmpeg flags, no local install.
FAQ
What CRF should I use for streaming video?
For HLS / DASH adaptive streaming, CRF 21–23 with -maxrate and -bufsize caps is the standard. CRF keeps quality consistent across complexity changes, while the bitrate ceiling protects against viewer bandwidth spikes. Use CRF 23 for the highest variant, CRF 24–25 for mid quality, CRF 26–28 for the lowest variant.
Two-pass vs CRF: when should I use each?
Use CRF when you care about consistent quality (any web or archival workflow). Use two-pass when you must hit a specific file size (e.g., Discord 25MB cap, broadcast bitrate spec, ad spec). Two-pass takes ~2x longer than CRF but gives precise size control. For streaming with a bitrate ceiling but quality-first behavior, combine CRF with -maxrate and -bufsize.
Why does H.265 take so much longer than H.264?
H.265 evaluates far more block sizes, prediction modes, and motion vectors per frame to achieve its 30–40% compression advantage. The HEVC specification is intentionally more complex than H.264 in exchange for that efficiency. Real-world: H.265 with libx265 -preset medium is roughly 3–5x slower than H.264 with libx264 -preset medium for the same quality output.
Is AV1 ready for production use in 2026?
Yes for delivery, with caveats. Hardware AV1 decoders are now common on flagship phones, current-gen consoles, and Apple Silicon, but older devices still need an H.264 fallback. For encoding, SVT-AV1 (libsvtav1) is the practical choice — 3–8x slower than H.264 at equivalent quality, versus 20–50x slower for libaom-av1. Netflix, YouTube, and Vimeo already serve AV1 to capable clients.
How do I batch compress videos with consistent quality across different sources?
Use CRF mode, not bitrate mode — CRF adapts to each source's complexity. A simple shell loop with -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k -movflags +faststart produces uniform perceived quality across mixed inputs. If you also need a hard file-size ceiling, layer on -maxrate and -bufsize (e.g., -maxrate 4M -bufsize 8M).
Does -preset slow really make files smaller?
Yes, but with diminishing returns. From medium → slow you save ~6% file size at the same quality but encoding takes ~70% longer. medium → veryslow saves ~14% for 6.4x the encode time. placebo is virtually identical to veryslow — don't use placebo. The practical sweet spots are medium (default), slow (overnight batches, final delivery), and fast (real-time or proxy workflows).
Related Articles
- How to Compress Video with FFmpeg — A beginner-friendly guide to reducing video file size with FFmpeg
- How to Convert Video Format with FFmpeg — Switch between MP4, MKV, WebM, and other containers with codec control
- Batch Video Transcoding API — Automate large-scale video compression through a cloud API