TechEarl

The ffmpeg Command Cheat Sheet

A scannable ffmpeg reference: convert containers, stream-copy without re-encoding, trim and cut, resize and crop, extract or replace audio, high-quality GIFs with palettegen, x264/x265/AV1 quality with -crf and -preset, change speed, concat, subtitles, and the fixes for the errors you actually hit.

Ishan Karunaratne⏱️ 12 min readUpdated
Share thisCopied
ffmpeg cheat sheet: -c copy stream copy, -ss/-to/-t trim, scale and crop filters, -vn audio extract, palettegen/paletteuse for high-quality GIFs, libx264/libx265/libsvtav1 with -crf and -preset, setpts and atempo speed, concat demuxer, subtitles, and common-error fixes.

ffmpeg does almost anything to a media file from one command line: convert a container, cut a clip, resize, strip or swap the audio, build a GIF, re-encode at a target quality. The flag surface is enormous and the documentation is a wall, so this page is the reference I actually keep open: the canonical 2026 command for each common task, grouped by what you are trying to do, with a one-line "why" on each. Every command below uses the current spellings, not the legacy aliases that still float around old blog posts.

Unlike a website-based downloader, ffmpeg is its own tool: free, open source, no account, and it runs entirely on your machine. There is nothing to agree to and nothing to upload. What you do with the output file is between you and the rights holder of the source.

The modern syntax in one minute

Old ffmpeg tutorials are full of -vcodec, -acodec, -ab, and -vframes. Those still work as aliases, but they are the legacy form and they make examples harder to read. The current spellings, and the few knobs that matter, are short enough to learn in a minute:

  • -c:v and -c:a set the codecs, not -vcodec / -acodec. So -c:v libx264 -c:a aac. Bitrate is -b:a 192k (audio) or -b:v 2M (video), and -frames:v 1 grabs a single frame, not -vframes 1.
  • -c copy is stream copy: remux with no re-encode. It is instant and lossless because the audio and video bytes are passed through untouched. Reach for it any time you are only changing the container or cutting on keyframes. The opposite is a re-encode, which is slow but lets you change codec, quality, resolution, or do frame-accurate cuts.
  • -crf is the quality knob for libx264 and libx265 (constant rate factor: lower is better quality and a bigger file). For x264 the sane range is 18 to 28, default 23; x265 defaults to 28; the AV1 encoder libsvtav1 uses a wider 0 to 63 scale (its own default is 35, but a CRF around 30 is a common starting point). -preset trades encode speed for compression efficiency (ultrafast to veryslow on x264/x265; a numeric -preset 6 style on SVT-AV1): a slower preset gives a smaller file at the same quality, not better quality.
  • -y overwrites the output without asking, -n never overwrites. -hide_banner drops the version preamble so the useful output is not buried. Put input options like -ss before -i, and output options after the last -i. That ordering is not cosmetic: ffmpeg applies options to the next file on the command line, so where they sit changes what they do.

That is the whole mental model. The cheat sheet below is those rules applied to each task.

Jump to: Basics | Trim and cut | Resize and crop | Audio | Video to GIF | Codecs and quality | Speed | Concat and merge | Subtitles | Common fixes

ffmpeg Cheat Sheet

The canonical 2026 command for each common task. -c copy means no re-encode (instant, lossless); -crf is the quality knob for x264/x265/AV1.

Basics

ffprobe -hide_banner in.mp4Show streams, codecs, duration, and resolution of a file.
ffprobe -v error -show_entries format=duration -of csv=p=0 in.mp4Print just the duration in seconds, script-friendly.
ffmpeg -i in.mov out.mp4Convert container (re-encodes with sane defaults).
ffmpeg -i in.mkv -c copy out.mp4Remux MKV to MP4 with no re-encode: instant, lossless, if codecs are MP4-compatible.
ffmpeg -y -hide_banner -i in.mp4 out.mp4-y overwrites without prompting; -hide_banner trims the version preamble.

Trim & cut

ffmpeg -ss 00:00:05 -t 12 -i in.mp4 -c copy out.mp4Fast lossless cut: seek 5s in, take 12s, copy streams. Cuts land on keyframes.
ffmpeg -ss 00:00:05 -to 00:00:17 -i in.mp4 -c copy out.mp4Cut to an absolute end timestamp instead of a duration.
ffmpeg -i in.mp4 -ss 00:00:05 -t 12 -c:v libx264 -crf 18 out.mp4Frame-accurate cut: -ss after -i and a re-encode (slower, no keyframe rounding).

