Video files too large to upload? Storage filling up fast? FFmpeg can solve both in a single command.
This guide walks through CRF, bitrate targeting, 2-pass encoding, and presets — the four core approaches to video compression. You'll also find ready-to-copy commands for common use cases: web delivery, social media, archiving, and mobile.
Understanding Video Compression Basics
Before diving into commands, it helps to understand the core trade-off: quality vs. file size.
There are two main encoding strategies:
- Variable bitrate (VBR) — Uses more bits for complex scenes and fewer for simple ones. Achieves better quality at smaller sizes.
- Constant bitrate (CBR) — Maintains a fixed data rate throughout. Used when bandwidth guarantees are required, like in live streaming.
The two dominant codecs today are H.264 (libx264) and H.265 (libx265). H.265 produces roughly half the file size of H.264 at equivalent quality, but encodes more slowly and has lower playback compatibility on older devices.
The codec is specified with the -c:v flag. Use -c:v libx264 for H.264 and -c:v libx265 for H.265.
Compress with CRF (Constant Quality)
CRF — Constant Rate Factor — fixes a quality level and lets the encoder decide the file size. It's the most popular FFmpeg compression method and the right default for most use cases.
CRF compression with H.264:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a copy output.mp4
CRF compression with H.265 (smaller file size at equivalent quality):
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -c:a copy output.mp4
To increase quality (at the cost of file size), lower the CRF. For fine-detail footage like screen recordings or animation, try CRF 18. For social media uploads where file size matters more than pixel-perfect quality, CRF 30–35 can cut file size dramatically without noticeable degradation.
Compress with Bitrate Targeting
Bitrate targeting is the right choice when you need strict control over file size or streaming bandwidth. If you have a target like "this file must be under 50 MB," this is your method.
A rough size estimate: duration (seconds) × bitrate (bps) ÷ 8 = bytes. A 60-second video at 2 Mbps works out to about 15 MB.
Encode video at a target of 2 Mbps:
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -c:a copy output.mp4
Specify both video and audio bitrates:
ffmpeg -i input.mp4 -c:v libx264 -b:v 1800k -c:a aac -b:a 192k output.mp4
One limitation of bitrate targeting: the same amount of data is used regardless of scene complexity. Simple scenes will have more bits than needed; complex scenes may not have enough. Unless you have a hard size requirement, CRF usually produces better results.
Optimize with 2-Pass Encoding
2-pass encoding is a two-stage process: FFmpeg first analyzes the entire video, then encodes it using that analysis. This allows it to distribute bits more efficiently across the video. It's most beneficial for long-form content or when you need the best possible quality at a fixed bitrate.
Pass 1 (analysis only — no output video is created):
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 1 -an -f null /dev/null
Pass 2 (final encode):
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 2 -c:a aac -b:a 192k output.mp4
For H.265, use -c:v libx265 -x265-params pass=1 in the first pass.
2-pass encoding takes roughly twice as long as a single pass, but yields better quality at the same bitrate. It's especially effective for DVD authoring, broadcast delivery, or any scenario with a strict file size ceiling. For everyday compression, CRF is usually sufficient.
Control Speed and Efficiency with Presets
FFmpeg's libx264 and libx265 include a preset system that balances encoding speed against compression efficiency.
Presets from fastest to slowest:
ultrafast → superfast → veryfast → faster → fast → medium (default) → slow → slower → veryslow
Encoding with a preset specified:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset slow -c:a copy output.mp4
To compare multiple presets on the same input:
for preset in fast medium slow veryslow; do
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset $preset -c:a copy output_${preset}.mp4
done
Practical recommendations: use medium (default) or slow for most compression tasks; use veryslow when you want the smallest possible file and have time to spare; use fast or veryfast for real-time processing or large batch jobs.
Optimal Settings by Use Case
Ready-to-use commands for the most common scenarios.
| Use Case | Codec | CRF | Preset | Notes |
|---|---|---|---|---|
| Web delivery | H.264 | 23 | slow | Maximum compatibility |
| Social media (X / Instagram) | H.264 | 28–30 | medium | File size priority |
| Long-term archive | H.265 | 24 | veryslow | Best ratio for storage |
| Mobile playback | H.264 | 26 | fast | Pair with resolution scaling |
Web delivery (compatibility first):
ffmpeg -i input.mp4 \
-c:v libx264 -crf 23 -preset slow \
-c:a aac -b:a 128k \
-movflags +faststart \
output_web.mp4
-movflags +faststart moves the moov atom to the beginning of the file, enabling playback to start before the download completes. This is a must-have flag for web video.
Social media (smallest file size):
ffmpeg -i input.mp4 \
-c:v libx264 -crf 30 -preset medium \
-vf "scale=1280:-2" \
-c:a aac -b:a 96k \
output_sns.mp4
Long-term archival (H.265, maximum compression):
ffmpeg -i input.mp4 \
-c:v libx265 -crf 24 -preset veryslow \
-c:a aac -b:a 128k \
output_archive.mp4
Mobile playback (downscale + lightweight):
ffmpeg -i input.mp4 \
-c:v libx264 -crf 26 -preset fast \
-vf "scale=720:-2" \
-c:a aac -b:a 96k \
output_mobile.mp4
Common Mistakes and How to Fix Them
Mistake 1: File got larger after compression
If the source video was already compressed, re-encoding can actually increase the file size due to encoding overhead. Fix: stream-copy the video with -c:v copy, or set a target bitrate below the source's original bitrate.
Mistake 2: Green or black frames in the output
This is usually a pixel format compatibility issue. Adding -pix_fmt yuv420p resolves it in most cases:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -pix_fmt yuv420p -c:a copy output.mp4
Mistake 3: Audio quality has degraded
Mistake 4: Encoding is extremely slow
Combining veryslow preset, 4K+ resolution, and H.265 can result in encode times measured in hours. GPU encoding dramatically reduces this:
# NVIDIA GPU (NVENC)
ffmpeg -i input.mp4 -c:v h264_nvenc -crf 23 -c:a copy output.mp4
Note that GPU encoders are generally less efficient than CPU encoders at equivalent settings — you'll get larger files or lower quality at the same nominal settings. Use GPU encoding when speed is the priority.
Wrapping Up
Choosing the right compression approach makes a real difference in the results.
- For quality-first compression, use CRF — pick a value and let FFmpeg handle the rest
- For strict file size requirements, use 2-pass — most effective for broadcast and delivery
- Tune speed vs. efficiency with presets —
slowandveryslowmeaningfully improve results - Don't forget
-movflags +faststartfor web video — it's easy to miss and important
If you're new to FFmpeg and want to get up to speed with the basics first, check out FFmpeg Usage Tutorial. If you need to cut footage without any quality loss, FFmpeg Lossless Cut covers that workflow.