Skip to content

Worked examples

Mattias Carlsson edited this page Sep 3, 2026 · 1 revision

Worked examples

Goal-shaped recipes: pick the row that matches what you are trying to get, and follow it end to end.

For the flags themselves — every option, every accepted value — see Documentation/usage.md, which is the reference. This page is the part a reference cannot be: sequences, with the reasoning and the checks in between.

Every example assumes you are in the mediaforge/ directory.


I just want a working ffmpeg

./mediaforge.sh build
./mediaforge.sh install

build compiles free codecs only — no GPL, no non-free — into workspace/, touching nothing outside the checkout. install then offers an interactive prefix menu.

Choose an isolated prefix. ~/.local/mediaforge rather than ~/.local directly: mediaforge installs ~1500 files, and an isolated subdirectory is the difference between an uninstall that leaves the tree pristine and one that has to guess which files were yours.

Do not wrap install in sudo for a prefix you own. The installer elevates itself when the prefix needs it. Running the whole thing as root into ~/.local/… leaves root-owned files in your home directory, and there is no chown-on-finish step by design.

# Right — installer elevates only if the prefix needs it
./mediaforge.sh install --prefix=/opt/ffmpeg

# Wrong — leaves root-owned files in your home
sudo ./mediaforge.sh install --prefix=$HOME/.local/mediaforge

Confirm what you got:

~/.local/mediaforge/bin/ffmpeg -version

I want the codecs everyone actually uses

x264 and x265 are GPL, so they need the licence tier raised:

./mediaforge.sh build --enable-gpl

That adds x264, x265, xvidcore and vid.stab. If you also want Fraunhofer AAC:

./mediaforge.sh build --enable-nonfree

--enable-nonfree implies GPL, and it also implies --aac=fdk_aac unless you name an AAC encoder yourself on the same command line — see Choosing implementations. The resulting binary is not redistributable. That is the trade you are making; for a local encoder it is usually the right one.

First time through, you will be prompted once per mutex group. Those answers are stored and you will not be asked again--clean-choices resets them.


I want to debug something inside libavcodec

./mediaforge.sh build --debug=symbols
./mediaforge.sh install

symbols is the level to reach for first: -O2 -g3, assertions off, no measurable runtime cost. It is what distributions ship as debuginfo, and the only level that stays behaviourally identical to a release build — balanced and full enable assertions, which can change behaviour while you are trying to observe it.

Verify you can actually step:

gdb --batch -ex 'break av_packet_alloc' -ex 'info breakpoints' \
    ~/.local/mediaforge/bin/ffmpeg

A breakpoint resolving to libavcodec/packet.c means it works.

Then do not run clean. The debug information lives in .dwo files under packages/, not in the prefix you installed. Deleting that tree leaves you with binaries that still run and a debugger that silently stops resolving source. Full story, including the exact failure message: Debug builds and split DWARF.

Reach for --debug=full (-O0) only when optimization is actively obstructing you — variables optimized away, inlined frames — and accept 4-5x slower encodes in exchange.


I want a single binary I can copy to another machine

./mediaforge.sh build --enable-nonfree --enable-static

Linux only. This needs static versions of every system library the codecs depend on, and most distributions do not ship them.

On Arch, the official packages carry no .a files at all, so this fails at the link step until you rebuild the handful you need with staticlibs in the PKGBUILD options=() array. On Debian and Ubuntu the -dev packages usually include both .so and .a, so it tends to work out of the box. BUILDING.md has the per-distribution detail and the list of libraries involved.

If you do not need true portability, drop --enable-static — a normal build is self-contained apart from system libraries you already have.

Note that this is orthogonal to --debug: a static and debug build is possible and produces very large intermediates, since the split .dwo files reduce what the linker reads but the final binary still carries what it links.


I want to match a specific FFmpeg release

./mediaforge.sh list-profiles
./mediaforge.sh build --profile=7.1

A profile pins every dependency to a version known good against that FFmpeg release, so you are reproducing a combination rather than assembling a new one. Profiles live in profiles/*.conf.

Without --profile no profile is loaded at all — each recipe uses its own built-in version, which currently amounts to the same set as the 8.0.1 profile. That distinction matters when you are chasing a version difference: an unflagged build is not "the 8.0.1 profile", it is the built-ins that happen to agree with it today.

A profile can also set a group's default (*_DEFAULT), which sits below your CLI flags and below stored choices in the ladder — so a profile never overrides a choice you made.

Switching profiles on an existing tree leaves stale artifacts behind. Pair it with a rebuild of what drifted:

./mediaforge.sh build --profile=6.1 --rebuild-outdated

One package failed and I want to retry just that one

Builds are tracked by stamp files. Remove the stamp and the next build redoes that package and nothing else:

ls workspace/.stamps/
rm workspace/.stamps/<package>-*
./mediaforge.sh build --enable-nonfree     # same flags as the original build

Pass the same flags as the original build. The stored choices cover the mutex groups, but the licence tier is not stored — a bare build after an --enable-nonfree build will resolve differently.

Failed builds leave logs in workspace/.logs/; successful ones clean up after themselves, so anything still there is a failure worth reading. For a configure-time link failure, packages/<pkg>/ffbuild/config.log usually names the missing library directly.

If the tree is confused enough that per-package retry is not helping:

./mediaforge.sh clean          # build tree + unpacked sources, keeps downloads
./mediaforge.sh build --enable-nonfree

clean deliberately keeps the verified tarballs and git clones — re-downloading and re-verifying ~110 archives to fix a build problem is rarely what you want. clean --all removes those too.


I want to check the tree before I trust it

./mediaforge.sh reconcile          # do the stamps still match the workspace?
./mediaforge.sh check-shadowers    # is anything shadowing system pkgconfig?
./mediaforge.sh check-updates      # has upstream moved past our pins?

reconcile exits 1 if a stamp has lost the artifacts it vouches for — the signal that a build claims to have produced something the workspace no longer contains. --prune drops those stamps so the next build redoes them.

check-updates polls GitHub releases and is rate-limited without a token:

GITHUB_TOKEN=ghp_xxx ./mediaforge.sh check-updates

See also