Skip to content

seems GitHub Actions was only installing the basic GStreamer runtime … #42

seems GitHub Actions was only installing the basic GStreamer runtime …

seems GitHub Actions was only installing the basic GStreamer runtime … #42

Workflow file for this run

name: Shader Binary Release
on:
push:
tags:
- 'v*'
permissions: write-all
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
shader_config:
# Shaders that REQUIRE GStreamer (media features)
- group: "media"
features: ""
gstreamer_required: true
shaders: "audiovis,computecolors,droste,fft,gabornoise,matrix,pathtracing,scenecolor,spiral,voronoi,fluid,cnn,synth,blockgame"
# Shaders that DON'T need GStreamer (pure GPU compute)
- group: "no-media"
features: "--no-default-features"
gstreamer_required: false
shaders: "asahi,buddhabrot,gabor,lorenz,galaxy,lich,mandelbulb,satan,sdvert,sinh,roto,orbits,dna,genuary2025_6,nebula,rorschach,poe2,tree,2dneuron,spiralchaos,cliffordcompute,water,volumepassage,currents,jfa,circuits"
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
ext: ""
archive_ext: ".tar.gz"
- os: windows-latest
target: x86_64-pc-windows-msvc
ext: ".exe"
archive_ext: ".zip"
- os: macos-latest
target: x86_64-apple-darwin
ext: ""
archive_ext: ".tar.gz"
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
# Install GStreamer for macOS (only for media shaders)
- name: Install macOS dependencies
if: runner.os == 'macOS' && matrix.shader_config.gstreamer_required
run: |
# Download and install official GStreamer packages
GSTREAMER_VERSION="1.26.4"
curl -L "https://gstreamer.freedesktop.org/data/pkg/osx/$GSTREAMER_VERSION/gstreamer-1.0-$GSTREAMER_VERSION-universal.pkg" -o gstreamer.pkg
curl -L "https://gstreamer.freedesktop.org/data/pkg/osx/$GSTREAMER_VERSION/gstreamer-1.0-devel-$GSTREAMER_VERSION-universal.pkg" -o gstreamer-devel.pkg
sudo installer -pkg gstreamer.pkg -target /
sudo installer -pkg gstreamer-devel.pkg -target /
# Set environment variables for build and runtime
echo "PKG_CONFIG_PATH=/Library/Frameworks/GStreamer.framework/Versions/1.0/lib/pkgconfig" >> $GITHUB_ENV
echo "GST_PLUGIN_PATH=/Library/Frameworks/GStreamer.framework/Versions/1.0/lib/gstreamer-1.0" >> $GITHUB_ENV
echo "DYLD_FALLBACK_LIBRARY_PATH=/Library/Frameworks/GStreamer.framework/Versions/1.0/lib" >> $GITHUB_ENV
# Install GStreamer for Linux (only for media shaders)
- name: Install Linux dependencies
if: runner.os == 'Linux' && matrix.shader_config.gstreamer_required
run: |
sudo apt-get update
sudo apt-get install -y \
libgtk-3-dev \
libudev-dev \
pkg-config \
build-essential \
libglib2.0-dev \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
patchelf
# Install GStreamer for Windows (only for media shaders)
- name: Install Windows dependencies
if: runner.os == 'Windows' && matrix.shader_config.gstreamer_required
shell: pwsh
run: |
Write-Host "Starting GStreamer installation process..."
$gstVer = "1.26.4"
$tempDir = "C:\gst-temp"
$installDir = "C:\gstreamer"
# Create necessary directories
New-Item -ItemType Directory -Force -Path $tempDir | Out-Null
New-Item -ItemType Directory -Force -Path $installDir | Out-Null
Write-Host "Downloading installers..."
$baseUrl = "https://gstreamer.freedesktop.org/data/pkg/windows/$gstVer/msvc"
$runtimeUrl = "$baseUrl/gstreamer-1.0-msvc-x86_64-$gstVer.msi"
$develUrl = "$baseUrl/gstreamer-1.0-devel-msvc-x86_64-$gstVer.msi"
Write-Host "Downloading MSVC 64-bit runtime installer..."
Invoke-WebRequest -Uri $runtimeUrl -OutFile "$tempDir\gstreamer.msi"
Write-Host "Downloading MSVC 64-bit development installer..."
Invoke-WebRequest -Uri $develUrl -OutFile "$tempDir\gstreamer-devel.msi"
Write-Host "Installing runtime package..."
$proc = Start-Process msiexec -ArgumentList "/i", "`"$tempDir\gstreamer.msi`"", "INSTALLDIR=$installDir", "/qn" -Wait -PassThru -NoNewWindow
if ($proc.ExitCode -ne 0) {
Write-Host "Runtime installation failed with code: $($proc.ExitCode)"
exit 1
}
Write-Host "Installing development package..."
$proc = Start-Process msiexec -ArgumentList "/i", "`"$tempDir\gstreamer-devel.msi`"", "INSTALLDIR=$installDir", "/qn" -Wait -PassThru -NoNewWindow
if ($proc.ExitCode -ne 0) {
Write-Host "Development installation failed with code: $($proc.ExitCode)"
exit 1
}
# Install libav/FFmpeg codecs package for video processing
Write-Host "Downloading FFmpeg/libav codecs package..."
try {
$libavUrl = "$baseUrl/gstreamer-1.0-libav-msvc-x86_64-$gstVer.msi"
Invoke-WebRequest -Uri $libavUrl -OutFile "$tempDir\gstreamer-libav.msi"
Write-Host "Installing FFmpeg/libav codecs package..."
$proc = Start-Process msiexec -ArgumentList "/i", "`"$tempDir\gstreamer-libav.msi`"", "INSTALLDIR=$installDir", "/qn" -Wait -PassThru -NoNewWindow
if ($proc.ExitCode -eq 0) {
Write-Host "✅ FFmpeg/libav codecs package installed successfully"
} else {
Write-Host "⚠️ FFmpeg/libav installation failed with code: $($proc.ExitCode) - continuing without FFmpeg codecs"
}
} catch {
Write-Host "⚠️ Could not download FFmpeg/libav package: $($_.Exception.Message)"
Write-Host "⚠️ Video processing may be limited without FFmpeg codecs"
}
Write-Host "Looking for GStreamer installation..."
$expectedPath = "$installDir\1.0\msvc_x86_64"
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
while (-not (Test-Path $expectedPath)) {
if ($stopwatch.Elapsed.TotalSeconds -gt 60) {
Write-Host "Timeout waiting for installation directory. Current structure:"
Get-ChildItem -Path $installDir -Recurse | Format-List
exit 1
}
Start-Sleep -Seconds 5
Write-Host "Waiting for installation directory... ($([int]$stopwatch.Elapsed.TotalSeconds)s)"
}
Write-Host "Setting environment variables..."
$env:GSTREAMER_1_0_ROOT_MSVC_X86_64 = $expectedPath
$env:GST_PLUGIN_PATH = "$expectedPath\lib\gstreamer-1.0"
$env:PKG_CONFIG_PATH = "$expectedPath\lib\pkgconfig"
$env:Path = "$expectedPath\bin;" + $env:Path
# Set environment variables for subsequent steps
"GSTREAMER_1_0_ROOT_MSVC_X86_64=$expectedPath" | Out-File -FilePath $env:GITHUB_ENV -Append
"GST_PLUGIN_PATH=$expectedPath\lib\gstreamer-1.0" | Out-File -FilePath $env:GITHUB_ENV -Append
"PKG_CONFIG_PATH=$expectedPath\lib\pkgconfig" | Out-File -FilePath $env:GITHUB_ENV -Append
"PATH=$expectedPath\bin;$env:Path" | Out-File -FilePath $env:GITHUB_ENV -Append
# Verify critical FFmpeg codec DLLs are installed
Write-Host "🔍 Verifying FFmpeg codec installation..."
$criticalCodecs = @("avformat-61.dll", "avcodec-61.dll", "avutil-59.dll", "gstlibav.dll")
$binPath = "$expectedPath\bin"
$pluginPath = "$expectedPath\lib\gstreamer-1.0"
foreach ($codec in $criticalCodecs) {
if ($codec -eq "gstlibav.dll") {
$codecPath = "$pluginPath\$codec"
} else {
$codecPath = "$binPath\$codec"
}
if (Test-Path $codecPath) {
Write-Host " ✅ Found: $codec"
} else {
Write-Host " ❌ Missing: $codec at $codecPath"
}
}
Write-Host "📊 Installation summary:"
Write-Host " Bin directory files: $((Get-ChildItem $binPath -ErrorAction SilentlyContinue).Count)"
Write-Host " Plugin directory files: $((Get-ChildItem $pluginPath -ErrorAction SilentlyContinue).Count)"
# Build all binaries for this shader group
- name: Build binaries
shell: bash
run: |
echo "Building ${{ matrix.shader_config.group }} shaders with features: ${{ matrix.shader_config.features }}"
IFS=',' read -ra SHADERS <<< "${{ matrix.shader_config.shaders }}"
for shader in "${SHADERS[@]}"; do
echo "Building shader: $shader"
cargo build --release --bin "$shader" ${{ matrix.shader_config.features }}
done
# Bundle GStreamer files for media shaders
- name: Bundle GStreamer for media shaders
if: matrix.shader_config.gstreamer_required
shell: bash
run: |
echo "🔧 Creating GStreamer bundle for media shaders on ${{ runner.os }}..."
BUNDLE_DIR="gstreamer_bundle"
mkdir -p "$BUNDLE_DIR/lib"
mkdir -p "$BUNDLE_DIR/lib/gstreamer-1.0"
mkdir -p "$BUNDLE_DIR/etc/ssl/certs"
if [[ "${{ runner.os }}" == "macOS" ]]; then
echo "📦 Bundling GStreamer for macOS..."
GSTREAMER_ROOT="/Library/Frameworks/GStreamer.framework/Versions/1.0"
LIB_EXT="dylib"
# Core libraries (macOS)
CORE_LIBS=(
"libgstreamer-1.0.0.dylib" "libgstbase-1.0.0.dylib" "libgstapp-1.0.0.dylib"
"libgstvideo-1.0.0.dylib" "libgstaudio-1.0.0.dylib" "libgstpbutils-1.0.0.dylib"
"libgsttag-1.0.0.dylib" "libgstfft-1.0.0.dylib" "libgstgl-1.0.0.dylib"
"libgstvulkan-1.0.0.dylib" "libgstcodecparsers-1.0.0.dylib" "libgstriff-1.0.0.dylib"
"libgstrtp-1.0.0.dylib" "libglib-2.0.0.dylib" "libgobject-2.0.0.dylib"
"libgio-2.0.0.dylib" "libgmodule-2.0.0.dylib" "libintl.8.dylib" "libffi.7.dylib"
"libpcre2-8.0.dylib" "liborc-0.4.0.dylib" "libz.1.dylib" "libbz2.1.dylib"
"libavformat.61.dylib" "libavutil.59.dylib" "libavcodec.61.dylib"
"libavfilter.10.dylib" "libswresample.5.dylib" "libSoundTouch.2.dylib" "libMoltenVK.dylib"
)
# Plugins (macOS)
PLUGINS=(
"libgstcoreelements.dylib" "libgstapp.dylib" "libgstplayback.dylib"
"libgsttypefindfunctions.dylib" "libgstvideoconvertscale.dylib" "libgstvideorate.dylib"
"libgstaudioconvert.dylib" "libgstaudioresample.dylib" "libgstvolume.dylib"
"libgstosxaudio.dylib" "libgstautodetect.dylib" "libgstaudiotestsrc.dylib"
"libgstaudiomixer.dylib" "libgstspectrum.dylib" "libgstsoundtouch.dylib"
"libgstaudioparsers.dylib" "libgstlibav.dylib" "libgstisomp4.dylib"
"libgstapplemedia.dylib" "libgstvideoparsersbad.dylib"
)
elif [[ "${{ runner.os }}" == "Windows" ]]; then
echo "Bundling GStreamer for Windows..."
GSTREAMER_ROOT="C:/gstreamer/1.0/msvc_x86_64"
LIB_EXT="dll"
# Core libraries (Windows) - these come from both lib/ and bin/ directories
CORE_LIBS=(
# GStreamer core (from lib/)
"gstreamer-1.0-0.dll" "gstbase-1.0-0.dll" "gstapp-1.0-0.dll"
"gstvideo-1.0-0.dll" "gstaudio-1.0-0.dll" "gstpbutils-1.0-0.dll"
"gsttag-1.0-0.dll" "gstfft-1.0-0.dll" "gstgl-1.0-0.dll"
"gstvulkan-1.0-0.dll" "gstcodecparsers-1.0-0.dll" "gstriff-1.0-0.dll"
"gstrtp-1.0-0.dll" "gstrtsp-1.0-0.dll" "gstsdp-1.0-0.dll"
"gstnet-1.0-0.dll" "gstcontroller-1.0-0.dll"
# GLib and dependencies (from lib/)
"glib-2.0-0.dll" "gobject-2.0-0.dll" "gio-2.0-0.dll"
"gmodule-2.0-0.dll" "gthread-2.0-0.dll"
"intl-8.dll" "ffi-7.dll" "pcre2-8-0.dll"
# Core dependencies (from lib/)
"orc-0.4-0.dll" "z.dll" "z-1.dll" "bz2.dll"
# Additional dependencies (from lib/)
"libwinpthread-1.dll" "libgcc_s_seh-1.dll" "libstdc++-6.dll"
"libiconv-2.dll" "libcharset-1.dll"
)
# CRITICAL: Additional codec libraries from bin/ directory
# These are essential for video processing and were missing!
BIN_CODEC_LIBS=(
"avformat-61.dll" "avcodec-61.dll" "avutil-59.dll"
"avfilter-10.dll" "swresample-5.dll" "swscale-8.dll"
"libvpx-1.dll" "libopus-0.dll" "libvorbis-0.dll"
"libogg-0.dll" "libmp3lame-0.dll" "libmpg123-0.dll"
)
# Plugins (Windows)
PLUGINS=(
# Core elements
"gstcoreelements.dll" "gstapp.dll" "gstplayback.dll"
"gsttypefindfunctions.dll" "gstvideoconvertscale.dll" "gstvideorate.dll"
"gstaudioconvert.dll" "gstaudioresample.dll" "gstvolume.dll"
"gstvideofilter.dll" "gstgio.dll"
# VIDEO DECODERS
"gstlibav.dll"
# Windows audio
"gstwasapi.dll" "gstwasapi2.dll" "gstdirectsound.dll"
"gstautodetect.dll" "gstaudiotestsrc.dll"
# Audio processing
"gstaudiomixer.dll" "gstspectrum.dll" "gstsoundtouch.dll"
"gstaudioparsers.dll"
# Container formats
"gstisomp4.dll" "gstvideoparsersbad.dll" "gstmatroska.dll"
"gstavi.dll" "gstflv.dll" "gstmpegtsdemux.dll" "gstasf.dll"
# Codec plugins
"gstvpx.dll" "gsttheora.dll" "gstmpg123.dll" "gstlame.dll"
"gstvorbis.dll" "gstogg.dll"
# Windows-specific video - for DirectShow support
"gstdirectshow.dll" "gstwinks.dll"
)
# Windows: Also create directories for helper executables
mkdir -p "$BUNDLE_DIR/bin"
mkdir -p "$BUNDLE_DIR/libexec/gstreamer-1.0"
elif [[ "${{ runner.os }}" == "Linux" ]]; then
echo " Bundling GStreamer for Linux..."
GSTREAMER_ROOT="/usr"
LIB_EXT="so"
# Core libraries (Linux)
CORE_LIBS=(
"libgstreamer-1.0.so.0" "libgstbase-1.0.so.0" "libgstapp-1.0.so.0"
"libgstvideo-1.0.so.0" "libgstaudio-1.0.so.0" "libgstpbutils-1.0.so.0"
"libgsttag-1.0.so.0" "libgstfft-1.0.so.0" "libgstgl-1.0.so.0"
"libgstvulkan-1.0.so.0" "libgstcodecparsers-1.0.so.0" "libgstriff-1.0.so.0"
"libgstrtp-1.0.so.0" "libglib-2.0.so.0" "libgobject-2.0.so.0"
"libgio-2.0.so.0" "libgmodule-2.0.so.0" "liborc-0.4.so.0"
)
# Plugins (Linux)
PLUGINS=(
"libgstcoreelements.so" "libgstapp.so" "libgstplayback.so"
"libgsttypefindfunctions.so" "libgstvideoconvert.so" "libgstvideorate.so"
"libgstaudioconvert.so" "libgstaudioresample.so" "libgstvolume.so"
"libgstpulseaudio.so" "libgstautodetect.so" "libgstaudiotestsrc.so"
"libgstaudiomixer.so" "libgstspectrum.so" "libgstsoundtouch.so"
"libgstaudioparsers.so" "libgstlibav.so" "libgstisomp4.so"
"libgstvideoparsersbad.so" "libgstv4l2.so"
)
fi
# Copy libraries
for lib in "${CORE_LIBS[@]}"; do
if [[ -f "$GSTREAMER_ROOT/lib/$lib" ]]; then
cp "$GSTREAMER_ROOT/lib/$lib" "$BUNDLE_DIR/lib/" 2>/dev/null || true
elif [[ -f "$GSTREAMER_ROOT/bin/$lib" ]]; then
cp "$GSTREAMER_ROOT/bin/$lib" "$BUNDLE_DIR/lib/" 2>/dev/null || true
fi
done
# Copy additional codec libraries from bin/ directory (Windows only)
if [[ "${{ runner.os }}" == "Windows" ]]; then
echo "📦 Copying critical codec libraries from bin directory..."
echo "🔍 Checking GStreamer installation at: $GSTREAMER_ROOT"
echo "🔍 Expected bin directory: $GSTREAMER_ROOT/bin"
# Debug: List what's actually in the bin directory
if [[ -d "$GSTREAMER_ROOT/bin" ]]; then
echo "✅ Bin directory exists. Contents:"
ls -la "$GSTREAMER_ROOT/bin" | head -20
echo "📊 Total files in bin: $(ls -1 "$GSTREAMER_ROOT/bin" | wc -l)"
else
echo "❌ Bin directory does not exist at: $GSTREAMER_ROOT/bin"
echo "🔍 Available directories in $GSTREAMER_ROOT:"
ls -la "$GSTREAMER_ROOT/" 2>/dev/null || echo "GSTREAMER_ROOT path invalid"
fi
for lib in "${BIN_CODEC_LIBS[@]}"; do
if [[ -f "$GSTREAMER_ROOT/bin/$lib" ]]; then
# Copy to bin directory so Windows restructuring can find them
cp "$GSTREAMER_ROOT/bin/$lib" "$BUNDLE_DIR/bin/" 2>/dev/null || true
echo " ✅ Copied codec to bin/: $lib"
else
echo " ❌ Missing codec: $lib (checked: $GSTREAMER_ROOT/bin/$lib)"
fi
done
fi
# Copy plugins with detailed logging
echo "📦 Copying GStreamer plugins..."
echo "🔍 Plugin directory: $GSTREAMER_ROOT/lib/gstreamer-1.0"
# Debug: Check plugin directory
if [[ -d "$GSTREAMER_ROOT/lib/gstreamer-1.0" ]]; then
echo "✅ Plugin directory exists"
echo "📊 Total plugins available: $(ls -1 "$GSTREAMER_ROOT/lib/gstreamer-1.0"/*.dll 2>/dev/null | wc -l)"
# Check for critical plugins specifically
for critical in "gstlibav.dll" "gstmpegtsdemux.dll" "gstasf.dll"; do
if [[ -f "$GSTREAMER_ROOT/lib/gstreamer-1.0/$critical" ]]; then
echo "✅ Found critical plugin: $critical"
else
echo "❌ Critical plugin missing: $critical"
fi
done
else
echo "❌ Plugin directory does not exist"
fi
for plugin in "${PLUGINS[@]}"; do
if [[ -f "$GSTREAMER_ROOT/lib/gstreamer-1.0/$plugin" ]]; then
cp "$GSTREAMER_ROOT/lib/gstreamer-1.0/$plugin" "$BUNDLE_DIR/lib/gstreamer-1.0/" 2>/dev/null || true
echo " ✅ Copied plugin: $plugin"
else
echo " ❌ MISSING plugin: $plugin (checked: $GSTREAMER_ROOT/lib/gstreamer-1.0/$plugin)"
fi
done
# Verify critical plugins are present
if [[ "${{ runner.os }}" == "Windows" ]]; then
echo "🔍 Verifying critical plugins in bundle..."
critical_plugins=("gstlibav.dll" "gstmpegtsdemux.dll" "gstasf.dll")
for critical in "${critical_plugins[@]}"; do
if [[ -f "$BUNDLE_DIR/lib/gstreamer-1.0/$critical" ]]; then
echo " ✅ Critical plugin verified: $critical"
else
echo " ❌ CRITICAL PLUGIN MISSING: $critical"
fi
done
fi
# Copy SSL certificates (if available)
if [[ -f "$GSTREAMER_ROOT/etc/ssl/certs/ca-certificates.crt" ]]; then
cp "$GSTREAMER_ROOT/etc/ssl/certs/ca-certificates.crt" "$BUNDLE_DIR/etc/ssl/certs/"
elif [[ -f "/etc/ssl/certs/ca-certificates.crt" ]]; then
cp "/etc/ssl/certs/ca-certificates.crt" "$BUNDLE_DIR/etc/ssl/certs/"
fi
# Copy GStreamer helper binaries
if [[ "${{ runner.os }}" == "Windows" ]]; then
# For Windows, copy important executables and helpers
for exe in "gst-plugin-scanner.exe" "gst-inspect-1.0.exe" "gst-launch-1.0.exe"; do
if [[ -f "$GSTREAMER_ROOT/bin/$exe" ]]; then
cp "$GSTREAMER_ROOT/bin/$exe" "$BUNDLE_DIR/bin/" 2>/dev/null || true
fi
done
# Copy plugin scanner to libexec
if [[ -f "$GSTREAMER_ROOT/libexec/gstreamer-1.0/gst-plugin-scanner.exe" ]]; then
cp "$GSTREAMER_ROOT/libexec/gstreamer-1.0/gst-plugin-scanner.exe" "$BUNDLE_DIR/libexec/gstreamer-1.0/" 2>/dev/null || true
elif [[ -f "$GSTREAMER_ROOT/bin/gst-plugin-scanner.exe" ]]; then
cp "$GSTREAMER_ROOT/bin/gst-plugin-scanner.exe" "$BUNDLE_DIR/libexec/gstreamer-1.0/" 2>/dev/null || true
fi
else
# macOS and Linux
mkdir -p "$BUNDLE_DIR/libexec/gstreamer-1.0"
mkdir -p "$BUNDLE_DIR/bin"
# Copy plugin scanner
if [[ -f "$GSTREAMER_ROOT/libexec/gstreamer-1.0/gst-plugin-scanner" ]]; then
cp "$GSTREAMER_ROOT/libexec/gstreamer-1.0/gst-plugin-scanner" "$BUNDLE_DIR/libexec/gstreamer-1.0/"
chmod +x "$BUNDLE_DIR/libexec/gstreamer-1.0/gst-plugin-scanner"
fi
# Copy essential tools
for tool in "gst-inspect-1.0" "gst-typefind-1.0" "gst-launch-1.0"; do
if [[ -f "$GSTREAMER_ROOT/bin/$tool" ]]; then
cp "$GSTREAMER_ROOT/bin/$tool" "$BUNDLE_DIR/bin/"
chmod +x "$BUNDLE_DIR/bin/$tool"
fi
done
fi
echo "✅ GStreamer bundle created: $(du -sh $BUNDLE_DIR | cut -f1)"
# Create release packages for each shader in the group
- name: Prepare release packages
shell: bash
run: |
IFS=',' read -ra SHADERS <<< "${{ matrix.shader_config.shaders }}"
for shader in "${SHADERS[@]}"; do
echo "Packaging shader: $shader"
# Create directory structure
mkdir -p "release/$shader/shaders"
# Copy the binary
cp "target/release/$shader${{ matrix.ext }}" "release/$shader/"
# Copy shader files
cp "shaders/$shader.wgsl" "release/$shader/shaders/"
cp "shaders/vertex.wgsl" "release/$shader/shaders/"
# Embed GStreamer for media shaders (cross-platform)
if [[ "${{ matrix.shader_config.gstreamer_required }}" == "true" ]]; then
echo " Embedding GStreamer for $shader..."
# Copy GStreamer bundle
cp -r "gstreamer_bundle" "release/$shader/gstreamer"
# Fix library paths (platform-specific)
echo "🔧 Fixing library paths for ${{ runner.os }}..."
BINARY="release/$shader/$shader${{ matrix.ext }}"
BUNDLE_LIB_DIR="release/$shader/gstreamer/lib"
BUNDLE_PLUGIN_DIR="$BUNDLE_LIB_DIR/gstreamer-1.0"
echo "Debug: Binary path: $BINARY"
echo "Debug: Bundle lib dir: $BUNDLE_LIB_DIR"
echo "Debug: Bundle exists: $(test -d release/$shader/gstreamer && echo yes || echo no)"
if [[ "${{ runner.os }}" == "macOS" ]]; then
echo "🍎 Processing macOS library paths..."
# Fix main binary
echo "Fixing main binary: $BINARY"
if [[ -f "$BINARY" ]]; then
otool -L "$BINARY" 2>/dev/null | grep -E "(@rpath|/Library/Frameworks/GStreamer.framework)" | awk '{print $1}' | while read dep; do
if [[ -n "$dep" ]]; then
lib_name=$(basename "$dep")
new_path="@loader_path/gstreamer/lib/$lib_name"
echo " Changing: $dep -> $new_path"
install_name_tool -change "$dep" "$new_path" "$BINARY" 2>/dev/null || true
fi
done
else
echo "❌ Binary not found: $BINARY"
fi
# Fix all libraries
echo "Fixing libraries in: $BUNDLE_LIB_DIR"
if [[ -d "$BUNDLE_LIB_DIR" ]]; then
for lib in "$BUNDLE_LIB_DIR"/*.dylib; do
if [[ -f "$lib" ]]; then
lib_name=$(basename "$lib")
echo " Processing library: $lib_name"
# Use a subshell to prevent script exit on errors
(
# Check if library is writable before attempting to modify
if [[ ! -w "$lib" ]]; then
echo " Skipping $lib_name (read-only)"
exit 0
fi
# Test if we can modify this library at all
if ! install_name_tool -id "@loader_path/$lib_name" "$lib" 2>/dev/null; then
echo " Skipping $lib_name (cannot modify - likely system/protected library)"
exit 0
fi
echo " Successfully modified ID for $lib_name"
# Fix dependencies
otool -L "$lib" 2>/dev/null | grep -E "(@rpath|/Library/Frameworks/GStreamer.framework)" | awk '{print $1}' | while read dep; do
if [[ -n "$dep" ]]; then
dep_lib_name=$(basename "$dep")
new_dep_path="@loader_path/$dep_lib_name"
if install_name_tool -change "$dep" "$new_dep_path" "$lib" 2>/dev/null; then
echo " Fixed dependency: $dep"
else
echo " Warning: Could not change dependency $dep in $lib_name"
fi
fi
done
) || echo " Error processing $lib_name, continuing..."
fi
done
else
echo "❌ Library directory not found: $BUNDLE_LIB_DIR"
fi
# Fix all plugins
echo "Fixing plugins in: $BUNDLE_PLUGIN_DIR"
if [[ -d "$BUNDLE_PLUGIN_DIR" ]]; then
for plugin in "$BUNDLE_PLUGIN_DIR"/*.dylib; do
if [[ -f "$plugin" ]]; then
plugin_name=$(basename "$plugin")
echo " Processing plugin: $plugin_name"
# Use a subshell to prevent script exit on errors
(
# Try to set the plugin ID, skip if it fails
if ! install_name_tool -id "@loader_path/../$plugin_name" "$plugin" 2>/dev/null; then
echo " Skipping $plugin_name (cannot modify)"
exit 0
fi
echo " Successfully modified ID for $plugin_name"
# Fix dependencies
otool -L "$plugin" 2>/dev/null | grep -E "(@rpath|/Library/Frameworks/GStreamer.framework)" | awk '{print $1}' | while read dep; do
if [[ -n "$dep" ]]; then
dep_lib_name=$(basename "$dep")
new_dep_path="@loader_path/../$dep_lib_name"
if install_name_tool -change "$dep" "$new_dep_path" "$plugin" 2>/dev/null; then
echo " Fixed dependency: $dep"
else
echo " Warning: Could not change dependency $dep in $plugin_name"
fi
fi
done
) || echo " Error processing $plugin_name, continuing..."
fi
done
else
echo "❌ Plugin directory not found: $BUNDLE_PLUGIN_DIR"
fi
elif [[ "${{ runner.os }}" == "Linux" ]]; then
# Linux: Use patchelf and $ORIGIN rpath
echo "Setting rpath for Linux binary..."
if command -v patchelf >/dev/null 2>&1; then
patchelf --set-rpath '$ORIGIN/gstreamer/lib' "$BINARY" 2>/dev/null || true
# Fix all libraries
for lib in "$BUNDLE_LIB_DIR"/*.so*; do
if [[ -f "$lib" ]]; then
patchelf --set-rpath '$ORIGIN' "$lib" 2>/dev/null || true
fi
done
# Fix all plugins
for plugin in "$BUNDLE_PLUGIN_DIR"/*.so; do
if [[ -f "$plugin" ]]; then
patchelf --set-rpath '$ORIGIN/..' "$plugin" 2>/dev/null || true
fi
done
else
echo "⚠️ patchelf not available, library paths may not work correctly"
fi
elif [[ "${{ runner.os }}" == "Windows" ]]; then
# Windows: DLLs use current directory by default, so restructure
echo "Windows DLL bundling and structure optimization..."
# Copy DLLs to release directory root (alongside exe)
echo "📦 Restructuring Windows GStreamer layout..."
# Copy all DLLs directly to exe directory (includes both core libs and codec libs)
echo "📦 Copying all DLLs from lib/ to exe directory..."
cp "release/$shader/gstreamer/lib"/*.dll "release/$shader/" 2>/dev/null || true
# CRITICAL: Copy codec DLLs from bin directory to exe directory
if [[ -d "release/$shader/gstreamer/bin" ]]; then
echo "📦 Copying critical codec DLLs from bin directory to exe directory..."
# Explicitly copy the 12 required codec DLLs
for codec_dll in "avformat-61.dll" "avcodec-61.dll" "avutil-59.dll" \
"avfilter-10.dll" "swresample-5.dll" "swscale-8.dll" \
"libvpx-1.dll" "libopus-0.dll" "libvorbis-0.dll" \
"libogg-0.dll" "libmp3lame-0.dll" "libmpg123-0.dll"; do
if [[ -f "release/$shader/gstreamer/bin/$codec_dll" ]]; then
cp "release/$shader/gstreamer/bin/$codec_dll" "release/$shader/" 2>/dev/null || true
echo " ✅ Copied critical codec: $codec_dll"
else
echo " ❌ MISSING critical codec: $codec_dll"
fi
done
# Copy other executables from bin
cp "release/$shader/gstreamer/bin"/*.exe "release/$shader/" 2>/dev/null || true
else
echo "❌ CRITICAL ERROR: No bin directory found in GStreamer bundle!"
fi
# Debug: Final count of DLLs in exe directory
echo "✅ Final DLL count in exe directory:"
ls -la "release/$shader/"*.dll 2>/dev/null | wc -l | xargs echo " Total DLLs:"
# Keep the lib folder structure for plugins
mkdir -p "release/$shader/lib"
cp -r "release/$shader/gstreamer/lib/gstreamer-1.0" "release/$shader/lib/" 2>/dev/null || true
# Keep libexec for plugin scanner
if [[ -d "release/$shader/gstreamer/libexec" ]]; then
cp -r "release/$shader/gstreamer/libexec" "release/$shader/" 2>/dev/null || true
fi
# Keep etc for configs
if [[ -d "release/$shader/gstreamer/etc" ]]; then
cp -r "release/$shader/gstreamer/etc" "release/$shader/" 2>/dev/null || true
fi
# Remove the original gstreamer folder
rm -rf "release/$shader/gstreamer" 2>/dev/null || true
echo "✅ Windows structure: exe + DLLs + lib/ + etc/ + libexec/"
fi
echo "✅ GStreamer embedded and paths fixed"
fi
# Create appropriate README based on shader group
echo "$shader Shader" > "release/$shader/README.txt"
echo "Requirements:" >> "release/$shader/README.txt"
if [[ "${{ matrix.shader_config.gstreamer_required }}" == "true" ]]; then
echo "1. No additional dependencies required - GStreamer is bundled!" >> "release/$shader/README.txt"
echo "2. The 'shaders' directory must remain in the same folder as the executable." >> "release/$shader/README.txt"
echo "3. Self-contained build with embedded media support (~80-100MB)." >> "release/$shader/README.txt"
if [[ "${{ runner.os }}" == "Windows" ]]; then
echo "" >> "release/$shader/README.txt"
echo "Windows Notes:" >> "release/$shader/README.txt"
echo "- If you see errors about missing DLLs, install Visual C++ Redistributable:" >> "release/$shader/README.txt"
echo " https://aka.ms/vs/17/release/vc_redist.x64.exe" >> "release/$shader/README.txt"
echo "- Use the .bat launcher for best compatibility" >> "release/$shader/README.txt"
fi
else
echo "1. No additional dependencies required - just run the executable!" >> "release/$shader/README.txt"
echo "2. The 'shaders' directory must remain in the same folder as the executable." >> "release/$shader/README.txt"
echo "3. This is a lightweight build without media support." >> "release/$shader/README.txt"
fi
# Windows-specific: create .bat launcher
if [[ "${{ runner.os }}" == "Windows" ]]; then
# For Windows,
if [[ "${{ matrix.shader_config.gstreamer_required }}" == "true" ]]; then
echo "@echo off" > "release/$shader/run_$shader.bat"
echo "setlocal" >> "release/$shader/run_$shader.bat"
echo "" >> "release/$shader/run_$shader.bat"
echo "REM Ensure shader directory exists" >> "release/$shader/run_$shader.bat"
echo "if not exist shaders mkdir shaders" >> "release/$shader/run_$shader.bat"
echo "" >> "release/$shader/run_$shader.bat"
echo "REM Set working directory to script location" >> "release/$shader/run_$shader.bat"
echo "cd /d \"%~dp0\"" >> "release/$shader/run_$shader.bat"
echo "" >> "release/$shader/run_$shader.bat"
echo "REM Configure GStreamer environment" >> "release/$shader/run_$shader.bat"
echo "set GST_PLUGIN_PATH=%~dp0lib\\gstreamer-1.0" >> "release/$shader/run_$shader.bat"
echo "set GST_PLUGIN_SYSTEM_PATH=" >> "release/$shader/run_$shader.bat"
echo "set GST_REGISTRY=%~dp0gst-registry.bin" >> "release/$shader/run_$shader.bat"
echo "set GST_PLUGIN_SCANNER=%~dp0libexec\\gstreamer-1.0\\gst-plugin-scanner.exe" >> "release/$shader/run_$shader.bat"
echo "" >> "release/$shader/run_$shader.bat"
echo "REM Disable conflicting environment variables" >> "release/$shader/run_$shader.bat"
echo "set GSTREAMER_1_0_ROOT_MSVC_X86_64=" >> "release/$shader/run_$shader.bat"
echo "set GSTREAMER_1_0_ROOT_MINGW_X86_64=" >> "release/$shader/run_$shader.bat"
echo "" >> "release/$shader/run_$shader.bat"
echo "REM Run the shader" >> "release/$shader/run_$shader.bat"
echo "$shader.exe %*" >> "release/$shader/run_$shader.bat"
echo "endlocal" >> "release/$shader/run_$shader.bat"
else
# Simple launcher for non-media shaders
echo "@echo off" > "release/$shader/run_$shader.bat"
echo "if not exist shaders mkdir shaders" >> "release/$shader/run_$shader.bat"
echo "$shader.exe %*" >> "release/$shader/run_$shader.bat"
fi
fi
# Create launcher script for Linux/MacOS
if [[ "${{ runner.os }}" != "Windows" ]]; then
echo '#!/bin/bash' > "release/$shader/run_$shader.sh"
echo 'mkdir -p shaders' >> "release/$shader/run_$shader.sh"
# Add GStreamer environment setup for media shaders
if [[ "${{ matrix.shader_config.gstreamer_required }}" == "true" ]]; then
echo 'SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"' >> "release/$shader/run_$shader.sh"
echo 'export GST_PLUGIN_PATH="$SCRIPT_DIR/gstreamer/lib/gstreamer-1.0"' >> "release/$shader/run_$shader.sh"
echo 'export GST_PLUGIN_SYSTEM_PATH=""' >> "release/$shader/run_$shader.sh"
echo 'export GST_REGISTRY="$SCRIPT_DIR/gstreamer/registry.bin"' >> "release/$shader/run_$shader.sh"
# Set plugin scanner for macOS and Linux
if [[ "${{ runner.os }}" == "macOS" ]]; then
echo 'export GST_PLUGIN_SCANNER="$SCRIPT_DIR/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner"' >> "release/$shader/run_$shader.sh"
elif [[ "${{ runner.os }}" == "Linux" ]]; then
echo 'export GST_PLUGIN_SCANNER="$SCRIPT_DIR/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner"' >> "release/$shader/run_$shader.sh"
fi
# Linux-specific: Add library path
if [[ "${{ runner.os }}" == "Linux" ]]; then
echo 'export LD_LIBRARY_PATH="$SCRIPT_DIR/gstreamer/lib:$LD_LIBRARY_PATH"' >> "release/$shader/run_$shader.sh"
fi
fi
echo "./$shader \"\$@\"" >> "release/$shader/run_$shader.sh"
chmod +x "release/$shader/run_$shader.sh"
fi
done
# Create archives for each shader
- name: Create archives
shell: bash
run: |
cd release
IFS=',' read -ra SHADERS <<< "${{ matrix.shader_config.shaders }}"
for shader in "${SHADERS[@]}"; do
echo "Creating archive for: $shader"
if [[ "${{ runner.os }}" == "Windows" ]]; then
7z a "../$shader-${{ matrix.target }}${{ matrix.archive_ext }}" "$shader"
else
tar -czf "../$shader-${{ matrix.target }}${{ matrix.archive_ext }}" "$shader"
fi
done
# Upload artifacts for each shader
- name: Upload artifacts
shell: bash
run: |
IFS=',' read -ra SHADERS <<< "${{ matrix.shader_config.shaders }}"
for shader in "${SHADERS[@]}"; do
echo "Uploading artifact for: $shader"
done
- name: Upload artifacts to GitHub
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.shader_config.group }}-${{ matrix.target }}
path: "*-${{ matrix.target }}${{ matrix.archive_ext }}"
release:
needs: [build]
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: artifacts/**/*
token: ${{ secrets.GITHUB_TOKEN }}
draft: false
prerelease: false
generate_release_notes: true