#!/usr/bin/env bash
#
# Compila ffmpeg e ffprobe LGPL, universali (arm64 + x86_64), per il bundle
# macOS.
#
#   tool/build_ffmpeg_macos.sh
#
# Scrive in third_party/ffmpeg/macos/, che non si versiona: i due eseguibili, il
# testo della LGPL preso dai sorgenti e BUILD.txt con versione, hash e
# configurazione. La fase «Embed FFmpeg» del Runner (tool/embed_ffmpeg_macos.sh)
# li copia da li' in Contents/MacOS/ e li firma. Il tarball dei sorgenti resta in
# build/ffmpeg-macos/: e' lui, insieme a questo script, che va caricato sul sito
# accanto al .dmg per l'offerta dei sorgenti.
#
# Perche' compilarli e non scaricarli: al 29/09/2026 nessuno pubblica una build
# LGPL per macOS. evermeet.cx (l'unica linkata da ffmpeg.org) e' GPL e solo
# Intel, ffmpeg.martin-riedl.de include x264/x265, Homebrew e' GPL. La
# decisione e' in docs/vendor/ffmpeg.md.
#
# Serve solo Xcode. Niente nasm: l'assembly x86 accelera la codifica, e a noi
# serve solo `-c copy`.
set -euo pipefail
cd "$(dirname "$0")/.."

readonly version=9.0.2
# Lo stesso hash che fissa la formula di Homebrew per questa versione: due fonti
# indipendenti, visto che qui non c'e' gpg per verificare la firma.
readonly sha256=8c3850283eb25fa026482078a04051e0be17347b09ef81a0849bec15a96e002e
# Uguale a MACOSX_DEPLOYMENT_TARGET del Runner: un binario con un minimo piu'
# alto farebbe partire l'app e fallire al primo film.
readonly min_macos=12.0

readonly work="$PWD/build/ffmpeg-macos"
readonly out="$PWD/third_party/ffmpeg/macos"
readonly tarball="$work/ffmpeg-$version.tar.xz"

# Le variabili che fanno trovare al compilatore le librerie di Homebrew. Una
# sola che sfugga e il binario si collega a /opt/homebrew: funziona su questa
# macchina e su nessun'altra.
unset CPATH C_INCLUDE_PATH LIBRARY_PATH PKG_CONFIG_PATH CFLAGS LDFLAGS

mkdir -p "$work"
if [[ ! -f "$tarball" ]]; then
  curl -fL --retry 3 -o "$tarball.part" \
    "https://ffmpeg.org/releases/ffmpeg-$version.tar.xz"
  mv "$tarball.part" "$tarball"
fi
echo "$sha256  $tarball" | shasum -a 256 -c -

jobs=$(sysctl -n hw.ncpu)

build_arch() {
  local arch=$1 ffarch=$2
  local src="$work/src-$arch"
  rm -rf "$src"
  mkdir -p "$src"
  tar -xf "$tarball" -C "$src" --strip-components 1

  local extra=()
  # Su arm64 niente assembly x86 da assemblare; su x86_64 si spegne perche'
  # richiederebbe nasm, e per rimuxare non serve.
  [[ "$arch" == x86_64 ]] && extra+=(--disable-x86asm)
  [[ "$arch" != "$(uname -m)" ]] && extra+=(--enable-cross-compile)

  # Niente --enable-gpl ne' --enable-version3: resta LGPL 2.1+.
  # --disable-autodetect e' la riga che conta: senza, configure trova da solo
  # cio' che c'e' sulla macchina (openssl, i framework hardware) e lo collega.
  # zlib e bzlib si riaccendono a mano: sono di sistema, e mkvmerge comprime con
  # zlib le tracce dei sottotitoli per default — senza, il demuxer Matroska
  # rifiuta quei file.
  # I demuxer, muxer, parser e decoder nativi restano tutti: ffprobe apre il
  # decoder per riempire formato pixel, canali e profilo, e un ffprobe ridotto
  # darebbe stream mezzi vuoti al calcolo della compatibilita'.
  # Dei dispositivi resta solo lavfi, che e' un «dispositivo» d'ingresso: genera
  # le clip della prova qui sotto e dei test d'integrazione.
  (
    cd "$src"
    ./configure \
      --arch="$ffarch" \
      --target-os=darwin \
      --cc="clang -arch $arch" \
      --extra-cflags="-mmacosx-version-min=$min_macos" \
      --extra-ldflags="-mmacosx-version-min=$min_macos" \
      --disable-autodetect \
      --enable-zlib \
      --enable-bzlib \
      --enable-static \
      --disable-shared \
      --disable-ffplay \
      --disable-doc \
      --disable-network \
      --disable-devices \
      --enable-indev=lavfi \
      ${extra[@]+"${extra[@]}"}
    make -j"$jobs" ffmpeg ffprobe
  )
}

