-
Notifications
You must be signed in to change notification settings - Fork 0
Choosing implementations
FFmpeg can be built against more than one library for the same job — two H.264 encoders, four TLS backends, three AV1 encoders. mediaforge does not build all of them. Each such job is a mutex group: exactly one implementation wins, and the recipes for the others are disabled for that build.
For the flag syntax and the accepted values, see
Documentation/usage.md.
This page is about how a choice is reached when you did not spell it out, and
why the defaults are what they are.
There are six: TLS, AAC, H.264, H.265, AV1 encoder, and
SPIR-V. Their flags, accepted values and defaults are listed in
Documentation/usage.md
and are not repeated here — that file is checked by the every-flag-is-documented
gate on every push, and a second copy on a wiki nothing checks would be free to
drift from it.
In the source, the built-in defaults live in one place as *_DEFAULT_BUILTIN
variables (lib/resolve.sh:21-26). ./mediaforge.sh --list-pkgs prints every
recipe with its category and mutex group, which is the authoritative answer to
"what is actually in this group".
Two flags look like group selectors and are not:
-
--flite-audio=(none|alsa|pulseaudio|oss|sun, defaultnone) picks a backend inside one recipe rather than between recipes. The FFmpeg filter never invokes flite's audio output, sononedropsau_alsa.ofromlibflite.aand keeps-lasoundout of a static link. -
--openssldir=is a path, not a choice. See the trust store section below.
Six rungs. Each one only fills a choice still unset by the rung above it.
| # | Source | Where |
|---|---|---|
| 1 |
CLI flag — --tls=openssl
|
option parser |
| 2 |
--menu selections |
run_menu, before the resolver |
| 3 | Stored choices from the last successful build |
load_stored_choices, mediaforge.sh:409
|
| 4 | Interactive prompt ("Pick a TLS backend") |
resolve_choices, mediaforge.sh:415
|
| 5 |
Profile default — *_DEFAULT from profiles/*.conf
|
lib/resolve.sh:250-255 |
| 6 |
Built-in default — *_DEFAULT_BUILTIN
|
lib/resolve.sh:21-26 |
The rung that surprises people is 3 above 4. load_stored_choices runs
before resolve_choices and assigns with :=, so a stored value leaves the
variable non-empty and the prompt's [ -z "$TLS_BACKEND" ] test never fires.
Once you have built successfully, you stop being asked. That is deliberate —
a second build of the same tree should not re-interrogate you — but it means a
choice you made once silently governs every later build until you change it.
To get the prompts back:
./mediaforge.sh build --clean-choices # delete $PREFIX/.mediaforge-choices--menu (rung 2) bypasses the store entirely: load_stored_choices returns
early when USE_MENU=true, so the menu always starts from the defaults rather
than from what you picked last time.
$PREFIX/.mediaforge-choices, written by save_stored_choices after a
successful resolve:
# Generated by mediaforge — edit at your own risk; --clean-choices removes this file.
STORED_TLS_BACKEND=gnutls
STORED_AAC_IMPL=native
STORED_H264_IMPL=x264
STORED_H265_IMPL=x265
STORED_AV1_ENC_IMPL=svtav1
STORED_SPIRV_IMPL=glslang
STORED_OPENSSLDIR=''
--dry-run skips both reading and writing it, so a dry run can never change what
your next real build does.
The file is parsed by name, not sourced. It used to be sourced, which made a
stored string and arbitrary code the same thing on the next build; _stored_choice
replaced that with a by-name parser. This is worth knowing if you edit the file by
hand: only the seven STORED_* keys above are read, and the value is taken as the
remainder of the line after the first =.
These are the descriptions the interactive prompts show
(lib/resolve.sh:196-236), which are the authoritative summary of why one option
is the default and what you give up by moving off it.
| Group | Options |
|---|---|
| TLS |
gnutls GnuTLS — free, default · openssl OpenSSL — Apache 2.0 · mbedtls mbedTLS — small footprint · libressl LibreSSL libtls · none no TLS support |
| AAC |
native FFmpeg native AAC (always available) · fdk_aac Fraunhofer FDK-AAC (requires --enable-nonfree) |
| H.264 |
x264 GPL, de-facto standard · openh264 BSD source, MPEG-LA royalties apply
|
| H.265 |
x265 GPL · kvazaar LGPL |
| AV1 |
svtav1 fastest, recommended · rav1e pure Rust · av1 libaom reference encoder, slow
|
| SPIR-V |
glslang Khronos reference, simpler build · shaderc Google wrapper, heavier build |
Two consequences worth pulling out. Choosing x264 or x265 means the build
needs --enable-gpl; choosing fdk_aac means it needs --enable-nonfree and
produces a binary that cannot be redistributed. And rav1e is the reason cargo
appears in the optional requirements — without it that recipe is skipped with a
warning rather than failing the build.
--enable-nonfree implies --aac=fdk_aac unless you picked an AAC encoder
explicitly this run (lib/resolve.sh:245).
This deliberately jumps the ladder. A stored native from a previous free build
would otherwise silently outrank the --enable-nonfree you just typed, and you
would get a nonfree build that had not enabled the one encoder nonfree is usually
for. An explicit --aac=native on the same command line still wins — the check
is against the CLI value captured before the store was consulted, not against the
resolved one.
So the full rule for AAC is: explicit --aac= this run > --enable-nonfree
implication > the ordinary six-rung ladder.
--openssldir=PATH sets the trust store compiled into the openssl and
libressl arms. It must be absolute — the value is baked into the library, so
a relative path would resolve against whatever the linking process's working
directory happened to be.
Unset, resolve_openssldir() probes a candidate list for a directory holding
cert.pem, and falls back to $PREFIX/etc/ssl:
/etc/ssl /etc/pki/tls /usr/local/etc/ssl
/opt/homebrew/etc/ca-certificates /usr/local/etc/ca-certificates
This matters most for --tls=libressl, because libtls has no runtime override
at all — no environment variable reads the trust store path, so the baked-in
value is the only default a user gets. recipes/crypto/libressl.sh stages
LibreSSL's bundled cert.pem on the fallback path and lib/install.sh ships it.
The value is validated hard (_validate_openssldir, lib/resolve.sh): absolute,
no .. segments, and a conservative character allowlist rather than a blocklist
of shell metacharacters. The reason is that this path is both stored in the
choices file and used as an install destination that may be written with sudo.
--enable-lto / --disable-lto opts SVT-AV1 — and any future LTO-aware recipe —
into link-time optimization. It is off by default, and that is not caution for
its own sake: GCC's LTO IR is not forward-compatible across major versions, so an
LTO-baked .a stops linking after a distribution GCC bump. On a rolling release
that is a quarterly breakage of every downstream consumer of the prefix.
--debug forces LTO off at every level regardless, because LTO objects hold
GIMPLE rather than DWARF — an LTO'd debug build has no debug info to speak of.
-
Documentation/usage.md— the full flag reference - Worked examples — these choices in context
-
./mediaforge.sh build --menu— pick interactively instead -
./mediaforge.sh --list-pkgs— every recipe with its category and group