Resize & crop

ffmpeg -i in.mp4 -vf scale=1280:-2 out.mp4Scale to 1280px wide, height auto (-2 keeps it even, required by most codecs).
ffmpeg -i in.mp4 -vf scale=-2:720 out.mp4Scale to 720px tall, width auto.
ffmpeg -i in.mp4 -vf crop=500:500:0:0 -c:a copy out.mp4crop=w:h:x:y. Top-left 500x500 box; copy audio so it is untouched.
ffmpeg -i in.mp4 -vf crop=in_w:in_w*9/16 out.mp4Center-crop to 16:9 using input dimensions; omitting x:y auto-centers.

Audio

ffmpeg -i in.mp4 -vn -c:a copy out.m4aExtract audio with no re-encode (works when the codec fits the container, e.g. AAC to .m4a).
ffmpeg -i in.mp4 -vn -c:a libmp3lame -q:a 2 out.mp3Extract and re-encode to MP3. -q:a 2 is VBR ~190 kbps, a better default than fixed CBR.
ffmpeg -i in.mp4 -c:v copy -an out.mp4Remove audio: -an drops it, -c:v copy keeps video untouched. Instant.
ffmpeg -i video.mp4 -i audio.m4a -c:v copy -c:a copy -map 0:v:0 -map 1:a:0 -shortest out.mp4Replace/add an audio track by muxing; -shortest stops at the shorter input.

Video to GIF

ffmpeg -i in.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" out.gifHigh-quality GIF in one pass: build an optimal 256-color palette, then map frames to it.
ffmpeg -ss 2 -t 3 -i in.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" clip.gifSame, but trim to a 3-second clip first (fast seek with -ss before -i).

Codecs & quality

ffmpeg -i in.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 192k out.mp4H.264, the universal default. -crf 23 is the baseline; lower for better quality.
ffmpeg -i in.mp4 -c:v libx265 -crf 28 -preset medium -c:a aac -b:a 192k out.mp4HEVC/H.265: ~half the size of x264 at the same quality, slower to encode.
ffmpeg -i in.mp4 -c:v libsvtav1 -crf 30 -preset 6 -c:a libopus -b:a 128k out.mp4AV1 via SVT-AV1: best compression, free codec. -preset is numeric (lower = slower/smaller).

Speed

ffmpeg -i in.mp4 -filter:v "setpts=0.5*PTS" -an out.mp42x faster, video only. setpts scales timestamps: smaller multiplier = faster.
ffmpeg -i in.mp4 -filter:v "setpts=2.0*PTS" -an out.mp4Half speed (slow motion), video only.
ffmpeg -i in.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" out.mp42x with audio in sync. atempo accepts 0.5 to 100.0, but above 2.0 it skips samples, so chain it (atempo=2.0,atempo=2.0) for clean 4x.

Concat & merge

ffmpeg -f concat -safe 0 -i list.txt -c copy out.mp4Join files with identical codecs, no re-encode. list.txt holds: file 'a.mp4' lines.
ffmpeg -i a.mp4 -i b.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]" -map "[v]" -map "[a]" out.mp4Join files with differing codecs/resolutions; re-encodes via the concat filter.

Subtitles

ffmpeg -i in.mp4 -i subs.srt -c copy -c:s mov_text out.mp4Soft subtitles: a selectable track the player can toggle on or off.
ffmpeg -i in.mp4 -vf subtitles=subs.srt out.mp4Hard subtitles (burned in): re-encodes the video with text painted on every frame.

Common fixes

ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4Move the MP4 moov atom to the front so it streams/seeks before fully downloaded.
ffmpeg -i in.mp4 -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" out.mp4Fix 'height not divisible by 2' encode errors by forcing even dimensions.
ffmpeg -i in.mp4 -vf "transpose=1" out.mp4Rotate 90 degrees clockwise (transpose=2 for counter-clockwise).

The rest of this page is the detail behind the rows: the gotchas that turn a command that "runs" into one that does what you meant.

Basics

Before transforming a file, look at it. ffprobe reports the streams, codecs, resolution, and duration:

