#!/usr/bin/env bash
# Compila o FFmpeg da PlayDepth: só as bibliotecas externas que a aplicação usa (x264 e x265 para codificar sem placa
# gráfica; NVENC/CUDA, Quick Sync e AMF para codificar com ela; SRT para o direto; dav1d para ler AV1; zlib). Tudo o
# resto (filtros, RTMP/RTMPS com a cifra do Windows, RTSP, HTTP, câmaras DirectShow) é do próprio FFmpeg.
#
# Corre no MSYS2 (ambiente UCRT64), com gcc, clang, nasm, cmake, ninja, meson, pkgconf, make e diffutils:
#   bash scripts/ffmpeg/compilar.sh <pasta com o código-fonte de fontes.txt> <pasta de saída>
# A pasta de saída fica com bin/ffmpeg.exe, bin/ffprobe.exe, LICENSE, README.txt e licencas/ (as licenças de cada
# biblioteca). O código-fonte e este script são o que a GPL obriga a disponibilizar junto do instalador.
set -euo pipefail

FONTES=$(cd "${1:?Indique a pasta com o código-fonte}" && pwd)
SAIDA=$(mkdir -p "${2:?Indique a pasta de saída}" && cd "$2" && pwd)
AQUI=$(cd "$(dirname "$0")" && pwd)
TRAB="$SAIDA/trabalho"
PREFIXO="$TRAB/prefixo"
TAREFAS=$(nproc)

rm -rf "$TRAB" "$SAIDA/bin" "$SAIDA/licencas"
mkdir -p "$TRAB" "$PREFIXO/include" "$PREFIXO/lib" "$SAIDA/bin" "$SAIDA/licencas"

