- FFmpeg anatomy:
ffmpeg -i input.mp4 [options] output.ext -c copyskips re-encoding (fastest, lossless quality) — use whenever you just need to trim or remux-crf 23controls H.264 quality: lower = better quality, larger file (0–51 scale, 18–28 is practical range)-vfapplies video filters: scale, crop, fps, overlay, palette- Always test with a short clip (
-t 5) before running on large files
Quick install
| Platform | Command |
|---|---|
| macOS (Homebrew) | brew install ffmpeg |
| Ubuntu / Debian | sudo apt install ffmpeg |
| Windows | Download from ffmpeg.org/download.html → add to PATH |
| Check version | ffmpeg -version |
| Check codecs | ffmpeg -codecs |
Quick reference — most-used flags
| Flag | Meaning |
|---|---|
-i input.mp4 | Input file (always before output options) |
-c copy | Copy streams without re-encoding (fast) |
-c:v libx264 | Encode video with H.264 |
-c:v libx265 | Encode video with H.265 (HEVC) — 40% smaller than H.264 |
-c:v libvpx-vp9 | Encode video with VP9 (web/WebM) |
-c:a aac | Encode audio with AAC |
-c:a libmp3lame | Encode audio with MP3 |
-c:a copy | Copy audio without re-encoding |
-an | Remove audio (no audio stream) |
-vn | Remove video (no video stream — audio extraction) |
-crf 23 | Quality factor for H.264/H.265 (lower = better) |
-b:v 2M | Set target video bitrate (2 Mbps) |
-b:a 128k | Set audio bitrate (128 kbps) |
-r 30 | Set output frame rate |
-t 10 | Limit duration to 10 seconds |
-ss 00:00:30 | Seek/start from 30 seconds |
-to 00:01:00 | End at 1 minute |
-vf "filter" | Apply a video filter |
-af "filter" | Apply an audio filter |
-y | Overwrite output without asking |
-n | Skip if output file exists |
Format conversion
Re-wrapping without re-encoding (fastest, no quality loss):
# MP4 → MKV (same streams, different container)
ffmpeg -i input.mp4 -c copy output.mkv
# MKV → MP4
ffmpeg -i input.mkv -c copy output.mp4
# MOV → MP4 (iPhone exports)
ffmpeg -i input.mov -c copy output.mp4
# AVI → MP4
ffmpeg -i input.avi -c:v libx264 -c:a aac output.mp4
# MP4 → WebM (re-encode for web)
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 33 -b:v 0 -c:a libopus output.webm Compress video for web
H.264 (best compatibility, works in all browsers and devices):
# Good quality / reasonable size (CRF 23)
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset fast -c:a aac -b:a 128k output.mp4
# Smaller file, slight quality drop (CRF 28)
ffmpeg -i input.mp4 -c:v libx264 -crf 28 -preset fast -c:a aac -b:a 128k output.mp4
# Maximum quality (CRF 18)
ffmpeg -i input.mp4 -c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k output.mp4 H.265 / HEVC (half the size of H.264 at same quality — iOS 11+, most modern browsers with codec support):
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset fast -c:a aac -b:a 128k output.mp4 CRF quality guide
| CRF | Quality | File size | Use for |
|---|---|---|---|
| 0 | Lossless | Very large | Archival |
| 18 | Near-lossless | Large | Master file |
| 23 | Good | Medium | General web |
| 28 | Acceptable | Small | Mobile, social |
| 35+ | Poor | Very small | Not recommended |
Preset speed guide
| Preset | Speed | File size |
|---|---|---|
ultrafast | Fastest encode | Largest file |
fast | Fast | Slightly larger |
medium (default) | Balanced | Balanced |
slow | Slow | Smaller file |
veryslow | Very slow | Smallest file |
Resize and scale
# Scale to 1280px wide, maintain aspect ratio
ffmpeg -i input.mp4 -vf "scale=1280:-1" output.mp4
# Scale to 720p height, maintain aspect ratio
ffmpeg -i input.mp4 -vf "scale=-1:720" output.mp4
# Force exact resolution (may stretch)
ffmpeg -i input.mp4 -vf "scale=1920:1080" output.mp4
# Scale to 1080p but pad to exact 16:9 (letterbox)
ffmpeg -i input.mp4 -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2" output.mp4
# Scale with even dimensions (required by some encoders)
ffmpeg -i input.mp4 -vf "scale=1280:trunc(ow/a/2)*2" output.mp4 Trim and cut
The fastest way uses -c copy (no re-encoding):
# From 30s to 90s (60-second clip)
ffmpeg -ss 00:00:30 -to 00:01:30 -i input.mp4 -c copy output.mp4
# From 30s, for 10 seconds
ffmpeg -ss 00:00:30 -t 10 -i input.mp4 -c copy output.mp4
# From the beginning, first 60 seconds
ffmpeg -i input.mp4 -t 60 -c copy output.mp4 Placing -ss before -i (as above) seeks efficiently using keyframes — fast but may be off by a fraction of a second. Placing -ss after -i decodes every frame — slow but frame-accurate. For social media clips where exact cuts matter, use -ss after -i and remove -c copy to re-encode.
# Frame-accurate cut (re-encodes — slower but precise)
ffmpeg -i input.mp4 -ss 00:00:30 -to 00:01:30 -c:v libx264 -crf 23 output.mp4 Audio operations
# Extract audio as MP3
ffmpeg -i input.mp4 -vn -c:a libmp3lame -b:a 192k output.mp3
# Extract audio as AAC
ffmpeg -i input.mp4 -vn -c:a aac -b:a 128k output.aac
# Extract audio losslessly as FLAC
ffmpeg -i input.mp4 -vn -c:a flac output.flac
# Remove audio from video
ffmpeg -i input.mp4 -an -c:v copy output.mp4
# Replace audio in a video
ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 output.mp4
# Change audio volume
ffmpeg -i input.mp4 -af "volume=1.5" output.mp4 # 1.5x louder
# Normalize audio (loudnorm)
ffmpeg -i input.mp4 -af "loudnorm=I=-16:TP=-1.5:LRA=11" output.mp4
# Fade in audio (2 second fade starting at 0)
ffmpeg -i input.mp4 -af "afade=t=in:ss=0:d=2" output.mp4
# Add silent audio to a silent video
ffmpeg -i input.mp4 -f lavfi -i anullsrc=r=44100:cl=stereo -c:v copy -c:a aac -shortest output.mp4 Create GIFs
Good GIFs require a two-pass approach for proper color palette:
# Step 1: generate palette
ffmpeg -i input.mp4 -ss 5 -t 3 -vf "fps=12,scale=480:-1:flags=lanczos,palettegen" palette.png
# Step 2: create GIF using the palette
ffmpeg -i input.mp4 -i palette.png -ss 5 -t 3 \
-filter_complex "fps=12,scale=480:-1:flags=lanczos[x];[x][1:v]paletteuse" \
output.gif One-liner (lower quality but simpler):
ffmpeg -i input.mp4 -ss 5 -t 3 -vf "fps=10,scale=320:-1" output.gif | Parameter | Adjust for |
|---|---|
fps=12 | Smoothness (8–15 for GIFs) |
scale=480:-1 | Width (height auto) |
-t 3 | Duration in seconds |
palettegen | Color accuracy (worth the two-pass) |
Screenshots and thumbnails
# Single screenshot at 10 seconds
ffmpeg -i input.mp4 -ss 00:00:10 -frames:v 1 thumbnail.jpg
# High-quality screenshot
ffmpeg -i input.mp4 -ss 00:00:10 -frames:v 1 -q:v 2 thumbnail.jpg
# Screenshot grid (one frame every 60 seconds)
ffmpeg -i input.mp4 -vf "fps=1/60" frames/thumb_%04d.jpg
# Video preview strip (contact sheet)
ffmpeg -i input.mp4 -vf "select=not(mod(n\,300)),scale=160:90,tile=10x5" contact_sheet.jpg Merge and concatenate
# Merge two videos (same codec/resolution — fast)
# Create a list file:
echo "file 'part1.mp4'
file 'part2.mp4'" > filelist.txt
ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mp4 Stack videos side by side:
# Side by side (horizontal)
ffmpeg -i left.mp4 -i right.mp4 \
-filter_complex "[0:v][1:v]hstack=inputs=2" \
output.mp4
# Stack vertically
ffmpeg -i top.mp4 -i bottom.mp4 \
-filter_complex "[0:v][1:v]vstack=inputs=2" \
output.mp4 Add text overlay (watermark)
# Simple text overlay
ffmpeg -i input.mp4 \
-vf "drawtext=text='My Watermark':fontsize=36:fontcolor=white:x=10:y=10" \
output.mp4
# Timestamp overlay
ffmpeg -i input.mp4 \
-vf "drawtext=text='%{pts\:hms}':fontsize=24:fontcolor=yellow:x=10:y=10" \
output.mp4
# Image watermark (logo in bottom-right)
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "[1:v]scale=100:-1[logo];[0:v][logo]overlay=W-w-10:H-h-10" \
output.mp4 Batch processing
# Convert all MP4 files in current directory to WebM
for f in *.mp4; do
ffmpeg -i "$f" -c:v libvpx-vp9 -crf 33 -b:v 0 -c:a libopus "${f%.mp4}.webm"
done
# Resize all videos to 1280px wide
for f in *.mp4; do
ffmpeg -i "$f" -vf "scale=1280:-1" -c:a copy "resized_$f"
done
# Extract thumbnails from all videos
for f in *.mp4; do
ffmpeg -i "$f" -ss 5 -frames:v 1 "${f%.mp4}.jpg"
done Useful one-liners
# Get video info (duration, resolution, codec)
ffprobe -v quiet -print_format json -show_streams input.mp4
# Speed up video 2x (with audio pitch correction)
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" -af "atempo=2.0" output.mp4
# Slow down video 2x
ffmpeg -i input.mp4 -vf "setpts=2.0*PTS" -af "atempo=0.5" output.mp4
# Rotate video 90 degrees clockwise
ffmpeg -i input.mp4 -vf "transpose=1" output.mp4
# Flip video horizontally (mirror)
ffmpeg -i input.mp4 -vf "hflip" output.mp4
# Stabilize shaky video
ffmpeg -i input.mp4 -vf "vidstabdetect" -f null -
ffmpeg -i input.mp4 -vf "vidstabtransform" output.mp4
# Convert image sequence to video
ffmpeg -framerate 24 -pattern_type glob -i "frames/*.jpg" -c:v libx264 output.mp4
# Create video from a single image with audio
ffmpeg -loop 1 -i image.jpg -i audio.mp3 -c:v libx264 -tune stillimage -c:a aac -shortest output.mp4 Summary
- Always start with
-c copy— only re-encode when you actually need to change codec or quality - CRF 23 +
-preset fast+ AAC 128k covers 90% of web video needs - Two-pass GIF generation (palettegen → paletteuse) produces dramatically better results than one-pass
- Use
-ssbefore-ifor speed, after-ifor frame accuracy ffprobeis FFmpeg’s companion for inspecting files without modifying them
FAQ
Why is my output file larger than the input?
You are re-encoding a compressed file to a lower CRF (higher quality) than the original, or using a slower preset without lowering the CRF. Try raising CRF by 2–3 points or using -c copy if no quality change is needed.
What is the difference between -t and -to?
-t specifies a duration from the start point. -to specifies an absolute end timestamp. -ss 30 -t 10 ends at 40s. -ss 30 -to 40 also ends at 40s — but -to is relative to the beginning of the input, not the -ss start.
Can FFmpeg handle 4K and HDR video?
Yes. For HDR (HDR10/Dolby Vision), use -c:v libx265 -x265-params "hdr-opt=1:repeat-headers=1:colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc" to preserve HDR metadata.
How do I speed up FFmpeg processing?
Enable GPU encoding: -c:v h264_nvenc (NVIDIA), -c:v h264_videotoolbox (Apple Silicon), -c:v h264_amf (AMD). Check available encoders with ffmpeg -encoders | grep h264.
What is the smallest file format for web video?
AV1 (codec libaom-av1 or libsvtav1) produces the smallest files at a given quality — 30–40% smaller than H.265, 50% smaller than H.264. Trade-off: slow encoding and limited playback support below 2023-era devices.
What to read next
- Linux Bash Cheat Sheet — shell scripting for batch video workflows
- GitHub Actions Cheat Sheet — automate video processing in CI
- SSH & GPG Cheat Sheet — transfer large video files securely
Related Articles
Deepen your understanding with these curated continuations.
tmux Cheat Sheet: Sessions, Panes, Windows & Config
Complete tmux reference — prefix key, sessions, windows, panes, copy mode, key bindings, plugins, and a starter .tmux.conf for 2026.
Vim Cheat Sheet: Modes, Navigation, Editing & Config
Complete Vim reference covering modes, movement, editing commands, search and replace, visual mode, split panes, macros, text objects, and a starter .vimrc.
SSH & GPG Cheat Sheet: Keys, Tunnels & Signed Commits
Complete SSH and GPG reference — key generation, ssh-agent, config file aliases, port forwarding, database tunneling, GPG signing, and signed git commits.