afmpeg

package
v0.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Overview

Package afmpeg is a pure-Go FFmpeg binding whose filesystem I/O runs on an afero.Fs — including a fully in-memory filesystem — with no CGO, no host FFmpeg install, and no temp files.

FFmpeg is supplied as a WebAssembly (WASI) module — the companion ffmpeg-wasi engine — and executed via wazero (a zero-dependency, pure-Go WASM runtime). Its filesystem syscalls are bridged to the afero.Fs the caller supplies (see internal/vfs), so inputs and outputs can stay entirely in RAM and the whole thing cross-compiles to a single static binary.

Build a Runtime once (compiling the module is the expensive step) and reuse it; Run serialises invocations, one at a time per Runtime. The module is never embedded (spec 0004 D-C) — supply it. For the project's own releases prefer WithModuleRelease, which fetches and signature-verifies a published ffmpeg-wasi artifact against a pinned key before it runs; otherwise use WithModuleURL (pin a URL + SHA-256) or one of WithModuleFile / WithModuleBytes / WithModuleFS:

rt, err := afmpeg.New(ctx,
	afmpeg.WithModuleRelease("n9.0.1-1", afmpeg.VariantLGPL))
if err != nil {
	return err
}
defer rt.Close(ctx)

// Build a media job and run it over an in-memory filesystem.
fs := afero.NewMemMapFs() // or any afero backend
// ... write inputs into fs ...
cmd := afmpeg.NewCommand(
	afmpeg.WithInput("in.mp4"),
	afmpeg.WithFilterComplex("[0:v]scale=1280:-2[v]"),
	afmpeg.WithOutput("out.mp4", afmpeg.Map("[v]"), afmpeg.VideoCodec("libx264")),
)
res, err := rt.RunJob(ctx, fs, cmd)
// res.ExitCode / res.Stderr report the outcome; a non-zero exit is not a Go
// error — only host-side failures are. The engine's structured results come
// back on res.Stdout.
out, err := afero.ReadFile(fs, "out.mp4") // the result, in memory

The Command builder renders to the engine's JSON job spec (Command.JobSpec); it is use-case-agnostic — a consumer's reel/timeline is composed on top, in the consumer's code (spec 0005). Probe reports a media file's container, duration, and streams over the same bridge.

Because the point is to process untrusted media, a Runtime is hardened by default: guest linear memory is capped (WithMemoryLimit, default 512 MB) so an over-allocating decode fails cleanly instead of OOM-killing the host, and every invocation runs under a deadline (WithTimeout, default one hour) so a non-terminating decode cannot wedge the Runtime. Both are tunable, and passing 0 removes a bound; a caller-supplied context deadline is always honoured over the default (spec 0027).

For a long job, attach a channel with WithProgress(ctx, ch) to receive live, best-effort progress (a completion fraction and byte counters) while Run/RunJob/ Frames execute; it never blocks or alters the job (spec 0031).

The WASM module is the default and sole sandboxed runtime. For consumers who are encode- or throughput-bound, an opt-in native backend runs the same engine as a native subprocess (spec 0028): the gitlab.com/phpboyscout/afmpeg/pkg/afmpeg/native package's native.NewFromRelease fetches and signature-verifies the native driver the same way WithModuleRelease does the .wasm, and WithBackend wires it in — the Command/Probe/Frames API is unchanged. It gives native-speed software encode (threads + SIMD) and, in the full profile, the HEVC/AV1 encoders that are impractical in WASM. It is CGO-free (a subprocess, not a linked library) and all I/O still crosses the caller's afero.Fs over an in-memory bridge.

Index

Constants

View Source
const (
	SeekFast     = "fast"
	SeekAccurate = "accurate"
)

Seek modes: fast lands on the keyframe at-or-before Start (cheap, the default); accurate additionally decodes and discards up to the exact frame — paying a fraction-of-a-GOP decode for frame accuracy. Accurate cannot apply to a copied stream (a copy can only cut on keyframes).

View Source
const CodecCopy = "copy"

CodecCopy is the codec sentinel that remuxes a mapped stream — passed through packet-for-packet with no decode/encode (mirrors ffmpeg's `-c copy`, spec 0013). Set it on Output.VideoCodec / Output.AudioCodec, with the copied input streams named in Output.Map as "in:type[:idx]" specifiers (e.g. "0:v", "0:a:0").

Variables

View Source
var ErrChecksumMismatch = errors.NewSentinel("afmpeg.checksum_mismatch", "afmpeg: module checksum mismatch")

ErrChecksumMismatch is returned by a URL-sourced module whose downloaded bytes do not match the expected SHA-256.

View Source
var ErrNoModule = errors.NewSentinel("afmpeg.no_module", "afmpeg: no wasm module configured (use WithModuleRelease, WithModuleURL, WithModuleFile, WithModuleBytes, or WithModuleFS)")

ErrNoModule is returned by New when no wasm module source is configured. The module is never embedded, so a WithModule* option is mandatory (spec 0004 D-C).

View Source
var ErrProvenanceMismatch = errors.NewSentinel("afmpeg.provenance_mismatch", "afmpeg: release provenance mismatch")

ErrProvenanceMismatch is returned when a release's provenance does not corroborate the requested variant. (Signature failures surface as signing/verify's ErrSignatureInvalid; checksum failures as ErrChecksumMismatch.)

