Skip to content

FFmpeg

currentMigrated from docs/utilities/ffmpeg.mdx at 37c3317fd058; modified for Encode Wiki · CC BY-SA 4.0

FFmpeg/FFmpeg

code.ffmpeg.org
Latest tag
n9.0.2
Last commit

FFmpeg is the multimedia framework almost every other tool on this wiki leans on. It ships three command-line programs: ffmpeg (decode, filter, encode, mux), ffprobe (inspect files) and ffplay (a minimal player), plus the libav* libraries that players, browsers and encoders such as Av1an use internally.

FFmpeg wraps external encoders rather than replacing them: libx264, libx265, libsvtav1, libaom-av1, libopus and so on are the same libraries as the standalone encoders, exposed through FFmpeg options. Which of them you have depends entirely on how your binary was built.

For a guided first encode, see Make your first FFmpeg encode.

PlatformRecommended source
Windowsgyan.dev or BtbN. Both offer release and git-master builds. Pick gyan.dev’s “full” build for encoding work; it includes libraries such as SVT-AV1 and dav1d that the “essentials” build leaves out. winget install ffmpeg installs it.
macOSHomebrew (brew install ffmpeg) or the static builds linked from the download page.
LinuxYour distribution’s package if it is recent. Debian/Ubuntu LTS packages are often several major versions behind; BtbN publishes static Linux builds as well.
AnyBuild from source following the compilation guide when you need a specific encoder version or a library no packaged build includes.

The FFmpeg project itself only publishes source code; every binary above is a third-party build. Encoders improve quickly, so an old distribution FFmpeg can be stuck on an SVT-AV1 or libaom release that is years out of date. ffmpeg -encoders shows what your build actually contains.

Licensing follows the build: FFmpeg is LGPL by default, becomes GPL when GPL libraries such as x264 or x265 are enabled, and builds with “nonfree” components such as libfdk_aac cannot be redistributed. See FFmpeg legal.

Terminal window
ffmpeg [global options] [input options] -i input [output options] output

Options apply to the next input or output file named after them, so position matters:

Terminal window
ffmpeg -r 24 -i input.mkv output.mkv # input option: treat the input as 24 fps
ffmpeg -i input.mkv -r 24 output.mkv # output option: convert to 24 fps, dropping or duplicating frames

A normal encode:

Terminal window
ffmpeg -i input.mkv -c:v libx264 -crf 20 -preset slow -c:a libopus -b:a 128k output.mkv

The :v and :a suffixes are stream specifiers. -c:v sets the video codec, -b:a the audio bitrate, -c:a:1 the codec of the second audio stream only. Encoder-specific options (-crf, -preset, -svtav1-params, -x265-params) are documented on each encoder’s page and in FFmpeg codecs; ffmpeg -h encoder=libsvtav1 prints the options your build’s wrapper accepts.

The output container is chosen from the file extension. Use -f only when there is no extension to go by, for example -f null - to decode without writing a file or -f yuv4mpegpipe - to pipe to another program.

Common general options:

OptionUse
-yOverwrite the output without asking.
-ss, -t, -toStart time, duration and end time. Before -i they apply to the input, after it to the output.
-frames:v NStop after N video frames.
-hide_bannerHide the build configuration that FFmpeg prints at startup.
-loglevel errorPrint only errors (useful in scripts).

Without -map, FFmpeg picks one video stream (highest resolution), one audio stream (most channels) and one subtitle stream if the output container can hold it. Extra audio tracks, subtitles, attachments and data streams are silently dropped. That is the most common surprise for newcomers.

Once you use -map, only the mapped streams go to the output:

Terminal window
ffmpeg -i input.mkv -map 0 -c:v libx264 -crf 20 -c:a copy -c:s copy output.mkv
MapSelects
-map 0Every stream of the first input
-map 0:v:0The first video stream
-map 0:aAll audio streams
-map 0:a:m:language:jpnAudio streams tagged Japanese
-map -0:a:1Removes the second audio stream from what is already mapped
-map '0:s?'All subtitle streams, without failing if there are none
-map 1:aAudio from the second input file (inputs are numbered from 0)

Quote maps that contain ? so your shell does not treat it as a wildcard. ffprobe input.mkv lists the streams with their indexes and languages.

-c copy copies the compressed stream into the new container untouched. It is fast and lossless, so use it for every stream you are not re-encoding:

Terminal window
ffmpeg -i input.mkv -map 0 -c copy output.mp4

The target container must support every copied codec. MP4, for example, cannot hold ASS or PGS subtitles, so the command above fails if the input has them; drop them with -map -0:s or keep Matroska. You can mix copy and encoding per stream:

Terminal window
ffmpeg -i input.mkv -map 0 -c copy -c:a:1 libopus -b:a:1 96k output.mkv

Cutting with -c copy can only start on a keyframe. With -ss before -i, FFmpeg keeps the frames from the previous keyframe so the cut starts earlier than you asked; re-encode the video if the cut has to be frame-accurate. For lossless cutting and joining of Matroska files, mkvmerge is usually easier.

Filters only run on streams you re-encode; you cannot filter and -c copy the same stream. A single-input chain uses -vf (video) or -af (audio), with filters separated by commas:

Terminal window
ffmpeg -i input.mkv -vf "crop=1920:800,scale=-2:720" -c:v libsvtav1 -crf 35 -preset 6 -c:a copy output.mkv

scale=-2:720 keeps the aspect ratio and rounds the width to an even number, which 4:2:0 encoders require. Filters with several inputs or outputs use -filter_complex with labelled pads. This one scales an encode back to the source resolution and stacks the two side by side for a visual comparison:

Terminal window
ffmpeg -i source.mkv -i encode.mkv -filter_complex "[1:v]scale=1920:1080:flags=bicubic[enc];[0:v][enc]hstack" -frames:v 1 compare.png

Commonly used filters include scale and zscale (resizing and colour conversion), crop, format (pixel format), fps, yadif/bwdif (deinterlacing) and the metric filters libvmaf, xpsnr, ssim and psnr. Anything more involved, such as denoising, debanding or inverse telecine, is usually done in VapourSynth.

Standalone encoders often get new features before FFmpeg’s wrappers expose them. Pipe decoded frames to them as Y4M:

Terminal window
ffmpeg -i input.mkv -pix_fmt yuv420p10le -strict -1 -f yuv4mpegpipe - | SvtAv1EncApp -i - --crf 30 --preset 4 -b output.ivf

-strict -1 is needed because 10-bit pixel formats are not part of the original Y4M specification and FFmpeg refuses to write them otherwise. The encoder writes video only; mux it with the audio afterwards using FFmpeg or mkvmerge.

Terminal window
ffprobe input.mkv
ffprobe -v error -show_streams -show_format -of json input.mkv

The first prints a readable summary of every stream. The second gives the full stream properties (codec, profile, pixel format, colour metadata, frame rate, language and disposition) as JSON for scripts. -select_streams v:0 limits the output to one stream, and -show_entries stream=codec_name,pix_fmt,color_transfer to specific fields.

To check that a file decodes cleanly from start to finish:

Terminal window
ffmpeg -v error -i output.mkv -f null -

Any decode error is printed; no output means the streams decoded without errors.