# Libav.xcframework (B54) Decoders-only, LGPL-only FFmpeg (TrueHD/MLP + DTS) plus the C shim in `shim/`, built as ONE dynamic framework per slice (install name `@rpath/Libav.framework/Libav`). - FFmpeg version: **7.1.2** (https://ffmpeg.org/releases/ffmpeg-7.1.2.tar.xz) - SHA-256: `089bc60fb59d6aecc5d994ff530fd0dcb3ee39aa55867849a2bbc4e555f9c304` (gpg-verified 2026-10-01: `ffmpeg-7.1.2.tar.xz.asc` is a good signature from "FFmpeg release signing key ", key `FCF986EA15E6E293A5644F10B4322F04D67658D8`, imported from https://ffmpeg.org/ffmpeg-devel.asc.) - Licence: LGPL-2.1-or-later (`LICENSE.LGPL-2.1`). `--disable-gpl --disable-nonfree`. ## Configure flags (`CONFIGURE_FLAGS` in `scripts/build-libav.sh`) ``` --disable-everything --disable-gpl --disable-nonfree --disable-autodetect --disable-programs --disable-doc --disable-network --disable-avformat --disable-avdevice --disable-avfilter --disable-swresample --disable-swscale --disable-shared --enable-static --enable-pic --enable-decoder=truehd,mlp,dca ``` Per slice: `--enable-cross-compile --target-os=darwin --arch=aarch64 --cc --sysroot` with `-target`/`-isysroot` extra cflags/ldflags. No extra flags were needed beyond the above. ## Slices (all arm64) and size per Libav.framework | Slice | Target | Size | | --- | --- | --- | | tvos-arm64 | arm64-apple-tvos26.0 | 1.4M | | tvos-arm64-simulator | arm64-apple-tvos26.0-simulator | 1.4M | | ios-arm64 | arm64-apple-ios26.0 | 1.4M | | ios-arm64-simulator | arm64-apple-ios26.0-simulator | 1.4M | | macos-arm64 | arm64-apple-macos14.0 | 1.4M | ## Rebuilding `./scripts/build-libav.sh` from the repo root. If the repo path contains whitespace, FFmpeg's configure cannot build out of tree, so scratch (tarball, source, per-slice builds, `build.log`) goes to `~/Library/Caches/reelhouse-libav` instead of `build/libav/`. The shim in `shim/` is LGPL-2.1-or-later and compiled into the framework, so changing it means rebuilding. ## Shim notes `ls_decode` converts S32 samples with `>> (32 - bits)`, which assumes FFmpeg left-justifies 24-bit samples in 32 bits. Outcome (Task 2's bit-exact check against `ffmpeg -c:a pcm_s24le`): proven bit-exact for TrueHD and DTS-HD MA (S32 is left-justified, so the shift is right for both); DTS core arrives as float and matches FFmpeg's own conversion within 1 LSB. No per-codec exception to the shift was needed. ### Shim hardening and exports (fix round 1) - `ls_decode` returns `LS_ERR_ARG` (-6) on a NULL decoder or out-pointer, zeroes every out-parameter up front, and returns `LS_ERR_FORMAT` for a decoded frame with fewer than 1 or more than 8 channels before writing anything. The capacity argument counts frames; the caller must size `out` for 8 channels per frame (`LibavDecoder` does), which the channel cap makes safe. - The link uses `-Wl,-exported_symbols_list` with a one-line list (`_ls_*`; generated by `scripts/build-libav.sh`), so only the shim API leaves the framework instead of ~1170 `av_*` symbols pulled in by `-all_load`. Verified with `nm -gU` on the tvos-arm64 and macos-arm64 slices: only `_ls_close/_ls_decode/_ls_open/_ls_reset/_ls_version`. - The source tarball is unchanged (same SHA-256 and gpg verification as above).