Compose a command with the builder¶
afmpeg.Command is a declarative description of a media job for the
ffmpeg-wasi engine — a sequence of inputs, an
optional filtergraph, and a sequence of outputs. It is use-case-agnostic: it models the
structure of a job, so it expresses any workflow (transcode, scale, overlay, concat,
thumbnail, audio extract, …). JobSpec() renders it to the engine's job spec; RunJob
runs it.
There are two equally valid ways to build one.
As a struct — explicit, inspectable data¶
Fill the struct directly when you want full control (it's copyable and serialisable — a pipeline can come from YAML/JSON):
cmd := afmpeg.Command{
Inputs: []afmpeg.Input{{Path: "in.mkv"}},
FilterComplex: "[0:v]scale=1280:-2[vout]",
Outputs: []afmpeg.Output{{
Path: "out.mp4",
Map: []string{"[vout]"},
VideoCodec: "libx264",
Options: map[string]string{"crf": "23", "movflags": "+faststart"},
}},
}
Which H.264 encoder?
libx264 needs the GPL module. The default LGPL module encodes H.264 via
"libopenh264" instead — swap VideoCodec accordingly. Both emit H.264/mp4; libx264 is
higher quality, openh264 is permissively licensed. See ffmpeg-wasi's variant docs.
With NewCommand — functional options¶
cmd := afmpeg.NewCommand(
afmpeg.WithInput("bg.mp4"),
afmpeg.WithInput("logo.png"),
afmpeg.WithFilterComplex("[0:v][1:v]overlay=10:10[v]"),
afmpeg.WithOutput("out.mp4",
afmpeg.Map("[v]"), afmpeg.VideoCodec("libx264"), afmpeg.WithOption("crf", "23")),
)
Both forms produce the same Command.
Run it¶
res, err := rt.RunJob(ctx, fs, cmd) // sugar for rt.Run(ctx, fs, string(spec)) from cmd.JobSpec()
if err != nil {
return err
}
if res.ExitCode != 0 {
return fmt.Errorf("engine failed: %s", res.Stderr)
}
// Structured results (process status, a probe's info) come back on res.Stdout.
JobSpec() emits {op:"process", inputs, filter, outputs}. The filter is the full ffmpeg
filter_complex (the engine parses it with libav); each output's Options map becomes the
encoder options. See obtain a module for the ffmpeg-wasi release.
Encoder options¶
Any encoder setting goes in an output's Options map (struct) or via WithOption (builder)
— nothing is blocked:
// a single-frame thumbnail
cmd := afmpeg.NewCommand(
afmpeg.WithInput("in.mp4"),
afmpeg.WithFilterComplex("[0:v]thumbnail[v]"),
afmpeg.WithOutput("thumb.png", afmpeg.Map("[v]"), afmpeg.WithOption("frames:v", "1")),
)
Notes¶
- Pixel/sample format, output framerate, and duration live in the filtergraph (e.g.
format=yuv420p,fps=30,trim) — the engine derives the container from the output path and the pixel/sample format from the graph + encoder. - A higher-level workflow (a "reel", a thumbnail sheet, …) is your code composed on this builder — afmpeg ships no opinionated workflow types.