#!/bin/zsh
# Builder B40 (Eval 3, 2026-10-05): the voice scorer's ffmpeg helper built from source for a low macOS floor.
#
#   zsh build_ffmpeg_floor.sh <build dir> <output dir> [deployment target, default 13.0]
#   (FF_EXTRA="--enable-..." adds components for a diagnostic build only; never for the bundle)
#
# Sources (kept in this folder; they double as the GPL source offer):
#   ffmpeg-8.1.1.tar.xz   https://ffmpeg.org/releases/ffmpeg-8.1.1.tar.xz
#                         sha256 b6863adde98898f42602017462871b5f6333e65aec803fdd7a6308639c52edf3 (= Homebrew's pin)
#   x264-b35605ace3ddf7c1a5d67a2eb553f034aef41d55.tar.xz
#                         `git archive` of https://code.videolan.org/videolan/x264.git at commit b35605a (r3222,
#                         API 165: the revision Homebrew's x264 r3222 bottle was built from)
#   x264-b35605a-version.h  what x264's version.sh prints in a full git clone at that commit. A tarball has no .git,
#                         so version.sh prints an empty version; the build puts these lines into x264_config.h instead,
#                         because the version string is written into every H.264 stream (SEI) and must match.
# Result: <prefix>/bin/ffmpeg, one static program (libx264 linked in, no other external library), minos = target.
set -euo pipefail
HERE=${0:A:h}
BUILD=${1:?build dir}
OUTDIR=${2:?output dir}
TARGET=${3:-13.0}
X264_COMMIT=b35605ace3ddf7c1a5d67a2eb553f034aef41d55
JOBS=${JOBS:-6}
# Optimisation level: -Os, as Homebrew's bottles are built (its compiler shim drops a project's own -O3 and adds -Os).
# The P1 reference clips come from the Homebrew bottles, and the Opus decoder's float output differed at -O3.
OPT=${OPT:--Os}
export MACOSX_DEPLOYMENT_TARGET=$TARGET
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
unset CFLAGS CXXFLAGS LDFLAGS CPPFLAGS PKG_CONFIG_PATH || true

echo "== $(date '+%H:%M:%S') check sources"
[[ $(shasum -a 256 $HERE/ffmpeg-8.1.1.tar.xz | cut -d' ' -f1) == b6863adde98898f42602017462871b5f6333e65aec803fdd7a6308639c52edf3 ]]
mkdir -p $BUILD $OUTDIR
BUILD=${BUILD:A}; OUTDIR=${OUTDIR:A}
# x264 is installed into the build folder (its Makefile cannot handle spaces in paths). ffmpeg is configured with a
# neutral prefix that is never written (it only appears in `ffmpeg -version`); the program is installed with DESTDIR.
PREFIX=$BUILD/x264-install
FF_PREFIX=/usr/local/hv-voice-ffmpeg
rm -rf $BUILD/x264-$X264_COMMIT $BUILD/ffmpeg-8.1.1
tar -xJf $HERE/x264-$X264_COMMIT.tar.xz -C $BUILD
tar -xJf $HERE/ffmpeg-8.1.1.tar.xz -C $BUILD

echo "== $(date '+%H:%M:%S') x264 (static, PIC; Homebrew's options minus the shared library and the CLI)"
cd $BUILD/x264-$X264_COMMIT
X264_CONF=(--prefix=$PREFIX --disable-lsmash --disable-swscale --disable-ffms --enable-static --enable-pic
           --enable-strip --disable-cli
           "--extra-cflags=-mmacosx-version-min=$TARGET $OPT" --extra-ldflags=-mmacosx-version-min=$TARGET)
echo "x264 configure: ${X264_CONF[*]}"
# x264's configure adds its own -O3 -ffast-math; the extra -Os comes later on every compile line, so it wins.
./configure "${X264_CONF[@]}"
# version.sh found no .git: replace its empty lines by the recorded ones (git clone at the same commit).
grep -v '^#define X264_VERSION \|^#define X264_POINTVER \|^#define X264_REV ' x264_config.h > x264_config.h.new
cat $HERE/x264-b35605a-version.h >> x264_config.h.new
mv x264_config.h.new x264_config.h
grep '^#define X264_' x264_config.h
make -j$JOBS
make install-lib-static

echo "== $(date '+%H:%M:%S') pkg-config stand-in on PATH (none on this Mac): answers only for x264 from its .pc file"
mkdir -p $BUILD/tools
cat > $BUILD/tools/pkg-config <<EOF
#!/bin/sh
# Minimal pkg-config for ffmpeg's configure: x264 only (from $PREFIX/lib/pkgconfig/x264.pc).
PC=$PREFIX/lib/pkgconfig
mode=""; pkg=""
for a in "\$@"; do
  case "\$a" in
    --version) echo 0.29.2; exit 0;;
    --exists|--print-errors|--static|--short-errors) [ "\$a" = --exists ] && mode=exists;;
    --cflags) mode="\$mode cflags";;
    --libs) mode="\$mode libs";;
    --modversion) mode="\$mode modversion";;
    --*) ;;
    *) [ -z "\$pkg" ] && pkg="\${a%% *}";;
  esac
