A cross‑platform CI project that builds portable FFmpeg binaries (and optional ffprobe) with a declarative profile of codecs/features. Works locally and on GitHub Actions; produces zipped artifacts per OS/arch ready to drop into your project.
- Linux: Ubuntu 22.04 (x86_64) — optional aarch64 via Docker/QEMU
- macOS: Apple Silicon (arm64) & Intel (x86_64)
- Windows: MSYS2/MinGW x86_64 (FFplay off by default)
Supports popular codecs via source builds by default:
- x264, x265 (8-, 10- and 12-bit in one library), SVT‑AV1, AOM‑AV1, dav1d (AV1 decode), libvpx (VP8/VP9)
- Opus, LAME (MP3), fdk‑aac (nonfree, opt‑in)
- zimg (zscale: colour space, transfer, tone mapping), libvmaf, libass + drawtext, libsrt
- Easily extendable (OpenH264, libvmaf, libass, etc.)
# Clone
git clone https://github.com/alfg/ffmpeg-builder.git
cd ffmpeg-builder
# Choose a profile (or edit/duplicate it)
cat profiles/default.yml
# Bootstrap toolchain & build deps + FFmpeg into ./out/<triplet>
./scripts/bootstrap-linux.sh # or bootstrap-macos.sh / bootstrap-windows.ps1
PROFILE=profiles/default.yml \
./scripts/build-ffmpeg.sh
# Package artifacts (zip + manifest)
./scripts/package.shArtifacts land in dist/ffmpeg-<version>-<os>-<arch>[-nonfree].zip with:
bin/ffmpeg,bin/ffprobe(andffplayif enabled)LICENSES/for bundled librariesbuild-manifest.jsonandconfigure-flags.txt
FFMPEG_VERSION=7.1ENABLE_X264=0 ENABLE_AOM=1 ...ENABLE_NONFREE=1 ENABLE_FDK_AAC=1PARALLEL=8
This project uses YAML profiles to control how FFmpeg and its third-party codec libraries (“ports”) are built. Profiles let you define:
- Which codecs to enable
- Whether the build is GPL/nonfree
- Which exact versions of libraries to use
- How many parallel jobs to use
- Whether FFmpeg is built static or shared
Profiles live in:
profiles/
minimal.yml
default.yml
full.ymlPROFILE=profiles/default.yml ./scripts/build-ffmpeg.sh
PROFILE=profiles/minimal.yml ./scripts/build-ffmpeg.sh
PROFILE=profiles/full.yml ./scripts/build-ffmpeg.shIf no profile is provided, default.yml is used.
A small, redistribution-safe build with only the essentials.
Recommended for most desktop apps.
Everything enabled, including nonfree fdk-aac (not redistributable).
ffmpeg:
version: 7.1
enable_ffplay: false
gpl: true
nonfree: false
ld_static: true
...Each port script reads its version using:
port_version NAME DEFAULTPrecedence:
- Environment variable
- Profile YAML
- Default fallback
Override example:
PORT_X265_VERSION=3.5 ./scripts/build-ffmpeg.shNonfree builds cannot be redistributed.
A tag push always builds profiles/default.yml — the profile input is only
read on workflow_dispatch — and only the tag path reaches the release job, so
a nonfree artifact cannot be published by the workflow. Dispatch-built nonfree
archives carry a -nonfree suffix and stay attached to the run.
The release archives are FFmpeg built --enable-gpl --enable-version3 and
statically linked against GPL libraries (x264, x265), so they are conveyed
under the GPL v3. Two things satisfy that, both automatic:
collect_licensescopies every linked library's license text intoLICENSES/inside each archive, alongsideconfigure-flags.txt.scripts/source-offer.shrenders the corresponding-source table — component, pinned version, license, upstream URL — from the profile on the tagged tree, and the release job puts it in the release body.
Run it locally to preview what a release will say:
./scripts/source-offer.sh profiles/default.yml- Reproducibility: cache the
./.build-cacheand.ccacheto speed up CI; pin versions by swapping source tarball URLs. - Security: If enabling
fdk-aac, setnonfree: trueand ensure redistribution aligns with license terms. - Extending: Add another script under
scripts/_ports/<lib>.shand append aCONFIG_FLAGS+=(--enable-lib<lib>)inbuild-ffmpeg.sh. - macOS universal: Build once per arch and
lipo -createinto a universal binary if you need a single file. - Linux aarch64: Use Docker + QEMU (
setup-qemu-action) to cross-compile or run onubuntu-24.04-armrunners when available.