Functions

func WithProgress added in v0.10.0

func WithProgress(ctx context.Context, ch chan<- Progress) context.Context

WithProgress returns a context that carries ch, so a subsequent Run, RunJob, or Frames on a Runtime reports live progress on it (spec 0031, D1). Progress is per-invocation — a Runtime is shared and serialises its calls — so it is attached to the call's context rather than to New.

Delivery is best-effort and never interferes with the job (D2): afmpeg sends on ch with a non-blocking send, so a slow or non-draining consumer simply misses intermediate samples; the invocation is never blocked or failed by it. afmpeg does not close ch — the caller owns its lifecycle — and stops sending once the call returns. A nil ch is a no-op.

Types

type Backend added in v0.8.0

type Backend interface {
	Invoke(ctx context.Context, fs afero.Fs, args ...string) (Result, error)
	Close(ctx context.Context) error
}

Backend runs a single engine invocation behind Runtime's stable API. The sandboxed wasm backend (wazero) is the default and the only one core afmpeg depends on; an opt-in native subprocess backend (spec 0028), constructed in a separate package (pkg/afmpeg/native) and injected with WithBackend, implements the same two methods — so RunJob/Probe/Frames and all result parsing never change with the backend.

Invoke consumes the engine argv (the job-spec JSON is args[0]) and the afero.Fs to serve, and returns the engine's Result — the same {ExitCode, Stdout, Stderr} Run surfaces. A non-zero engine exit is a Result with a nil error; only host-side failures (spawn, the fs bridge, cancellation) return an error. Close releases the backend's resources and is called by Runtime.Close.

type Chapter added in v0.6.0

type Chapter struct {
	Start float64 `json:"start"`
	End   float64 `json:"end"`
	Title string  `json:"title"`
}

Chapter is one chapter of a probed input (spec 0020): its bounds in seconds and its title tag.

type Command

type Command struct {
	Inputs        []Input
	FilterComplex string
	Outputs       []Output
}

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 plain, comparable-ish, copyable data — fill it directly for full control, or build it with NewCommand. JobSpec() renders it to the engine's JSON "process" job spec; it is use-case-agnostic (a consumer's reel/timeline is composed on top of it, in the consumer's code).

func NewCommand

func NewCommand(opts ...CommandOption) Command

NewCommand builds a Command from functional options — sugar for filling the struct. A zero-value Command{} works just as well for fully-explicit control.

func (Command) JobSpec added in v0.3.0

func (c Command) JobSpec() ([]byte, error)

JobSpec renders the command to the ffmpeg-wasi engine's "process" job spec — inputs, the filtergraph, and each output's codecs / maps / windows / encoder options — after validating the seek/window contract (spec 0014). It is pure — no I/O, safe to inspect or log.

type CommandOption

type CommandOption func(*Command)

CommandOption configures a Command during NewCommand.

func WithConcatInput added in v0.5.0

func WithConcatInput(paths ...string) CommandOption

WithConcatInput adds an input that joins like-codec segments into one continuous input via the concat demuxer (a stream-copy join, spec 0013) — distinct from the concat filter, which decodes and re-encodes.

func WithFilterComplex

func WithFilterComplex(graph string) CommandOption

