Choose and Verify FFmpeg Codecs Before You Encode
Copy a codec name off a forum post and ffmpeg will happily reply "Unknown encoder" with no further clue. This guide gets you from a bare command to a verified encode: the codec your build actually has, the options that belong to it, and a two-second test file that proves the whole chain works. The examples were checked against FFmpeg 8.0.1 on Linux.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 10 minutes for the first pass. You need an installed ffmpeg, a readable input file if you are testing your own media, and enough space for a temporary output. Nothing here needs root privileges. Keep the input and output paths as ordinary user files.
1. Confirm the installation and version
Start by checking the executable that will run your command. This catches the common distraction where a shell, container or service is using a different FFmpeg build from the one you expected.
$ command -v ffmpeg
$ ffmpeg -version | sed -n '1,4p'
Expected output begins with a path such as /usr/bin/ffmpeg and a version line. This machine reports ffmpeg version 8.0.1. The available codecs depend on how the package was built, so do not copy a codec name from another machine without checking it here.
Checkpoint
If command -v prints nothing, install or enable the FFmpeg package through your distribution's normal package management, then repeat this step. Do not work around a missing binary by changing a service or adding a system-wide symlink.
2. Read the codec capability flags
Ask FFmpeg for its enabled codec list and inspect the six-character capability field. The first character means decoding, the second means encoding, and later characters identify video, audio, subtitles and other properties.
$ ffmpeg -hide_banner -codecs 2>/dev/null | sed -n '1,16p'
$ ffmpeg -hide_banner -codecs 2>/dev/null | grep -E ' (h264|aac|opus) '
A line beginning VFS..D h264 has a decoding marker in the first position and describes the H.264 codec. A line beginning .EVIL. a64_multi has an encoding marker in the second position. The exact list varies with the package build.
A codec name is not the same thing as a usable encoder. One codec can have several implementations, such as a native encoder and an external-library encoder. Use the separate encoder and decoder lists when you pick a name for -c:v or -c:a, not the codec list.
3. Check the encoder and its private options
List encoders, then request help for the exact implementation. The generic options described by ffmpeg-codecs(1) apply broadly, while private options belong only to the selected codec.
$ ffmpeg -hide_banner -encoders 2>/dev/null | grep -E ' (libx264|aac|libopus) '
$ ffmpeg -hide_banner -h encoder=libx264 2>/dev/null | sed -n '1,35p'
On the checked installation, libx264, aac and libopus are present. The encoder help reports options including -preset, -tune and -crf for libx264. Do not assume that an option shown for libx264 is accepted by another H.264 encoder: each implementation defines its own set.
4. Run a small, reversible encode
Before you touch a long recording, make a two-second test file. FFmpeg's built-in test pattern needs no input file of your own, so nothing you own is at risk.
$ TEST_OUT=/tmp/ffmpeg-codecs-test.mp4
$ ffmpeg -hide_banner -y \
-f lavfi -i 'testsrc2=size=320x180:rate=10' \
-t 2 -an -c:v libx264 -preset veryfast -crf 28 "$TEST_OUT"
Successful output ends with a summary containing a video stream and a line similar to video:...kB. The -y flag permits replacement of this disposable path. Do not use it with a valuable destination unless overwriting is deliberate.
Verify the result with a probe rather than trusting the exit status alone:
$ ffprobe -hide_banner -v error \
-show_entries stream=codec_name,codec_type,width,height \
-of default=noprint_wrappers=1 "$TEST_OUT"
codec_name=h264
codec_type=video
width=320
height=180
Remove only this temporary file when you are finished:
$ rm -- "$TEST_OUT"
5. Apply generic options with care
The manpage documents options shared by encoders and decoders, but their effect depends on the media type and codec. For example, -threads defaults to automatic selection for supported video codecs. Set it only when you have a reason to cap or reproduce parallelism:
$ ffmpeg -hide_banner -i /path/to/input.mp4 \
-c:v libx264 -threads 4 -c:a copy /path/to/output.mp4
-c:a copy leaves the audio stream compressed as it is, while the video is encoded by libx264. If the output container or player rejects that audio format, choose an audio encoder after checking it with -encoders, for example -c:a aac -b:a 128k. The codec guide lists -b as a bitrate option and gives 128K as the default audio bitrate, but an explicit value makes a production command easier to review.
Other generic options have sharp trade-offs. -lowres decodes at half, quarter or eighth resolution, and -skip_frame can discard frames. These help with analysis, previews or resource limits, but they are wrong for a faithful transcode. The default for -skip_frame is default, not all.
6. Keep decoding boundaries explicit
Do not enable experimental decoding merely to make an unfamiliar file open. The codec documentation warns that experimental decoders can pose a security risk when decoding untrusted input. For files from outside your control, use a current package, keep the output directory separate, and avoid running conversion commands as root.
You can narrow the input decoder set with the documented codec_whitelist option when your workflow requires an allow-list. Its value is a comma-separated list, and the default is to allow all decoders. Treat that as a policy decision. A narrow list can make a pipeline fail on a legitimate input rather than silently selecting another decoder.
Common traps
- "Unknown encoder": the name is absent from
ffmpeg -encoders, or the package lacks the external library that encoder needs. Choose an encoder present on this installation or install the distribution package that supplies the required build feature. - The codec list looks right but the command fails. You selected a codec name instead of an encoder implementation, or placed an option after the wrong output. Recheck
-h encoder=NAMEand keep output-specific options with their output. - The output is unexpectedly large or poor. Bitrate and quality controls are codec-specific. Inspect the selected encoder's help instead of carrying
-crf,-qscaleor a preset over from another encoder. - A test works but the real file fails. Compare the input's streams and pixel format, then test a short section of the real file. A generated test pattern proves the encoder works, not that every source format is supported.
Done means
- Executable confirmed:
command -v ffmpegidentifies the intended executable and its version is known. - Encoder confirmed: the selected implementation appears in
ffmpeg -encoders. - Options checked:
ffmpeg -h encoder=NAMEhas been checked for private options. - Encode verified: a short encode completes and
ffprobereports the expected stream codec. - Cleaned up: temporary output is removed, and no valuable file was overwritten.