bash
ffprobe -hide_banner in.mp4

That tells you whether -c copy is even an option (you cannot stream-copy a codec the target container does not support) and what the audio and video tracks actually are. For a single value in a script, ask for one field:

bash
ffprobe -v error -show_entries format=duration -of csv=p=0 in.mp4

A plain container change re-encodes by default. If the existing codecs already fit the target container, skip the re-encode entirely with -c copy. Remuxing an MKV to MP4 this way takes a second and loses nothing:

bash
ffmpeg -i in.mkv -c copy out.mp4

Trim and cut

There are two ways to cut, and the difference is the single most common ffmpeg confusion. With -ss before -i and -c copy, the cut is fast and lossless but lands on the nearest keyframe, so the start can be a fraction of a second early or late:

bash
ffmpeg -ss 00:00:05 -t 12 -i in.mp4 -c copy out.mp4

Use -t for a duration or -to for an absolute end timestamp. When you need a frame-accurate cut, drop -c copy, move -ss after -i, and let ffmpeg re-encode:

bash
ffmpeg -i in.mp4 -ss 00:00:05 -t 12 -c:v libx264 -crf 18 out.mp4

It is slower, but the cut lands exactly where you asked. For the full treatment of keyframe alignment and splitting one file into segments, see trim and cut a video with ffmpeg.

Resize and crop

Scaling takes a scale filter. Set one dimension and use -2 for the other so ffmpeg keeps the aspect ratio and rounds to an even number (most codecs reject odd dimensions):

bash
ffmpeg -i in.mp4 -vf scale=1280:-2 out.mp4

Cropping uses crop=w:h:x:y: output width, output height, then the left and top offset of the box. Omit x:y and ffmpeg centers the crop for you:

bash
ffmpeg -i in.mp4 -vf crop=500:500:0:0 -c:a copy out.mp4

Add -c:a copy so the audio is passed through rather than silently re-encoded. You can use the input-dimension variables in_w and in_h to express a ratio crop, like center-cropping to 16:9 regardless of source size. The full filter reference, plus using cropdetect to find black bars automatically, is in crop a video with ffmpeg.

Audio

To pull the audio out of a video, -vn drops the video stream. If the audio codec already fits the target container, copy it out with no quality loss:

bash
ffmpeg -i in.mp4 -vn -c:a copy out.m4a

When the target format differs (say you need MP3), re-encode and pick a quality. -q:a 2 is variable-bitrate around 190 kbps, a better default than a fixed CBR rate:

bash
ffmpeg -i in.mp4 -vn -c:a libmp3lame -q:a 2 out.mp3

The reverse, removing audio, copies the video untouched and drops the sound with -an:

bash
ffmpeg -i in.mp4 -c:v copy -an out.mp4

To replace or add a track, give ffmpeg two inputs and map explicitly so it does not guess. -shortest stops at the shorter of the two so you do not get a long silent tail:

bash
ffmpeg -i video.mp4 -i audio.m4a -c:v copy -c:a copy -map 0:v:0 -map 1:a:0 -shortest out.mp4

For the full extract workflow, including grabbing one track out of a multi-track file with -map 0:a:1, see extract audio from a video with ffmpeg.

Video to GIF

A bare ffmpeg -i in.mp4 out.gif produces a muddy, dithered GIF because it maps every frame against a single global palette. The fix is a two-step palette: palettegen builds an optimal 256-color palette from the source, paletteuse maps the frames to it. The single-command form uses split so the input is read once and no temp file is needed:

bash
ffmpeg -i in.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" out.gif

fps and scale are the two biggest file-size levers; flags=lanczos gives a sharp downscale. To grab a short clip first, fast-seek with -ss before -i:

bash
ffmpeg -ss 2 -t 3 -i in.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" clip.gif

The full walkthrough, including per-frame palettes and the "use MP4 instead of GIF for big files" reality, is in convert video to a high-quality GIF with ffmpeg. Once you have a GIF, optimize and compress it with gifsicle shaves it down further, and converting it to WebP is usually a bigger win than any GIF tweak.

Codecs and quality

For H.264, the universal default, the quality knob is -crf (lower is better, 23 is the baseline) and -preset trades encode time for a smaller file at the same quality:

