Skip to content

Build from source

You don't need to build — every release ships both variants across the profiles, as WASM modules and native drivers. But the whole pipeline is MIT and reproducible, so building it yourself is easy.

Prerequisites

  • Docker (the build runs in a wasi-sdk image; nothing is installed on your host).
  • ~2 GB of disk and a few minutes.

Build a variant

docker build -f build/Dockerfile \
  --build-arg VARIANT=lgpl \
  --target artifact -o dist .
docker build -f build/Dockerfile \
  --build-arg VARIANT=gpl \
  --target artifact -o dist .

The module lands at dist/ffmpeg-wasi-<variant>.wasm. To build a different upstream FFmpeg, add --build-arg FFMPEG_VERSION=n8.1.2 (any FFmpeg release tag).

Build the intermediate profile

Add --build-arg PROFILE=intermediate (default lean) to build the full software-codec module — the LGPL encoders, the native codec/container batches, and text/subtitle burn-in:

docker build -f build/Dockerfile \
  --build-arg VARIANT=lgpl --build-arg PROFILE=intermediate \
  --target artifact -o dist .

It lands at dist/ffmpeg-wasi-intermediate-<variant>.wasm — the same asset the release publishes. See variants & profiles.

With just:

just build lgpl              # lean (default)
just build lgpl intermediate # intermediate profile

Build the native driver (Backend B)

The same engine also builds to a native ELF (spec 0028) via build/Dockerfile.native — the subprocess afmpeg's native backend drives for native-speed encode. It takes the same VARIANT/PROFILE args, and adds a third profile, full (native-only): intermediate + AV1 (SVT-AV1, both variants) and HEVC (x265, gpl only).

docker build -f build/Dockerfile.native \
  --build-arg VARIANT=gpl --build-arg PROFILE=full \
  --target artifact -o dist-native .

It lands at dist-native/driver, published as ffmpeg-wasi-driver-linux-amd64-full-gpl. Use PROFILE=lean or intermediate for the lighter native drivers; lgpl full builds AV1 but not HEVC (x265 is GPL). linux/amd64 only for now.

Run it

The repo bundles a tiny wazero harness that loads the module and runs it (it provides the env setjmp/longjmp imports and the WebAssembly feature set the build needs):

go run ./tools/run dist/ffmpeg-wasi-lgpl.wasm
# or: just run lgpl

You'll see the engine's capability report — the FFmpeg version and the available codecs/muxers/filters — confirming it links and runs:

ffmpeg-wasi engine
vocab_version: 9
ffmpeg: n8.1.2
libavcodec 4070502  libavformat 4066406  libavfilter 724582
encoders:
  libopenh264 yes
  libx264     no          # gpl variant only
  mjpeg       yes
  aac         yes
  ...
decoders:
  h264       yes
  ...

The report probes a fixed handful of codecs — libopenh264, libx264, mjpeg, aac, flac and pcm_s16le for encode; h264, hevc, vp9, aac, mp3, opus and flac for decode. It is a build smoke test, not an inventory: for the full set see codecs.

What the build does

Four small scripts under build/, orchestrated by build/Dockerfile:

  1. deps.sh — clones/cross-compiles the external codec libraries into $PREFIX: openh264 (+ libx264 on gpl), and for the intermediate/full profiles Opus/MP3/Vorbis/WebP/VP8-9, freetype/harfbuzz/libass, AV1 decode (libdav1d), and — native full only — x265 / SVT-AV1.
  2. libav.sh — clones FFmpeg, configures it single-threaded for wasm32-wasi (libraries only), and makes the libav* archives.
  3. driver.sh — links the engine (src/driver.c) + the wasi compat shims against those archives into one .wasm command module.
  4. toolchain.sh — the shared wasi-sdk/clang cross-compile environment.

All four branch on TARGET (wasm by default, native for the driver), so one build system produces both artifacts. See The build for what makes it work (single-threaded config, setjmp/longjmp lowering, the POSIX/WASI compat shims) and The native driver for the TARGET=native path.