title: Command, Input, Output and FrameJob fields description: Every field of afmpeg's job types: what it means, what it defaults to, the builder option that sets it, and what is rejected. date: 2026-08-02 tags: [reference, command, job-spec, fields] authors: [Matt Cockayne matt@phpboyscout.uk]
Command, Input, Output and FrameJob fields¶
The declarative job types and every field on them. A Command is plain data: fill the struct
directly, or build it with NewCommand and the functional options. Both produce the same value,
and JobSpec() renders either to the JSON the ffmpeg-wasi
engine consumes.
Task-shaped versions of this material live in the how-to guides; this page is the field list.
Command¶
| Field | Builder option | Default | Meaning |
|---|---|---|---|
Inputs |
WithInput, WithConcatInput |
empty | Inputs in order. Index 0 is the first, and that index is what a map specifier like 0:v refers to. |
FilterComplex |
WithFilterComplex |
empty | The whole filter_complex graph as one string, parsed by libav's avfilter_graph_parse2. Omit it to mux or copy without a graph. |
Outputs |
WithOutput |
empty | Outputs in order. |
JobSpec() is pure (no I/O), so it is safe to render and log a job before running it.
RunJob(ctx, fs, cmd) is Run with the rendered spec.
Input¶
type Input struct {
Path string
Concat []string
Seek *Seek
Format string
Options map[string]string
}
| Field | Builder option | Default | Meaning |
|---|---|---|---|
Path |
WithInput(path) |
— | The input path, resolved against the afero.Fs you pass to Run. |
Concat |
WithConcatInput(paths...) |
nil | Like-codec files joined into one continuous input through the concat demuxer (a packet-level join, no re-encode). When set, Path is ignored. Distinct from the concat filter, which decodes and re-encodes. |
Seek |
SeekTo(sec), SeekAccurateTo(sec) |
nil | Start the input at a point instead of decoding from the beginning. |
Format |
InputFormat(name) |
auto-probe | Force the demuxer by name (rawvideo, s16le, mp4, …). Required for headerless input, and for a file whose extension would mislead the probe. |
Options |
DemuxerOption(k, v) |
nil | Demuxer options as an AVDictionary. Raw geometry rides here: video_size, pixel_format, framerate for rawvideo; sample_rate, ch_layout for PCM. |
An option key the demuxer does not consume is an error from the engine, not a silent no-op. A
misspelled pixel_fmt fails the job rather than producing wrong output.
Seek¶
type Seek struct {
Start float64 // seconds
Mode string // SeekFast (default when empty) or SeekAccurate
}
| Mode | Constant | What it does | Cost |
|---|---|---|---|
| fast | SeekFast, the default when Mode is empty |
Demuxer jumps to the keyframe at or before Start; earlier packets are never read. |
cheap |
| accurate | SeekAccurate |
Fast seek, then decode and discard up to the exact frame. | a fraction of a GOP of decoding |
SeekAccurate cannot feed a copied stream. A stream copy can only cut on keyframes, so
Command.JobSpec() rejects the combination before the engine sees it:
afmpeg: output "out.mp4" maps copied stream "0:v" from an accurate-seek input
(copy cuts on keyframes; use SeekFast)
Output¶
type Output struct {
Path string
Map []string
VideoCodec string
AudioCodec string
SubtitleCodec string
Options map[string]string
BitstreamFilters map[string]string
Duration float64
End float64
CopyTS bool
Format string
FormatOptions map[string]string
Metadata map[string]string
Chapters string
StreamMetadata map[string]StreamMeta
}
| Field | Builder option | Default | Meaning |
|---|---|---|---|
Path |
WithOutput(path) |
— | Output path in the afero.Fs. The muxer is guessed from its extension unless Format says otherwise. |
Map |
Map(label), repeated |
nil | What to mux: graph output pads in brackets ([vout]) and/or input streams as in:type[:idx] specifiers (0:v, 0:a:0, 0:s). |
VideoCodec |
VideoCodec(name) |
engine default for the container | The video encoder (libopenh264, libx264, …) or CodecCopy to remux. |
AudioCodec |
AudioCodec(name) |
engine default for the container | The audio encoder (aac, libopus, …) or CodecCopy. |
SubtitleCodec |
(set the field) | none | Encoder for a subtitle stream mapped as N:s (srt, webvtt, mov_text), or CodecCopy. Works alone (a sidecar .srt) or alongside video and audio (an embedded track). |
Options |
EncoderOption(k, v) |
nil | Options offered to every encoder this output opens, by their libav names. Reserve it for what they share (threads, flags); an option only one of them has fails the job when it reaches the others. See option names below. |
VideoOptions / AudioOptions / SubtitleOptions |
VideoOption(k, v) / AudioOption(k, v) / SubtitleOption(k, v) |
nil | Options for that kind's encoder only, winning over Options on a key collision. An output names at most one encoder per kind, so this is as precise as the codec selection itself. |
BitstreamFilters |
BitstreamFilter(mapKey, name) |
auto | Override the bitstream filter for one copied stream, keyed by its Map entry. "none" force-disables. Absent, the muxer inserts whatever the container requires. |
Duration |
Duration(sec) |
0 (to the end) | Stop after this many seconds (ffmpeg's -t). |
End |
End(sec) |
0 (to the end) | Stop at this position (ffmpeg's -to). |
CopyTS |
CopyTS() |
false | Keep source timestamps instead of zero-basing the output. Under CopyTS, End is an absolute source position. |
Format |
OutputFormat(name) |
from the path extension | Force the muxer (hls, dash, segment, mpegts, …). |
FormatOptions |
FormatOption(k, v) |
nil | Muxer options passed to write_header: hls_time, hls_segment_filename, movflags, … Distinct from Options, which reach the encoder. |
Metadata |
(set the field) | nil | Container-level tags on the output (title, artist, …). |
Chapters |
(set the field) | drop chapters | "copy" carries the first input's chapters across; an input index ("1") picks another; "" or "none" drops them. Authoring chapters inline is not supported. |
StreamMetadata |
(set the field) | nil | Per-stream language, disposition flags and tags, keyed by the Map entry the stream comes from. |
Fields with no builder option are set on the struct. Both forms are first-class. The builder covers the common ones, the struct covers all of them.
Option names¶
Options, FormatOptions and Input.Options are libav option dictionaries. They are not
ffmpeg command-line flags, and the two vocabularies differ in ways that are easy to miss:
| On an ffmpeg command line | Here |
|---|---|
-b:v 300k |
Options{"b": "300k"}, because the CLI parses the :v itself and libav never sees it |
-crf 23 |
Options{"crf": "23"}, the same name |
-movflags +faststart |
FormatOptions{"movflags": "+faststart"}, a muxer option |
-frames:v 1 |
no equivalent: it is a CLI output limit, use FrameJob for stills |
An option name that no encoder on the output has fails the job rather than being ignored, so a misspelling is loud. Two things that check cannot cover:
Optionsreaches every encoder the output opens. On an output with bothVideoCodecandAudioCodec,{"crf": "23"}is offered to the audio encoder too, andaacrefuses it, so the job fails even though the option was meant for the video encoder. Address it withVideoOptionsinstead (spec 0045).- A generic option set on the wrong kind is accepted and does nothing. Every encoder inherits
the whole generic
AVCodecContexttable, sog(a GOP size) inAudioOptionspasses the check and has no effect. The check catches unknown names, not wrong kinds. Addressing the option to the right map is the only thing that prevents it.
StreamMeta¶
type StreamMeta struct {
Language string // e.g. "eng"
Disposition []string // e.g. {"default", "forced"}
Tags map[string]string // arbitrary per-stream tags
}
Applied to the output stream before the header is written.
CodecCopy¶
afmpeg.CodecCopy is the string "copy". Set it on VideoCodec, AudioCodec or
SubtitleCodec and name the source stream in Map, and the packets pass through untouched, with
no decode and no encode.
What Command.JobSpec() rejects¶
Validation happens in Go, before the engine is invoked. Three things fail here:
| Condition | Error |
|---|---|
Duration or End negative |
output "…": Duration and End must be non-negative |
both Duration and End set |
output "…": Duration and End are mutually exclusive |
a copied Map entry whose input has SeekAccurate |
output "…" maps copied stream "…" from an accurate-seek input |
Everything else (an unknown codec, a map entry naming a stream that does not exist, a
filtergraph that will not parse) is the engine's to reject, and comes back as a non-zero
Result.ExitCode with the detail in Result.Stderr.
FrameJob¶
The frames op: pull still images out of one video input, without hand-tuning an fps/select
graph into the image2 muxer.
type FrameJob struct {
Input string
Format string
Options map[string]string
Select FrameSelect
Path string
Codec string
Scale string
Count int
}
| Field | Default | Meaning |
|---|---|---|
Input |
— | The video path. |
Format / Options |
auto-probe | Force and parameterise the demuxer, exactly as on Input. |
Select |
— | Which frames. Exactly one selector, see below. |
Path |
— | Required. Output template with an optional integer token, e.g. out/frame_%03d.png. A template with no token is valid only for a single frame. |
Codec |
png |
Image encoder: png, mjpeg, webp, … |
Scale |
none | ffmpeg scale arguments applied to each frame, e.g. 320:-2. |
Count |
0 (engine default) | Caps how many frames are emitted. |
An empty Path fails before the engine is reached:
afmpeg: FrameJob.Path (output template) is required.
FrameSelect, exactly one¶
type FrameSelect struct {
Timestamp *float64
Timestamps []float64
Interval float64
SceneThreshold *float64
Thumbnail bool
}
| Selector | Picks |
|---|---|
Timestamp |
the single frame at that second (a pointer, so 0 means the first frame rather than "unset") |
Timestamps |
one frame at each listed second |
Interval |
a frame every N seconds across the input (N > 0) |
SceneThreshold |
scene-change frames scoring above the threshold (select='gt(scene,T)') |
Thumbnail |
representative frames via the thumbnail filter |
Setting none or more than one fails in Go:
See also¶
- Compose a command with the builder
- Results, probes and progress values: what comes back
- Limitations: what these types deliberately cannot express