#!/usr/bin/env bash set -euo pipefail FFMPEG_VERSION="8.1.2" FFMPEG_SHA256="464beb5e7bf0c311e68b45ae2f04e9cc2af88851abb4082231742a74d97b524c" DEPLOYMENT_TARGET="12.0" HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DEST="${HERE}/ffmpeg" WORK="${KV_FFMPEG_WORKDIR:-$(mktemp -d)}" echo "===================================================" echo " Building LGPL ffmpeg ${FFMPEG_VERSION} (arm64, decode-only)" echo " work : ${WORK}" echo " dest : ${DEST}" echo "===================================================" command -v curl >/dev/null || { echo "ERROR: curl not found"; exit 1; } command -v make >/dev/null || { echo "ERROR: make not found (xcode-select --install)"; exit 1; } TARBALL="${WORK}/ffmpeg-${FFMPEG_VERSION}.tar.xz" SRC="${WORK}/ffmpeg-${FFMPEG_VERSION}" STAGE="${WORK}/stage" echo "[1/5] Fetching source..." if [[ ! -f "$TARBALL" ]]; then curl -sSL -o "$TARBALL" "https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.xz" fi ACTUAL="$(shasum -a 256 "$TARBALL" | awk '{print $1}')" [[ "$ACTUAL" == "$FFMPEG_SHA256" ]] || { echo "ERROR: sha256 mismatch for the ffmpeg tarball" echo " expected $FFMPEG_SHA256" echo " got $ACTUAL" exit 1 } rm -rf "$SRC" "$STAGE" tar -xf "$TARBALL" -C "$WORK" # LGPL only: no --enable-gpl, no --enable-nonfree, no external codec library. Bundling the Homebrew # ffmpeg instead would drag x264/x265 in and relicense the whole app under the GPL. # # The player only ever opens a local file (the timelapse is downloaded to a temp path first), so the # network stack, the protocols and every encoder are compiled out. --install-name-dir=@rpath is what # makes the dylibs relocatable inside Contents/Frameworks instead of hardcoding an absolute path. echo "[2/5] configure..." cd "$SRC" ./configure \ --prefix="$STAGE" \ --arch=arm64 \ --extra-cflags="-mmacosx-version-min=${DEPLOYMENT_TARGET}" \ --extra-ldflags="-mmacosx-version-min=${DEPLOYMENT_TARGET}" \ --install-name-dir="@rpath" \ --enable-shared \ --disable-static \ --enable-pic \ --disable-programs \ --disable-doc \ --disable-autodetect \ --disable-everything \ --disable-avdevice \ --disable-avfilter \ --disable-swresample \ --disable-network \ --disable-gpl \ --disable-nonfree \ --enable-videotoolbox \ --enable-decoder=h264,hevc,mjpeg,mjpegb \ --enable-hwaccel=h264_videotoolbox,hevc_videotoolbox \ --enable-parser=h264,hevc,mjpeg \ --enable-demuxer=mov,matroska,avi,flv,mpegts,h264,hevc,mjpeg,image2 \ --enable-protocol=file \ --enable-bsf=h264_mp4toannexb,hevc_mp4toannexb,extract_extradata echo "[3/5] make..." make -j"$(sysctl -n hw.ncpu)" make install echo "[4/5] Staging into ${DEST}..." rm -rf "$DEST" mkdir -p "${DEST}/include" "${DEST}/lib" cp -R "${STAGE}/include/"* "${DEST}/include/" # `make install` lays out libavcodec.62.28.102.dylib + a libavcodec.62.dylib symlink, but a symlink does # not survive a git checkout on every machine. Copy the real file under its soname instead, which is # also the name dyld looks up at runtime (the install name is @rpath/libavcodec.62.dylib). for f in "${STAGE}/lib/"*.dylib; do [[ -L "$f" ]] && continue cp "$f" "${DEST}/lib/$(basename "$(otool -D "$f" | tail -1)")" done chmod u+w "${DEST}/lib/"*.dylib echo "[5/5] Verifying install names..." FAIL=0 for f in "${DEST}/lib/"*.dylib; do ID="$(otool -D "$f" | tail -1)" [[ "$ID" == @rpath/* ]] || { echo " BAD id: $f -> $ID"; FAIL=1; } while read -r dep; do case "$dep" in /usr/lib/*|/System/*|@rpath/*) ;; *) echo " BAD dep in $(basename "$f"): $dep"; FAIL=1 ;; esac done < <(otool -L "$f" | tail -n +2 | awk '{print $1}') done [[ "$FAIL" -eq 0 ]] || { echo "ERROR: absolute paths left in the dylibs"; exit 1; } echo "" echo "Done. Vendored:" ls -lh "${DEST}/lib/" echo "" echo "Now rebuild the app and check that nothing points at Homebrew:" echo " otool -L build/macos/Build/Products/Release-beta/*.app/Contents/Frameworks/krevoxa_video.framework/Versions/A/krevoxa_video"