Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 181 additions & 8 deletions CLAUDE.md

Large diffs are not rendered by default.

17 changes: 10 additions & 7 deletions Scripts/deps-expected-plugins.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"_comment": "Required VapourSynth plugin filenames per platform \u2014 the contract for a COMPLETE deps bundle. The package-deps-* scripts assert every file listed here exists in the staged bundle before zipping and FAIL the build if any are missing, so a silently-failed download (e.g. a dead upstream URL) becomes a red build instead of an incomplete bundle shipping. Plugin directory: windows-x64 = vapoursynth/vs-plugins, macos/linux = vapoursynth/plugins. Lists exclude data files (nnedi3 weights) and runtime libs (fftw); they cover the VapourSynth plugin binaries only. Update this when adding or removing a plugin.",
"_comment": "Required VapourSynth plugin filenames per platform the contract for a COMPLETE deps bundle. The package-deps-* scripts assert every file listed here exists in the staged bundle before zipping and FAIL the build if any are missing, so a silently-failed download (e.g. a dead upstream URL) becomes a red build instead of an incomplete bundle shipping. Plugin directory: windows-x64 = vapoursynth/vs-plugins, macos/linux = vapoursynth/plugins. Lists exclude data files (nnedi3 weights) and runtime libs (fftw); they cover the VapourSynth plugin binaries only. Update this when adding or removing a plugin. An entry containing a '/' is a path relative to the BUNDLE ROOT rather than a filename in the plugin directory: zsmooth ships one build per CPU baseline in vapoursynth/zsmooth/, deliberately outside the autoload directory, because both builds register the same namespace and the worker loads exactly one by path (DependencyLocator::zsmooth_plugin).",
"windows-x64": [
"AddGrain.dll",
"CAS.dll",
Expand Down Expand Up @@ -32,8 +32,9 @@
"libtemporalmedian.dll",
"libzstd.dll",
"neo-f3kdb.dll",
"vsznedi3.dll",
"zsmooth.dll"
"vapoursynth/zsmooth/zsmooth-haswell.dll",
"vapoursynth/zsmooth/zsmooth-x86_64_v2.dll",
"vsznedi3.dll"
],
"macos-arm64": [
"libaddgrain.dylib",
Expand Down Expand Up @@ -69,7 +70,7 @@
"libttempsmooth.dylib",
"libvivtc.dylib",
"libznedi3.dylib",
"libzsmooth.dylib"
"vapoursynth/zsmooth/libzsmooth.dylib"
],
"macos-x64": [
"libaddgrain.dylib",
Expand Down Expand Up @@ -102,7 +103,8 @@
"libttempsmooth.dylib",
"libvivtc.dylib",
"libznedi3.dylib",
"libzsmooth.dylib"
"vapoursynth/zsmooth/libzsmooth-haswell.dylib",
"vapoursynth/zsmooth/libzsmooth-x86_64_v2.dylib"
],
"linux-x64": [
"libaddgrain.so",
Expand Down Expand Up @@ -136,7 +138,8 @@
"libttempsmooth.so",
"libvivtc.so",
"libznedi3.so",
"libzsmooth.so"
"vapoursynth/zsmooth/libzsmooth-haswell.so",
"vapoursynth/zsmooth/libzsmooth-x86_64_v2.so"
],
"linux-arm64": [
"libaddgrain.so",
Expand Down Expand Up @@ -171,6 +174,6 @@
"libttempsmooth.so",
"libvivtc.so",
"libznedi3.so",
"libzsmooth.so"
"vapoursynth/zsmooth/libzsmooth.so"
]
}
144 changes: 126 additions & 18 deletions Scripts/download-deps-linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,42 @@ NPROC=$(nproc)
PYTHON_VERSION="3.12.8"
PYTHON_MAJOR_MINOR="3.12"

