← All 75 books ffmpeg, one command per page Get the full edition · £10
One command per page

ffmpeg, one command per page

Thirty commands for the person who converts video every week and was never shown the machine underneath: the three zones of every command line, the pipeline of demuxers and codecs that copy sidesteps, streams counted from zero, -map taking control of what travels, the CRF dial and the preset staircase, two passes to hit a file size, yuv420p for players that demand it, the webcam as just another input, and ffprobe reading the facts before any flag is typed.


Steve Hodgkiss 5 commands

A diagram, the trap, and one thing to go run this week. That's a page.

ffmpeg, one command per page

Thirty commands for the person who converts video every week and was never shown the machine underneath: the three zones of every command line, the pipeline of demuxers and codecs that copy sidesteps, streams counted from zero, -map taking control of what travels, the CRF dial and the preset staircase, two passes to hit a file size, yuv420p for players that demand it, the webcam as just another input, and ffprobe reading the facts before any flag is typed.


Set in Space Grotesk, Inter and JetBrains Mono (SIL Open Font License).

Every fact, flag, default and number in this book is as the official FFmpeg documentation states it, fetched and read during this build: the ffmpeg(1), ffprobe(1), ffplay(1), ffmpeg-formats(1), ffmpeg-devices(1), ffmpeg-filters(1) and ffmpeg-utils(1) manual pages from ffmpeg.org, and the official wiki at trac.ffmpeg.org (Encode/H.264 and Capture/Webcam pages). Teaching conventions (one command a page) are named as conventions. An independent guide, not affiliated with or endorsed by the FFmpeg developers.

General information only. Not professional advice; check flags against your own ffmpeg build, which may differ.

© 2026 Steve Hodgkiss. All rights reserved. Personal use only; no redistribution rights.

Edition 1.0 · stevehodgkiss.net

Contents

Contents


Part 1 · The trade4
One line, three zones5
Automatic selection6
Copy changes nothing7
Part 2 · Cutting time
-ss jumps, twice8
Part 3 · Inspecting
ffprobe, the reader9
Part 1 of 3
structure, streams
1

The trade

The shape of every command line and the pipeline underneath it: zones and order, packets and frames, indices from zero, and who chooses streams when you don't.


In this part
  1. 01One line, three zones
  2. 02Automatic selection
  3. 03Copy changes nothing

Per the ffmpeg(1) man page Synopsis: ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ... Per Description: ffmpeg is a universal media converter; it reads from an arbitrary number of inputs specified by the -i option and writes to an arbitrary number of outputs; anything found on the command line which cannot be interpreted as an option is considered to be an output url.

ffmpeg · No. 01
The trade

One line, three zones

Global, input, output

ONE COMMAND LINE, THREE ZONESglobalinput options -i in.mp4-c:v libx264 out.mp4$ ffmpeg -ss 10 -i in.mp4 -c:v libx264 out.mp4Options attach to the NEXT file; global options come first

The man page's synopsis is the whole grammar: global options, then inputs with their options, then outputs with theirs. ffmpeg reads an arbitrary number of inputs (files, pipes, devices) and writes an arbitrary number of outputs. Anything on the line that isn't an option is an output url.

The general rule: options apply to the next specified file. Order matters, the same option can appear twice, and options reset between files. All inputs first, never mixed.

Where an option sits decides what it touches. That's the first thing to read on any ffmpeg line.

TRY THIS WEEK

Take any ffmpeg command you ran this week and circle its three zones: what's global, what belongs to the input, what belongs to the output.

Per the ffmpeg(1) man page Stream selection, Automatic stream selection: in the absence of any map options for a particular output file, ffmpeg inspects the output format to check which types of streams can be included; for each acceptable stream type, ffmpeg will pick one stream, when available, from among all the inputs; for video, it is the stream with the highest resolution; for audio, it is the stream with the most channels; for subtitles, the first subtitle stream found, with a text-based versus image-based caveat; when several streams of the same type rate equally, the stream with the lowest index is chosen; data or attachment streams are not automatically selected and can only be included using -map.

ffmpeg · No. 02
The trade

Automatic selection

Best video, most channels

AUTOMATIC STREAM SELECTION PICKS ONE PER TYPEinput 0video 640x360video 1920x1080audio 5.1 chselection ruleshighest resolution videomost channels audiofirst subtitle streamoutputData and attachment streams are never picked automatically: -map only

Skip -map and ffmpeg still chooses. For each stream type the output container accepts, it takes exactly one: the highest-resolution video, the most-channelled audio, the first subtitles, with ties broken by the lowest index.

