A practical cheatsheet for video automation, clipping, and media processing pipelines.
brew install ffmpeg # macOS
apt-get install ffmpeg # Ubuntu/Debian
choco install ffmpeg # Windows- Quick Reference
- Format Conversion
- Trimming & Clipping
- Resizing & Scaling
- Audio Operations
- Overlays & Watermarks
- Text & Subtitles
- Speed Control
- Concatenation
- Thumbnails & Storyboards
- GIF Creation
- Encoding Settings
- Batch Processing
- Deep Dives
| Flag | Description |
|---|---|
-i |
Input file |
-y |
Overwrite output without asking |
-c copy |
Copy streams without re-encoding (fast) |
-c:v libx264 |
H.264 video encoder |
-c:a aac |
AAC audio encoder |
-vf |
Video filter |
-af |
Audio filter |
-filter_complex |
Complex multi-stream filter |
-ss |
Start time (seek) |
-t |
Duration |
-to |
End time |
-an |
Remove audio |
-vn |
Remove video |
-map |
Select specific streams |
| Selector | Meaning |
|---|---|
[0:v] |
Video from first input |
[0:a] |
Audio from first input |
[1:v] |
Video from second input |
[0:v:0] |
First video stream from first input |
-ss 30 # 30 seconds
-ss 00:01:30 # 1 minute 30 seconds
-ss 00:01:30.500 # With milliseconds# MP4 to MKV - just change container
ffmpeg -i input.mp4 -c copy output.mkv
# MP4 to MOV
ffmpeg -i input.mp4 -c copy output.mov# Any format to MP4 (H.264 + AAC)
ffmpeg -i input.avi -c:v libx264 -crf 23 -c:a aac output.mp4
# High quality H.264
ffmpeg -i input.mov -c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k output.mp4
# To H.265 (50% smaller, slower encode)
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -c:a aac output.mp4Deep dive: Format Conversion | Codecs
# Trim from 10s to 40s
ffmpeg -i input.mp4 -ss 00:00:10 -to 00:00:40 output.mp4
# Trim 30 seconds starting at 1 minute
ffmpeg -i input.mp4 -ss 00:01:00 -t 00:00:30 output.mp4# Fast but may have a few seconds of inaccuracy
ffmpeg -ss 00:01:00 -i input.mp4 -t 00:00:30 -c copy output.mp4Note: -ss before -i = fast input seeking (keyframe-based). After -i = accurate but slower.
# Re-encode for precise cuts
ffmpeg -i input.mp4 -ss 00:00:37 -t 00:00:10 -c:v libx264 -c:a aac output.mp4# Keep 0-5s, 10-15s, 20-25s
ffmpeg -i input.mp4 \
-vf "select='between(t,0,5)+between(t,10,15)+between(t,20,25)',setpts=N/FRAME_RATE/TB" \
-af "aselect='between(t,0,5)+between(t,10,15)+between(t,20,25)',asetpts=N/SR/TB" \
output.mp4Deep dive: Trimming Guide
# Scale to 1280x720
ffmpeg -i input.mp4 -vf "scale=1280:720" output.mp4
# Scale width, auto-height (preserve aspect)
ffmpeg -i input.mp4 -vf "scale=1280:-2" output.mp4# Fit in 1920x1080, add black bars
ffmpeg -i input.mp4 -vf \
"scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black,setsar=1" \
output.mp4# YouTube 1080p (16:9)
ffmpeg -i input.mp4 -vf \
"scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:-1:-1:black,setsar=1" \
output_youtube.mp4
# Instagram/TikTok (9:16 vertical)
ffmpeg -i input.mp4 -vf \
"scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:-1:-1:black,setsar=1" \
output_vertical.mp4
# Instagram Square (1:1)
ffmpeg -i input.mp4 -vf \
"scale=1080:1080:force_original_aspect_ratio=decrease,pad=1080:1080:-1:-1:black,setsar=1" \
output_square.mp4# Crop to center 1280x720
ffmpeg -i input.mp4 -vf "crop=1280:720" output.mp4
# Crop with offset (x=100, y=50)
ffmpeg -i input.mp4 -vf "crop=1280:720:100:50" output.mp4
# Crop to 16:9 from center
ffmpeg -i input.mp4 -vf "crop=ih*16/9:ih" output.mp4Deep dive: Scaling Guide
# Copy audio without re-encoding
ffmpeg -i input.mp4 -vn -c:a copy output.aac
# Extract as MP3
ffmpeg -i input.mp4 -vn -c:a libmp3lame -q:a 2 output.mp3
# Extract as WAV
ffmpeg -i input.mp4 -vn -c:a pcm_s16le output.wavffmpeg -i video.mp4 -i audio.mp3 \
-map 0:v -map 1:a -c:v copy -c:a aac -shortest \
output.mp4# Lower music volume, mix with video audio
ffmpeg -i video.mp4 -i music.mp3 \
-filter_complex "[1:a]volume=0.3[music];[0:a][music]amix=inputs=2:duration=first[a]" \
-map 0:v -map "[a]" -c:v copy -c:a aac output.mp4# 2s fade in, 3s fade out (for 30s audio)
ffmpeg -i input.mp4 -af "afade=t=in:d=2,afade=t=out:st=27:d=3" output.mp4ffmpeg -i input.mp4 -an -c:v copy output.mp4Deep dive: Audio Extraction | Audio Mixing
# Bottom-right corner with padding
ffmpeg -i video.mp4 -i logo.png \
-filter_complex "overlay=main_w-overlay_w-10:main_h-overlay_h-10" \
output.mp4
# Top-left corner
ffmpeg -i video.mp4 -i logo.png \
-filter_complex "overlay=10:10" \
output.mp4
# Center
ffmpeg -i video.mp4 -i logo.png \
-filter_complex "overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2" \
output.mp4# Show logo from 5s to 15s only
ffmpeg -i video.mp4 -i logo.png \
-filter_complex "overlay=10:10:enable='between(t,5,15)'" \
output.mp4ffmpeg -i video.mp4 -i logo.png \
-filter_complex "[1:v]format=argb,geq=p(X,Y):a='0.5*alpha(X,Y)'[logo];[0:v][logo]overlay=10:10" \
output.mp4ffmpeg -i main.mp4 -i pip.mp4 \
-filter_complex "[1:v]scale=320:180[pip];[0:v][pip]overlay=main_w-overlay_w-10:10" \
-map 0:a -c:a copy output.mp4Deep dive: Overlays Guide
# Basic text
ffmpeg -i input.mp4 \
-vf "drawtext=text='Hello World':x=100:y=100:fontsize=48:fontcolor=white" \
output.mp4
# With background box
ffmpeg -i input.mp4 \
-vf "drawtext=text='Hello':x=100:y=100:fontsize=48:fontcolor=white:box=1:boxcolor=black@0.6:boxborderw=10" \
output.mp4
# Centered text
ffmpeg -i input.mp4 \
-vf "drawtext=text='Centered':x=(w-text_w)/2:y=(h-text_h)/2:fontsize=48" \
output.mp4# Show text from 2s to 8s
ffmpeg -i input.mp4 \
-vf "drawtext=text='Now Showing':x=100:y=100:fontsize=48:enable='between(t,2,8)'" \
output.mp4ffmpeg -i video.mp4 -vf "subtitles=subs.srt" output.mp4
# With styling
ffmpeg -i video.mp4 \
-vf "subtitles=subs.srt:force_style='FontName=Arial,FontSize=24,PrimaryColour=&HFFFFFF'" \
output.mp4ffmpeg -i video.mp4 -i subs.srt \
-c copy -c:s srt \
-metadata:s:s:0 language=eng \
output.mkvDeep dive: Subtitles Guide
# 2x speed
ffmpeg -i input.mp4 \
-filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" \
-map "[v]" -map "[a]" output.mp4
# 4x speed (chain atempo for >2x)
ffmpeg -i input.mp4 \
-filter_complex "[0:v]setpts=0.25*PTS[v];[0:a]atempo=2.0,atempo=2.0[a]" \
-map "[v]" -map "[a]" output.mp4# 0.5x speed (half speed)
ffmpeg -i input.mp4 \
-filter_complex "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]" \
-map "[v]" -map "[a]" output.mp4| Speed | setpts | atempo |
|---|---|---|
| 2x | 0.5*PTS | 2.0 |
| 1.5x | 0.667*PTS | 1.5 |
| 0.5x | 2.0*PTS | 0.5 |
| 0.25x | 4.0*PTS | 0.5,0.5 |
Deep dive: Speed Manipulation
Create files.txt:
file 'video1.mp4'
file 'video2.mp4'
file 'video3.mp4'
ffmpeg -f concat -safe 0 -i files.txt -c copy output.mp4ffmpeg -i video1.mp4 -i video2.avi \
-filter_complex \
"[0:v]scale=1920:1080,fps=30,format=yuv420p[v0]; \
[1:v]scale=1920:1080,fps=30,format=yuv420p[v1]; \
[v0][0:a][v1][1:a]concat=n=2:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" output.mp4ffmpeg -i video1.mp4 -i video2.mp4 \
-filter_complex "xfade=transition=fade:duration=1:offset=4" \
output.mp4Deep dive: Concatenation Guide
# At 5 seconds
ffmpeg -i input.mp4 -ss 00:00:05 -frames:v 1 -q:v 2 thumbnail.jpg
# High quality PNG
ffmpeg -i input.mp4 -ss 00:00:05 -frames:v 1 thumbnail.png# One per 10 seconds
ffmpeg -i input.mp4 -vf "fps=1/10" -q:v 2 thumb_%04d.jpgffmpeg -i input.mp4 \
-vf "select='gt(scene,0.4)',thumbnail" \
-frames:v 1 best_scene.jpg# 4x4 grid from scenes
ffmpeg -i input.mp4 \
-vf "select='gt(scene,0.4)',scale=320:180,tile=4x4" \
-frames:v 1 storyboard.jpg
# Time-based grid (every 10 seconds)
ffmpeg -i input.mp4 \
-vf "fps=1/10,scale=240:135,tile=5x4" \
-frames:v 1 storyboard.jpgDeep dive: Thumbnails | Storyboards
ffmpeg -i input.mp4 -vf "fps=10,scale=480:-1" output.gifffmpeg -i input.mp4 \
-filter_complex "fps=10,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
output.gifffmpeg -ss 10 -t 3 -i input.mp4 \
-filter_complex "fps=10,scale=480:-1,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
output.gifDeep dive: GIF Creation
Lower = better quality, larger file. Range 0-51.
# Visually lossless (~18)
ffmpeg -i input.mov -c:v libx264 -crf 18 output.mp4
# Good quality (~23, default)
ffmpeg -i input.mov -c:v libx264 -crf 23 output.mp4
# Smaller file (~28)
ffmpeg -i input.mov -c:v libx264 -crf 28 output.mp4Slower = better compression, smaller file.
# Fast encoding
ffmpeg -i input.mov -c:v libx264 -preset fast -crf 23 output.mp4
# Best compression
ffmpeg -i input.mov -c:v libx264 -preset veryslow -crf 23 output.mp4# Fast start for streaming
ffmpeg -i input.mov -c:v libx264 -crf 23 -movflags +faststart output.mp4# NVIDIA GPU
ffmpeg -i input.mp4 -c:v h264_nvenc output.mp4
# Intel QuickSync
ffmpeg -init_hw_device qsv=hw -i input.mp4 -c:v h264_qsv output.mp4Deep dive: Codecs | Hardware Acceleration
# Convert all AVI to MP4
for f in *.avi; do
ffmpeg -i "$f" -c:v libx264 -crf 23 "${f%.avi}.mp4"
done# Using GNU Parallel
find . -name "*.avi" | parallel -j4 'ffmpeg -i {} -c:v libx264 -crf 23 {.}.mp4'for f in *.mp4; do
ffmpeg -ss 5 -i "$f" -frames:v 1 -q:v 2 "${f%.mp4}_thumb.jpg"
doneDeep dive: Batch Processing
# Quick info
ffprobe input.mp4
# Detailed stream info
ffprobe -show_streams input.mp4
# JSON output
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4
# Get duration
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4For comprehensive coverage on each topic:
- Concepts & Terminology - Containers, codecs, streams
- Command Anatomy - How commands are structured
- Filters & Filter Graphs - Filter syntax and patterns
Test commands with these public samples:
https://storage.rendi.dev/sample/big_buck_bunny_720p_16sec.mp4
https://storage.rendi.dev/sample/Neon_Lights_5sec.mp3
https://storage.rendi.dev/sample/rendi_banner_white.png
MIT License