# FFmpeg major.minor series. THIS MUST MATCH the same pin in
# download-deps-macos.sh and download-deps-windows.ps1 —
# app/test/ffmpeg_version_pin_test.dart fails the push gate if the three drift.
# A per-OS FFmpeg is a per-OS encoder: the arguments in pipeline_executor.rs
# would then mean subtly different things depending on where the job ran.
#
# Pinning the SERIES rather than a full version is deliberate. Every upstream
# here publishes "latest build of the X.Y branch" and garbage-collects older
# series, so a full-version pin cannot be held for long — that is precisely how
# the previous n7.1 pin turned into a 404.
FFMPEG_SERIES="9.0"

# Fail the build if the FFmpeg we installed is not the series we pinned.
# Without this, an upstream that silently redirects "latest" to a new series
# reintroduces cross-platform skew with nothing to notice it.
assert_ffmpeg_series() {
local bin="$1"
local reported
# No backslashes in this parser on purpose: a bracket expression [.]
# matches a literal dot without one. Written with sed backrefs first,
# the escapes were mangled into control characters in transit and the
# check silently reported an empty version.
reported=$("$bin" -version 2>/dev/null | head -1 | grep -oE "version n?[0-9]+[.][0-9]+" | grep -oE "[0-9]+[.][0-9]+" | head -1)
if [ -z "$reported" ]; then
echo " ERROR: could not read a version from $bin" >&2
exit 1
fi
if [ "$reported" != "$FFMPEG_SERIES" ]; then
echo " ERROR: FFmpeg is $reported but this bundle pins $FFMPEG_SERIES." >&2
echo " Upstream moved the URL to a different series. Update FFMPEG_SERIES" >&2
echo " in ALL THREE download-deps-* scripts together, or platforms drift." >&2
exit 1
fi
echo " FFmpeg $reported (matches the pinned $FFMPEG_SERIES series)"
}

echo "=== VapourBox Linux Dependencies Builder ==="
echo "Architecture: $ARCH"
echo "Platform: $PLATFORM_DIR"
Expand Down Expand Up @@ -447,13 +483,16 @@ if [ "$FORCE" = true ] || [ ! -f "$DEPS_DIR/ffmpeg/ffmpeg" ]; then
# gracefully at init. (The previous John Van Sickle build had no hw accel.)
BTBN_BASE="https://github.com/BtbN/FFmpeg-Builds/releases/download/latest"
if [ "$ARCH" = "x86_64" ]; then
FFMPEG_URL="$BTBN_BASE/ffmpeg-n7.1-latest-linux64-gpl-7.1.tar.xz"
FFMPEG_URL="$BTBN_BASE/ffmpeg-n${FFMPEG_SERIES}-latest-linux64-gpl-${FFMPEG_SERIES}.tar.xz"
else
FFMPEG_URL="$BTBN_BASE/ffmpeg-n7.1-latest-linuxarm64-gpl-7.1.tar.xz"
FFMPEG_URL="$BTBN_BASE/ffmpeg-n${FFMPEG_SERIES}-latest-linuxarm64-gpl-${FFMPEG_SERIES}.tar.xz"
fi

echo " Downloading static FFmpeg (BtbN, hardware-enabled)..."
curl -L -o "$BUILD_DIR/ffmpeg.tar.xz" "$FFMPEG_URL"
echo " Downloading static FFmpeg $FFMPEG_SERIES (BtbN, hardware-enabled)..."
# -f, or a 404 body is written to the tarball and surfaces much later as an
# unexplained `tar: Error is not recoverable`. That is exactly how the n7.1
# asset ageing out of BtbN's rolling `latest` tag presented.
curl -fL -o "$BUILD_DIR/ffmpeg.tar.xz" "$FFMPEG_URL"

