FFmpeg Commands Cheat Sheet: Every Flag Explained
By Mark Fulton · 2026-09-28 · 13 min read

Most useful FFmpeg commands are one input, a handful of flags that each make one trade, and an output: -c:v libx264 -crf 23 trades file size for quality, -preset trades encoding time for compression, -c copy trades cut accuracy for speed and zero quality loss, and -ss placed before -i trades nothing at all when you re-encode. Below is every command the tools on this site actually run, copied from the source code, with each flag decoded and a link to the page that runs it without a terminal.
Every VidClip tool is FFmpeg compiled to WebAssembly, running in your browser tab with a fixed recipe. That means the commands on this page are not examples someone typed into a blog once. They are the exact argument lists that produce real files every day, so you can paste them into a terminal and get the same result.
Two honest notes before the commands. First, free exports on this site add a small corner watermark through an extra -i wm.png input and an overlay filter; I have left that part out of every command below, so what you see is the clean recipe. Second, inside the browser the input is always called in.<ext> and the output out.mp4, because the files live in a virtual file system. Swap in your own file names.
What does an FFmpeg command actually consist of?
Every command has the same skeleton: ffmpeg [input options] -i input [output options] output. The rule that trips everyone up comes straight from the official ffmpeg documentation: options apply to the next file named on the line, so order matters. -ss 10 before -i seeks in the input. -ss 10 after -i tells the output to throw frames away until it reaches ten seconds. Same flag, different job.
Here are the four building blocks that appear in almost every command below:
| Block | Flags | What it does | What it costs |
|---|---|---|---|
| Video encoder | -c:v libx264 -preset veryfast -pix_fmt yuv420p |
Encodes H.264, the codec nearly every player accepts | Encoding time, and one generation of quality loss |
| Quality target | -crf 21 (or 22, 23, 28, 32) |
Holds visual quality roughly constant and lets size float | You cannot predict the final size |
| Audio encoder | -c:a aac -b:a 128k |
AAC at 128 kbps, the MP4 default everywhere | About 1 MB per minute of audio |
| Web layout | -movflags +faststart |
Moves the MP4 index to the front so playback starts before download finishes | A second pass over the file when writing |
The -pix_fmt yuv420p part is there for compatibility. The FFmpeg H.264 encoding guide notes that QuickTime and most other players only support 4:2:0 chroma subsampling for H.264, and that depending on your source FFmpeg might otherwise pick a pixel format those players reject. A screen recording in 4:4:4 is the classic case: it plays fine in VLC and shows a black box in QuickTime.
Which flags control quality and which control speed?
This is the split that matters most, and the one that bare cheat sheets skip.
CRF controls quality. For 8-bit x264 the scale runs 0 to 51, where 23 is the default, lower is better, and 17 or 18 is treated as visually lossless or close to it. The scale is exponential: the H.264 guide says raising CRF by 6 roughly halves the bitrate and file size, and lowering it by 6 roughly doubles it. I go through what that means for real clip sizes in video compression by the numbers.
Preset controls speed. Presets run from ultrafast to veryslow (plus placebo, which the guide tells you to ignore), with medium as the default. A slower preset searches harder, so at the same CRF it produces a smaller file, and at the same bitrate it produces a better-looking one. It never changes the quality target itself.
VidClip runs veryfast on purpose. The encoder here is single-threaded WebAssembly on your own laptop, so encoding time is the binding constraint. In a terminal with a real multi-core build, medium or slow is usually the better default.
Compress: the command behind /compress-video
ffmpeg -i in.mp4 -c:v libx264 -preset veryfast -pix_fmt yuv420p -crf 28 -c:a aac -b:a 128k -movflags +faststart out.mp4
| Flag | Meaning | The trade |
|---|---|---|
-crf 28 |
The "medium" setting; "high" is 23, "small" is 32 | Each step of 6 roughly halves or doubles size |
-preset veryfast |
Fast motion search | Bigger file than slow at the same CRF |
-b:a 128k |
Audio re-encoded at a fixed rate | Audio stops shrinking below this point |
Run it on the page: compress a video in your browser.
Compress to a target size: the Pro variant
CRF cannot aim at a number of megabytes, so the Pro exact-size mode switches to a bitrate. The code takes your target in bytes, multiplies by 8, keeps 97% as a margin for container overhead, divides by the clip length and subtracts 128 kbps for audio. For a 60-second clip with a 10,000,000-byte budget, that works out to 1,165 kbps of video:
ffmpeg -i in.mp4 -c:v libx264 -preset veryfast -pix_fmt yuv420p -b:v 1165k -maxrate 1689k -bufsize 2330k -c:a aac -b:a 128k -movflags +faststart out.mp4
-maxrate is set to 1.45 times the target and -bufsize to twice it, which lets complex scenes borrow bits without letting the average drift. If the budget works out below 100 kbps of video, the tool refuses rather than shipping a smear. The full method, including why two-pass encoding exists, is in compress a video to an exact file size.
Convert: the command behind /convert-to-mp4
ffmpeg -i in.mov -c:v libx264 -preset veryfast -pix_fmt yuv420p -crf 21 -c:a aac -b:a 128k -movflags +faststart out.mp4
Same recipe with CRF 21, a little under the default, because a conversion should look like the original rather than a compressed copy of it. Run it: convert any video to MP4.
How do you cut or mute without re-encoding?
With -c copy. The ffmpeg documentation describes stream copy as passing packets through without decoding or encoding, which makes it very fast with no quality loss. The catch is where the cut lands.
Trim: two commands behind /trim-video
The lossless version, which is a Pro feature because a copied stream cannot carry a watermark:
ffmpeg -ss 12.000 -i in.mp4 -t 8.000 -c copy -movflags +faststart out.mp4
The frame-accurate version, which is what the free tier runs:
ffmpeg -ss 12.000 -i in.mp4 -t 8.000 -c:v libx264 -preset veryfast -pix_fmt yuv420p -crf 21 -c:a aac -b:a 128k -movflags +faststart out.mp4
| Flag | Meaning | The trade |
|---|---|---|
-ss 12.000 before -i |
Input seeking: jump to the nearest seek point before 12 s | Fast, because nothing before it is decoded |
-t 8.000 |
Keep 8 seconds | It is a duration, not an end time |
-c copy |
Copy packets untouched | The clip starts on a keyframe, not your exact second |
-crf 21 |
Re-encode near the source quality | Real encoding time, one generation of loss |
Why the two behave differently comes down to one sentence in the ffmpeg docs: when transcoding with accurate seeking on (the default), the stretch between the seek point and your requested time is decoded and discarded; with stream copy it is kept. So the re-encode lands on the exact frame and the copy starts at the keyframe before it. The FFmpeg wiki's Seeking page adds a detail worth knowing: when -ss sits before -i, timestamps reset to zero, which is why -t 8 here means eight seconds of output. I walk through keyframes in detail in lossless video trimming and keyframes.
Run it: trim a video without uploading it.
Mute: the command behind /mute-video
The Pro version copies the video and drops audio:
ffmpeg -i in.mp4 -c:v copy -an out.mp4
-an disables audio output entirely. The Pro tool keeps the original container if it is MP4, MOV, WebM or MKV. The free version re-encodes video at -crf 21 with -an so the watermark can be drawn, which means it takes longer and costs one generation of quality. Run it: mute a video.
Extract audio: the command behind /video-to-mp3
ffmpeg -i in.mp4 -vn -c:a libmp3lame -b:a 192k out.mp3
-vn is the mirror of -an: it drops video. libmp3lame is the MP3 encoder, and the tool offers 128k, 192k and 320k. The audio is re-encoded, so a 320k MP3 made from 128k AAC is not better than its source, only bigger. Audio has nowhere to show a watermark, so this one is clean on the free tier. Run it: convert video to MP3, and see extracting audio from video for when to keep the original track instead.
What command makes a GIF that doesn't band?
A GIF can only hold 256 colours per frame. Map every frame to a generic palette and you get banding and grain. The fix is to build the palette from the clip itself, in the same command:
ffmpeg -i in.mp4 -filter_complex "[0:v]fps=12,scale=480:-2:flags=lanczos,split[a][b];[a]palettegen=stats_mode=diff[p];[b][p]paletteuse=dither=bayer:bayer_scale=4" -loop 0 out.gif
| Piece | Meaning | The trade |
|---|---|---|
fps=12 |
Keep 12 frames per second (tool range 5 to 24) | Fewer frames, smaller file, less smooth |
scale=480:-2:flags=lanczos |
480 px wide, height kept in proportion and even | Lanczos resampling keeps edges crisp when shrinking; it is not the default scaler |
split[a][b] |
Two copies of the stream: one to analyse, one to draw | None, it just avoids a second pass over the file |
palettegen=stats_mode=diff |
Build a palette weighted toward what moves | Static backgrounds get fewer palette entries |
paletteuse=dither=bayer:bayer_scale=4 |
Ordered dithering with a subtle pattern | Less visible crosshatch, slightly more banding than scale 2 |
-loop 0 |
Loop forever | None |
Each part checks out against the palettegen and paletteuse filter documentation: diff computes histograms only for the part that differs from the previous frame, which helps when the background is static, and bayer_scale runs 0 to 5 with a default of 2, where a higher value hides the pattern at the cost of more banding. I measured what each palette and dither choice does to real clips in making a high-quality GIF from video.
Run it: make a GIF in your browser.
How do you change speed without chipmunk audio?
Video and audio need separate filters. setpts rewrites the video timestamps; atempo changes the audio tempo without resampling it, so voices keep their pitch. Here is the 2x command behind the speed tool:
ffmpeg -i in.mp4 -filter_complex "[0:v]setpts=PTS/2[v]" -map "[v]" -map "0:a?" -filter:a atempo=2 -c:v libx264 -preset veryfast -pix_fmt yuv420p -crf 21 -c:a aac -b:a 128k -movflags +faststart out.mp4
And at 4x and a quarter speed, the audio filter becomes a chain:
-filter:a atempo=2,atempo=2
-filter:a atempo=0.5,atempo=0.5
| Flag | Meaning | The trade |
|---|---|---|
setpts=PTS/2 |
Halve every frame's timestamp, so video plays twice as fast | Audio is untouched; it needs its own filter |
-map "0:a?" |
Take the audio if there is one | The trailing ? stops silent clips from failing |
atempo=2 |
Double the audio tempo | Above 2 in one stage, samples get skipped |
Two details make this work. The ? on -map 0:a? is documented behaviour: a map with a trailing question mark is ignored if it matches no streams. Before that was added, a screen recording with no audio track failed outright. And atempo has a floor of 0.5 per stage; the current filter documentation allows up to 100, but says anything above 2 skips samples rather than blending them and suggests chaining instead. The tool keeps every stage between 0.5 and 2, so 4x is two doublings and 0.25x is two halvings. More on speed ramps in speeding up or slowing down video.
Run it: change video speed.
What about crop, rotate, resize and still frames?
All four are one video filter on top of the standard encode (-c:v libx264 -preset veryfast -pix_fmt yuv420p, AAC audio, faststart).
Crop to 9:16 from a 1920x1080 source:
ffmpeg -i in.mp4 -vf crop=608:1080:656:0 -c:v libx264 -preset veryfast -pix_fmt yuv420p -crf 21 -c:a aac -b:a 128k -movflags +faststart out.mp4
crop=w:h:x:y. The tool computes the largest box of your chosen ratio (9:16, 4:5, 1:1 or 16:9), centres it, and forces width, height and both offsets to even numbers, because yuv420p stores colour at half resolution and an odd offset puts the colour plane half a sample out. Run it: crop a video.
Rotate 90 degrees clockwise:
ffmpeg -i in.mp4 -vf transpose=1 -c:v libx264 -preset veryfast -pix_fmt yuv420p -crf 21 -c:a aac -b:a 128k -movflags +faststart out.mp4
transpose=1 is clockwise, transpose=2 counterclockwise, transpose=1,transpose=1 is 180 degrees, and hflip or vflip mirror the frame. Avoid transpose=0: it rotates counterclockwise and also flips. Run it: rotate a video, and see fixing a sideways video for when the problem is only a metadata flag.
Resize to 720 tall:
ffmpeg -i in.mp4 -vf scale=-2:720 -c:v libx264 -preset veryfast -pix_fmt yuv420p -crf 22 -c:a aac -b:a 128k -movflags +faststart out.mp4
-2 means "work out the width from the aspect ratio, then round to an even number". Plain -1 keeps the ratio but can produce an odd width that H.264 in 4:2:0 refuses. The tool offers 480, 720 and 1080 and only downscales. Run it: resize a video, and read crop vs resize if you are not sure which one you need.
Grab a still frame at five seconds:
ffmpeg -ss 5.000 -i in.mp4 -frames:v 1 -q:v 2 out.png
-frames:v 1 stops after one frame. -q:v is a fixed quality scale whose meaning depends on the encoder, so it matters for JPEG and very little for PNG, which is lossless. The Pro contact sheet swaps in -vf fps=1/N,scale=320:-2,tile=4x3 to sample twelve frames across the clip into one image. Run it: save a frame from a video.
When is a terminal the better tool than a web page?
When the job is not one file with a fixed recipe. A terminal wins for batch work over a folder, for files larger than browser memory comfortably holds, for multi-threaded encodes with a slow preset, and for anything these tools do not do: joining clips, burning subtitles, HDR, or two-pass encoding. For reference, this is the standard two-pass command from the H.264 guide. It is not something a VidClip tool runs:
ffmpeg -i input -c:v libx264 -b:v 1M -maxrate 1M -bufsize 2M -pass 1 -f mp4 /dev/null
ffmpeg -i input -c:v libx264 -b:v 1M -maxrate 1M -bufsize 2M -pass 2 output.mp4
On Windows, replace /dev/null with NUL.
One more terminal-only gotcha: shell quoting. The tools here pass arguments as a list, so nothing needs escaping. In a shell, any filtergraph containing ; or [ ] must be wrapped in quotes, and zsh treats the ? in 0:a? as a wildcard unless you quote it. Every command above is quoted to paste cleanly into bash or zsh.
For a single clip on a machine where you cannot or would rather not install anything, a browser tab with the flags already chosen is the faster route. The full list is on the tools page.
Frequently asked questions
What is the most useful FFmpeg command?
The re-encode to H.264 MP4: ffmpeg -i in.mov -c:v libx264 -crf 21 -pix_fmt yuv420p -c:a aac -b:a 128k -movflags +faststart out.mp4. It fixes the most common problem people have with video, which is a file that will not play or upload somewhere, and changing the CRF turns it into a compressor.
What does -c copy do?
It copies the compressed streams into the new file without decoding or encoding them. That makes it nearly instant and lossless, but it cannot apply filters, cannot change the codec, and cuts can only start on a keyframe. Use it to trim, remux or drop a track; re-encode for anything else.
Why does -ss go before -i?
Placed before -i, it seeks the input directly to the nearest seek point, so FFmpeg does not decode everything before your start time. When you re-encode, FFmpeg then decodes and discards the gap, so the cut is still exact. Placed after -i, it decodes the whole file up to that point and throws it away, which gives the same frame but takes much longer on a long clip.
Can FFmpeg run in a browser?
Yes. FFmpeg compiles to WebAssembly, and every tool on this site is that build running on your own CPU, with the file held in browser memory and nothing uploaded. It is slower than a native multi-threaded install, which is why the recipes here use the veryfast preset, but for a single file it needs no install at all.
Every command on this page also runs as a tool on this site, no terminal needed. Start with the compressor or browse all the tools.
Sources
- FFmpeg project, ffmpeg command-line documentation
- FFmpeg project, palettegen, paletteuse, atempo and other filter documentation
- FFmpeg wiki, H.264 encoding guide