Skip to content

ffmpeg 9: network, hardware decoding, codecs — and two shipping builds with no x86 assembly - #30

Open
jcelerier wants to merge 15 commits into
masterfrom
feature/ffmpeg-more
Open

ffmpeg 9: network, hardware decoding, codecs — and two shipping builds with no x86 assembly#30
jcelerier wants to merge 15 commits into
masterfrom
feature/ffmpeg-more

Conversation

@jcelerier

Copy link
Copy Markdown
Member

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

Networkudp udplite tcp tls dtls rtp srtp rtsp rtmp/rtmps https srt,
plus the whip muxer (WebRTC egress). WHIP is native in ffmpeg 9 and needs
only a TLS backend, so no libdatachannel or libsrtp. There is no WHEP
demuxer
in ffmpeg (checked 9.0 and master), so WebRTC ingest is not
available this way — GStreamer's whepsrc remains 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, so EXTRALIBS stays empty and the
produced binaries have exactly the same ldd / import table as before —
verified on Linux and Windows. vaapi and Intel libvpl are deliberately
absent: 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 Vulkan
compute 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 --arch value ffmpeg's configure does not recognise,
which makes it fall through to arch=unknown and silently disable ARCH_X86
and HAVE_X86ASM:

platform flag effect
Linux x86_64 --arch=x86-64-v3 all x86 assembly disabled
macOS x86_64h --arch=x86_64h 2514 asm symbols in the x86_64 slice, 0 in x86_64h

macOS 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.mak for HAVE_X86ASM=yes and fail the build
rather than let it regress quietly again.

Structure

Flags are layered 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>      ISA-dependent flags

so changing a codec is one file, not three. common/build-media-deps.sh holds
every recipe and installs into one prefix with .pc files — deliberately not
into 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.org is x264's only
    upstream 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:
    • ARM port. Upstream's CMake is unconditionally x86 (enable_language(ASM_NASM)
      • -DARCH_X86_64=1) so it cannot configure on aarch64, even though the C
        sources 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.
    • LTO off by default. -flto made every archive member LLVM bitcode, and
      ld 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:

leg machine notes
Linux x86_64 almalinux container HAVE_X86ASM, CONFIG_SAND, 18 Vulkan filters, ProRes GPU decode
Linux aarch64 Arch ARM board CONFIG_SAND, V4L2_REQUEST, HEVC_V4L2REQUEST_HWACCEL, 9 v4l2 decoders
macOS arm64 macmini-m1 clean prefix, WHIP via openssl, VideoToolbox
macOS x86_64 macmini-x64 thin x86_64 links as both slices, 2621 asm symbols
Windows x86_64 desktop-u6umokq import table clean: no vulkan-1/amfrt64/nvcuda/libcrypto
WASM emsdk 5.0.5 builds clean

Windows arm64 is not covered — it is not in the CI matrix.

Downstream: score needs no CMake change. ffmpeg emits everything into
Libs: rather than Libs.private:, so its existing pkg_check_modules picks
up the whole set and pkg-config --exists --print-errors is clean across all
seven modules.

Before merging

  • The core hash rotates on all three platforms. build-all.sh, all.sh,
    deps.sh, Dockerfile.centos and qtfeatures are all core-hash inputs, so
    the next run does full LLVM+Qt core rebuilds. One-time, but hours.
  • -system-webp is not yet proven end-to-end. qtimageformats compiles its
    bundled libwebp straight into QWebpPlugin unless this is set, which would
    put 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.
  • macOS x86_64 is now thin. Qt, llvm-libs and score keep their x86_64h
    slices; only ffmpeg and its codecs are single-arch, which is what lets them
    carry assembly. macOS/common.sh is untouched.

Follow-up, not in this PR

clone-llvm.sh, clone-faust.sh and clone-qt.sh share a bug class fixed here
three times (_md_clone, clone-openssl.sh, clone-ffmpeg.sh): they guard a
multi-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.sh is the one worth fixing — an unpatched LLVM means score's JIT
fails at runtime, not at build time. clone-fftw.sh also tests -d on a
tarball, so it re-downloads fftw on every build.

Jean-Michael Celerier 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ffmpeg: build some codecs

1 participant