bash
ffmpeg -i in.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 192k out.mp4

libx265 (HEVC) gets you roughly half the file size at the same visual quality, at the cost of slower encoding and patchier playback support; its CRF scale runs a little different (default 28):

bash
ffmpeg -i in.mp4 -c:v libx265 -crf 28 -preset medium -c:a aac -b:a 192k out.mp4

AV1 through libsvtav1 compresses best of the three and is royalty-free. Its -crf runs 0 to 63 (the encoder's own default is 35; a CRF around 30 is a common starting point for 1080p) and -preset is numeric from 0 to 13, where a lower number is slower and smaller:

bash
ffmpeg -i in.mp4 -c:v libsvtav1 -crf 30 -preset 6 -c:a libopus -b:a 128k out.mp4

Note -c copy cannot bridge incompatible codecs, so converting between MP4 and WebM always re-encodes. The codec-by-codec tradeoffs and the VP9 path are in convert WebM to MP4 (and back) with ffmpeg.

Speed

The setpts filter rescales the video presentation timestamps: a smaller multiplier plays faster. For video alone, drop the audio with -an:

bash
ffmpeg -i in.mp4 -filter:v "setpts=0.5*PTS" -an out.mp4

To speed up the audio in sync, use atempo, which changes tempo without shifting pitch. The catch readers hit constantly: while current ffmpeg accepts a single atempo value from 0.5 to 100.0, any tempo above 2.0 skips samples rather than blending them, so for clean results you chain atempo instances each within the 0.5 to 2.0 sweet spot. Here is a clean 2x with both streams:

bash
ffmpeg -i in.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" out.mp4

For a clean 4x you would write atempo=2.0,atempo=2.0. The chaining trick and smooth slow motion via frame interpolation are in speed up or slow down a video with ffmpeg.

Concat and merge

If the files share the same codecs, parameters, and resolution, the concat demuxer joins them with no re-encode. Write a text file listing them, then:

bash
ffmpeg -f concat -safe 0 -i list.txt -c copy out.mp4

where list.txt holds one file 'clip1.mp4' line per input. When the inputs differ (different codec, resolution, or framerate), the concat demuxer will produce a broken file; use the concat filter instead, which re-encodes everything to a common format:

bash
ffmpeg -i a.mp4 -i b.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]" -map "[v]" -map "[a]" out.mp4

Subtitles

There are two ways to attach subtitles, and they are not interchangeable. Soft subtitles ride along as a selectable track the viewer can toggle; for an MP4 the subtitle codec is mov_text:

bash
ffmpeg -i in.mp4 -i subs.srt -c copy -c:s mov_text out.mp4

Hard subtitles are burned into the picture, so they always show and survive any re-upload, but they require a re-encode and cannot be turned off:

bash
ffmpeg -i in.mp4 -vf subtitles=subs.srt out.mp4

Common fixes

A few errors come up so often they are worth memorizing. An MP4 that will not start playing until fully downloaded has its moov atom at the end; move it to the front:

bash
ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4

The dreaded height not divisible by 2 error means a codec rejected an odd dimension after scaling. Force both dimensions even:

bash
ffmpeg -i in.mp4 -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" out.mp4

And a video that displays sideways (common with phone footage) rotates with transpose:

bash
ffmpeg -i in.mp4 -vf "transpose=1" out.mp4

transpose=1 is 90 degrees clockwise, transpose=2 counter-clockwise. To grab a single still frame for a thumbnail instead, see extract a thumbnail or frame from a video with ffmpeg.

FAQ

See also

Sources

Authoritative references this article was fact-checked against.

TagsffmpegffprobevideoCLIencodingGIFlibx264transcode

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

Regex Cheat Sheet

Regex Cheat Sheet including regex symbols, ranges, grouping, assertions, syntax tables, examples, matches, and compatibility tables. Definitive Regular Expressions Quick Reference!

Elasticsearch Cheat Sheet

Practitioner reference for Elasticsearch 9.x: index and document operations, Query DSL, aggregations, vector / kNN search, ESQL, cluster management, version compatibility notes, and the gotchas that bite first-time operators.

MySQL Cheat Sheet

MySQL cheat sheet covering CLI commands, database and table operations, joins, indexes, backups, user management, and transactions, with version notes for 5.7, 8.0, and 8.4.