WithFilterComplex sets the filtergraph (the engine parses it with libav's avfilter_graph_parse2).

func WithInput

func WithInput(path string, opts ...InputOption) CommandOption

WithInput adds an input at path, configured by the given input options.

func WithOutput

func WithOutput(path string, opts ...OutputOption) CommandOption

WithOutput adds an output at path, configured by the given output options.

type ExtractedFrame added in v0.6.0

type ExtractedFrame struct {
	Path      string  `json:"path"`
	Index     int     `json:"index"`
	Timestamp float64 `json:"timestamp"`
}

ExtractedFrame is one frame the engine wrote, from its result JSON.

type FetchOption added in v0.3.0

type FetchOption func(*fetchConfig)

FetchOption configures WithModuleURL.

func WithCacheDir added in v0.3.0

func WithCacheDir(dir string) FetchOption

WithCacheDir overrides where the module is cached (default: the OS user cache dir, under "afmpeg").

func WithGunzip added in v0.3.0

func WithGunzip() FetchOption

WithGunzip decompresses a gzip-compressed download (e.g. an ffmpeg.wasm.gz).

func WithHTTPClient added in v0.3.0

func WithHTTPClient(client *http.Client) FetchOption

WithHTTPClient overrides the HTTP client used for the download.

func WithSHA256 added in v0.3.0

func WithSHA256(hexsum string) FetchOption

WithSHA256 verifies the downloaded module against an expected hex SHA-256. Strongly recommended — the module is executable code.

type FractionSource added in v0.13.0

type FractionSource uint8

FractionSource identifies how Progress.Fraction was derived (spec 0034, D4).

const (
	// SourceUnknown means Fraction could not be determined; it is -1.
	SourceUnknown FractionSource = iota
	// SourceBytes means Fraction is byte-observed at the fs bridge: input bytes
	// read over the total size of the declared inputs (spec 0031 phase A). It
	// tracks completion well when the inputs dominate the work, and poorly when
	// the encode does.
	SourceBytes
	// SourceEngine means Fraction is engine-derived from out_time/duration (spec
	// 0032 phase B) — accurate regardless of input size, including for generative
	// inputs. Preferred whenever available.
	SourceEngine
)

func (FractionSource) String added in v0.13.0

func (s FractionSource) String() string

type FrameJob added in v0.6.0

type FrameJob struct {
	// Input is the video path. Format/Options force/parameterise the demuxer for
	// headerless or raw inputs (spec 0024), same as Input.Format/Options.
	Input   string
	Format  string
	Options map[string]string

	// Select chooses which frames — exactly one selector (see FrameSelect).
	Select FrameSelect

	// Path is the output template with an optional integer token, e.g.
	// "out/frame_%03d.png". Zero tokens is valid only for a single frame.
	Path string

	// Codec is the image encoder: "png" (default), "mjpeg", "webp" (0018), …
	Codec string

	// Scale is optional ffmpeg scale args applied to each frame, e.g. "320:-2".
	Scale string

	// Count caps the number of frames emitted (0 = the engine default).
	Count int
}

FrameJob is a declarative request to pull still frames from one video input to templated image files — the engine's "frames" op (spec 0021). It is the typed alternative to hand-tuning a `process` job's fps/select graph into an image2 muxer: the timestamps, count, and naming live in fields, not a graph string. Render it with JobSpec(), or run it with Runtime.Frames.

func (FrameJob) JobSpec added in v0.6.0

func (j FrameJob) JobSpec() ([]byte, error)

JobSpec renders the frames job to the engine's "frames" job spec after validating the one-of selector. Pure — no I/O.

type FrameSelect added in v0.6.0

type FrameSelect struct {
	// Timestamp extracts the single frame at this many seconds (pointer so 0 —
	// the first frame — is distinct from unset).
	Timestamp *float64

	// Timestamps extracts one frame at each listed second.
	Timestamps []float64

	// Interval extracts a frame every N seconds across the input (N > 0).
	Interval float64

	// SceneThreshold extracts scene-change frames whose score exceeds this
	// (select='gt(scene,T)'); a pointer so 0 is distinct from unset.
	SceneThreshold *float64

	// Thumbnail extracts representative frames via the thumbnail filter.
	Thumbnail bool
}

FrameSelect chooses which frames a FrameJob extracts. Exactly one field must be set (validated) — the selectors are mutually exclusive (spec 0021 D-0021-B).

type FramesResult added in v0.6.0

type FramesResult struct {
	Frames []ExtractedFrame
	Count  int
}

FramesResult is the outcome of a frames job: the written frames and their count.

type Input

type Input struct {
	Path string

	// Concat lists like-codec files joined into one continuous input via the
	// concat *demuxer* (a stream-copy join, distinct from the concat filter which
	// re-encodes). When set, Path is ignored.
	Concat []string

	// Seek starts the input at a point instead of decoding from the beginning
	// (spec 0014) — the engine seeks the demuxer to the keyframe at-or-before
	// Start, so the packets before it are never read.
	Seek *Seek

	// Format forces the demuxer by name (e.g. "rawvideo", "s16le", "mp4") instead
	// of auto-probing — required for headerless/raw inputs (spec 0024).
	Format string

	// Options are demuxer options passed as an AVDictionary (spec 0024); raw
	// geometry rides here (e.g. {"video_size": "1280x720", "pixel_format":
	// "yuv420p", "framerate": "25"} for rawvideo, {"sample_rate": "48000"} for
	// PCM). An unconsumed key is a typed error.
	Options map[string]string
}

Input is one media input: a single Path, or a Concat playlist of like-codec files joined via the concat demuxer (spec 0013), optionally windowed by Seek.

type InputOption

type InputOption func(*Input)

InputOption configures an Input added via WithInput / WithConcatInput.

func DemuxerOption added in v0.5.0

func DemuxerOption(key, value string) InputOption

DemuxerOption sets one demuxer option on an input (spec 0024) — raw geometry rides here, e.g. DemuxerOption("video_size", "1280x720").

func InputFormat

func InputFormat(name string) InputOption

InputFormat forces the input's demuxer by name (e.g. "rawvideo", "s16le", "mp4") instead of auto-probing — required for headerless/raw inputs (spec 0024).

func SeekAccurateTo added in v0.5.0

func SeekAccurateTo(start float64) InputOption

SeekAccurateTo starts the input at exactly start seconds: a fast seek plus decode-and-discard up to the precise frame. Costs a fraction-of-a-GOP decode; cannot feed a copied stream (a copy can only cut on keyframes).

func SeekTo added in v0.5.0

func SeekTo(start float64) InputOption

SeekTo starts the input at start seconds via a fast (keyframe) seek — the demuxer jumps to the keyframe at-or-before start, so nothing before it is read or decoded (spec 0014).

type Measurement added in v0.9.0

type Measurement struct {
	Time  float64 `json:"t"`
	Key   string  `json:"key"`
	Value string  `json:"value"`
}

Measurement is one analysis-filter data point (spec 0017 §Q): the source Time in seconds, the metadata Key with the "lavfi." prefix dropped (e.g. "cropdetect.w", "r128.I", "silence_start", "black_start"), and its Value. Values are the filters' own strings — a consumer parses the numeric ones as needed. The series is consecutive-deduplicated per key, so a stable measurement (cropdetect) appears once while discrete events (silence_start/silence_end) each appear.

Analysis filters that only log by default (ebur128, astats) need their metadata=1 option to populate this — e.g. filter "ebur128=metadata=1".

type Option

type Option func(*config) error

Option configures a Runtime at construction.

func WithBackend added in v0.8.0

func WithBackend(b Backend) Option

WithBackend replaces the default sandboxed wasm backend with a custom one — the opt-in native subprocess backend (spec 0028), constructed in a separate package (pkg/afmpeg/native) and passed here. When set, the WithModule* options are ignored: no wasm module is compiled, and the Runtime drives the provided backend behind the unchanged RunJob/Probe/Frames API. WASM stays the default — a Runtime built without this option is fully sandboxed (spec 0028 D-0028-C). New still preflights the vocabulary against the backend, so an outdated native engine is rejected just as an outdated module is.

func WithMemoryLimit added in v0.5.0

func WithMemoryLimit(bytes int) Option

WithMemoryLimit caps the guest's linear memory at bytes (rounded up to whole 64 KiB wasm pages, clamped to the wasm32 maximum of 4 GiB). Past the cap the guest's memory.grow fails, so an over-allocating decode returns ENOMEM and exits non-zero instead of OOM-killing the host (spec 0027 §4A). A default of 512 MB applies when this option is absent; WithMemoryLimit(0) removes the cap for a consumer that knowingly wants the unbounded behaviour.

func WithModuleBytes

func WithModuleBytes(module []byte) Option

WithModuleBytes supplies the ffmpeg.wasm module as raw bytes.

func WithModuleFS

func WithModuleFS(fs afero.Fs, path string) Option

WithModuleFS loads the ffmpeg.wasm module from an afero filesystem.

func WithModuleFile

func WithModuleFile(path string) Option

WithModuleFile loads the ffmpeg.wasm module from a host filesystem path.

func WithModuleRelease added in v0.5.0

func WithModuleRelease(tag string, variant Variant, opts ...ReleaseOption) Option

WithModuleRelease loads a certified ffmpeg-wasi release for (tag, variant): it fetches the module plus its checksums, signature, and provenance, and verifies — against afmpeg's pinned OpenPGP trust keys — the detached signature over the checksums, the module's and provenance's checksums, and that provenance names this variant (spec 0010, revised to gitlab.com/phpboyscout/go/signing). Only then is the module compiled. Any tamper fails with a typed error (signing/verify.ErrSignatureInvalid, ErrChecksumMismatch, ErrProvenanceMismatch).

Unlike WithModuleURL (bring-your-own, uncertified), this path is for the project's own published releases — there is no way to skip verification.

The default profile is ProfileLean; pass WithReleaseProfile(ProfileIntermediate) to load the full software-codec build. Either way the module, its provenance entry, and its checksum are verified through the same trust chain.

func WithModuleURL added in v0.3.0

func WithModuleURL(url string, opts ...FetchOption) Option

WithModuleURL downloads the wasm module from url and uses it, caching it locally so it is fetched only once. The consumer chooses the URL and accepts its licence — afmpeg bundles no module (spec 0004 D-C). Pair it with WithSHA256: the module is executable code, so verify it.

func WithTimeout added in v0.5.0

func WithTimeout(d time.Duration) Option

WithTimeout sets the default maximum duration of a single invocation. Run imposes it only when the caller's context carries no deadline of its own; a caller deadline is always honoured as-is (spec 0027 §4B). A default of 1 hour applies when this option is absent; WithTimeout(0) removes the default deadline.

type Output

type Output struct {
	Path       string
	Map        []string // graph pads ("[vout]") and/or copied input streams ("0:v")
	VideoCodec string   // the video encoder (e.g. "libx264"), or CodecCopy to remux
	AudioCodec string   // the audio encoder (e.g. "aac"), or CodecCopy to remux

	// Options are offered to EVERY encoder this output opens. On an output with
	// both VideoCodec and AudioCodec, {"crf": "23"} is offered to the audio
	// encoder too — and aac refuses it, failing the job. Reserve this for what
	// the encoders genuinely share ("threads", "flags") and address the rest with
	// the three maps below (spec 0045 D2).
	//
	// These are libav AVOption names, not ffmpeg command-line flags: the CLI's
	// `-b:v 300k` is {"b": "300k"} here, because the CLI parses the `:v` suffix
	// itself and libav never sees it. An option no encoder consumes fails the job
	// rather than being dropped.
	Options map[string]string

	// VideoOptions, AudioOptions and SubtitleOptions reach only that kind's
	// encoder and win over Options on a key collision (spec 0045 D1). An output
	// names at most one encoder per kind, so this is as precise as the codec
	// selection itself.
	//
	// The scoping cannot be inferred further down: every encoder inherits the
	// generic AVCodecContext option table, so a video-only generic option (`g`,
	// `bf`, `refs`) set on an audio encoder is accepted and silently does
	// nothing. Saying the kind here is what prevents that.
	VideoOptions    map[string]string
	AudioOptions    map[string]string
	SubtitleOptions map[string]string

	// SubtitleCodec transcodes a subtitle stream named in Map by an "N:s"
	// specifier (spec 0019) to this encoder (e.g. "srt", "webvtt", "mov_text"),
	// or CodecCopy to remux it unchanged. An output may carry it alone (a sidecar
	// .srt/.vtt) or alongside video/audio (an embedded track).
	SubtitleCodec string

	// BitstreamFilters overrides the bitstream filter for a copied stream, keyed
	// by its Map entry (e.g. {"0:v": "h264_mp4toannexb"}); "none" force-disables.
	// Absent → the muxer auto-inserts any container-required filter (spec 0013).
	BitstreamFilters map[string]string

	// Duration stops the output after this many seconds (-t); End stops it at a
	// position (-to). Mutually exclusive (spec 0014). On the default zero-based
	// timeline the two coincide; under CopyTS, End is an absolute source position.
	Duration float64
	End      float64

	// CopyTS preserves the source timestamps instead of zero-basing the output —
	// a clip starting at t=0 is the default; set CopyTS when timelines must stay
	// aligned across outputs (spec 0014).
	CopyTS bool

	// Format forces the muxer by name (e.g. "hls", "dash", "segment", "mpegts")
	// instead of guessing from the path extension — needed where the extension
	// doesn't imply the muxer (spec 0015).
	Format string

	// FormatOptions are muxer options passed to write_header (spec 0015) — segment
	// timing/naming (hls_time, hls_segment_filename, …), fragmentation flags
	// (movflags), etc. Distinct from Options, which reach the encoder.
	FormatOptions map[string]string

	// Metadata sets container-level tags on the output (spec 0020) — e.g.
	// {"title": "…", "artist": "…"} → the muxer's metadata.
	Metadata map[string]string

	// Chapters is a chapter passthrough directive (spec 0020): "copy" carries the
	// first input's chapters onto the output, an input index ("1") picks another,
	// and "" / "none" drops them. Authoring chapters inline is not supported.
	Chapters string

	// StreamMetadata sets per-stream language / disposition / tags, keyed by the
	// Map entry the stream comes from (a graph pad "[vout]" or a copied "0:a").
	StreamMetadata map[string]StreamMeta
}

Output is one muxed output: its path, the graph output pads / stream specifiers to mux, the encoders, and their options.

type OutputOption

type OutputOption func(*Output)

OutputOption configures an Output added via WithOutput.

func AudioCodec

func AudioCodec(codec string) OutputOption

AudioCodec sets an output's audio encoder (e.g. "aac").

func AudioOption added in v0.16.0

func AudioOption(key, value string) OutputOption

AudioOption sets one option on the output's audio encoder only — e.g. AudioOption("b", "128000"). It overrides EncoderOption on the same key.

func BitstreamFilter added in v0.5.0

func BitstreamFilter(mapKey, filter string) OutputOption

BitstreamFilter overrides the bitstream filter for a copied stream, keyed by its Map entry (e.g. BitstreamFilter("0:v", "h264_mp4toannexb")); "none" force-disables. Absent → the muxer auto-inserts any container-required filter on a remux (spec 0013).

func CopyTS added in v0.5.0

func CopyTS() OutputOption

CopyTS preserves source timestamps instead of zero-basing the output (spec 0014) — for when timelines must stay aligned across outputs.

func Duration

func Duration(sec float64) OutputOption

Duration stops the output after sec seconds (-t). Mutually exclusive with End.

func EncoderOption added in v0.16.0

func EncoderOption(key, value string) OutputOption

EncoderOption sets one option on EVERY encoder the output opens — its video, audio and subtitle encoders alike (spec 0045 D2). Reserve it for what they genuinely share, such as "threads" or "flags"; an option only one of them has fails the job when it reaches the others. For one kind, use VideoOption, AudioOption or SubtitleOption.

These are libav AVOption names, not ffmpeg command-line flags: the CLI's "-b:v 300k" is EncoderOption("b", "300k") or VideoOption("b", "300k") here, because the CLI parses the ":v" suffix itself and libav never sees it.

func End added in v0.5.0

func End(sec float64) OutputOption

End stops the output at position sec (-to). Mutually exclusive with Duration; an absolute source position under CopyTS, an output position otherwise.

func FormatOption added in v0.5.0

func FormatOption(key, value string) OutputOption

FormatOption sets one muxer option on an output (spec 0015) — segment timing/ naming, fragmentation flags, etc.; e.g. FormatOption("hls_time", "4"). Distinct from WithOption, which sets an encoder option.

func Map

func Map(label string) OutputOption

Map adds a graph output pad / stream specifier to mux (e.g. Map("[vout]")).

func OutputFormat

func OutputFormat(name string) OutputOption

OutputFormat forces the muxer by name (e.g. "hls", "dash", "segment", "mpegts") when the path extension doesn't imply it (spec 0015).

func SubtitleOption added in v0.16.0

func SubtitleOption(key, value string) OutputOption

SubtitleOption sets one option on the output's subtitle encoder only. It overrides EncoderOption on the same key.

func VideoCodec

func VideoCodec(codec string) OutputOption

VideoCodec sets an output's video encoder (e.g. "libx264").

func VideoOption added in v0.16.0

func VideoOption(key, value string) OutputOption

VideoOption sets one option on the output's video encoder only (spec 0045 D1) — e.g. VideoOption("crf", "23"). It overrides EncoderOption on the same key.

type OutputResult added in v0.9.0

type OutputResult struct {
	Path      string         `json:"path"`
	Segmented bool           `json:"segmented,omitempty"`
	Streams   []OutputStream `json:"streams"`
}

OutputResult is one muxed output: its Path, whether it Segmented into a set of files (an hls/dash/segment muxer — Path is then the playlist/manifest), and the streams the engine wrote.

type OutputStream added in v0.9.0

type OutputStream struct {
	Type        string `json:"type"`
	Codec       string `json:"codec"`
	Disposition string `json:"disposition,omitempty"`
}

OutputStream is one written stream: its media Type and Codec, and Disposition "copy" for a stream-copied (remuxed) stream.

type Probe

type Probe struct {
	Format      string
	DurationSec float64
	StartSec    float64 // the container's start time (nonzero e.g. after a copy_ts trim)
	Streams     []ProbeStream

	// Tags is the container-level metadata (spec 0020) — title/artist/…
	Tags map[string]string
	// Chapters is the container's chapter list (spec 0020).
	Chapters []Chapter
}

Probe describes a media input: its container format, duration, start offset, and streams.

type ProbeStream added in v0.4.0

type ProbeStream struct {
	Index      int    `json:"index"`
	Type       string `json:"type"` // "video" or "audio"
	Codec      string `json:"codec"`
	Width      int    `json:"width"`       // video
	Height     int    `json:"height"`      // video
	SampleRate int    `json:"sample_rate"` // audio
	Channels   int    `json:"channels"`    // audio

	// Metadata (spec 0020): the stream's language, its set disposition flags
	// (default/forced/attached_pic/…), and its tags.
	Language    string            `json:"language"`
	Disposition []string          `json:"disposition"`
	Tags        map[string]string `json:"tags"`
}

ProbeStream is one stream within a probed input.

type ProcessResult added in v0.9.0

type ProcessResult struct {
	Outputs  []OutputResult `json:"outputs"`
	Analysis []Measurement  `json:"analysis,omitempty"`
}

ProcessResult is the structured result of a process job (Run / RunJob), parsed from Result.Stdout. Outputs describes each muxed output the engine produced; Analysis carries any measurements analysis filters emitted (spec 0017 §Q).

func ParseResult added in v0.9.0

func ParseResult(res Result) (ProcessResult, error)

ParseResult decodes the structured process result from a Run / RunJob Result. An empty Stdout (or a non-process op) yields a zero ProcessResult, not an error. (A non-zero Result.ExitCode means the engine failed — check that first; the engine emits this result JSON only on success.)

type Profile added in v0.7.0

type Profile string

Profile selects a release's capability profile (spec 0022): lean (the default, web-delivery essentials), intermediate (lean + every practical software codec/filter), or full (intermediate + the heavy native-only encoders x265/HEVC and SVT-AV1). A profile is a distinct, separately-signed asset published in the same release; the trust chain is identical. lean and intermediate exist as both WASM modules and native drivers; full is native-only (0022 §4 — the heavy encoders need threads/SIMD), so it is selectable only via native.NewFromRelease.

const (
	// ProfileLean is the default: web-delivery essentials at the smallest size,
	// published as ffmpeg-wasi-<variant>.wasm.
	ProfileLean Profile = "lean"
	// ProfileIntermediate is lean + every practical software codec/format/filter
	// (no hardware, no heavy encoders), published as
	// ffmpeg-wasi-intermediate-<variant>.wasm.
	ProfileIntermediate Profile = "intermediate"
	// ProfileFull is intermediate + the heavy native-only encoders (x265/HEVC in
	// the gpl variant, SVT-AV1 in both; spec 0023). Native only — there is no WASM
	// full module; select it through native.NewFromRelease.
	ProfileFull Profile = "full"
)

func ResolveReleaseProfile added in v0.8.0

func ResolveReleaseProfile(opts ...ReleaseOption) (Profile, error)

ResolveReleaseProfile applies the given release options and reports the selected capability profile, defaulting to ProfileLean. It lets a caller that must build a profile-dependent asset name outside this package — the native backend's driver filename (spec 0028) — honour WithReleaseProfile exactly as WithModuleRelease does, instead of re-implementing the option plumbing. An unknown profile is a typed error, matching WithModuleRelease's validation.

type Progress added in v0.10.0

type Progress struct {
	// Fraction is completion in [0,1], or -1 when it cannot be determined — a
	// purely generative input with no source file and no engine duration, the
	// startup window before the engine's first record (spec 0034, D1), or inputs
	// fully consumed while the job is still encoding (D3). It never decreases
	// across an invocation, even when a demuxer seeks backwards.
	//
	// Fraction == 1 is not a completion signal: use the invocation's return. A
	// job whose inputs are small relative to its output exhausts them long before
	// it finishes, and reports -1 for that tail rather than a premature 1.
	Fraction float64

	// Source says how Fraction was derived, so a caller can decide how far to
	// trust it (spec 0034, D4). SourceUnknown exactly when Fraction is -1.
	Source FractionSource

	Elapsed     time.Duration // since the invocation began
	InputBytes  int64         // bytes read from inputs so far
	InputTotal  int64         // total size of the inputs being read, 0 if unknown
	OutputBytes int64         // bytes written to outputs so far (observed at the fs bridge)

	// Populated once a phase-B engine record has arrived (zero before then, and
	// for a pre-v9 engine that emits nothing):
	Frame   int64         // frames processed
	OutTime time.Duration // media timestamp reached
	Speed   float64       // ×realtime encode speed (host-derived: OutTime/Elapsed)
}

Progress is one best-effort progress sample for an in-flight invocation (spec 0031). It is emitted while Run/RunJob/Frames execute, to a channel the caller attaches with WithProgress.

Phase A derives progress from the bytes flowing through the filesystem bridge: afmpeg implements the fs the engine reads and writes, so it can watch input consumed and output produced without any engine cooperation. Fraction comes from input read position (bytes_read / input_size), which tracks completion closely for linear demuxers.

Phase B (spec 0032) refines this from the engine itself: a v9+ engine streams NDJSON progress records over the /dev/afmpeg-progress device, which fill Frame/OutTime/Speed and — when the engine also reports the media duration — derive Fraction from out_time/duration (accurate even for a generative input with no source file). When no engine record has arrived (early startup, or an engine that reports no duration) the byte-observed values remain the fallback.

Spec 0034 settles which source wins when both are available: the engine's is authoritative, and Fraction reports -1 rather than a byte ratio the engine is about to contradict. Source says which one produced the value.

type Provenance added in v0.5.0

type Provenance struct {
	FFmpegVersion  string                       `json:"ffmpeg_version"`
	BuildTag       string                       `json:"build_tag"`
	Commit         string                       `json:"commit"`
	Variants       map[string]ProvenanceVariant `json:"variants"`
	ToolingLicense string                       `json:"tooling_license"`
}

Provenance mirrors the subset of ffmpeg-wasi's provenance.json that afmpeg surfaces and asserts on a certified release.

func FetchReleaseAsset added in v0.8.0

func FetchReleaseAsset(ctx context.Context, tag, assetFile, provKey string, opts ...ReleaseOption) ([]byte, Provenance, error)

FetchReleaseAsset fetches and verifies a single named asset from an ffmpeg-wasi release — the identical trust chain as WithModuleRelease: the KMS/OpenPGP signature over checksums.txt against afmpeg's pinned keys (with the WKD cross-check online), the asset's checksum, and that provenance names it under provKey. It returns the verified bytes and the release provenance.

This is the general primitive behind acquiring any signed release artifact; it exists so the opt-in native backend (pkg/afmpeg/native) can fetch a certified native driver (spec 0028 D-0028-D) through the same trust root. Most consumers use WithModuleRelease (for the .wasm) or native.NewFromRelease (for the driver) rather than calling this directly. The ReleaseOptions (WithReleaseBaseURL, WithReleaseBundleDir, WithReleaseCacheDir, WithReleaseHTTPClient, WithReleaseWKDEmail, WithReleaseProvenance) all apply.

type ProvenanceVariant added in v0.5.0

type ProvenanceVariant struct {
	File       string `json:"file"`
	License    string `json:"license"`
	H264Encode string `json:"h264_encode"`
	// Profile is the capability class ("lean"/"intermediate"); empty for pre-0022
	// releases that predate the field.
	Profile string `json:"profile,omitempty"`
}

ProvenanceVariant is one variant's record in the provenance manifest.

type ReleaseOption added in v0.5.0

type ReleaseOption func(*releaseConfig)

ReleaseOption configures WithModuleRelease.

func WithReleaseBaseURL added in v0.5.0

func WithReleaseBaseURL(url string) ReleaseOption

WithReleaseBaseURL fetches the release from an alternate base (a mirror or an internal artifact store). The signature is still verified against the pinned key, so the source is untrusted — only the bytes' authenticity matters.

func WithReleaseBundleDir added in v0.5.0

func WithReleaseBundleDir(dir string) ReleaseOption

WithReleaseBundleDir verifies a release from a local directory of pre-fetched assets (the module, checksums.txt, checksums.txt.sig, provenance.json) — for air-gapped use. Verification is identical and still mandatory (D-0010-G); only the fetch is replaced.

func WithReleaseCacheDir added in v0.5.0

func WithReleaseCacheDir(dir string) ReleaseOption

WithReleaseCacheDir overrides where the verified module is cached.

func WithReleaseHTTPClient added in v0.5.0

func WithReleaseHTTPClient(client *http.Client) ReleaseOption

WithReleaseHTTPClient overrides the HTTP client used to fetch the release (and, when the WKD cross-check is enabled, to fetch the WKD key).

func WithReleaseProfile added in v0.7.0

func WithReleaseProfile(profile Profile) ReleaseOption

WithReleaseProfile selects the capability profile to load: ProfileLean (the default — web-delivery essentials) or ProfileIntermediate (lean + every practical software codec/filter, spec 0022). The intermediate module is a distinct, separately-signed asset (ffmpeg-wasi-intermediate-<variant>.wasm) verified through the same trust chain — this is the certified equivalent of reaching for the intermediate build with WithModuleURL. ProfileFull is native-only (the heavy HEVC/AV1 encoders); WithModuleRelease rejects it — load it with native.NewFromRelease instead.

func WithReleaseProvenance added in v0.5.0

func WithReleaseProvenance(into *Provenance) ReleaseOption

WithReleaseProvenance writes the verified provenance of the loaded release into into — so a consumer can log or assert exactly what it loaded.

func WithReleaseWKDEmail added in v0.5.0

func WithReleaseWKDEmail(email string) ReleaseOption

WithReleaseWKDEmail overrides the Web Key Directory identity afmpeg cross-checks its embedded signing key against (spec 0011). The default (ffmpeg-wasi-release@phpboyscout.uk) is correct for canonical releases; override it for a mirror that publishes its own WKD, or pass "" to disable the cross-check entirely (verification still happens against the pinned embedded key — the cross-check is a second, independent anchor, not the trust root).

type Result

type Result struct {
	ExitCode int
	Stdout   string
	Stderr   string
}

Result is the outcome of a Run: the exit code and the module's captured stdout and stderr. A non-zero ExitCode is reported here with a nil error; only host-side failures (module instantiation, the vfs bridge, context cancellation) return an error. The ffmpeg-wasi engine returns its structured results (process status, probe info) as JSON on Stdout.

type Runtime

type Runtime struct {
	// contains filtered or unexported fields
}

Runtime drives an engine backend behind a stable API. Build it once with New — compiling the wasm module (the default backend) is the expensive step — and reuse it. Run serialises invocations: one at a time per Runtime (spec 0004 D-0004-B).

func New

func New(ctx context.Context, opts ...Option) (*Runtime, error)

New returns a reusable Runtime. By default it compiles the configured wasm module once (exactly one WithModule* option is required); with WithBackend it drives the supplied backend instead and compiles nothing.

func (*Runtime) Close

func (r *Runtime) Close(ctx context.Context) error

Close releases the runtime's resources. It waits for any in-flight invocation to finish first (respecting ctx) so a running job is never yanked out from under itself, then marks the runtime closed — a subsequent Run fails cleanly.

func (*Runtime) Frames added in v0.6.0

func (r *Runtime) Frames(ctx context.Context, fs afero.Fs, job FrameJob) (FramesResult, error)

Frames runs a frame-extraction job over the fs bridge and parses the engine's per-frame result JSON — the third op beside Probe and RunJob (spec 0021).

func (*Runtime) Probe

func (r *Runtime) Probe(ctx context.Context, fs afero.Fs, path string) (Probe, error)

Probe reports a media file's container/stream info over the fs bridge, via the ffmpeg-wasi engine's probe op (`{"op":"probe"}`), reading the structured JSON it returns on stdout. It needs the ffmpeg-wasi engine (the structured module). For a raw/headerless input that only opens with a forced demuxer or demuxer options, use ProbeInput.

func (*Runtime) ProbeInput added in v0.6.0

func (r *Runtime) ProbeInput(ctx context.Context, fs afero.Fs, input Input) (Probe, error)

ProbeInput probes one Input, forwarding its Format (forced demuxer) and Options (demuxer dictionary) — so a rawvideo/PCM input, probeable only with those (spec 0024), works through the typed API just as it does for a process job.

func (*Runtime) Run

func (r *Runtime) Run(ctx context.Context, fs afero.Fs, args ...string) (Result, error)

Run executes one ffmpeg invocation with its filesystem bridged to fs (paths in args resolve against fs, e.g. "in/clip.mp4", "out/reel.mp4"). It returns the exit code and captured stderr; a non-zero exit is reported in Result with a nil error. Only host-side failures return a non-nil error.

func (*Runtime) RunJob added in v0.3.0

func (r *Runtime) RunJob(ctx context.Context, fs afero.Fs, c Command) (Result, error)

RunJob renders c as a job spec and runs it over the fs bridge — sugar for Run with the rendered spec. Structured results (process status, probe info) come back on Result.Stdout.

type Seek added in v0.5.0

type Seek struct {
	Start float64 // seconds
	Mode  string  // SeekFast (default when empty) or SeekAccurate
}

Seek is an input's start window (mirrors ffmpeg's -ss).

type StreamMeta added in v0.6.0

type StreamMeta struct {
	Language    string            `json:"language,omitempty"`
	Disposition []string          `json:"disposition,omitempty"`
	Tags        map[string]string `json:"tags,omitempty"`
}

StreamMeta is per-output-stream metadata (spec 0020): a language tag, a set of disposition flag names (e.g. "default", "forced", "attached_pic"), and arbitrary tags. Applied to the output stream before the header is written.

type Variant added in v0.5.0

type Variant string

Variant selects which licence build of the ffmpeg-wasi engine to load (spec 0010 D-0010-H).

const (
	// VariantLGPL is the default, proprietary-compatible build (H.264 via openh264).
	VariantLGPL Variant = "lgpl"
	// VariantGPL adds libx264 and is GPL-licensed.
	VariantGPL Variant = "gpl"
)

Directories

Path Synopsis
Package native runs media jobs through a native ffmpeg-wasi driver subprocess (spec 0028 Backend B) instead of the sandboxed wasm module — the opt-in escape hatch for hardware acceleration and native-speed encode.
Package native runs media jobs through a native ffmpeg-wasi driver subprocess (spec 0028 Backend B) instead of the sandboxed wasm module — the opt-in escape hatch for hardware acceleration and native-speed encode.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL