ffmpeg 9: network, hardware decoding, codecs — and two shipping builds with no x86 assembly - #30
Open
jcelerier wants to merge 15 commits into
Open
ffmpeg 9: network, hardware decoding, codecs — and two shipping builds with no x86 assembly#30jcelerier wants to merge 15 commits into
jcelerier wants to merge 15 commits into
Conversation
added 15 commits
August 8, 2026 09:54
Every platform's ffmpeg.sh carried its own copy of the flag list, so enabling a codec meant editing three scripts and noticing that the fourth had drifted. Layer them the way qt.sh already consumes common/qtfeatures: common/ffmpeg-features shared by linux/macos/mingw common/ffmpeg-features.<platform> TLS backend, hwaccel, OS bits common/ffmpeg-features.<arch> the few genuinely ISA-dependent flags ffmpeg_features (common/ffmpeg-features.sh) concatenates them and the result is word-split at the configure call, exactly like $(cat qtfeatures). Unlike qtfeatures these files take "#" comments, which is where the reasoning for each flag now lives. wasm deliberately does not layer on the shared file -- it shares almost none of it (no network, no external codecs, no hardware, and payload size is the binding constraint), so ffmpeg-features.wasm is self-contained. common/media-deps-codecs gets the same treatment for the dependency list. .gitignore needed the accompanying "!common/ffmpeg-features.*" rules: the repo ignores "*.*" with an allowlist, so every one of the layered files was invisible to git and CI would have failed with "ffmpeg_features: missing common/ffmpeg-features.linux".
Adds common/build-media-deps.sh, a per-platform media-deps.sh calling it, and
the version pins. Everything installs into ONE prefix with .pc files -- the
sysroot on Linux/MSYS, $INSTALL_PREFIX on macOS -- rather than into ffmpeg's own
prefix, because the planned gstreamer build needs the same codecs and the same
hwaccel headers and should get them by pointing PKG_CONFIG_PATH at one place.
Codecs: dav1d, x264, x265, opus, vpx, webp, snappy, svtjpegxs. Protocol: srt.
Hardware acceleration is headers-only and therefore free: ffnvcodec (NVIDIA),
AMF (AMD) and Vulkan install headers, and ffmpeg dlopen()s libcuda /
libnvcuvid / libnvidia-encode / libamfrt64 / libvulkan at runtime. Measured on
linux-x86_64: EXTRALIBS stays empty and ldd on the result is unchanged. vaapi
and Intel libvpl are deliberately absent -- both are real link-time
dependencies and would break "runs on every machine"; Intel is covered by
Vulkan Video and, on Windows, d3d11va/d3d12va.
macOS/openssl.sh was a stub. It is real now and runs in the MEDIA stage (so it
does not rotate the expensive macOS core hash): SecureTransport is not in
ffmpeg's dtls_protocol_deps_any, so without a real openssl the whip muxer and
srtp are simply unavailable on mac. libsrt links the same openssl. -arch has to
be baked into $CC there -- Configure reads a bare "arm64" as a second target.
Sourcing notes learned the hard way:
- macOS ships bash 3.2, where ${a[-1]} is "bad array subscript", so _md_clone
takes the ref BEFORE the mirror list;
- x264 must build in-tree (its configure refuses out-of-tree once a config.h
exists) and must NOT be cleaned with make: on MSYS that is the native
C:\gnu\bin\make.exe and it hangs indefinitely on x264's Makefile, so the
generated files are deleted directly;
- dav1d cannot reuse $MESON_COMMON_FLAGS (those are pipewire's options and
meson hard-errors on options a project does not define).
Mirrors: dav1d, libvpx and libwebp now come from GitHub rather than
code.videolan.org / chromium.googlesource.com, and x264/x265/SVT-JPEG-XS from
ossia forks. code.videolan.org -- x264's only upstream -- was unreachable for
hours on 2026-08-08 from two continents, which is enough to take out every
platform's media build at once. _md_clone walks a mirror list and re-points
origin before retrying, so a dep that MOVES repo does not strand the cached
clones the self-hosted runners keep between runs.
common/patches/ffmpeg/0001-rpi.patch is applied on EVERY Linux build, not just
the Pi legs, so the bump was blocked on it. Rebased onto 9.0: the 8.1 patch
still applied except for 5 hunks, all mechanical --
configure 2 -- the --enable-omx/-omx-rpi help lines it
anchored on were removed upstream
libavcodec/v4l2_buffers.c 2 -- 9.0 added an #include and turned a
/* fallthrough */ comment into av_fallthrough
fftools/ffmpeg_dec.c 1 -- video_frame_process() was reindented
The tests/checkasm and tests/ref/fate hunks are dropped rather than rebased:
they only register the rpi_sand asm check with checkasm and fate, neither of
which this SDK builds, so carrying them is pure rebase tax on every bump.
Verified: applies with zero fuzz to a pristine ffmpeg-9.0 tarball, the patched
tree builds clean on linux-x86_64 with the full flag set, and the Pi feature set
still configures (CONFIG_SAND, CONFIG_V4L2_REQUEST, CONFIG_HEVC_V4L2REQUEST_HWACCEL).
clone-ffmpeg.sh falls back to github and then ffmpeg.org when the ossia mirror
has no asset for the pinned version, so a bump is never blocked on someone
uploading a tarball first. ffmpeg-9.0.tar.bz2 has since been uploaded to the
sdk36 release (sha256 ce84a9d0...), so the fast path is live again.
--arch is the ISA family and --cpu the tuning target, and they are not interchangeable. Linux/ffmpeg.sh passed --arch=x86-64-v3, which matches no entry in configure's arch case; arch fell back to "unknown" and configure silently turned off ARCH_X86 and HAVE_X86ASM -- every x86 assembly kernel in libavcodec and libswscale. Every shipped Linux x86_64 build has been decoding in pure C. Now --arch=x86_64 --cpu=x86-64-v3, and the script greps config.mak for HAVE_X86ASM=yes afterwards so this cannot regress quietly again. Network is on for the first time: udp/udplite, tcp, rtp/srtp, rtsp, rtmp, http, hls, and via each platform's TLS backend also tls, dtls, https, rtmps and the whip muxer (WebRTC egress, native in ffmpeg 9 -- no libdatachannel or libsrtp needed). There is no WHEP demuxer in ffmpeg, on 9.0 or master, so WebRTC ingest is not available this way. TLS backend per platform: openssl on Linux (core stage) and macOS (media stage), schannel on Windows. schannel is a system SSP, needs no library shipped, validates against the Windows certificate store, and ffmpeg 9's tls_schannel.c implements DTLS and the SRTP keying-material export -- so whip works there too. Hardware decode/encode, all dlopen- or OS-only: NVIDIA via ffnvcodec, AMD via AMF, everything else via Vulkan Video, plus d3d11va/d3d12va/dxva2 and MediaFoundation on Windows and VideoToolbox on macOS. Sizes, stripped ffmpeg CLI on linux-x86_64: 29.4 MB before, 45.7 MB with the whole set.
ffmpeg 9 does not link glslang or shaderc -- there is no --enable-libglslang.
It probes for a build-time EXECUTABLE (glslc, glslang, glslangValidator) and
compiles its GLSL shaders to .spv during the build, so this costs nothing at
runtime: verified on linux-x86_64 that EXTRALIBS is unchanged and the only
link flag added is -lm.
What the missing spirv_compiler was costing us (all gated on it in configure):
- 18 Vulkan compute filters (scale/overlay/gblur/bwdif/nlmeans/chromaber/...)
- Vulkan hwaccel for prores, prores_raw, ffv1, dpx and apv -- i.e. GPU ProRes
decode, which is squarely in score's wheelhouse
- the ffv1_vulkan and prores_ks_vulkan encoders
- swscale's SPIR-V backend (that one also wants spirv-headers)
Not affected either way: h264/hevc/av1/vp9 Vulkan decode, which is
fixed-function (*_vulkan_hwaccel_deps="vulkan", no spirv_compiler) and already
worked.
Packages exist everywhere -- almalinux 9 appstream (glslang 16.0 +
spirv-headers-devel), homebrew (16.5), and MSYS2 clang64, where glslang was in
fact already installed. The probe is not gated by --disable-autodetect.
These three files are inputs to the core hash, but this change set already
rotates it (build-all.sh / all.sh gained the media-deps step), so it costs no
extra rebuild.
qtimageformats does not link a system libwebp by default -- it compiles
src/3rdparty/libwebp/**.c straight into QWebpPlugin:
qt_internal_extend_target(QWebpPlugin CONDITION QT_FEATURE_system_webp
LIBRARIES WrapWebP::WrapWebP)
qt_internal_extend_target(QWebpPlugin CONDITION NOT QT_FEATURE_system_webp
SOURCES ../../../3rdparty/libwebp/src/dec/...)
Now that we build libwebp for ffmpeg's --enable-libwebp, a statically linked
score would pull the same symbols from two places: QWebpPlugin's copy and ours
via libavcodec. Two versions of libwebp in one binary is an ODR violation, and
the versions are not even the same (Qt's bundled tree vs our 1.6.0).
-system-webp fixes it, but Qt is a CORE-stage build and libwebp was a MEDIA
dep, so the library did not exist yet when qt.sh ran. media-deps.sh now takes an
explicit dep list, and each build_core() calls `./media-deps.sh webp` ahead of
qt.sh. No new discovery plumbing was needed: webp installs both
WebPConfig.cmake and libwebp.pc into a prefix each platform's qt.sh already has
on CMAKE_PREFIX_PATH / PKG_CONFIG_PATH.
libtiff is bundled by qtimageformats the same way, but we do not build one and
ffmpeg decodes TIFF natively, so there is nothing to collide with there.
Found by actually running the media stage on all three platforms rather than
just Linux.
Windows (MSYS), where the shell paths and the native toolchain disagree:
- x264's `make install` copied the archive and then died in llvm-ranlib.exe
with "unable to load '/c/.../libx264.a'": the mingw binaries do not
understand the MSYS form. The autotools recipes now configure with the
native prefix, like cmake already did via MEDIA_DEPS_PREFIX_CMAKE.
- libvpx bakes its source path into the generated Makefile and
build/make/configure.sh canonicalises a relative "." to $(pwd), so an
in-tree build does not dodge it either; mingw32-make then fails with "No
rule to make target '/d/.../libs.mk'". Reach configure through cygpath -m.
- libsrt does an unconditional find_package(OpenSSL). ffmpeg uses schannel on
Windows, so nothing had built one -- MSYS/openssl.sh is now real (it was a
stub with the wrong source dir and no `make install`) and runs in the media
stage for libsrt only. SRT without encryption cannot do passphrase streams,
which is how SRT is actually deployed.
- ffmpeg then still rejected srt: srt.pc has "Requires.private: openssl
libcrypto" and with --pkg-config-flags=--static pkg-config refuses the
package outright unless those resolve, so openssl's prefix has to be on
PKG_CONFIG_PATH even though ffmpeg does not link it.
- vulkan headers now come from our pinned Vulkan-Headers instead of MSYS2's
package. pacman's version floats, ffmpeg 9 needs >= 1.3.277, and a core
built before that package was current fails with "vulkan requested but not
found". It also keeps MSYS2 out of the shipped SDK.
Cross-platform:
- CMAKE_INSTALL_LIBDIR=lib. CMake defaults to lib64 on RedHat-family distros,
which split the prefix (cmake deps in sysroot/lib64, meson/autotools ones in
sysroot/lib) and produced a baffling "opus not found using pkg-config" on
Linux while opus had plainly just been built.
- _md_clone tested only that the directory existed, so a leftover empty or
half-cloned dir made it skip the clone and fail in the checkout with "not a
git repository" -- permanently, on every later run. Routine on Windows,
where rm -rf empties a directory it cannot remove. Test for .git instead.
- build_media_deps now reports a failed recipe explicitly instead of trusting
set -e, which twice let a broken dep through to ffmpeg and turned a clear
failure into "<codec> not found using pkg-config" much later.
clone-openssl.sh guarded on the tarball rather than the extracted tree, so a
source dir removed by hand while the tarball survived was never re-extracted and
the caller died on `cd openssl-3.5.7: No such file or directory`. The
self-hosted runners keep their work dir between runs, so this was a live hazard.
bsdtar rejects -a in extract mode outright on macOS 15 ("Option -a is not
permitted in mode -x"); macOS 26's bsdtar only warns. So this passed on the
arm64 runner (macOS 26) and failed on the Intel one (macOS 15) -- and only
started mattering now, because macOS/openssl.sh used to be a stub and this
clone script had never run on a Mac at all.
The asset is always .tar.gz, so name the decompressor.
NB: common/build-onnxruntime.sh has the same `tar xaf` on an extract path and
runs on the macOS `extra` stage for x86_64; it is untouched here but will fail
the same way on an Intel runner.
… hard dep Two problems, both of which leave a build that looks fine and fails much later. Fetch and patch sat behind one `[[ ! -d ffmpeg-$VERSION ]]`, so anything that interrupted the script between them -- a missing `patch`, a killed job -- left an EXTRACTED BUT UNPATCHED tree that every later run then skipped. The failure surfaces far from the cause, as "Unknown option --enable-sand" out of ffmpeg's configure, and on the aarch64 leg it would quietly cost the whole Raspberry Pi v4l2-request hardware decode path. The runners keep their work dir between runs, so the state was permanent. Gate the patch on a .ossia-prepared marker written only after it succeeds, and make a failed fetch exit rather than fall through. `yum -y install patch` also ran unconditionally on the Linux branch. `patch` is preinstalled nearly everywhere and yum exists only on the almalinux build image, so this made the scripts unrunnable on any other distro -- caught on an Arch aarch64 box with "yum: command not found". Install it only when it is actually missing and yum is actually present.
The rebase onto 9.0 applied with zero rejected hunks, which is exactly why these
slipped through: the patch context around both call sites was unchanged, so
`patch` was perfectly happy. They are compile errors, and only on aarch64 --
x86_64 never passes --enable-v4l2-request, so it never compiles these files and
the earlier "builds clean on linux-x86_64" was true and beside the point.
v4l2_req_hevc_vx.c ff_attach_decode_data() went from (AVFrame *) to
(AVCodecContext *, AVFrame *). avctx is already the
enclosing alloc_frame()'s first parameter.
v4l2_m2m_dec.c AVCodec.pix_fmts no longer exists; decoders declare their
formats with the CODEC_PIXFMTS() macro from
codec_internal.h.
Without these the Raspberry Pi / ARM SBC hardware decode path does not build at
all on the only architecture that uses it.
Verified by configuring linux-x86_64 with the aarch64 feature set forced on
(--enable-sand --enable-v4l2-request --enable-v4l2-m2m --enable-libdrm
--enable-libudev --enable-libv4l2), which is what actually compiles the patched
files: the whole tree builds clean. That check runs in minutes on any x86 box
and is worth repeating on every ffmpeg bump -- the aarch64 legs are the only
ones that would otherwise catch this, and they are the slowest to run.
The Intel leg built ffmpeg twice, as x86_64 and x86_64h, and lipo'd them. But
--arch=x86_64h is not a value ffmpeg's configure knows: it falls through to
arch=unknown and silently disables ARCH_X86 and HAVE_X86ASM. Measured on the
SDK currently installed on macmini-x64 (ffmpeg 8.1, built by CI):
libavcodec.a x86_64 slice: 2514 x86 asm symbols
libavcodec.a x86_64h slice: 0
macOS prefers the x86_64h slice on every Haswell-or-newer Mac, so in practice
Intel Macs have been running ffmpeg with no assembly at all. Same defect as the
--arch=x86-64-v3 one on Linux, and it also explains why the lipo worked: an
asm-free slice is cleanly x86_64h, whereas a slice WITH assembly cannot be,
because nasm does not emit the x86_64h subtype.
So build ffmpeg and the codecs once, as native x86_64. ld accepts a native
Mach-O x86_64 object into an x86_64h link -- cpusubtype is
CPU_SUBTYPE_X86_64_ALL and x86_64 code is valid on x86_64h hardware -- so the
thin libraries serve both slices of a fat consumer. Qt, llvm-libs and score keep
their x86_64h slices; macOS/common.sh is untouched.
The one thing ld cannot bridge is LLVM BITCODE: with -flto each member has to go
to codegen for one exact target, so it is ignored by a link for any other
subtype. SVT-JPEG-XS was the only dependency shipping bitcode (74 of its 76
members) and ossia/SVT-JPEG-XS now turns that off. media-deps.sh checks every
archive for bitcode members and fails with an explanation, because otherwise the
symptom only appears much later, in someone else's x86_64h link.
That LTO detail was the actual cause of every x86_64/x86_64h link failure seen
while developing this; the architecture was never the problem.
Verified on macmini-x64 (Xcode 16.2, ld-1115.7.3): all twelve deps plus ffmpeg
build, libavcodec.a carries 2621 asm symbols, and a consumer links against the
thin libraries as BOTH x86_64 and x86_64h with zero ignored files, producing
binaries of each subtype.
libvpx returns on this leg as a result -- it was only ever dropped because its
configure has no x86_64h target.
sdk.yml builds windows arm64 too (windows-11-arm / CLANGARM64), which I had missed: openssl.sh exited 1 on any non-x86_64 arch, so the media-windows-arm64 job would have failed on a leg that has nothing to do with this change. OpenSSL 3.5 genuinely has no mingw target for Windows-on-ARM -- Configurations/10-main.conf offers mingw and mingw64, both x86, and "mingw64" would configure x86_64 assembly into an ARM build. Its only consumer here is libsrt, so skip openssl there and build SRT with -DENABLE_ENCRYPTION=OFF instead. SRT still works on that arch; passphrase-protected streams do not. ffmpeg's own TLS on Windows is schannel and never involved openssl either way.
Two gaps from issue #26 that are cheap and close real holes. libmp3lame: ffmpeg has NO native MP3 encoder -- `grep -c ff_mp3_encoder allcodecs.c` is 0 -- so score cannot export MP3 at all today. lame is ~1.5 MB of source and builds everywhere. SourceForge is its only home and has no git mirror worth trusting, so the tarball is mirrored on the ossia sdk36 release (sha256 ddfe36cab873...) with SourceForge as fallback. That needed a tarball fetcher; _md_fetch_tar mirrors _md_clone's mirror-list semantics, and names the decompressor rather than using -a, which bsdtar rejects on macOS 15. libxml2: gates ffmpeg's dash and imf demuxers (dash_demuxer_deps="libxml2"). Having just turned network on, not being able to play a DASH stream was an odd hole. Built parser-only -- python, tests, programs, iconv, icu, zlib and lzma all off -- because ffmpeg only needs xmlCheckVersion and the tree/reader API, and leaving zlib/lzma on would put -lz -llzma into libxml-2.0.pc and drag them into ffmpeg's --static pkg-config resolution. Verified on linux-x86_64: both build, ffmpeg reports --enable-libmp3lame and --enable-libxml2, the libmp3lame encoder is present, and the dash and imf demuxers now exist. Nothing else moved -- HAVE_X86ASM, SAND, AMF, VULKAN, FFNVCODEC, SVTJPEGXS, VPX, WEBP, SRT, OPENSSL, WHIP, X264, X265, DAV1D, OPUS, SNAPPY all still enabled.
ffmpeg only probes for a SPIR-V compiler inside `if enabled vulkan`; the else branch is a plain `disable spirv_compiler`. macOS does not enable vulkan -- that would mean shipping MoltenVK, a real runtime dependency, where VideoToolbox already covers Apple hardware -- so the glslang added to macOS/deps.sh in 15f0bb4 was installed on every macOS runner and never invoked. Measured on the two platforms where it does apply, both now confirmed equivalent: linux-x86_64 18 vulkan filters, 5 compute hwaccels, 2 vulkan encoders windows-x86_64 18 vulkan filters, 5 compute hwaccels, 2 vulkan encoders (the hwaccels being prores, prores_raw, ffv1, dpx and apv -- i.e. GPU ProRes decode). macOS gets none of those, which is a consequence of the MoltenVK decision rather than something to fix here, so it is written down in common/ffmpeg-features.macos next to the flags themselves.
CI's macos-15 runners are Apple Silicon, so the x86_64 leg is a CROSS build.
cmake handles that from CMAKE_OSX_ARCHITECTURES, but meson and autotools do not
-- they probe the HOST machine and configure an arm64 build regardless of the
-arch in $CFLAGS. media-macos-x86_64 failed with dav1d assembling
src/arm/64/cdef.S for x86_64:
<instantiation>:132:9: error: invalid instruction mnemonic 'b.gt'
Not reproducible on macmini-x64, where the same build is native -- which is why
local validation missed it. Reproduced on macmini-arm64 by targeting x86_64,
i.e. the CI configuration.
So when the target arch differs from `uname -m`, generate a meson cross file and
pass --host / --target to the autotools deps (x264, libvpx, lame).
SVT-JPEG-XS needed more than that. Its SIMD sources are C intrinsics whose
-mavx2 / -mavx512vl flags come from check_both_flags_add, which probes the HOST
compiler; cross-compiling to x86_64 from arm64 those probes fail, the flags are
never added, and the AVX files fail with "always_inline function
'_mm256_setzero_si256' requires target feature 'avx'". Auto-detection cannot fix
that -- the target really is x86, it is the host that cannot probe it -- so
ossia/SVT-JPEG-XS now lets -DSVT_JPEGXS_ARCH_X86 override the detection and the
cross build forces the C-only path. That path is bit-exact with the SIMD one
(verified earlier on aarch64), just slower.
Also wipe each cmake dep's build directory before configuring, as dav1d and
libvpx already did. A reused build dir has now caused two separate confusions:
cmake reads CFLAGS from the environment only on the FIRST configure, so a stale
dir silently keeps the previous arch and install prefix.
Verified on macmini-m1 (arm64 host -> x86_64 target, the CI configuration): all
fifteen archives come out x86_64, with zero LLVM bitcode members.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #26.
ffmpeg 8.1 → 9.0, with the codec / protocol / hardware-acceleration set from
that issue, built and verified on every platform the SDK ships.
What this adds
Network —
udp udplite tcp tls dtls rtp srtp rtsp rtmp/rtmps https srt,plus the
whipmuxer (WebRTC egress). WHIP is native in ffmpeg 9 and needsonly a TLS backend, so no
libdatachannelorlibsrtp. There is no WHEPdemuxer in ffmpeg (checked 9.0 and master), so WebRTC ingest is not
available this way — GStreamer's
whepsrcremains the route for that.Hardware decode/encode, at zero portability cost — NVIDIA (ffnvcodec),
AMD (AMF), Vulkan Video, d3d11va/d3d12va/dxva2 + MediaFoundation on Windows,
VideoToolbox on macOS, v4l2-m2m / v4l2-request on ARM. All of these are either
dlopen/LoadLibrary-based or OS APIs, soEXTRALIBSstays empty and theproduced binaries have exactly the same
ldd/ import table as before —verified on Linux and Windows.
vaapiand Intellibvplare deliberatelyabsent: both link for real and would break "runs on every machine". Intel
hardware is covered by Vulkan Video and, on Windows, D3D11/12.
Codecs — dav1d, x264, x265, opus, libvpx, libwebp, snappy (Hap encode) and
JPEG XS on every architecture.
glslang as a build-time tool. ffmpeg 9 does not link glslang; it invokes it
to compile shaders to
.spv, so this is free at runtime and unlocks 18 Vulkancompute filters, GPU ProRes / ProRes RAW / FFV1 / DPX / APV decode, and the
ffv1/prores_ks Vulkan encoders.
Two bugs that were already shipping
Both the same defect — an
--archvalue ffmpeg's configure does not recognise,which makes it fall through to
arch=unknownand silently disableARCH_X86and
HAVE_X86ASM:--arch=x86-64-v3--arch=x86_64hmacOS prefers the x86_64h slice on every Haswell-or-newer Mac, so Intel Macs
have been running ffmpeg with no assembly at all. Both are fixed, and both
ffmpeg.sh scripts now grep
config.makforHAVE_X86ASM=yesand fail the buildrather than let it regress quietly again.
Structure
Flags are layered the way
qt.shalready consumescommon/qtfeatures:so changing a codec is one file, not three.
common/build-media-deps.shholdsevery recipe and installs into one prefix with
.pcfiles — deliberately notinto ffmpeg's prefix, because the planned GStreamer build needs the same codecs
and the same hwaccel headers and should find them in one place.
Upstream forks
ossia/x264,ossia/x265— mirrors.code.videolan.orgis x264's onlyupstream and was unreachable for hours on 2026-08-08 from two continents,
which is enough to take out every platform's media build at once.
ossia/SVT-JPEG-XS— two fixes:enable_language(ASM_NASM)-DARCH_X86_64=1) so it cannot configure on aarch64, even though the Csources already carry the non-x86 fallback. Verified: x86 unit tests still
11997/11997, and given byte-identical input the aarch64 C-only build
produces byte-identical bitstreams to the x86 SIMD build across
yuv420p/422p/444p and 8/10/12-bit, and decodes x86 streams to the same md5.
-fltomade every archive member LLVM bitcode, andld can only consume a bitcode member from a link targeting its exact
architecture — which made the library unusable from a fat macOS binary. This
was the root cause of every x86_64/x86_64h failure hit while developing this;
the architecture itself was never the problem.
Validation
Every leg built end-to-end, not just configured:
HAVE_X86ASM,CONFIG_SAND, 18 Vulkan filters, ProRes GPU decodeCONFIG_SAND,V4L2_REQUEST,HEVC_V4L2REQUEST_HWACCEL, 9 v4l2 decodersvulkan-1/amfrt64/nvcuda/libcryptoWindows arm64 is not covered — it is not in the CI matrix.
Downstream: score needs no CMake change. ffmpeg emits everything into
Libs:rather thanLibs.private:, so its existingpkg_check_modulespicksup the whole set and
pkg-config --exists --print-errorsis clean across allseven modules.
Before merging
build-all.sh,all.sh,deps.sh,Dockerfile.centosandqtfeaturesare all core-hash inputs, sothe next run does full LLVM+Qt core rebuilds. One-time, but hours.
-system-webpis not yet proven end-to-end. qtimageformats compiles itsbundled libwebp straight into
QWebpPluginunless this is set, which wouldput two copies of libwebp in a statically linked score. The option exists and
libwebp is discoverable where Qt looks, but confirming it needs a full static
Qt build — the first real proof will be the next core build.
slices; only ffmpeg and its codecs are single-arch, which is what lets them
carry assembly.
macOS/common.shis untouched.Follow-up, not in this PR
clone-llvm.sh,clone-faust.shandclone-qt.shshare a bug class fixed herethree times (
_md_clone,clone-openssl.sh,clone-ffmpeg.sh): they guard amulti-step preparation behind a test for the first step's output, so an
interrupted run leaves an unpatched tree that every later run silently reuses.
clone-llvm.shis the one worth fixing — an unpatched LLVM means score's JITfails at runtime, not at build time.
clone-fftw.shalso tests-don atarball, so it re-downloads fftw on every build.