Skip to content

afmpeg

A pure-Go FFmpeg binding that runs on a virtual / in-memory filesystem. No CGO, no host FFmpeg install, no temp files: FFmpeg is embedded as a WebAssembly module and executed via wazero (a zero-dependency, pure-Go WASM runtime), with its I/O bridged to an afero.Fs — so inputs and outputs can live entirely in memory (or any afero backend), and the whole thing cross-compiles to a single static binary.

Status: released

afmpeg runs real FFmpeg over a virtual filesystem today: the vfs bridge, the runtime (New/Run/Probe/Close), the Command builder (JobSpec()/RunJob for the ffmpeg-wasi engine), and WithModuleURL module fetching. Pair it with a released ffmpeg-wasi module to transcode entirely in memory. See the latest afmpeg release; design rationale is in the specs under Development (start with 0001).

Why it exists

It was extracted from a need in keryx: keryx renders short reels by shelling out to the ffmpeg binary, which needs real files on disk — so it can't render an in-memory project (a remote cloned into RAM, no local checkout). Every existing Go option was rejected: purego bindings are immature and still need host libav; CGO bindings break a clean static cross-compile; and the existing wazero/WASM binding lacks the filters and codecs real workflows need. afmpeg is the "wazero + WASM done right" synthesis — a maintained FFmpeg-WASM build with the codecs/filters we need, a first-class afero virtual-filesystem I/O layer, and a clean Go API. Until afmpeg is usable, keryx renders local-filesystem-only; afmpeg reaching usable status is what lifts that lock-out.

How it works

Three layers — the middle one is the novel engineering:

  1. Embedded FFmpeg-WASM module — FFmpeg + x264 compiled to wasm32-wasi, configured to only the codecs/filters needed; shipped as a separate artifact, not embedded.
  2. The afero ↔ wazero vfs bridge (the heart) — routes the guest ffmpeg's WASI filesystem syscalls to a sys.FS backed by the caller's afero.Fs, so reads and writes hit an in-memory filesystem with no host disk touched.
  3. The Go API — compile the module once into a reusable Runtime, then Run an ffmpeg invocation over a supplied afero.Fs; a general command builder layers on top.

See the architecture explainer for the full flow, and the roadmap for how the specs decompose the build.

Where to go next

The Go API reference lives on pkg.go.dev.