echo " Extracting..."
tar -xJf "$BUILD_DIR/ffmpeg.tar.xz" -C "$BUILD_DIR"
Expand All @@ -468,6 +507,7 @@ if [ "$FORCE" = true ] || [ ! -f "$DEPS_DIR/ffmpeg/ffmpeg" ]; then
cp "$FFMPEG_DIR/ffmpeg" "$DEPS_DIR/ffmpeg/"
cp "$FFMPEG_DIR/ffprobe" "$DEPS_DIR/ffmpeg/"
chmod +x "$DEPS_DIR/ffmpeg/ffmpeg" "$DEPS_DIR/ffmpeg/ffprobe"
assert_ffmpeg_series "$DEPS_DIR/ffmpeg/ffmpeg"
echo " Downloaded FFmpeg"
else
echo " FFmpeg already exists, skipping"
Expand Down Expand Up @@ -984,34 +1024,60 @@ build_plugin "tmedian" \
"libtmedian.so" \
"$PLUGIN_BUILD_ENV meson setup build --buildtype=release && ninja -C build"

# zsmooth (core.zsmooth.CCD - chroma denoiser; also Cnr4 and a set of
# RemoveGrain/TemporalMedian-family filters).
# zsmooth — one build per CPU baseline
#
# core.zsmooth.CCD (also Cnr4 and a set of RemoveGrain/TemporalMedian-family
# filters). Upstream publishes only `haswell` (an AVX2 baseline) and `znver4`
# x86 builds, compiled throughout with NO runtime dispatch — so on a pre-2013
# CPU the library loads fine and then dies with an illegal instruction the
# instant a filter runs. That is issue #82 (reported on Windows, but this
# bundle took the same haswell asset), and it is silent: vspipe prints nothing.
#
# So x86 ships both builds outside the autoload directory and the worker loads
# exactly one by path (DependencyLocator::zsmooth_plugin). They cannot share a
# directory: each registers the namespace `zsmooth`, so whichever autoloads
# second is rejected. aarch64 has a single NEON baseline and needs no split.
#
# Taken pre-built rather than built from source: zsmooth is written in Zig, and
# adding a Zig toolchain to every deps build for one plugin is not worth it. The
# author publishes a binary for every platform/arch VapourBox targets.
# Measured at 720x576: `x86_64` is 2.0x slower than haswell on CCD and 3.0x on
# Cnr4, `x86_64_v2` 1.4x on both — which is why the portable build is v2
# (SSE4.2/POPCNT, everything from Nehalem 2009 on) and why the fast build is
# still shipped rather than dropped for one portable binary.
#
# Keep ZSMOOTH_VERSION in step across download-deps-{macos,linux}.sh and
# download-deps-windows.ps1 — a version skew would make the same job produce
# different chroma per OS.
ZSMOOTH_VERSION="0.19.0"
# Must satisfy zsmooth's build.zig.zon `minimum_zig_version` (0.15.2 for 0.19.0).
ZIG_VERSION="0.15.2"
ZSMOOTH_DIR="$DEPS_DIR/vapoursynth/zsmooth"
mkdir -p "$ZSMOOTH_DIR"

echo ""
echo "=== Installing zsmooth ==="

# The pre-built asset: haswell on x86, the only build on aarch64.
case "$ARCH" in
aarch64|arm64) ZSMOOTH_ASSET="zsmooth-aarch64-linux-gnu.zip" ;;
*) ZSMOOTH_ASSET="zsmooth-x86_64-linux-gnu.zip" ;;
aarch64|arm64)
ZSMOOTH_ASSET="zsmooth-aarch64-linux-gnu.zip"
ZSMOOTH_PREBUILT="$ZSMOOTH_DIR/libzsmooth.so"
;;
*)
ZSMOOTH_ASSET="zsmooth-x86_64-linux-gnu.zip"
ZSMOOTH_PREBUILT="$ZSMOOTH_DIR/libzsmooth-haswell.so"
;;
esac
echo ""
echo "=== Downloading zsmooth ==="
if [ "$FORCE" = true ] || [ ! -f "$PLUGINS_DIR/libzsmooth.so" ]; then