done
[ "\$pkg" = x264 ] || exit 1
f=\$PC/x264.pc
[ -f "\$f" ] || exit 1
out=""
case "\$mode" in *cflags*) out="\$out -I$PREFIX/include";; esac
case "\$mode" in *libs*) out="\$out -L$PREFIX/lib -lx264 -lpthread -lm -ldl";; esac
case "\$mode" in *modversion*) sed -n 's/^Version: //p' "\$f"; exit 0;; esac
[ -n "\$out" ] && echo \$out
exit 0
EOF
chmod 755 $BUILD/tools/pkg-config

echo "== $(date '+%H:%M:%S') ffmpeg 8.1.1 (only the voice path: libx264 + native AAC encode, native VP8/VP9/Opus/AAC/H.264"
echo "   decode, Matroska/WebM and MP4/MOV demux and mux, the filters the ffmpeg program inserts for -ss/-t and format"
echo "   negotiation, file/pipe I/O; plus lavfi color/anullsrc and the wrapped_avframe/PCM decoders the lavfi input needs,"
echo "   so a warm-up can make a synthetic input without a camera or microphone)"
cd $BUILD/ffmpeg-8.1.1
export PATH=$BUILD/tools:$PATH
FF_CONF=(--prefix=$FF_PREFIX --cc=clang --host-cflags= --host-ldflags= --optflags=$OPT
         --enable-gpl --enable-libx264 --enable-pthreads --enable-neon
         --disable-autodetect --disable-everything --disable-network --disable-doc --disable-ffplay --disable-ffprobe
         --enable-encoder=libx264,aac
         --enable-decoder=vp8,vp9,opus,aac,h264,wrapped_avframe,pcm_u8,pcm_s16le,pcm_s32le,pcm_f32le,pcm_f64le
         --enable-demuxer=matroska,mov
         --enable-muxer=mp4,mov,webm,matroska
         --enable-parser=vp8,vp9,opus,aac,h264
         --enable-bsf=aac_adtstoasc,vp9_superframe
         --enable-filter=aformat,anull,aresample,atrim,asetpts,format,null,scale,trim,setpts,transpose,hflip,vflip,color,anullsrc
         --enable-indev=lavfi
         --enable-protocol=file,pipe
         --extra-cflags=-mmacosx-version-min=$TARGET --extra-ldflags=-mmacosx-version-min=$TARGET)
[[ -n ${FF_EXTRA:-} ]] && FF_CONF+=(${=FF_EXTRA})
echo "ffmpeg configure: ${FF_CONF[*]}"
./configure "${FF_CONF[@]}" > $BUILD/ffmpeg-configure.out
grep -i 'license\|libx264\|External libraries' -A2 $BUILD/ffmpeg-configure.out | head -20
make -j$JOBS
make install-progs DESTDIR=$BUILD/destdir
mkdir -p $OUTDIR/bin
cp $BUILD/destdir$FF_PREFIX/bin/ffmpeg $OUTDIR/bin/ffmpeg
cp $BUILD/ffmpeg-configure.out $OUTDIR/ffmpeg-configure.out
cp $BUILD/x264-$X264_COMMIT/x264_config.h $OUTDIR/x264_config.h
FFSHA=$(shasum -a 256 $OUTDIR/bin/ffmpeg | cut -d' ' -f1)
X2T=x264-$X264_COMMIT.tar.xz
/usr/bin/python3 - "$OUTDIR/BUILD.json" <<PYEOF
import json, sys
json.dump({"target": "$TARGET", "x264_commit": "$X264_COMMIT", "x264_tarball": "$X2T",
           "x264_tarball_sha256": "$(shasum -a 256 $HERE/$X2T | cut -d' ' -f1)",
           "ffmpeg_tarball_sha256": "$(shasum -a 256 $HERE/ffmpeg-8.1.1.tar.xz | cut -d' ' -f1)",
           "x264_configure": "./configure ${X264_CONF[*]//$BUILD/<build>}", "ffmpeg_configure": "./configure ${FF_CONF[*]}",
           "ff_extra": "${FF_EXTRA:-}", "opt": "$OPT", "script_sha256": "$(shasum -a 256 $HERE/build_ffmpeg_floor.sh | cut -d' ' -f1)",
           "clang": "$(clang --version | head -1)", "sdk": "$(xcrun --show-sdk-version)",
           "ffmpeg_sha256_as_built": "$FFSHA"}, open(sys.argv[1], "w"), indent=1)
PYEOF
echo "== $(date '+%H:%M:%S') done"
otool -L $OUTDIR/bin/ffmpeg
otool -l $OUTDIR/bin/ffmpeg | grep -A4 LC_BUILD_VERSION | grep -E 'minos|sdk'
$OUTDIR/bin/ffmpeg -hide_banner -version | head -3
shasum -a 256 $OUTDIR/bin/ffmpeg