Two footnotes from the man page: subtitle selection checks whether the output format's default subtitle encoder is text-based or image-based and only picks a matching type, and data or attachment streams are never chosen automatically; they only travel with -map.

One stream per type. Sensible for one-file conversions, wrong the moment inputs multiply.

TRY THIS WEEK

Run ffprobe -show_streams on one file today and predict which stream automatic selection would pick before converting.

Per the ffmpeg(1) man page Main options: -c[:stream_specifier] codec (input/output,per-stream) and -codec select an encoder (when used before an output file) or a decoder (when used before an input file) for one or more streams; codec is the name of a decoder/encoder or a special value copy (output only) to indicate that the stream is not to be re-encoded; for each stream, the last matching c option is applied; example: ffmpeg -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT encodes all video streams with libx264 and copies all audio streams.

ffmpeg · No. 03
The trade

Copy changes nothing

Packets straight through

COPY: PACKETS STRAIGHT ACROSSdemuxermuxerdecoderfilterencoder-c copyno decode, no filter, no encodeFast and lossless when the codecs already suit the container

copy is the special codec value that means don't re-encode: packets travel from demuxer straight to muxer, untouched, fast, and lossless. The man page's own example encodes video with libx264 while the audio rides through as -c:a copy.

Specifiers aim it: -c:v picks codecs for video, -c:a audio, -c:s subtitles, and the last matching option wins, so a broad -c copy followed by -c:v libx264 copies everything except the video it re-encodes.

Default choice for cutting, remuxing and stripping. If the codecs already suit the container, copying beats converting.

TRY THIS WEEK

Remux one file to a new container with -c copy today and compare its runtime to any re-encode you've done.

Per the ffmpeg(1) man page Main options: -ss position (input/output) seeks in the input file to position when used as an input option (before -i); note that in most formats it is not possible to seek exactly, so ffmpeg will seek to the closest seek point before position; when transcoding and -accurate_seek is enabled (the default), this extra segment between the seek point and position will be decoded and discarded; when doing stream copy or when -noaccurate_seek is used, it will be preserved; when used as an output option (before an output url), it decodes but discards input until the timestamps reach position.

ffmpeg · No. 04
Cutting time

-ss jumps, twice

Input seek, output skip

-ss BEFORE AND AFTER -ibefore -i: jump, fastafter -i: decode and discard, exactInput seek lands on the closest seek point; output side decodes up to it

Same flag, two homes. Before -i, -ss seeks in the input: the man page notes most formats can't seek exactly, so ffmpeg lands on the closest seek point and, when transcoding with accurate seek on by default, quietly decodes and discards the gap. Fast, and frame-accurate when re-encoding.

Before the output url, -ss decodes but discards everything until the timestamps reach position. Exact, and slow, because the whole front of the file is decoded on the way.

Want it fast, put -ss before -i. Want it frame-exact under stream copy, accept the slow side.

TRY THIS WEEK

Cut the same 30-second clip twice, -ss before and after -i, and time both runs.

Per the ffprobe(1) man page: ffprobe [options] input_url gathers information from multimedia streams and prints it in the console; -show_format shows information about the container format (printed within a section named FORMAT); -show_streams shows information about each media stream (each printed within a section named STREAM); -print_format, -of and -output_format set the output printing format, and for printing the output in JSON format specify -output_format json; -select_streams selects only the streams specified by the stream specifier, e.g. ffprobe -show_streams -select_streams a INPUT shows only audio streams; -count_frames counts the number of frames per stream and reports it in the corresponding stream section.

ffmpeg · No. 05
Inspecting

ffprobe, the reader

Facts before flags

FFPROBE READS BEFORE YOU WRITEinputFORMATcontainer, duration, bitrateSTREAMcodec, size, rate, per streamJSON-print_format json for scripts-select_streams a-count_framesffprobe [options] input_url: the cheapest debugging in video

Every choice in this book starts with knowing what's in the file. ffprobe -show_format -show_streams INPUT prints the container's facts and one block per stream: codec, size, rate, duration. The synopsis is ffprobe [options] input_url, nothing else.

For scripts, -print_format json makes the output parseable, -select_streams a narrows it to audio (or v for video), and -count_frames reports the exact number of frames per stream when you need ground truth.

Probe first, convert second. The cheapest debugging in video is reading what's already true.

TRY THIS WEEK

Probe your most-used media file today and write down its real codec, resolution and duration.

Index

Index


-ss jumps, twice8
Automatic selection6
Copy changes nothing7
ffprobe, the reader9
One line, three zones5