FFmpeg has a reputation for being intimidating. The command syntax is unusual, there are thousands of options, and error messages aren't always helpful. But the truth is, most of what people actually need to do with FFmpeg comes down to about a dozen commands.
This guide covers everything from basic operations to advanced techniques, with every command tested and ready to copy-paste.
What you'll learn
- How FFmpeg commands are structured and how to read options
- Video conversion, audio extraction, compression, trimming, and merging
- GIF conversion, thumbnail extraction, and creating video from images
- Watermarks, subtitles, cropping, and noise reduction
- Inspecting media files in detail with ffprobe
How FFmpeg Commands Are Structured
Every FFmpeg command follows this pattern:
ffmpeg [input options] -i input_file [output options] output_file
The position of options matters. Options placed before -i apply to the input. Options placed after -i apply to the output. This is different from most CLI tools and trips up a lot of newcomers.
Some examples:
# Simplest possible command — just convert the format
ffmpeg -i input.mp4 output.avi
# Input option: seek to a specific position before reading
ffmpeg -ss 00:01:00 -i input.mp4 output_trimmed.mp4
# Output option: set the bitrate of the output
ffmpeg -i input.mp4 -b:v 1M output.mp4
Quick reference for common options:
| Option | Meaning | Example |
|---|---|---|
-c:v | Video codec | -c:v libx264 |
-c:a | Audio codec | -c:a aac |
-b:v | Video bitrate | -b:v 2M |
-b:a | Audio bitrate | -b:a 192k |
-r | Frame rate | -r 30 |
-s | Resolution | -s 1920x1080 |
-ss | Seek start position | -ss 00:01:30 |
-t | Duration in seconds | -t 60 |
-to | End timestamp | -to 00:05:00 |
-vn | No video | For audio-only extraction |
-an | No audio | For silent video output |
Converting Video Formats
Convert MP4 to AVI (or any other format)
ffmpeg -i input.mp4 output.avi
FFmpeg reads the file extensions and automatically picks appropriate codecs. For simple format changes, this is all you need.
Change the container without re-encoding
ffmpeg -i input.mp4 -c copy output.mkv
-c copy tells FFmpeg to copy all streams as-is, without re-encoding. This is instant and lossless — it just changes the wrapper format.
Convert iPhone MOV to MP4
ffmpeg -i input.mov -c:v libx264 -c:a aac output.mp4
A common use case when sharing iPhone videos with people who aren't on Apple devices.
Extracting and Converting Audio
Extract audio from a video file
ffmpeg -i input.mp4 -vn -c:a libmp3lame -q:a 2 output.mp3
What each option does:
-vn= no video (skip the video stream)-c:a libmp3lame= encode audio as MP3-q:a 2= audio quality (0 is best, 9 is worst; 2 is excellent)
For higher quality, use AAC instead:
ffmpeg -i input.mp4 -vn -c:a aac -b:a 192k output.m4a
Convert between audio formats
# WAV to MP3
ffmpeg -i input.wav -c:a libmp3lame -b:a 320k output.mp3
# MP3 to FLAC (lossless)
ffmpeg -i input.mp3 -c:a flac output.flac
# Reduce audio bitrate (smaller file)
ffmpeg -i input.mp3 -b:a 128k output_compressed.mp3
Compressing Video
Reducing file size while preserving quality is probably the most common FFmpeg use case.
If you're unsure which codec to use, see H.264 vs H.265 vs AV1 Comparison for a detailed breakdown.
Compress with H.265 (HEVC)
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -c:a aac output.mp4
The -crf (Constant Rate Factor) value controls the quality-compression tradeoff:
| CRF range | Quality | File size |
|---|---|---|
| Below 18 | Nearly lossless | Large |
| 18–23 | High quality (typical use) | Medium |
| 24–28 | Acceptable (web delivery) | Small |
| Above 28 | Visible degradation | Very small |
H.265 delivers roughly the same quality as H.264 at half the file size. The tradeoff is longer encoding time.
Compress with H.264
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output.mp4
H.264 has much broader device compatibility than H.265. The -preset option lets you trade speed for file size:
| Preset | Encoding speed | File size |
|---|---|---|
| ultrafast | Very fast | Largest |
| fast | Fast | Larger |
| medium | Balanced (default) | Medium |
| slow | Slow | Smaller |
| veryslow | Slowest | Smallest |
# Speed priority (processing lots of videos)
ffmpeg -i input.mp4 -c:v libx264 -preset fast -crf 23 output.mp4
# Quality priority (archival)
ffmpeg -i input.mp4 -c:v libx264 -preset slow -crf 18 output.mp4
For a deeper dive into CRF tuning and codec selection, see the FFmpeg Video Compression Guide. To dramatically speed up encoding with your GPU, check out the FFmpeg GPU Encoding Guide.
Trimming, Cutting, and Merging
Cut a specific time range
# Extract 3 minutes 30 seconds starting at 1:30 (= 1:30 to 5:00)
ffmpeg -ss 00:01:30 -t 00:03:30 -i input.mp4 -c copy output_clip.mp4
-ss 00:01:30= start at 1 minute 30 seconds-t 00:03:30= extract 3 minutes 30 seconds-c copy= no re-encoding (instant, lossless)
Placing -ss before -i uses input seeking, which jumps directly to the position without decoding everything before it. This makes trimming nearly instant even for very long videos.
You can also specify -t in seconds:
# Extract 60 seconds starting at 1:30
ffmpeg -ss 00:01:30 -t 60 -i input.mp4 -c copy output_clip.mp4
If you prefer specifying an absolute end time, place both -ss and -to after -i:
# From 1:30 to 5:00 (-to uses absolute input timestamps)
ffmpeg -i input.mp4 -ss 00:01:30 -to 00:05:00 -c copy output_clip.mp4
This is slower than input seeking (FFmpeg decodes from the start) but -to reliably refers to the absolute position in the input file.
Concatenate videos using a file list
For videos with the same codec and resolution, the file list method is fastest.
Create a text file listing all the videos to join (filelist.txt):
file 'video1.mp4'
file 'video2.mp4'
file 'video3.mp4'
Then run:
ffmpeg -f concat -safe 0 -i filelist.txt -c copy output_merged.mp4
Merge videos with different formats or resolutions
When combining videos with different properties, re-encoding is required:
ffmpeg -i video1.mp4 -i video2.mp4 \
-filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[outv][outa]" \
-map "[outv]" -map "[outa]" output_merged.mp4
Changing Resolution and Frame Rate
Resize video
# Resize to 1920x1080
ffmpeg -i input.mp4 -s 1920x1080 output.mp4
# Resize width to 1280px, maintain aspect ratio
ffmpeg -i input.mp4 -vf scale=1280:-2 output.mp4
# Resize height to 720px, maintain aspect ratio
ffmpeg -i input.mp4 -vf scale=-2:720 output.mp4
Using -2 for one dimension tells FFmpeg to calculate that dimension automatically while preserving the aspect ratio. The -2 ensures the value is rounded to the nearest even number, which is required by most codecs.
Change frame rate
# Convert to 30fps
ffmpeg -i input.mp4 -r 30 output.mp4
# Convert to 60fps
ffmpeg -i input.mp4 -r 60 output.mp4
Reducing the frame rate (e.g., 60fps to 30fps) significantly reduces file size with minimal perceived quality loss for most content.
GIF Conversion, Thumbnails, and Images to Video
Convert video to GIF
A naive conversion produces large files with poor color quality. Palette optimization dramatically improves both:
# Step 1: Generate an optimized palette
ffmpeg -i input.mp4 -vf "fps=15,scale=480:-2:flags=lanczos,palettegen" palette.png
# Step 2: Convert using the palette
ffmpeg -i input.mp4 -i palette.png \
-lavfi "fps=15,scale=480:-2:flags=lanczos[x];[x][1:v]paletteuse" output.gif
What each part does:
fps=15= reduce to 15 frames per second (plenty for GIFs)scale=480:-2= resize to 480px wideflags=lanczos= high-quality resizing algorithmpalettegen/paletteuse= generate and apply an optimized color palette
You can also do it in a single command:
ffmpeg -i input.mp4 \
-lavfi "fps=15,scale=480:-2:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
output.gif
Extract thumbnails from video
# Extract a single frame at the 10-second mark
ffmpeg -ss 10 -i input.mp4 -frames:v 1 thumbnail.jpg
# Extract frames at regular intervals (every 10 seconds)
ffmpeg -i input.mp4 -vf "fps=1/10" thumbnail_%03d.jpg
# Extract keyframes only (fastest)
ffmpeg -skip_frame nokey -i input.mp4 -fps_mode vfr keyframe_%03d.jpg
-frames:v 1 means "output only 1 video frame." fps=1/10 means "1 frame every 10 seconds."
Create video from an image sequence
# From image001.png, image002.png, image003.png...
ffmpeg -framerate 24 -i image%03d.png -c:v libx264 -pix_fmt yuv420p output.mp4
-framerate 24= 24 frames per secondimage%03d.png= 3-digit zero-padded sequence (001, 002, 003...)-pix_fmt yuv420p= compatibility mode for most players
Useful for time-lapse videos and animated sequences.
Loop a single image into a video
ffmpeg -loop 1 -i input.jpg -t 10 -c:v libx264 -pix_fmt yuv420p output.mp4
Useful for social media thumbnails and presentation backgrounds.
Watermarks, Subtitles, Cropping, and Noise Reduction
Add a watermark (image overlay)
# Place a logo in the bottom-right corner (10px margin)
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "overlay=W-w-10:H-h-10" output.mp4
The overlay filter coordinates work like this:
W/H= input video width / heightw/h= overlay image width / heightW-w-10= position from the right edge minus logo width minus 10px
Common placement patterns:
| Position | overlay value |
|---|---|
| Top-left | overlay=10:10 |
| Top-right | overlay=W-w-10:10 |
| Bottom-left | overlay=10:H-h-10 |
| Bottom-right | overlay=W-w-10:H-h-10 |
| Center | overlay=(W-w)/2:(H-h)/2 |
Draw text on video
ffmpeg -i input.mp4 \
-vf "drawtext=text='Sample':fontsize=24:fontcolor=white:x=10:y=10" \
output.mp4
Soft subtitles (togglable in the player)
ffmpeg -i input.mp4 -i subtitle.srt -c:v copy -c:a copy -c:s mov_text output.mp4
The subtitle data is stored inside the MP4 file but not burned into the video. Players that support it let users turn subtitles on or off.
Hard subtitles (burned into the video)
ffmpeg -i input.mp4 -vf subtitles=subtitle.srt output.mp4
This permanently renders the subtitles onto the video frames. They'll always be visible regardless of player, but can't be removed later.
For AI-powered automatic subtitle generation, see Auto-Generate Subtitles with FFmpeg and Whisper.
Crop (cut out a region)
# Crop 640x480 from the center
ffmpeg -i input.mp4 -vf "crop=640:480" output.mp4
# Crop from the top-left corner
ffmpeg -i input.mp4 -vf "crop=640:480:0:0" output.mp4
# Detect black bars automatically
ffmpeg -i input.mp4 -vf "cropdetect" -f null - 2>&1 | grep cropdetect
The crop filter syntax is crop=width:height:x:y. Omitting x and y crops from the center.
For black bar removal, use a two-step process. First detect the crop values, then apply them:
# cropdetect output example: crop=1920:800:0:140
ffmpeg -i input.mp4 -vf "crop=1920:800:0:140" output.mp4
Noise reduction
For video noise, use the nlmeans (Non-Local Means) filter:
ffmpeg -i input.mp4 -vf "nlmeans=s=3.5:p=7:r=15" output.mp4
s= denoising strength (higher = stronger; default 1.0)p= patch size (odd number; default 7)r= search radius (odd number; default 15)
For audio noise, use the arnndn (Recurrent Neural Network) filter. The model file must be downloaded separately:
# Download the model (one-time setup)
curl -LO https://github.com/richardpl/arnndn-models/raw/master/bd.rnnn
# Run noise reduction
ffmpeg -i input.mp4 -af "arnndn=m=bd.rnnn" output.mp4
Model files are available from the arnndn-models repository. bd.rnnn is a general-purpose noise reduction model that works well for background noise in meeting recordings and podcasts.
Inspecting Media with ffprobe
ffprobe is a media analysis tool installed alongside FFmpeg. Use it to check codecs, resolution, bitrate, and more before starting a conversion.
Display file information
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4
-v quiet= suppress the FFmpeg banner-print_format json= output in JSON format-show_format= container info (format, duration, bitrate)-show_streams= stream info (codec, resolution, fps)
Common ffprobe queries
# Show only resolution
ffprobe -v error -select_streams v:0 \
-show_entries stream=width,height -of csv=p=0 input.mp4
# Show only duration (seconds)
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
# Show codec name
ffprobe -v error -select_streams v:0 \
-show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 input.mp4
Making a habit of checking the source file before encoding helps you avoid unexpected conversion results.
Common Questions
How do I adjust audio volume?
# Double the volume
ffmpeg -i input.mp4 -af volume=2.0 output.mp4
# Halve the volume
ffmpeg -i input.mp4 -af volume=0.5 output.mp4
How do I rotate a video?
# Rotate 90 degrees clockwise
ffmpeg -i input.mp4 -vf transpose=1 output.mp4
# Rotate 180 degrees
ffmpeg -i input.mp4 -vf "hflip,vflip" output.mp4
How do I change playback speed?
# 2x speed (both video and audio)
ffmpeg -i input.mp4 -vf setpts=0.5*PTS -af atempo=2.0 output.mp4
# 0.5x speed (slow motion)
ffmpeg -i input.mp4 -vf setpts=2.0*PTS -af atempo=0.5 output.mp4
How do I force overwrite an existing output file?
ffmpeg -y -i input.mp4 output.mp4
The -y flag skips the "file already exists, overwrite?" prompt.
What about licensing for commercial projects?
For details on GPL vs LGPL and what to include when redistributing, see the FFmpeg Commercial License Guide.
Next Steps: Learning FFmpeg
Once you've worked through the commands above, here's how to go deeper.
Official documentation
Start here. It's in English and comprehensive.
- FFmpeg docs: https://ffmpeg.org/documentation.html
- FFmpeg Wiki: https://trac.ffmpeg.org/wiki — practical how-to articles
- Man pages: run
man ffmpegon Linux/Mac for the full command reference
Recommended learning path
FFmpeg rewards hands-on practice over passive reading. A structured progression:
- Basic commands (this article) — format conversion, audio extraction, trimming
- Filters — start with
scaleandcrop, then move tofilter_complex. The Video Compression Guide covers CRF tuning in depth - Encoding parameters — CRF vs. bitrate control, codec-specific tuning (x264, x265, SVT-AV1). See the GPU Encoding Guide for hardware acceleration
- Automation — Python integration for batch processing, VPS encoding server for remote offloading
Community resources
- Stack Overflow — the
[ffmpeg]tag has thousands of answered questions - Reddit r/ffmpeg — practical discussion, good for specific use-case questions
- FFmpeg mailing list (
ffmpeg-user@ffmpeg.org) — developers sometimes respond directly
Wrapping Up
Here's a quick reference table for the most common operations:
| Task | Key options |
|---|---|
| Format conversion | ffmpeg -i input.mp4 output.avi |
| Lossless remux | -c copy |
| Audio extraction | -vn -c:a libmp3lame |
| H.265 compression | -c:v libx265 -crf 28 |
| Trim a clip | -ss start -to end -c copy |
| Merge clips | -f concat -i filelist.txt |
| Resize | -vf scale=1280:-2 |
| GIF conversion | palettegen + paletteuse |
| Thumbnail extraction | -frames:v 1 |
| Watermark | -filter_complex overlay=... |
| Burn subtitles | -vf subtitles=subtitle.srt |
| Crop | -vf crop=width:height:x:y |
| Noise reduction | -vf nlmeans / -af arnndn |
The best way to learn FFmpeg is to start with one concrete task — say, compressing a video or extracting audio — and then gradually explore from there.
For automating repetitive tasks, Python integration is the way to go:
- Automating FFmpeg with Python: Batch Processing Scripts — Build scripts to bulk-process video files