#!/usr/bin/env bash # build_ffmpeg_lgpl.sh -- the Windows FFmpeg the dashboard + engine ship, LGPL-2.1-or-later ONLY. # # Runs on Linux (WSL Ubuntu 24.04 measured), cross-compiles for x86_64 Windows with llvm-mingw (UCRT). # # bash scripts/ffmpeg/build_ffmpeg_lgpl.sh # fetch, deps, ffmpeg, export, bundle # bash scripts/ffmpeg/build_ffmpeg_lgpl.sh # fetch | deps | ffmpeg | export | bundle # # FFBUILD_ROOT work dir on the Linux side (default ~/ffbuild) # FFMPEG_LGPL_OUT bin/include/lib for Windows (default /mnt/c/ffmpeg-lgpl/8.1.1) # FFMPEG_LGPL_SRC corresponding-source tree root (default /mnt/c/ffmpeg-lgpl/oss -> ffmpeg//win64/...) # JOBS make -j (default nproc) # # After this, on Windows: # python scripts\ffmpeg\make_msvc_import_libs.py C:\ffmpeg-lgpl\8.1.1 (.def -> MSVC .lib via lib.exe) # python scripts\ffmpeg\check_ffmpeg_build.py C:\ffmpeg-lgpl\8.1.1\bin (licence + exact encoder/muxer set) # python scripts\ffmpeg\smoke_ffmpeg_build.py C:\ffmpeg-lgpl\8.1.1\bin (encode/decode/hwaccel matrix) # # What makes this LGPL-2.1+ and not GPL/LGPL-3: no --enable-gpl, no --enable-version3, no # --enable-nonfree, and --disable-autodetect so nothing on the build host is pulled in behind our # back. configure prints "License: LGPL version 2.1 or later"; this script refuses to continue # otherwise. The encoder/muxer/protocol/indev sets come from ffmpeg_allowlist.json (each entry # names the code that needs it) and check_ffmpeg_build.py holds the result to exactly that set. # # External code linked into the DLLs (all permissive, all static, no extra DLLs): # zlib 1.3.2 (zlib licence) / dav1d 1.5.4 (BSD-2-Clause, AV1 software decode) # nv-codec-headers 13.0.19.1 (MIT, header-only; loads nvcuda/nvcuvid/nvEncodeAPI at runtime) # AMF headers 1.4.36 (MIT, header-only; loads amfrt64.dll at runtime) # llvm-mingw 20260922 runtime pieces (mingw-w64 CRT startup/libmingwex, compiler-rt builtins) # # Deliberately NOT built: libx264/libx265 (GPL), libopenh264 (see scripts/ffmpeg/README.md), # libvpl/QSV, network protocols, ffplay, docs. Two screen-capture source filters are off: # amf_capture (does not compile against the AMF 1.4.36 headers: DisplayCapture.h:43) and # gfxcapture (C++/WinRT, needs a C++ runtime in avfilter-11.dll and does not compile with # libc++: std::system_error without ). Nothing here captures the screen. set -euo pipefail FF_VER=8.1.1 HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ALLOWLIST="$HERE/ffmpeg_allowlist.json" ROOT="${FFBUILD_ROOT:-$HOME/ffbuild}" OUT="${FFMPEG_LGPL_OUT:-/mnt/c/ffmpeg-lgpl/$FF_VER}" SRC_OUT="${FFMPEG_LGPL_SRC:-/mnt/c/ffmpeg-lgpl/oss}" JOBS="${JOBS:-$(nproc)}" DL="$ROOT/dl" # verified downloads SRC="$ROOT/src" # unpacked sources BUILD="$ROOT/build" # build trees; FFmpeg configure runs in $BUILD/ffmpeg DEPS="$BUILD/deps" # static deps + headers; referenced as ../deps from $BUILD/ffmpeg TC="$ROOT/toolchain" # llvm-mingw STAGE="$ROOT/stage" # make install DESTDIR PREFIX=/enchant/ffmpeg-lgpl # fixed fake prefix: the configure string compiled into the DLLs is # the same on every machine that runs this script # ---- pinned inputs: name | url | sha256 -------------------------------------------------------- # ffmpeg sha256 == the mac build's (enchant-dashboard-mac scripts/fetch_deps_mac.sh FF_LGPL_SHA) # and the tarball is also checked against FFmpeg's release signature (FFMPEG_KEY_FPR). PINS=( "ffmpeg-8.1.1.tar.xz|https://ffmpeg.org/releases/ffmpeg-8.1.1.tar.xz|b6863adde98898f42602017462871b5f6333e65aec803fdd7a6308639c52edf3" "ffmpeg-8.1.1.tar.xz.asc|https://ffmpeg.org/releases/ffmpeg-8.1.1.tar.xz.asc|-" "ffmpeg-devel.asc|https://ffmpeg.org/ffmpeg-devel.asc|-" "llvm-mingw-20260922-ucrt-ubuntu-22.04-x86_64.tar.xz|https://github.com/mstorsjo/llvm-mingw/releases/download/20260922/llvm-mingw-20260922-ucrt-ubuntu-22.04-x86_64.tar.xz|bb7bb7654b33d5aa8712acb837c963b2e0c56352560c76105270a3268c665c21" "nv-codec-headers-13.0.19.1.tar.gz|https://github.com/FFmpeg/nv-codec-headers/releases/download/n13.0.19.1/nv-codec-headers-13.0.19.1.tar.gz|eab9d02d461035a4baded23d4f2e2834e5b17934820b79cea45baaf0c85383eb" "AMF-headers-v1.4.36.tar.gz|https://github.com/GPUOpen-LibrariesAndSDKs/AMF/releases/download/v1.4.36/AMF-headers-v1.4.36.tar.gz|ec07ee21b820a73f5bae224e92fd3c492f52732d4885f0637f48189afdd87564" "zlib-1.3.2.tar.xz|https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.xz|d7a0654783a4da529d1bb793b7ad9c3318020af77667bcae35f95d0e42a792f3" "dav1d-1.5.4.tar.xz|https://downloads.videolan.org/pub/videolan/dav1d/1.5.4/dav1d-1.5.4.tar.xz|686616b7c69eb88d44459391ab25cac13b6647a3b288835c5784e71c1514a5c5" # Not an input to the build: the notice text llvm-mingw's statically linked mingw-w64 runtime # asks binaries to carry (its tarball ships only LLVM's LICENSE.TXT). "COPYING.MinGW-w64-runtime.txt|https://raw.githubusercontent.com/mingw-w64/mingw-w64/v13.0.0/COPYING.MinGW-w64-runtime/COPYING.MinGW-w64-runtime.txt|e9b2dc02451ea29092a1f25fa0f3c07207ed421f1807dffb0c4e6dce69dee7bd" ) # FFmpeg release signing key FFMPEG_KEY_FPR=FCF986EA15E6E293A5644F10B4322F04D67658D8 # Why these versions (not just "latest"): # nv-codec-headers 13.0: libavcodec/nvdec.h enables NVDEC 4:2:2 (NVDEC_HAVE_422_SUPPORT) only # for SDK >= 13.0 -- Blackwell H.264/HEVC 4:2:2 hardware decode needs it. 13.x makes NVENC # require driver >= 570.0 (nvenc.c nvenc_print_driver_requirement); the engine's CUDA 12.8+ # runtime already requires that. 13.1 would raise it further ("(unknown)" in 8.1.1). # AMF 1.4.36: the minimum FFmpeg 8.1.1 accepts (configure). AMFInit is called with the header's # AMF_FULL_VERSION, so older headers work with more AMD drivers. # --cuda-path=/nonexistent: clang picks the PTX ISA version from whatever CUDA toolkit it finds # on the BUILD host (measured: /usr/local/cuda 13.0 -> .version 8.3, needs driver >= 545; # no toolkit -> PTX 4.2). Pinning "no toolkit" makes the embedded PTX the same on every # machine and JIT-able by any driver the NVENC floor (570) already implies. The kernels only # use FFmpeg's compat/cuda headers (-nocudainc -nocudalib), never the toolkit. die() { echo "ERROR: $*" >&2; exit 1; } step() { echo; echo "==== $*"; } # Tool PATH: llvm-mingw first, then the distro. Windows' PATH (WSL appends it) is dropped so a # lib.exe or clang.exe on the Windows side can never be picked up by configure. export PATH="$TC/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" export LC_ALL=C allow_names() { # allow_names -> configure component names, one per line python3 - "$ALLOWLIST" "$1" <<'PY' import json, sys a = json.load(open(sys.argv[1], encoding="utf-8")) ren = a.get("muxer_configure_names", {}) if sys.argv[2] == "muxers" else {} for k in sorted(k for k in a[sys.argv[2]] if not k.startswith("_")): print(ren.get(k, k)) PY } allow_csv() { allow_names "$1" | paste -sd, -; } pin_field() { # pin_field <1|2|3> local p; for p in "${PINS[@]}"; do [ "${p%%|*}" = "$1" ] && { echo "$p" | cut -d'|' -f"$2"; return; } done; die "no pin for $1" } check_host() { local t missing="" for t in curl gpg xz tar make nasm pkg-config meson ninja python3 clang-18 sha256sum; do command -v "$t" >/dev/null || missing="$missing $t" done [ -z "$missing" ] || die "missing host tools:$missing sudo apt-get install -y curl gnupg xz-utils make nasm pkg-config meson ninja-build python3 clang-18" # clang-18 only compiles the CUDA filters (scale_cuda...) to PTX; it needs the NVPTX backend. clang-18 -print-targets 2>/dev/null | grep -q nvptx64 || die "clang-18 has no nvptx64 target" } # ---- fetch --------------------------------------------------------------------------------------- do_fetch() { step "fetch + verify -> $DL" mkdir -p "$DL" local p name url sha got for p in "${PINS[@]}"; do IFS='|' read -r name url sha <<<"$p" if [ ! -s "$DL/$name" ]; then echo " get $url" curl -fSL --retry 3 -o "$DL/$name.part" "$url" mv "$DL/$name.part" "$DL/$name" fi [ "$sha" = "-" ] && continue got=$(sha256sum "$DL/$name" | cut -d' ' -f1) [ "$got" = "$sha" ] || die "sha256 mismatch for $name want $sha got $got" echo " ok $name $sha" done # FFmpeg's own signature, with a throwaway keyring holding only the key we pin. local gh; gh=$(mktemp -d) GNUPGHOME="$gh" gpg --batch --quiet --import "$DL/ffmpeg-devel.asc" 2>/dev/null GNUPGHOME="$gh" gpg --batch --with-colons --fingerprint 2>/dev/null \ | grep -q "^fpr:::::::::$FFMPEG_KEY_FPR:" || die "ffmpeg-devel.asc does not carry key $FFMPEG_KEY_FPR" GNUPGHOME="$gh" gpg --batch --status-fd 1 --verify "$DL/ffmpeg-$FF_VER.tar.xz.asc" "$DL/ffmpeg-$FF_VER.tar.xz" 2>/dev/null \ | grep -q "^\[GNUPG:\] VALIDSIG $FFMPEG_KEY_FPR " || die "ffmpeg-$FF_VER.tar.xz: signature does not verify with $FFMPEG_KEY_FPR" rm -rf "$gh" echo " ok ffmpeg-$FF_VER.tar.xz signed by $FFMPEG_KEY_FPR" } unpack() { # unpack rm -rf "${SRC:?}/$2"; mkdir -p "$SRC/$2" tar -xf "$DL/$1" -C "$SRC/$2" --strip-components=1 } # ---- deps ------------------------------------------------------------------------------------------ do_deps() { step "toolchain + deps -> $DEPS" if [ ! -x "$TC/bin/x86_64-w64-mingw32-clang" ]; then rm -rf "$TC"; mkdir -p "$TC" tar -xf "$DL/llvm-mingw-20260922-ucrt-ubuntu-22.04-x86_64.tar.xz" -C "$TC" --strip-components=1 fi x86_64-w64-mingw32-clang --version | head -1 rm -rf "$DEPS"; mkdir -p "$DEPS/include" "$DEPS/lib/pkgconfig" "$SRC" "$BUILD" # nv-codec-headers: headers + ffnvcodec.pc, nothing compiled. unpack nv-codec-headers-13.0.19.1.tar.gz nv-codec-headers make -C "$SRC/nv-codec-headers" PREFIX="$DEPS" install >/dev/null # AMF: only the public headers (AMF/core, AMF/components). unpack AMF-headers-v1.4.36.tar.gz amf-headers cp -r "$SRC/amf-headers/AMF" "$DEPS/include/" # zlib: static libz.a with the mingw makefile. unpack zlib-1.3.2.tar.xz zlib make -C "$SRC/zlib" -f win32/Makefile.gcc -j"$JOBS" libz.a \ PREFIX=x86_64-w64-mingw32- CC=x86_64-w64-mingw32-clang AR=x86_64-w64-mingw32-ar \ RC=x86_64-w64-mingw32-windres STRIP=x86_64-w64-mingw32-strip >/dev/null cp "$SRC/zlib/zlib.h" "$SRC/zlib/zconf.h" "$DEPS/include/" cp "$SRC/zlib/libz.a" "$DEPS/lib/" # dav1d: static, 8+10 bit, asm on, no tools/tests. unpack dav1d-1.5.4.tar.xz dav1d cat > "$BUILD/cross-mingw64.txt" </dev/null ninja -C "$BUILD/dav1d" install >/dev/null ls -l "$DEPS/lib" } # ---- ffmpeg ---------------------------------------------------------------------------------------- ff_configure_args() { local enc mux proto indev enc=$(allow_csv encoders); mux=$(allow_csv muxers); proto=$(allow_csv protocols); indev=$(allow_csv indevs) FF_CONFIGURE=( --prefix=$PREFIX --arch=x86_64 --target-os=mingw32 --enable-cross-compile --cross-prefix=x86_64-w64-mingw32- --cc=x86_64-w64-mingw32-clang --cxx=x86_64-w64-mingw32-clang++ --pkg-config=pkg-config --pkg-config-flags=--static --nvcc=clang-18 "--nvccflags=--cuda-gpu-arch=sm_30 -O2 --cuda-path=/nonexistent" --extra-cflags=-I../deps/include --extra-ldflags=-L../deps/lib --enable-shared --disable-static --disable-autodetect --disable-doc --disable-ffplay --enable-w32threads --disable-network --disable-protocols --enable-protocol="$proto" --disable-encoders --enable-encoder="$enc" --disable-muxers --enable-muxer="$mux" --disable-indevs --enable-indev="$indev" --disable-outdevs --disable-filter=amf_capture,gfxcapture --enable-zlib --enable-libdav1d --enable-ffnvcodec --enable-cuda --enable-cuda-llvm --enable-cuvid --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-mediafoundation --enable-amf ) } do_ffmpeg() { step "ffmpeg $FF_VER configure + build" [ -d "$DEPS/include/AMF" ] || die "deps missing -- run the deps step first" unpack "ffmpeg-$FF_VER.tar.xz" ffmpeg rm -rf "$BUILD/ffmpeg" "$STAGE"; mkdir -p "$BUILD/ffmpeg" ff_configure_args # PKG_CONFIG_LIBDIR (not _PATH): only our deps are visible, never the build host's .pc files. ( cd "$BUILD/ffmpeg" && PKG_CONFIG_LIBDIR="$DEPS/lib/pkgconfig" \ "$SRC/ffmpeg/configure" "${FF_CONFIGURE[@]}" > "$BUILD/configure.out" 2>&1 ) \ || { tail -40 "$BUILD/configure.out"; tail -40 "$BUILD/ffmpeg/ffbuild/config.log"; die "configure failed"; } grep -q "^License: LGPL version 2.1 or later" "$BUILD/configure.out" \ || { grep -n "^License" "$BUILD/configure.out"; die "configure did not come out LGPL 2.1+ -- refusing to build"; } local want for want in "External libraries:" "External libraries providing hardware acceleration:"; do sed -n "/^$want/,/^$/p" "$BUILD/configure.out" done # Everything configure was asked for must actually be on. configure quietly drops a component # whose dependency check failed; a build that "succeeded" without nvenc is the failure mode. # (library switches live in config.h, per-component ones in config_components.h) local cfg="$BUILD/configured.h" c cat "$BUILD/ffmpeg/config.h" "$BUILD/ffmpeg/config_components.h" > "$cfg" for c in CONFIG_ZLIB CONFIG_LIBDAV1D CONFIG_FFNVCODEC CONFIG_CUDA CONFIG_CUDA_LLVM CONFIG_CUVID \ CONFIG_NVDEC CONFIG_NVENC CONFIG_D3D11VA CONFIG_DXVA2 CONFIG_MEDIAFOUNDATION CONFIG_AMF \ HAVE_W32THREADS CONFIG_SCALE_CUDA_FILTER CONFIG_H264_NVENC_ENCODER CONFIG_H264_MF_ENCODER \ CONFIG_H264_AMF_ENCODER CONFIG_DSHOW_INDEV CONFIG_LAVFI_INDEV; do grep -q "^#define $c 1" "$cfg" || die "$c is not enabled in config.h (configure dropped it)" done for c in CONFIG_GPL CONFIG_VERSION3 CONFIG_NONFREE; do grep -q "^#define $c 0" "$cfg" || die "$c is not 0 in config.h" done # Every allowlisted component must be on: configure silently drops a name inside a comma list # that matches nothing (e.g. --enable-muxer=3gp; the component is "tgp"). local kind suffix n for kind in encoders:ENCODER muxers:MUXER protocols:PROTOCOL indevs:INDEV; do suffix=${kind#*:} for n in $(allow_names "${kind%%:*}"); do grep -q "^#define CONFIG_${n^^}_${suffix} 1" "$cfg" || die "allowlisted ${kind%%:*} '$n' is not enabled (CONFIG_${n^^}_${suffix})" done done ( cd "$BUILD/ffmpeg" && make -j"$JOBS" > "$BUILD/make.out" 2>&1 ) \ || { tail -40 "$BUILD/make.out"; die "make failed"; } ( cd "$BUILD/ffmpeg" && make install DESTDIR="$STAGE" > "$BUILD/install.out" 2>&1 ) \ || { tail -40 "$BUILD/install.out"; die "make install failed"; } echo " built: $(ls "$STAGE$PREFIX/bin")" } # ---- export ---------------------------------------------------------------------------------------- do_export() { step "export -> $OUT" local s="$STAGE$PREFIX" [ -f "$s/bin/avcodec-62.dll" ] || die "no staged build -- run the ffmpeg step first" rm -rf "$OUT"; mkdir -p "$OUT/bin" "$OUT/lib/pkgconfig" "$OUT/licenses" cp "$s"/bin/*.dll "$s/bin/ffmpeg.exe" "$s/bin/ffprobe.exe" "$OUT/bin/" cp -r "$s/include" "$OUT/" cp "$s"/lib/*.def "$s"/lib/*.dll.a "$OUT/lib/" # .pc files: relocatable instead of pointing at the fake prefix. local pc; for pc in "$s"/lib/pkgconfig/*.pc; do sed "s|^prefix=.*|prefix=\${pcfiledir}/../..|" "$pc" > "$OUT/lib/pkgconfig/$(basename "$pc")" done # (MSVC import libs are made on Windows from the .def files: make_msvc_import_libs.py. # The llvm-dlltool .lib that install puts in bin/ is not shipped.) cp "$SRC/ffmpeg/COPYING.LGPLv2.1" "$OUT/licenses/FFmpeg-COPYING.LGPLv2.1.txt" cp "$SRC/ffmpeg/LICENSE.md" "$OUT/licenses/FFmpeg-LICENSE.md" cp "$SRC/zlib/LICENSE" "$OUT/licenses/zlib-LICENSE.txt" cp "$SRC/dav1d/COPYING" "$OUT/licenses/dav1d-COPYING.txt" sed -n '1,/\*\//p' "$SRC/nv-codec-headers/include/ffnvcodec/nvEncodeAPI.h" > "$OUT/licenses/nv-codec-headers-MIT.txt" sed -n '1,/THE SOFTWARE\./p' "$SRC/amf-headers/AMF/core/Factory.h" > "$OUT/licenses/AMF-headers-MIT.txt" cp "$DL/COPYING.MinGW-w64-runtime.txt" "$OUT/licenses/mingw-w64-runtime-COPYING.txt" cp "$TC/LICENSE.TXT" "$OUT/licenses/llvm-LICENSE.txt" write_buildinfo > "$OUT/BUILD_INFO.txt" ( cd "$OUT" && find bin lib include -type f | sort | xargs sha256sum ) > "$OUT/SHA256SUMS" du -sh "$OUT"; ls -l "$OUT/bin" } write_buildinfo() { ff_configure_args local p echo "FFmpeg $FF_VER -- Enchant Dashboard (Windows) LGPL-2.1-or-later build" echo "built: $(date -u +%Y-%m-%dT%H:%M:%SZ) on $(uname -srm)" echo "script: scripts/ffmpeg/build_ffmpeg_lgpl.sh" echo "toolchain: $(x86_64-w64-mingw32-clang --version | head -1) (llvm-mingw 20260922, UCRT)" echo "nvcc: $(clang-18 --version | head -1)" echo "nasm: $(nasm -v)" echo "build-id: $(ff_build_id) (first 12 hex of sha256 over the configure arguments joined by \" \")" echo echo "configure:" printf ' %s\n' "${FF_CONFIGURE[@]}" echo sed -n '/^License:/p' "$BUILD/configure.out" echo "NVCCFLAGS: $(sed -n 's/^NVCCFLAGS=//p' "$BUILD/ffmpeg/ffbuild/config.mak")" echo "PTX: $(cat "$BUILD"/ffmpeg/libavfilter/*.ptx | grep -E '^\.(version|target)' | sort | uniq -c | tr -s ' ' | paste -sd';' -)" echo echo "inputs (sha256):" for p in "${PINS[@]}"; do IFS='|' read -r name url sha <<<"$p" echo " $(sha256sum "$DL/$name" | cut -d' ' -f1) $name <$url>" done } # ---- bundle (corresponding source; local only, nothing is uploaded) -------------------------------- # The tree is shared with the macOS repo (scripts/make_ffmpeg_source_package.sh there) and is # published as-is at the URL in scripts/ffmpeg_source_url.txt: # # /ffmpeg// # ffmpeg-.tar.xz (+ .asc) the upstream release, byte-identical, ONE for all platforms # COPYING.LGPLv2.1 from that tarball # SHA256SUMS of everything under / (re-run after merging the platforms) # win64/README.txt index: the source URL, LATEST, how to rebuild # win64/LATEST -> the build-id the newest installer ships # win64// build-id = first 12 hex of sha256(configure args joined by " ") # configure_line.txt build_ffmpeg_lgpl.sh ffmpeg_allowlist.json make_msvc_import_libs.py # check_ffmpeg_build.py BUILD_INFO.txt BINARIES.sha256 README.txt deps/ # # A build-id directory is never removed or rewritten -- an installed Enchant keeps pointing at the # source it shipped. A new configure line is a new build-id; a new FFmpeg version a new /. ff_build_id() { ff_configure_args printf '%s' "${FF_CONFIGURE[*]}" | sha256sum | cut -c1-12 } do_bundle() { local V="$SRC_OUT/ffmpeg/$FF_VER" ID D f have url step "source tree -> $V" [ -f "$OUT/bin/avutil-60.dll" ] || die "no exported build in $OUT -- run the export step first" ID=$(ff_build_id) # The build-id must describe the binaries next to it, not just this script's current line. have=$(python3 - "$OUT/bin/avutil-60.dll" <<'PY' import hashlib, re, shlex, sys b = open(sys.argv[1], "rb").read() i = b.find(b"--prefix=") s, e = b.rfind(b"\0", 0, i) + 1, b.find(b"\0", i) print(hashlib.sha256(" ".join(shlex.split(b[s:e].decode())).encode()).hexdigest()[:12]) PY ) [ "$have" = "$ID" ] || die "the binaries in $OUT are build $have, this script's configure line is $ID" mkdir -p "$V/win64" for f in "ffmpeg-$FF_VER.tar.xz" "ffmpeg-$FF_VER.tar.xz.asc"; do [ -f "$V/$f" ] || cp "$DL/$f" "$V/$f" done [ "$(sha256sum "$V/ffmpeg-$FF_VER.tar.xz" | cut -d' ' -f1)" = "$(pin_field "ffmpeg-$FF_VER.tar.xz" 3)" ] \ || die "$V/ffmpeg-$FF_VER.tar.xz is not the pinned tarball" tar -xOf "$V/ffmpeg-$FF_VER.tar.xz" "ffmpeg-$FF_VER/COPYING.LGPLv2.1" > "$V/COPYING.LGPLv2.1" D="$V/win64/$ID" if [ -d "$D" ]; then echo " win64/$ID already exists -- never rewritten" else mkdir -p "$D/deps" ff_configure_args printf '%s\n' "${FF_CONFIGURE[*]}" > "$D/configure_line.txt" cp "$HERE/build_ffmpeg_lgpl.sh" "$HERE/ffmpeg_allowlist.json" "$HERE/make_msvc_import_libs.py" \ "$HERE/check_ffmpeg_build.py" "$D/" cp "$OUT/BUILD_INFO.txt" "$D/BUILD_INFO.txt" ( cd "$OUT/bin" && sha256sum -- *.dll *.exe ) > "$D/BINARIES.sha256" for f in ffmpeg-devel.asc nv-codec-headers-13.0.19.1.tar.gz AMF-headers-v1.4.36.tar.gz zlib-1.3.2.tar.xz \ dav1d-1.5.4.tar.xz COPYING.MinGW-w64-runtime.txt; do cp "$DL/$f" "$D/deps/" done cat > "$D/README.txt" <) Use your own build (or a modified FFmpeg) with Enchant Dashboard: 1. close Enchant Dashboard 2. copy the DLLs of your build over the ones with the same names in the installation folder (default %LOCALAPPDATA%\\Programs\\Enchant Dashboard) and over those present in its engine\\ subfolder 3. start Enchant Dashboard. It loads the DLLs from those folders and does not check their contents; keep the same major versions (the file names). An Enchant update puts the shipped files back -- copy yours again afterwards. EOF fi echo "$ID" > "$V/win64/LATEST" url=$(grep -v '^#' "$HERE/../ffmpeg_source_url.txt" 2>/dev/null | sed '/^[[:space:]]*$/d' | head -1) case "$url" in ""|*TBD*) url="${url:-TBD-FFMPEG-SOURCE-URL} (not published yet)" ;; *) url="${url%/}/$FF_VER/" ;; esac cat > "$V/win64/README.txt" < "$V/SHA256SUMS" du -sh "$V"; echo " build-id $ID"; cat "$V/SHA256SUMS" } # ---- main -------------------------------------------------------------------------------------------- check_host [ $# -gt 0 ] || set -- fetch deps ffmpeg export bundle for s in "$@"; do case "$s" in fetch) do_fetch ;; deps) do_deps ;; ffmpeg) do_ffmpeg ;; export) do_export ;; bundle) do_bundle ;; *) die "unknown step '$s' (fetch|deps|ffmpeg|export|bundle)" ;; esac done