FFmpeg is confusing until it isn't
The FFmpeg command line scares people away. You search for "how to convert a video," find a wall of flags you've never seen before, and close the tab.
About five commands handle 90% of what you'll ever need, though. The syntax follows a pattern that clicks once you see it. And once FFmpeg clicks, you'll wonder why you ever used a GUI for batch video work.
This guide covers installing FFmpeg, breaking down the command line syntax, running the commands that actually matter, and figuring out what to do when your needs outgrow the terminal.
What FFmpeg actually is
FFmpeg is a free, open-source toolkit for working with video and audio from the command line. It reads almost any media format, converts between them, trims clips, extracts audio, resizes, compresses, and a lot more. The project has been around since 2000 and as of March 2026, the latest stable release is version 8.1.
It runs on Windows, macOS, and Linux. When other tools handle video behind the scenes (VLC, OBS, Handbrake), they're often calling FFmpeg under the hood.
You interact with it by typing commands in a terminal. No GUI, no drag-and-drop. That's the tradeoff: it's less intuitive but far more powerful and scriptable than any desktop app.
FFmpeg actually ships with three utilities:
ffmpeg — the main tool for processing video and audio
ffprobe — inspects media files and reports what's inside them (codec, resolution, bitrate, duration). The ffprobe tutorial covers this in detail.
ffplay — a minimal media player for testing
You'll spend 95% of your time with ffmpeg itself, but knowing about ffprobe saves you when you need to figure out why a file won't play or what codec you're dealing with before picking a command.
Install FFmpeg on your machine
Before downloading anything, check if it's already there. Open a terminal and run:
If you see version info, you're set. If you get "command not found" (or "'ffmpeg' is not recognized" on Windows), pick your OS below.
Windows
Go to ffmpeg.org/download.html and pick a Windows build. The gyan.dev builds are popular and well-maintained. Grab the "full" build — it includes all codecs.
Extract the zip to
C:\ffmpeg\so the binaries end up inC:\ffmpeg\bin\.Add
C:\ffmpeg\bin\to your system PATH:Hit Start, type "Environment Variables," open it
Under System variables, find
Path, click Edit, then NewPaste
C:\ffmpeg\bin\Save everything and close
Open a new Command Prompt (the old one won't see the PATH change) and verify:
The where ffmpeg output should show C:\ffmpeg\bin\ffmpeg.exe. If you get "'ffmpeg' is not recognized as an internal or external command," the PATH entry is wrong or you're still in the old terminal window.
Windows troubleshooting: The most common issue is extracting the zip and ending up with a nested folder like C:\ffmpeg\ffmpeg-8.1-full_build\bin\ instead of C:\ffmpeg\bin\. Check the actual path to ffmpeg.exe and make sure your PATH matches it exactly.
macOS
Homebrew is the path of least resistance:
This installs ffmpeg, ffprobe, and ffplay in one go. Homebrew builds include most common codecs (H.264, H.265, AAC, VP9, AV1) by default.
No Homebrew? Download a prebuilt binary from evermeet.cx and move it into /usr/local/bin/.
Linux (Ubuntu/Debian)
Fedora uses sudo dnf install ffmpeg-free (or sudo dnf install ffmpeg if you have RPM Fusion enabled). Arch uses sudo pacman -S ffmpeg.
Most distros have it in their default repos, but those builds sometimes lag behind or miss certain codecs. If you need the latest version or a specific encoder like NVENC for GPU-accelerated encoding, grab a static build from the FFmpeg download page instead.
How the FFmpeg command line syntax works
Every FFmpeg command follows one structure:
That's it. Input on the left, output on the right. Options that come before -i affect how FFmpeg reads the input. Options after -i but before the output filename affect encoding.
A few flags you'll see everywhere:
-i input.mp4— the input file-c:v libx264— video codec (what encoder to use)-c:a aac— audio codec-c copy— skip encoding entirely, just copy the streams as-is-crf 23— quality level for H.264 (lower = better quality, bigger file)-vf "filter"— apply a video filter (resize, crop, etc.)-y— overwrite output without asking-n— never overwrite (exit if file exists)
The pattern -c:v means "codec for video." The :v is a stream specifier. -c:a targets audio. -c copy targets everything. Once you see the pattern, the flags stop looking random.
A concrete example:
Reading left to right: take input.mov, encode the video stream with H.264 at quality 23, encode the audio with AAC at 128kbps, and write the result to output.mp4. Every FFmpeg command line operation follows this same left-to-right flow. For a deeper explanation of codec choices and when to transcode vs remux, see the transcoding guide.
Containers vs codecs (quick detour)
This trips up beginners constantly. A container (MP4, MKV, MOV, WebM) is the file format. It's the box. A codec (H.264, H.265, VP9, AAC) is how the video or audio inside that box is compressed. The same H.264 video can live inside an MP4, an MKV, or a MOV container.
Why this matters: when FFmpeg says "Decoder not found," it's talking about the codec, not the file extension. And when you convert .mkv to .mp4 with -c copy, you're changing the container without touching the codec. No re-encoding, nearly instant.
Your first FFmpeg commands
These are the operations you'll reach for most. Each one solves a real problem.
Convert a video format
This re-encodes a MOV file to MP4 with H.264 video and AAC audio. CRF 23 is the default quality and it's good enough for almost everything. For a full breakdown of CRF values and how they affect file size, check the video compression guide.
If the codecs are already compatible and you just need to change the container:
That finishes in seconds because it copies the streams without re-encoding. This is called remuxing, and it's one of the most useful tricks to know. No quality loss, nearly instant.
Trim a clip
Cuts from 1:30 to 2:00. The -c copy makes it fast but not frame-accurate — FFmpeg can only start a stream copy on a keyframe. If your clip starts a second or two early, that's why.
For frame-accurate cuts, you need to re-encode:
Note the -ss moved before -i for faster seeking, and -to is now relative to the seek point (30 seconds of content). The trimming guide covers keyframe-accurate cutting, splitting files into segments, and extracting multiple clips in one pass.
Extract audio
-vn drops the video stream. -q:a 2 sets MP3 quality (0 is best, 9 is worst, 2 is roughly equivalent to 190kbps VBR). You can also just copy the audio if it's already in a format you want:
This is useful when you know the input already has AAC audio. Check with ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of csv=p=0 input.mp4 to see the audio codec before deciding.
Resize a video
The -2 tells FFmpeg to calculate the width automatically while keeping the aspect ratio and making sure it's divisible by 2 (which H.264 requires). Want 1080p? Change 720 to 1080.
For social media formats, you might need exact dimensions with letterboxing:
That scales the video to fit within 1080x1920 (TikTok/Reels vertical) and adds black bars if the aspect ratio doesn't match.
Extract a single frame as an image
Grabs one frame at the 10-second mark. Putting -ss before -i makes it fast because FFmpeg seeks using the file index instead of decoding everything from the start. For batch frame extraction and scene detection tricks, see the frame extraction guide.
Merge multiple clips
Create a text file listing your clips:
Then:
This only works if all clips share the same codec, resolution, and frame rate. If they don't, you'll get garbled output or an error like DTS ... < ... out of order. The merge guide covers all three concatenation methods (concat demuxer, concat protocol, and filter) and when each one applies.
Add a watermark
Places logo.png in the bottom-right corner with 10px padding. W and H are the video dimensions, w and h are the overlay dimensions. The watermark guide covers text overlays, opacity control, animated watermarks, and responsive scaling.
Burn subtitles onto a video
This hardcodes the subtitles into the video pixels. Once burned in, they can't be turned off, but they'll show up everywhere (social media, old TVs, any player). The subtitles filter reads SRT, ASS, and SSA formats. If your subtitle file has a weird path or special characters, wrap the whole filter in single quotes and escape as needed.
For soft subtitles (the kind viewers can toggle on/off), embed them as a stream instead:
Soft subs keep the video untouched. The -c:s mov_text encodes the subtitle stream for MP4 containers. MKV uses -c:s srt or -c:s ass instead.
Compress a video
CRF 28 trades some quality for a much smaller file. The -preset slow makes the encoder work harder to compress efficiently (slower encode, smaller output). Available presets from fastest to smallest output: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow. -movflags +faststart moves metadata to the front of the file so web players can start playing before the full download finishes. For a complete breakdown of presets, two-pass encoding, and H.265/AV1 options, there's the compression deep dive.
Convert between GIF and video
GIF to MP4 (shrinks file size dramatically):
The -pix_fmt yuv420p is required for browser compatibility. Without it, some players show a green or garbled image. See the full GIF to MP4 guide for palette handling and loop control.
MP4 to GIF (for thumbnails and previews):
GIFs get large fast. The MP4 to GIF guide covers palette optimization to keep file sizes under control.
Reading FFmpeg's output (it's not as scary as it looks)
When you run a command, FFmpeg dumps a wall of text before it starts working. Most of it is just info about the input file. Here's what to pay attention to:
This tells you the format, duration, bitrate, resolution, frame rate, and audio specs. When something goes wrong, this block is where you start debugging. If you want to extract this info programmatically (JSON output, batch scripting, specific fields), that's what ffprobe is for.
The progress line at the bottom during encoding:
fps=142— how fast it's encoding (frames per second of processing)speed=4.73x— processing 4.73 seconds of video per real secondtime=00:02:30.76— how far through the file you aresize=28672kB— output file size so farq=23.0— the current quantizer value (relates to CRF)
If the progress line stops moving but FFmpeg hasn't quit, it's probably stuck on a problematic frame. Hit q to quit cleanly.
Troubleshooting common FFmpeg command line errors
These are the errors you'll hit first and what they actually mean.
"'ffmpeg' is not recognized" / "command not found"
FFmpeg isn't in your PATH. On Windows, double-check that C:\ffmpeg\bin\ (or wherever you extracted it) is in your system PATH, not just user PATH. On macOS/Linux, run which ffmpeg to see if it's installed somewhere unexpected.
"No such file or directory"
The input file path is wrong. If the filename has spaces, wrap it in quotes: ffmpeg -i "my video.mp4" output.mp4. On Windows, use forward slashes or escaped backslashes in paths.
"Decoder ... not found" / "Encoder ... not found"
Your FFmpeg build doesn't include that codec. This happens with minimal installs. Run ffmpeg -encoders or ffmpeg -decoders to see what's available. Fix: install a "full" build or compile from source with the codec enabled.
"height/width not divisible by 2"
H.264 and H.265 require even dimensions. Fix your scale filter: use -vf "scale=-2:720" (the -2 auto-rounds) instead of -vf "scale=-1:720".
"Non monotonous DTS in output stream"
Usually shows up during concat or trimming with -c copy. The timestamps in your clips don't line up. Fix: add -avoid_negative_ts make_zero or re-encode instead of stream copying.
"Discarding ID3 tags" / "invalid dropping"
Mostly harmless warnings. FFmpeg is stripping metadata it can't carry into the output format. Your output file is probably fine. Check it to be sure.
Common mistakes (and how to avoid them)
Forgetting -c copy when you don't need re-encoding. If you're just changing containers or trimming, add -c copy. It's the difference between 2 seconds and 2 minutes.
Putting flags in the wrong order. Options before -i affect the input. Options after -i affect the output. Mix them up and FFmpeg either ignores the flag or throws an error. When in doubt, follow the pattern: ffmpeg [input options] -i input [output options] output.
Not checking the output. FFmpeg won't warn you about subtle problems. It'll happily write a file with audio drift, wrong aspect ratio, or missing streams. Always spot-check the result. A quick ffprobe output.mp4 confirms the basics.
Using -c copy when you should re-encode. Stream copying is fast, but it can't change codecs, apply filters, or do frame-accurate cuts. If you need any of those, you need to re-encode.
Overwriting the input file. FFmpeg won't let you use the same filename for input and output, but you can still overwrite files you didn't mean to. Use -n to prevent overwrites or -y to auto-confirm them.
When the FFmpeg command line isn't enough
The CLI is the right tool for one-off jobs and small scripts. Where it breaks down:
Scale. Processing hundreds of files means writing bash loops, managing parallelism, handling failures, and monitoring progress. It's doable, but it's infrastructure work you probably don't want to maintain.
Server-side processing. Running FFmpeg on your web server pins the CPU. One big encode blocks everything else. You end up building a job queue, and now you're maintaining FFmpeg infrastructure instead of your actual product. The tradeoffs are covered in the hosted vs self-hosted comparison.
Team workflows. FFmpeg on a laptop works for one person. When multiple services need video processing, you need a shared API, not a shared binary.
No-server environments. If you're working with n8n, Zapier, or similar automation tools, you can't install FFmpeg. You need an API endpoint. See running FFmpeg in the cloud without a server.
This is where a hosted FFmpeg API fits. You send the same FFmpeg command line syntax you'd run locally, but it executes on remote infrastructure. No servers to maintain, no scaling to think about. The syntax is identical -- if you can write the CLI command, you can use the API. The complete API guide walks through setup and first calls, or jump straight to code with the REST API tutorial (curl, Python, and Node examples).
Ready to try it? Get an API key and run your first FFmpeg command through the API in under a minute.
FAQ
Is FFmpeg free?
Yes. FFmpeg is licensed under LGPL/GPL and is completely free to use, including for commercial purposes. You don't need a license or API key to download and run it.
Does FFmpeg work on Windows?
It does. There's no installer -- you download a zip, extract it, and add it to your PATH. The Windows installation section above walks through each step. The FFmpeg command line works identically across operating systems.
What does -c copy do?
It tells FFmpeg to copy the audio and video streams without re-encoding. This makes operations like remuxing (changing containers) and basic trimming nearly instant, but it can't apply filters, change codecs, or do frame-accurate cuts.
How do I check what codecs FFmpeg supports?
Run ffmpeg -encoders to list all available encoders and ffmpeg -decoders for decoders. To check a specific codec: ffmpeg -h encoder=libx264. Your available codecs depend on how FFmpeg was built.
What's the difference between FFmpeg and ffprobe?
FFmpeg processes media (converts, trims, compresses). ffprobe inspects media (reports codec, resolution, bitrate, duration). They're bundled together. Use ffprobe to figure out what's in a file, then FFmpeg to do something with it. Our ffprobe tutorial covers it end to end.
Can I use FFmpeg commands through an API?
Yes. Services like RenderIO let you send the exact same FFmpeg command string over HTTP. The syntax you learn on the command line transfers directly. No new SDK to learn, no abstraction layer to figure out.
Keep going
You know enough now to handle most video processing tasks from a terminal. Pick a real task -- convert that screen recording sitting on your desktop, trim a clip for a presentation, extract audio from a meeting recording. That's how the FFmpeg command line sticks: using it on something you actually need done.
FFmpeg cheat sheet -- 50 commands organized by task