Taking the command with you
The command panel on every tool is not decoration. It is the same program, and once you can read it, a folder of five hundred files is one line away.
The tools on this site run FFmpeg, compiled to WebAssembly, inside your browser. That is convenient and private, but a browser tab has a ceiling: one thread, a memory limit, one file at a time. FFmpeg installed on your own machine has none of those. Every tool page shows the exact command it is about to run so that when you hit the ceiling, you can take the command with you. This guide is about reading it and using it.
Installing
On macOS with Homebrew: brew install ffmpeg. On Windows with winget: winget install ffmpeg, or download a build from the links on ffmpeg.org and put the folder on your PATH. On Debian or Ubuntu: sudo apt install ffmpeg. Afterwards, ffmpeg -version in a terminal should print a version and a long list of configuration flags. You will also have ffprobe, which reads files without changing them and is the terminal equivalent of the media info tool.
Reading a command
Take the line the compress tool produces at its defaults:
ffmpeg -i input.mov -vf scale=-2:720 -c:v libx264 -preset veryfast -crf 28 -pix_fmt yuv420p -c:a aac -b:a 96k -movflags +faststart output.mp4
The structure is always the same: options, then an input, then options that apply to the output, then the output. Reading left to right:
| Piece | Meaning |
|---|---|
-i input.mov | The input file. You can have several, each with its own -i. |
-vf scale=-2:720 | A video filter: scale to 720 pixels tall, width calculated and rounded to even. |
-c:v libx264 | The video codec. c is codec, :v means video. -c:v copy would mean do not re-encode. |
-preset veryfast -crf 28 | Encoder settings, explained in the compression guide. |
-pix_fmt yuv420p | The colour format every player understands. |
-c:a aac -b:a 96k | Audio codec and bitrate. -an would drop the audio entirely. |
-movflags +faststart | Put the index at the front so the file streams. |
output.mp4 | The output. FFmpeg picks the container from the extension. |
Once you can read one, you can read all of them, because every tool here is a variation: a different filter, a different codec, -ss and -to for a time range, -map to pick a stream. Open a few tools and watch the command change as you move the controls; that is the fastest way to learn the vocabulary.
Running it on a folder
This is the reason to leave the browser. The command is the same; the shell loops over the files.
In bash or zsh (macOS, Linux, Git Bash on Windows):
for f in *.mov; do
ffmpeg -i "$f" -vf scale=-2:720 -c:v libx264 -preset veryfast -crf 28 -pix_fmt yuv420p -c:a aac -b:a 96k -movflags +faststart "${f%.mov}.mp4"
done
In PowerShell:
Get-ChildItem *.mov | ForEach-Object {
ffmpeg -i $_.FullName -vf scale=-2:720 -c:v libx264 -preset veryfast -crf 28 -pix_fmt yuv420p -c:a aac -b:a 96k -movflags +faststart "$($_.BaseName).mp4"
}
Two habits keep this safe. Always write to a different name or a different folder than the input, because FFmpeg will happily overwrite a source if you tell it to and there is no undo. And run it on two files before running it on two hundred; the cost of a wrong setting scales with the batch.
Things the browser cannot do that the terminal can
- Threads. The browser build is single-threaded. Native FFmpeg uses every core. A file that takes ten minutes here takes one on a laptop.
- Hardware encoding.
-c:v h264_videotoolboxon a Mac,h264_nvencon an Nvidia card,h264_qsvon Intel,h264_amfon AMD. Several times faster again, at a small cost in quality per megabyte, which is fine for anything that is not archival. - VP9 and AV1. The VP9 encoder crashes in the WebAssembly build, so WebM output here is VP8. Natively,
-c:v libvpx-vp9and-c:v libsvtav1work and produce much smaller files. - Files larger than memory. The browser holds the input and the output in RAM. The terminal streams from disk and does not care.
- URLs as input.
-i https://example.com/file.mp4works natively, and so does reading from a camera or a capture device.
The errors you will meet first
- "width not divisible by 2" or "height not divisible by 2"
- You scaled to an odd dimension. Use
-2for the computed side, as the tools here do, or pick even numbers. - "Could not find tag for codec ... in stream"
- You asked for a container that cannot hold the stream you are copying. Either re-encode that stream or choose a different container. Containers and codecs has the table.
- "Output file is empty, nothing was encoded"
- Usually a time range that does not overlap the file:
-sspast the end, or-tobefore-ss. - "No such filter"
- Your build was compiled without that filter. Rare with the packaged builds above, common with minimal ones.
ffmpeg -filterslists what you have. - "Unknown encoder 'libx264'"
- A build without the x264 library. The Homebrew, winget and Ubuntu builds all include it; some Docker images do not.
- It runs but the colours are wrong or the file will not play on a phone
- You forgot
-pix_fmt yuv420p. Without it, a PNG-sourced or screen-recorded input can produce a colour format many players reject.
Two more commands worth knowing
ffprobe -hide_banner file.mp4 prints the streams, codecs, resolution, frame rate, duration and bitrate of a file. Add -show_format -show_streams for every field it knows, or -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 to get just the two numbers you want for a script.
ffmpeg -f concat -safe 0 -i list.txt -c copy joined.mp4 joins files without re-encoding, where list.txt contains one line per file in the form file 'part1.mp4'. It only works when the parts were encoded identically, which is exactly the constraint the merge tool has and explains why it re-encodes when they were not.
When to come back
The terminal is better for batches, for big files and for speed. The browser is better when you want to see the command assembled as you change things, when the file is something you do not want to install software for, and when you are on a machine that is not yours. They are the same FFmpeg. Use whichever is nearer.