# Só as bibliotecas desta pasta: nenhuma do MSYS2 entra no executável por engano.
export PKG_CONFIG_LIBDIR="$PREFIXO/lib/pkgconfig"
export PKG_CONFIG_PATH="$PREFIXO/lib/pkgconfig"
export CFLAGS="-O2 -I$PREFIXO/include"
export CXXFLAGS="-O2 -I$PREFIXO/include"
export LDFLAGS="-L$PREFIXO/lib -static"
CMAKE=(cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$PREFIXO" -DBUILD_SHARED_LIBS=OFF)

# 1. Confere o código-fonte com fontes.txt (nome e SHA-256) e extrai cada ficheiro.
declare -A PASTA
while read -r ficheiro hash _licenca _url; do
  [[ -z "$ficheiro" || "$ficheiro" == \#* ]] && continue
  caminho=$(find "$FONTES" -type f -name "$ficheiro" -print -quit)
  [[ -n "$caminho" ]] || { echo "Falta $ficheiro em $FONTES" >&2; exit 1; }
  echo "$hash  $caminho" | sha256sum --check --quiet || { echo "SHA-256 errado: $ficheiro" >&2; exit 1; }
  # Cada ficheiro tem uma só pasta de topo: extrai-se para uma pasta própria e usa-se essa.
  destino="$TRAB/fonte-${ficheiro%%-*}"
  mkdir -p "$destino"
  tar -xf "$caminho" -C "$destino"
  PASTA[${ficheiro%%-*}]="$destino/$(ls -1 "$destino")"
done < "$AQUI/fontes.txt"

licenca() { cp "$1" "$SAIDA/licencas/$2.txt"; }
# Compila e instala uma pasta do CMake (em linhas separadas: com «a && b» o set -e não pararia numa falha de «a»).
construir() {
  cmake --build "$1" -j "$TAREFAS"
  cmake --install "$1"
}

# 2. Bibliotecas.
echo "== zlib"
(cd "${PASTA[zlib]}" && make -f win32/Makefile.gcc -j"$TAREFAS" libz.a \
  && make -f win32/Makefile.gcc install SHARED_MODE=0 BINARY_PATH="$PREFIXO/bin" INCLUDE_PATH="$PREFIXO/include" \
    LIBRARY_PATH="$PREFIXO/lib")
licenca "${PASTA[zlib]}/LICENSE" zlib

echo "== mbedTLS"
"${CMAKE[@]}" -S "${PASTA[mbedtls]}" -B "$TRAB/mbedtls-build" -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DGEN_FILES=OFF \
  -DUSE_STATIC_MBEDTLS_LIBRARY=ON -DUSE_SHARED_MBEDTLS_LIBRARY=OFF
construir "$TRAB/mbedtls-build"
licenca "${PASTA[mbedtls]}/LICENSE" mbedtls

echo "== SRT"
"${CMAKE[@]}" -S "${PASTA[srt]}" -B "$TRAB/srt-build" -DENABLE_SHARED=OFF -DENABLE_STATIC=ON -DENABLE_APPS=OFF \
  -DENABLE_ENCRYPTION=ON -DUSE_ENCLIB=mbedtls -DENABLE_CXX_DEPS=ON -DUSE_STATIC_LIBSTDCXX=ON \
  -DSSL_INCLUDE_DIRS="$PREFIXO/include" -DSSL_LIBRARY_DIRS="$PREFIXO/lib" \
  -DSSL_LIBRARIES="mbedtls;mbedx509;mbedcrypto"
construir "$TRAB/srt-build"
licenca "${PASTA[srt]}/LICENSE" srt

echo "== x264"
(cd "${PASTA[x264]}" && ./configure --prefix="$PREFIXO" --enable-static --disable-cli --enable-pic --disable-lavf \
  --disable-swscale --disable-ffms --disable-gpac --disable-lsmash && make -j"$TAREFAS" && make install)
licenca "${PASTA[x264]}/COPYING" x264

echo "== x265"
"${CMAKE[@]}" -S "${PASTA[x265]}/source" -B "$TRAB/x265-build" -DENABLE_SHARED=OFF -DENABLE_CLI=OFF
construir "$TRAB/x265-build"
licenca "${PASTA[x265]}/COPYING" x265

echo "== cabeçalhos NVIDIA (NVENC/NVDEC/CUDA)"
make -C "${PASTA[nv]}" PREFIX="$PREFIXO" install
sed -n '1,30p' "${PASTA[nv]}/include/ffnvcodec/nvEncodeAPI.h" > "$SAIDA/licencas/nv-codec-headers.txt"

echo "== cabeçalhos AMD AMF"
cp -r "${PASTA[AMF]}/AMF" "$PREFIXO/include/"
sed -n '1,40p' "${PASTA[AMF]}/AMF/core/Version.h" > "$SAIDA/licencas/amf.txt"

echo "== Intel VPL (Quick Sync)"
# Única alteração ao código-fonte (a mesma das compilações BtbN): o VPL troca o wcscpy_s por uma versão sua quando
# «_MSC_VER < 1400», o que também é verdade sem o compilador da Microsoft e choca com o stralign.h do mingw-w64; com a
# condição certa, o MinGW usa o wcscpy_s do Windows.
sed -i 's/^#if _MSC_VER < 1400$/#if defined(_MSC_VER) \&\& _MSC_VER < 1400/' \
  "${PASTA[libvpl]}/libvpl/src/windows/mfx_dispatcher_defs.h"
"${CMAKE[@]}" -S "${PASTA[libvpl]}" -B "$TRAB/libvpl-build" -DBUILD_TOOLS=OFF -DBUILD_EXAMPLES=OFF \
  -DINSTALL_EXAMPLES=OFF -DBUILD_TESTS=OFF
construir "$TRAB/libvpl-build"
# A biblioteca estática é C++: quem a liga precisa também da biblioteca padrão do C++.
sed -i 's/^Libs.private:.*$/Libs.private: -lstdc++/' "$PREFIXO/lib/pkgconfig/vpl.pc"
licenca "${PASTA[libvpl]}/LICENSE" libvpl

echo "== dav1d (AV1)"
meson setup "$TRAB/dav1d-build" "${PASTA[dav1d]}" --prefix="$PREFIXO" --libdir=lib --buildtype=release \
  --default-library=static -Denable_tools=false -Denable_tests=false
ninja -C "$TRAB/dav1d-build" install
licenca "${PASTA[dav1d]}/COPYING" dav1d

# O SRT e o x265 indicam a biblioteca do C++ pelo caminho completo; o configure do FFmpeg só trata como bibliotecas
# as entradas «-l…» e poria esse ficheiro antes deles na ligação (ficariam por resolver).
sed -i 's#[^ ]*/libstdc++\.a#-lstdc++#g' "$PREFIXO/lib/pkgconfig/srt.pc" "$PREFIXO/lib/pkgconfig/x265.pc"

# 3. FFmpeg. Sem deteção automática: entra só o que está pedido aqui.
echo "== FFmpeg"
CONFIGURACAO=(
  --prefix="$PREFIXO/ffmpeg" --pkg-config-flags=--static
  --extra-cflags="-I$PREFIXO/include" --extra-ldflags="-L$PREFIXO/lib -static"
  --enable-gpl --enable-version3 --disable-autodetect --disable-debug --disable-doc --disable-ffplay
  --enable-zlib --enable-libx264 --enable-libx265 --enable-libsrt --enable-libdav1d --enable-libvpl
  --enable-ffnvcodec --enable-cuda-llvm --enable-cuvid --enable-nvenc --enable-nvdec
  --enable-amf --enable-d3d11va --enable-dxva2 --enable-schannel
)
(cd "${PASTA[ffmpeg]}" && ./configure "${CONFIGURACAO[@]}" && make -j"$TAREFAS" && make install)
cp "$PREFIXO/ffmpeg/bin/ffmpeg.exe" "$PREFIXO/ffmpeg/bin/ffprobe.exe" "$SAIDA/bin/"
cp "${PASTA[ffmpeg]}/COPYING.GPLv3" "$SAIDA/LICENSE"
licenca "${PASTA[ffmpeg]}/LICENSE.md" ffmpeg

# 4. README no formato que os scripts da aplicação leem («Version:», «Source Code:»), com a configuração e as fontes.
VERSAO=$("$SAIDA/bin/ffmpeg.exe" -hide_banner -version | head -1 | awk '{print $3}')
{
  echo "FFmpeg 64-bit static Windows build for PlayDepth"
  echo
  echo "Version: $VERSAO-playdepth"
  echo
  echo "License: GPL v3"
  echo
  echo "Source Code: codigo-fonte-ffmpeg (next to the installer; build script scripts/ffmpeg/compilar.sh)"
  echo
  echo "Configuration: ${CONFIGURACAO[*]}" | sed "s#$PREFIXO#<prefixo>#g"
  echo
  echo "Toolchain: $(gcc --version | head -1); $(clang --version | head -1); $(nasm -v)"
  echo
  echo "Sources (file, SHA-256, license, origin):"
  grep -v '^#' "$AQUI/fontes.txt"
} > "$SAIDA/README.txt"

echo "Feito: $SAIDA/bin"
"$SAIDA/bin/ffmpeg.exe" -hide_banner -version | head -1
