afmpeg

module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jun 28, 2026 License: MIT

README

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: design approved, implementation not started. This repo holds the design + requirements. The thesis is docs/development/specs/0001-afmpeg.md (the source of truth); the five gating decisions in its §10 are resolved, and the work is decomposed into component specs 0002–0006. Read those before implementing.

Why this exists

It was extracted from a need in keryx (the content-marketing tool): 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). keryx's spike (keryx/docs/development/spikes/ffmpeg-render-binding.md) evaluated the existing options and found none viable:

  • purego/dlopen bindings (e.g. ffgo) — immature, and still need host libav libs.
  • CGO libav bindings (e.g. go-astiav) — mature and in-memory-capable, but CGO breaks a clean static cross-compile.
  • wazero + embedded ffmpeg.wasm (e.g. go-ffmpreg) — the right posture (pure Go, no host deps, embeddable), but the stock builds lack the filters/codecs many workflows need (e.g. xfade, AAC) and aren't filesystem-virtualised.

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 — so a consumer (keryx, or anyone) can transcode / filter / mux entirely in memory, pure Go.

Until afmpeg is usable, keryx renders local-filesystem-only (in-memory render locked out). 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 down to only the codecs/filters real workflows need. Shipped as a separate downloadable artifact, never //go:embed-ed (see Licensing below).
  2. The afero ↔ wazero vfs bridge (the heart) — the guest ffmpeg's WASI filesystem syscalls are routed to a mounted experimental/sys.FS that afmpeg implements backed by an afero.Fs. The guest's reads and writes hit the caller's filesystem (e.g. an in-memory MemMapFs) with no host disk touched.
  3. The Go API — compile the module once into a reusable Runtime, then Run an ffmpeg invocation with its I/O bridged to a caller-supplied afero.Fs. A general, use-case-agnostic command builder layers on top (spec 0005).
rt, _ := afmpeg.New(ctx, afmpeg.WithModuleFile("ffmpeg.wasm")) // compile once, reuse
defer rt.Close(ctx)

fs := afero.NewMemMapFs()            // or the caller's in-memory worktree
// ... write inputs into fs ...
res, _ := rt.Run(ctx, fs, "-i", "in/clip.mp4", /* … */, "out/reel.mp4")
out, _ := afero.ReadFile(fs, "out/reel.mp4")   // the result, in memory

The signatures above are the intended shape (spec 0004), not yet implemented.

Licensing

The Go package is permissively licensed. FFmpeg + x264 is GPL, so the full/GPL ffmpeg.wasm is distributed as a separate downloadable artifact rather than embedded — the copyleft obligation attaches only to a consumer who fetches and bundles it, not to the library. An LGPL/openh264 variant is tracked for fully-permissive consumers. x264 is the single GPL component in the target render set; AAC, xfade, the mp4 muxer, and the audio filters are all already LGPL-clean. See spec 0001 §10 (D-C).

Roadmap

Spec Scope
0001 The thesis: design, requirements, the resolved decision record (§10)
0002 The reproducible FFmpeg → wasm32-wasi build pipeline + licence variants
0003 The afero.Fs → wazero sys.FS adapter (the core)
0004 New / Run / Probe / Close — the public API
0005 General, use-case-agnostic ffmpeg command builder (a consumer's reel is built on it)
0006 Deferred: LGPL build-out, perf (wasm-threads), native backend, CLI

Directories

Path Synopsis
internal
vfs
Package vfs bridges an afero.Fs to wazero's experimental/sys.FS so a WebAssembly guest's WASI filesystem syscalls (path_open, fd_read, fd_write, fd_seek, …) read and write the caller's afero filesystem — including a fully in-memory MemMapFs — with no host disk access.
Package vfs bridges an afero.Fs to wazero's experimental/sys.FS so a WebAssembly guest's WASI filesystem syscalls (path_open, fd_read, fd_write, fd_seek, …) read and write the caller's afero filesystem — including a fully in-memory MemMapFs — with no host disk access.
pkg
afmpeg
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.
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.

Jump to

Keyboard shortcuts

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