build_arch arm64 aarch64
build_arch x86_64 x86_64

staging="$work/out"
rm -rf "$staging"
mkdir -p "$staging"
for tool in ffmpeg ffprobe; do
  lipo -create "$work/src-arm64/$tool" "$work/src-x86_64/$tool" \
    -output "$staging/$tool"
done
cp "$work/src-arm64/COPYING.LGPLv2.1" "$staging/LICENSE.LGPL-2.1.txt"

# --- Le verifiche: sono loro la configurazione dichiarata che nessuna fonte
# --- esterna ci darebbe. Un binario che non le passa non arriva in third_party.

fail() {
  echo "ERRORE: $*" >&2
  exit 1
}

for tool in ffmpeg ffprobe; do
  bin="$staging/$tool"

  archs=$(lipo -archs "$bin")
  [[ "$archs" == *arm64* && "$archs" == *x86_64* ]] ||
    fail "$tool non e' universale: $archs"

  for arch in arm64 x86_64; do
    # Solo librerie di sistema: una riga fuori da /usr/lib e /System e' una
    # dipendenza che sul Mac di chi installa non c'e'.
    foreign=$(otool -arch "$arch" -L "$bin" | tail -n +2 |
      grep -v -E '^[[:space:]]+(/usr/lib/|/System/)' || true)
    [[ -z "$foreign" ]] || fail "$tool ($arch) si collega a: $foreign"

    minos=$(vtool -arch "$arch" -show-build "$bin" | awk '/minos/ {print $2}')
    [[ "$minos" == "$min_macos" ]] ||
      fail "$tool ($arch) chiede macOS $minos invece di $min_macos"
  done

  # `-L` va a capo fra «Public» e «License»: si cerca la parte che sta su una
  # riga sola, e che in una build GPL non c'e'.
  "$bin" -hide_banner -L | grep -q 'GNU Lesser General Public' ||
    fail "$tool non si dichiara LGPL"
  if "$bin" -hide_banner -buildconf | grep -q -E -- '--enable-(gpl|nonfree)'; then
    fail "$tool e' configurato GPL o nonfree"
  fi
done

# Il taglio vero, sulle due architetture: una clip generata, divisa con lo
# stesso segment muxer e `-c copy` dell'app, e riletta da ffprobe.
smoke="$work/smoke"
rm -rf "$smoke"
mkdir -p "$smoke"
"$staging/ffmpeg" -hide_banner -loglevel error \
  -f lavfi -i testsrc=duration=4:size=320x240:rate=25 \
  -f lavfi -i sine=duration=4 \
  -c:v mpeg4 -g 25 -c:a aac -shortest "$smoke/clip.mkv"
for arch in arm64 x86_64; do
  if [[ "$arch" == x86_64 ]] && ! arch -x86_64 /usr/bin/true 2>/dev/null; then
    echo "AVVISO: Rosetta non c'e', la prova x86_64 si salta" >&2
    continue
  fi
  arch "-$arch" "$staging/ffmpeg" -hide_banner -loglevel error \
    -i "$smoke/clip.mkv" -map 0 -c copy \
    -f segment -segment_format matroska -segment_times 2 \
    "$smoke/part-$arch.%03d.mkv"
  for part in "$smoke/part-$arch".00{0,1}.mkv; do
    arch "-$arch" "$staging/ffprobe" -v error -show_entries stream=codec_name \
      -of csv=p=0 "$part" | grep -q mpeg4 ||
      fail "ffprobe ($arch) non legge $part"
  done
done

{
  echo "FFmpeg $version, LGPL 2.1 or later"
  echo "Source: https://ffmpeg.org/releases/ffmpeg-$version.tar.xz"
  echo "SHA-256: $sha256"
  echo "Built by tool/build_ffmpeg_macos.sh for arm64 + x86_64, macOS $min_macos+"
  echo
  "$staging/ffmpeg" -hide_banner -buildconf
} >"$staging/BUILD.txt"

rm -rf "$out"
mkdir -p "$(dirname "$out")"
mv "$staging" "$out"
echo "Pronti in $out"
