Video format conversion is one of the most common tasks in media processing. Whether you need MP4 for the web, MOV for Apple workflows, or WebM for open-source projects, FFmpeg handles them all from the command line. This guide covers everything from basic conversions to advanced codec selection and batch processing.
Basic Format Conversion
The simplest conversion just changes the container format. FFmpeg detects the output format from the file extension:
# Convert MKV to MP4
ffmpeg -i input.mkv output.mp4
# Convert AVI to MOV
ffmpeg -i input.avi output.mov
# Convert MP4 to WebM
ffmpeg -i input.mp4 output.webmWhen you don't specify codecs, FFmpeg picks defaults for the target container. This works but doesn't give you control over quality or compatibility.
Understanding Containers vs Codecs
Before diving deeper, it helps to understand the difference:
- Container (MP4, MKV, MOV, AVI, WebM) — the file format that holds video, audio, and metadata
- Video codec (H.264, H.265, VP9, AV1) — how video data is compressed
- Audio codec (AAC, Opus, MP3, FLAC) — how audio data is compressed
A container is like a box; codecs are what's inside. The same video codec can live in different containers.
| Container | Common Video Codecs | Common Audio Codecs | Best For |
|---|---|---|---|
| MP4 | H.264, H.265, AV1 | AAC, MP3 | Web, mobile, general use |
| MKV | Any | Any | Archiving, multi-track media |
| MOV | H.264, H.265, ProRes | AAC, PCM | Apple ecosystem, editing |
| WebM | VP8, VP9, AV1 | Vorbis, Opus | Web (open-source) |
| AVI | H.264, MPEG-4 | MP3, PCM | Legacy compatibility |
Codec Selection Guide
H.264 — Maximum Compatibility
H.264 (libx264) plays on virtually every device and browser. It's the safest choice for general distribution.
ffmpeg -i input.avi -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output.mp4H.265 (HEVC) — Better Compression
H.265 (libx265) delivers ~50% smaller files at the same quality. Support is growing but not yet universal.
ffmpeg -i input.avi -c:v libx265 -crf 28 -preset medium -c:a aac -b:a 128k output.mp4Note: H.265 uses a different CRF scale. CRF 28 in H.265 is roughly equivalent to CRF 23 in H.264.
VP9 — Open-Source, Web-Friendly
VP9 is Google's royalty-free codec. It pairs with WebM and is supported by all modern browsers.
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus -b:a 128k output.webmThe -b:v 0 tells FFmpeg to use pure CRF mode (no bitrate ceiling).
AV1 — Next Generation
AV1 offers the best compression ratio but encoding is very slow. Use it when you have time and want the smallest files.
ffmpeg -i input.mp4 -c:v libaom-av1 -crf 30 -cpu-used 4 -c:a libopus -b:a 128k output.mkv-cpu-used 4 speeds up encoding significantly (range 0-8, higher = faster but lower quality).
Codec Comparison
| Codec | Compression | Speed | Browser Support | License |
|---|---|---|---|---|
| H.264 | Good | Fast | Universal | Licensed |
| H.265 | Better | Medium | Growing | Licensed |
| VP9 | Better | Slow | All modern | Royalty-free |
| AV1 | Best | Very slow | Growing | Royalty-free |
Audio Codec Pairing
Each container works best with certain audio codecs:
# MP4 + AAC (most common pairing)
ffmpeg -i input.mkv -c:v libx264 -crf 23 -c:a aac -b:a 192k output.mp4
# WebM + Opus (best quality per bitrate)
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus -b:a 128k output.webm
# MKV + FLAC (lossless audio)
ffmpeg -i input.mov -c:v libx264 -crf 18 -c:a flac output.mkv
# MOV + PCM (uncompressed, for editing)
ffmpeg -i input.mp4 -c:v copy -c:a pcm_s16le output.mov| Audio Codec | Quality | File Size | Best Container |
|---|---|---|---|
| AAC | Good | Small | MP4, MOV |
| Opus | Excellent | Smallest | WebM, MKV |
| MP3 | Good | Small | MP4, AVI, MKV |
| FLAC | Lossless | Large | MKV |
| PCM | Lossless | Very large | MOV, WAV |
Stream Copy — Instant Conversion
When the source codecs are compatible with the target container, you can copy streams without re-encoding. This is instant and lossless:
# Remux MKV to MP4 without re-encoding
ffmpeg -i input.mkv -c copy output.mp4
# Copy video, re-encode audio only
ffmpeg -i input.mkv -c:v copy -c:a aac -b:a 128k output.mp4Stream copy only works when the codecs are supported by the target container. For example, you can't put VP9 video into an AVI container.
Quality vs File Size
CRF Mode — Best for Local Files
CRF (Constant Rate Factor) gives the best quality-to-size ratio. The encoder adjusts bitrate scene by scene. For a deeper dive into compression techniques, see our video compression guide.
# High quality (larger file)
ffmpeg -i input.avi -c:v libx264 -crf 18 -c:a aac -b:a 192k output.mp4
# Balanced quality
ffmpeg -i input.avi -c:v libx264 -crf 23 -c:a aac -b:a 128k output.mp4
# Smaller file (lower quality)
ffmpeg -i input.avi -c:v libx264 -crf 28 -c:a aac -b:a 96k output.mp4Two-Pass Encoding — Best for Target File Size
When you need a specific file size, use two-pass encoding:
# Pass 1: analyze
ffmpeg -i input.avi -c:v libx264 -b:v 2M -pass 1 -an -f null /dev/null
# Pass 2: encode
ffmpeg -i input.avi -c:v libx264 -b:v 2M -pass 2 -c:a aac -b:a 128k output.mp4Presets — Speed vs Compression
Slower presets produce smaller files at the same quality:
# Fast encoding, larger file
ffmpeg -i input.avi -c:v libx264 -crf 23 -preset fast -c:a aac output.mp4
# Slow encoding, smaller file
ffmpeg -i input.avi -c:v libx264 -crf 23 -preset slow -c:a aac output.mp4Converting with Resolution Changes
Combine format conversion with scaling:
# Convert to 720p MP4
ffmpeg -i input.mkv -c:v libx264 -crf 23 -vf "scale=-2:720" -c:a aac -b:a 128k output.mp4
# Convert to 1080p WebM
ffmpeg -i input.avi -c:v libvpx-vp9 -crf 30 -b:v 0 -vf "scale=-2:1080" -c:a libopus output.webmBatch Conversion Scripts
Convert All Files in a Directory
# Convert all AVI files to MP4
for f in *.avi; do
ffmpeg -i "$f" -c:v libx264 -crf 23 -c:a aac -b:a 128k "${f%.avi}.mp4"
done
# Convert all MKV files to MP4 (stream copy if possible)
for f in *.mkv; do
ffmpeg -i "$f" -c copy "${f%.mkv}.mp4"
doneConvert with Custom Quality per Format
#!/bin/bash
# Batch convert to multiple formats
INPUT="input.mp4"
# Web-optimized MP4
ffmpeg -i "$INPUT" -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k -movflags +faststart web.mp4
# High-quality MKV archive
ffmpeg -i "$INPUT" -c:v libx265 -crf 22 -preset slow -c:a flac archive.mkv
# WebM for open-source hosting
ffmpeg -i "$INPUT" -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus -b:a 128k web.webmRecursive Conversion
# Find and convert all AVI files recursively
find . -name "*.avi" -exec sh -c '
ffmpeg -i "$1" -c:v libx264 -crf 23 -c:a aac "${1%.avi}.mp4"
' _ {} \;Web Optimization — faststart
For MP4 files served on the web, always add -movflags +faststart. This moves metadata to the beginning of the file so playback can start before the full download completes:
ffmpeg -i input.mkv -c:v libx264 -crf 23 -c:a aac -movflags +faststart output.mp4Common Conversion Recipes
Here are ready-to-use commands for the most frequent conversions:
# MOV (iPhone) to MP4 for sharing
ffmpeg -i input.mov -c:v libx264 -crf 23 -c:a aac -b:a 128k -movflags +faststart output.mp4
# AVI to MP4 (re-encode)
ffmpeg -i input.avi -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output.mp4
# MP4 to WebM for web embedding
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus -b:a 128k output.webm
# MKV to MP4 (lossless remux)
ffmpeg -i input.mkv -c copy -movflags +faststart output.mp4
# Any format to GIF (short clip)
ffmpeg -i input.mp4 -vf "fps=10,scale=320:-1" -t 5 output.gif
# MP4 to HLS for streaming
ffmpeg -i input.mp4 -c copy -hls_time 10 -hls_list_size 0 output.m3u8Troubleshooting
"Discarding packet" warnings — The source container has compatibility issues. Add -err_detect ignore_err to skip corrupt packets.
"Non-monotonous DTS" errors — Timestamp issues in the source. Fix with:
ffmpeg -i input.mkv -fflags +genpts -c:v libx264 -crf 23 -c:a aac output.mp4Codec not supported in container — You're trying to put an incompatible codec in a container (e.g., VP9 in AVI). Either change the container or re-encode with a compatible codec.
Output file is larger than input — This happens when converting from a more efficient codec to a less efficient one, or when the source was heavily compressed. Try lowering the CRF value or using a more efficient codec.
Cloud Alternative with FFHub
Converting video formats locally works fine for one-off tasks, but batch conversions can tie up your machine for hours. FFHub lets you run FFmpeg commands in the cloud via API — same FFmpeg syntax, no local CPU usage.
This is especially useful when you need to convert large batches of files, integrate format conversion into a web application, or process videos on machines without FFmpeg installed.
Summary
- Use stream copy (
-c copy) when codecs are compatible — it's instant - Choose H.264 + AAC in MP4 for maximum compatibility
- Choose VP9 + Opus in WebM for web-focused, royalty-free delivery
- Use CRF mode for quality-focused encoding
- Add
-movflags +faststartfor web-served MP4 files - Use batch scripts to convert entire directories at once
Related Articles
- How to Compress Video with FFmpeg - Reduce file size with CRF, presets, and resolution scaling
- How to Extract Audio from Video with FFmpeg - Pull audio tracks from any video format
- FFmpeg Video Compression Best Practices - Advanced encoding strategies for optimal quality and size