if [ "$FORCE" = true ] || [ ! -f "$ZSMOOTH_PREBUILT" ]; then
rm -rf "$BUILD_DIR/zsmooth"
mkdir -p "$BUILD_DIR/zsmooth"
if curl -sL -o "$BUILD_DIR/zsmooth/zsmooth.zip" \
"https://github.com/adworacz/zsmooth/releases/download/${ZSMOOTH_VERSION}/${ZSMOOTH_ASSET}" \
&& unzip -q -o "$BUILD_DIR/zsmooth/zsmooth.zip" -d "$BUILD_DIR/zsmooth"; then
so_path=$(find "$BUILD_DIR/zsmooth" -name "*.so" -type f 2>/dev/null | head -1)
if [ -n "$so_path" ]; then
cp "$so_path" "$PLUGINS_DIR/libzsmooth.so"
patchelf --set-rpath '$ORIGIN:$ORIGIN/../../lib' "$PLUGINS_DIR/libzsmooth.so" 2>/dev/null || true
echo " Downloaded pre-built zsmooth -> libzsmooth.so"
cp "$so_path" "$ZSMOOTH_PREBUILT"
patchelf --set-rpath '$ORIGIN:$ORIGIN/../../lib' "$ZSMOOTH_PREBUILT" 2>/dev/null || true
echo " Downloaded pre-built zsmooth -> $(basename "$ZSMOOTH_PREBUILT")"
BUILT_PLUGINS+=("zsmooth")
else
echo " Failed: no .so in the zsmooth archive"
Expand All @@ -1023,9 +1089,51 @@ if [ "$FORCE" = true ] || [ ! -f "$PLUGINS_DIR/libzsmooth.so" ]; then
fi
rm -rf "$BUILD_DIR/zsmooth"
else
echo " zsmooth already exists, skipping"
echo " $(basename "$ZSMOOTH_PREBUILT") already exists, skipping"
fi

# The portable x86 build has no upstream asset and must be compiled. Zig brings
# its own libc and builds zsmooth's fftw dependency itself, so this adds no apt
# package — only network access, since `zig build` fetches zsmooth's own Zig
# dependencies.
case "$ARCH" in
aarch64|arm64) : ;;
*)
ZSMOOTH_V2="$ZSMOOTH_DIR/libzsmooth-x86_64_v2.so"
if [ "$FORCE" = true ] || [ ! -f "$ZSMOOTH_V2" ]; then
echo " Building zsmooth $ZSMOOTH_VERSION (x86_64_v2, runs without AVX2)..."
# Subshell so a failure cannot abort the script under `set -e`; the
# file check below decides whether it worked.
(
set -e
cd "$BUILD_DIR"
rm -rf zig-toolchain zsmooth-src zig.tar.xz
curl -fsSL -o zig.tar.xz \
"https://ziglang.org/download/${ZIG_VERSION}/zig-x86_64-linux-${ZIG_VERSION}.tar.xz"
mkdir -p zig-toolchain
tar -xf zig.tar.xz -C zig-toolchain --strip-components=1
git clone --depth 1 --branch "$ZSMOOTH_VERSION" \
https://github.com/adworacz/zsmooth.git zsmooth-src
cd zsmooth-src
"$BUILD_DIR/zig-toolchain/zig" build \
-Doptimize=ReleaseFast -Dcpu=x86_64_v2
cp zig-out/lib/libzsmooth.so "$ZSMOOTH_V2"
) || true

if [ -f "$ZSMOOTH_V2" ]; then
patchelf --set-rpath '$ORIGIN:$ORIGIN/../../lib' "$ZSMOOTH_V2" 2>/dev/null || true
echo " Built zsmooth -> $(basename "$ZSMOOTH_V2")"
else
echo " Warning: failed to build the portable zsmooth"
FAILED_PLUGINS+=("zsmooth-x86_64_v2")
fi
rm -rf "$BUILD_DIR/zig-toolchain" "$BUILD_DIR/zsmooth-src" "$BUILD_DIR/zig.tar.xz"
else
echo " $(basename "$ZSMOOTH_V2") already exists, skipping"
fi
;;
esac

# DeScratch (core.descratch.DeScratch - vertical scratch removal)
# Built from source: the repo carries the VapourSynth + AviSynthPlus headers as
# submodules, so a recursive clone is required (build_plugin can't fetch those).
Expand Down
Loading
Loading