Merge pull request #4 from irlserver/feat/bundled-ffmpeg #210
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build | |
| on: | |
| push: | |
| branches: [main, master] | |
| pull_request: | |
| workflow_call: | |
| # The plugin bundles its own static FFmpeg/libsrt, so the only remaining tie to | |
| # a specific OBS release is libobs itself. libobs gates a module on | |
| # (major, minor) <= host version and looks up nothing but obs_module_*, so | |
| # building against the OLDEST supported line produces one artifact that loads | |
| # on that line and every newer one. That is why there is no per-OBS-line matrix | |
| # here any more. | |
| env: | |
| OBS_VERSION: "32.1.2" | |
| OBS_DEPS_VERSION: "2025-08-23" | |
| jobs: | |
| linux-x64: | |
| runs-on: ubuntu-26.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential cmake pkg-config nasm meson ninja-build \ | |
| libobs-dev libva-dev | |
| # Only the install prefix is cached. The source and object trees are an | |
| # order of magnitude larger and the build-marker files live inside the | |
| # prefix, so a restored prefix alone is enough to skip every dep build. | |
| - name: Cache bundled deps | |
| id: cache-deps | |
| uses: actions/cache@v4 | |
| with: | |
| path: deps/.build/prefix | |
| key: irl-deps-linux-x64-${{ hashFiles('deps/versions.env', 'deps/build-deps.sh') }} | |
| - name: Build bundled deps | |
| run: ./deps/build-deps.sh | |
| - name: Configure | |
| run: cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo | |
| - name: Build | |
| run: cmake --build build --parallel | |
| - name: Verify isolation | |
| run: ./scripts/verify-plugin.sh build/obs-irl-source.so | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: obs-irl-source-linux-x64 | |
| path: build/obs-irl-source.so | |
| windows-x64: | |
| runs-on: windows-2025-vs2026 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup MSVC | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| with: | |
| arch: x64 | |
| # librist builds with meson. It has to be the Windows-native meson (so it | |
| # detects cl.exe rather than looking for a POSIX toolchain), which | |
| # path-type: inherit below then makes visible inside MSYS2. | |
| - name: Install meson | |
| shell: pwsh | |
| run: pip install --disable-pip-version-check meson ninja | |
| # FFmpeg's configure needs a POSIX shell even when it drives cl.exe. | |
| # path-type: inherit keeps the MSVC environment visible inside MSYS2. | |
| - name: Setup MSYS2 | |
| uses: msys2/setup-msys2@v2 | |
| with: | |
| msystem: MSYS | |
| path-type: inherit | |
| update: false | |
| install: make nasm diffutils pkgconf | |
| - name: Cache bundled deps | |
| id: cache-deps | |
| uses: actions/cache@v4 | |
| with: | |
| path: deps/.build/prefix | |
| key: irl-deps-windows-x64-${{ hashFiles('deps/versions.env', 'deps/build-deps.sh') }} | |
| - name: Build bundled deps | |
| shell: msys2 {0} | |
| run: ./deps/build-deps.sh | |
| - name: Cache OBS build | |
| id: cache-obs | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| obs-src | |
| obs-deps | |
| key: obs-build-${{ env.OBS_VERSION }}-${{ env.OBS_DEPS_VERSION }}-v3 | |
| # obs-deps is still needed here, but only to build libobs itself. The | |
| # plugin no longer links its FFmpeg. | |
| - name: Download OBS dependencies | |
| if: steps.cache-obs.outputs.cache-hit != 'true' | |
| shell: pwsh | |
| run: | | |
| Invoke-WebRequest ` | |
| -Uri "https://github.com/obsproject/obs-deps/releases/download/${{ env.OBS_DEPS_VERSION }}/windows-deps-${{ env.OBS_DEPS_VERSION }}-x64.zip" ` | |
| -OutFile obs-deps.zip | |
| Expand-Archive obs-deps.zip -DestinationPath obs-deps | |
| - name: Clone OBS source | |
| if: steps.cache-obs.outputs.cache-hit != 'true' | |
| run: git clone --depth 1 --branch ${{ env.OBS_VERSION }} https://github.com/obsproject/obs-studio.git obs-src | |
| - name: Patch OBS to build only libobs | |
| if: steps.cache-obs.outputs.cache-hit != 'true' | |
| shell: pwsh | |
| run: | | |
| # Keep only libobs + w32-pthreads, remove all other subdirectories | |
| # (plugins, frontend, renderers, tests) | |
| $lines = Get-Content obs-src/CMakeLists.txt | |
| $output = @() | |
| $done = $false | |
| foreach ($line in $lines) { | |
| if ($done) { continue } | |
| if ($line -match '^\s*add_subdirectory\(libobs\)\s*$') { | |
| $output += 'add_subdirectory(deps/w32-pthreads)' | |
| $output += $line | |
| $done = $true | |
| } else { | |
| $output += $line | |
| } | |
| } | |
| $output | Set-Content obs-src/CMakeLists.txt | |
| # Disable automatic dependency download (we provide deps via CMAKE_PREFIX_PATH) | |
| (Get-Content obs-src/cmake/windows/defaults.cmake) ` | |
| -replace '^include\(buildspec\)', '# include(buildspec)' | | |
| Set-Content obs-src/cmake/windows/defaults.cmake | |
| # Skip multi-architecture subprocess builds (OBS normally launches | |
| # a child cmake for x86 which would fail in our stripped-down tree) | |
| @" | |
| include_guard(GLOBAL) | |
| include(compilerconfig) | |
| if(NOT DEFINED OBS_PARENT_ARCHITECTURE) | |
| set(OBS_PARENT_ARCHITECTURE `${CMAKE_VS_PLATFORM_NAME}) | |
| endif() | |
| "@ | Set-Content obs-src/cmake/windows/architecture.cmake | |
| - name: Configure OBS | |
| if: steps.cache-obs.outputs.cache-hit != 'true' | |
| shell: cmd | |
| run: > | |
| cmake -S obs-src -B obs-src/build | |
| -G "Visual Studio 18 2026" -A x64 | |
| -DCMAKE_PREFIX_PATH=%CD%\obs-deps | |
| -DENABLE_UI=OFF | |
| -DENABLE_PLUGINS=OFF | |
| - name: Build OBS (libobs only) | |
| if: steps.cache-obs.outputs.cache-hit != 'true' | |
| shell: cmd | |
| run: cmake --build obs-src/build --config Release --target libobs --target w32-pthreads | |
| - name: Configure | |
| shell: cmd | |
| run: > | |
| cmake -B build | |
| -G "Visual Studio 18 2026" -A x64 | |
| -DOBS_SOURCE_DIR=%CD%\obs-src | |
| - name: Build | |
| shell: cmd | |
| run: cmake --build build --config RelWithDebInfo --parallel | |
| - name: Verify isolation | |
| shell: pwsh | |
| run: | | |
| $dll = "build/RelWithDebInfo/obs-irl-source.dll" | |
| $deps = (dumpbin /dependents $dll) -join "`n" | |
| $exports = (dumpbin /exports $dll) -join "`n" | |
| $fail = $false | |
| if ($deps -match 'av(codec|format|util)-\d+\.dll|sws(cale)?-\d+\.dll|swresample-\d+\.dll') { | |
| Write-Host " FAIL plugin still imports a host FFmpeg DLL"; $fail = $true | |
| } else { | |
| Write-Host " ok no FFmpeg DLL imports (host FFmpeg not required)" | |
| } | |
| if ($exports -match '\bav_|\bavcodec_|\bsrt_|\bmbedtls_') { | |
| Write-Host " FAIL bundled stack symbols are exported"; $fail = $true | |
| } else { | |
| Write-Host " ok bundled stack symbols not exported" | |
| } | |
| if ($exports -match 'obs_module_load') { | |
| Write-Host " ok obs_module_load exported" | |
| } else { | |
| Write-Host " FAIL obs_module_load missing"; $fail = $true | |
| } | |
| if ($fail) { Write-Host $deps; Write-Host $exports; exit 1 } | |
| - name: Collect runtime dependencies | |
| shell: pwsh | |
| run: | | |
| # Copy w32-pthreads.dll next to the plugin | |
| $w32dll = Get-ChildItem -Path obs-src/build/deps/w32-pthreads -Filter "w32-pthreads.dll" -Recurse | Select-Object -First 1 | |
| if ($w32dll) { | |
| Copy-Item $w32dll.FullName build/RelWithDebInfo/ | |
| } | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: obs-irl-source-windows-x64 | |
| path: | | |
| build/RelWithDebInfo/obs-irl-source.dll | |
| build/RelWithDebInfo/w32-pthreads.dll | |
| # PDB ships in the CI artifact (not the release zip) so a crash | |
| # log resolves obs-irl-source.dll frames to function names. | |
| # OBS's crash handler reads it if it sits next to the DLL. | |
| build/RelWithDebInfo/obs-irl-source.pdb | |
| macos-arm64: | |
| runs-on: macos-15 | |
| env: | |
| MACOSX_DEPLOYMENT_TARGET: "12.0" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # ffmpeg is intentionally NOT installed from Homebrew. The plugin links | |
| # the bundled static stack instead, which is what removes its dependency | |
| # on whatever FFmpeg the host OBS ships. | |
| - name: Install build tools | |
| run: brew install cmake pkg-config nasm meson ninja simde uthash jansson | |
| - name: Cache bundled deps | |
| id: cache-deps | |
| uses: actions/cache@v4 | |
| with: | |
| path: deps/.build/prefix | |
| key: irl-deps-macos-arm64-${{ hashFiles('deps/versions.env', 'deps/build-deps.sh') }} | |
| - name: Build bundled deps | |
| run: ./deps/build-deps.sh | |
| - name: Cache OBS build | |
| id: cache-obs | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| obs-src | |
| obs-deps | |
| key: obs-macos-arm64-${{ env.OBS_VERSION }}-${{ env.OBS_DEPS_VERSION }}-v3 | |
| - name: Download OBS dependencies | |
| if: steps.cache-obs.outputs.cache-hit != 'true' | |
| run: | | |
| curl -L -o macos-deps.tar.xz \ | |
| "https://github.com/obsproject/obs-deps/releases/download/${{ env.OBS_DEPS_VERSION }}/macos-deps-${{ env.OBS_DEPS_VERSION }}-arm64.tar.xz" | |
| mkdir -p obs-deps | |
| tar -xf macos-deps.tar.xz -C obs-deps | |
| - name: Clone OBS source | |
| if: steps.cache-obs.outputs.cache-hit != 'true' | |
| run: git clone --depth 1 --branch ${{ env.OBS_VERSION }} https://github.com/obsproject/obs-studio.git obs-src | |
| - name: Patch OBS to build only libobs | |
| if: steps.cache-obs.outputs.cache-hit != 'true' | |
| run: | | |
| # Truncate CMakeLists.txt after add_subdirectory(libobs) | |
| sed -i '' '/^add_subdirectory(libobs)/q' obs-src/CMakeLists.txt | |
| # Disable automatic dependency download | |
| sed -i '' 's/^include(buildspec)/# include(buildspec)/' obs-src/cmake/macos/defaults.cmake | |
| # Allow Homebrew paths (OBS blocks them by default) | |
| sed -i '' '/CMAKE_IGNORE_PREFIX_PATH/d' obs-src/cmake/macos/defaults.cmake | |
| # Relax OBS's SDK/Xcode floor. OBS gates the whole app on a very | |
| # recent SDK, but we only build libobs with the UI off, which | |
| # compiles on the runner's SDK. | |
| sed -i '' -E 's/set\(obs_macos_minimum_sdk [0-9.]+\)/set(obs_macos_minimum_sdk 1.0)/' obs-src/cmake/macos/compilerconfig.cmake | |
| sed -i '' -E 's/set\(obs_macos_minimum_xcode [0-9.]+\)/set(obs_macos_minimum_xcode 1.0)/' obs-src/cmake/macos/compilerconfig.cmake | |
| - name: Configure OBS | |
| if: steps.cache-obs.outputs.cache-hit != 'true' | |
| run: > | |
| cmake -S obs-src -B obs-src/build | |
| -G Xcode | |
| -DENABLE_UI=OFF | |
| -DCMAKE_OSX_DEPLOYMENT_TARGET=12.0 | |
| -DCMAKE_PREFIX_PATH="$PWD/obs-deps;$(brew --prefix)" | |
| - name: Build OBS (libobs only) | |
| if: steps.cache-obs.outputs.cache-hit != 'true' | |
| run: cmake --build obs-src/build --config Release --target libobs --parallel | |
| # PkgConfig is disabled so a stray Homebrew or obs-deps FFmpeg .pc cannot | |
| # shadow the bundled headers. | |
| - name: Configure | |
| run: > | |
| cmake -B build | |
| -DCMAKE_BUILD_TYPE=RelWithDebInfo | |
| -DOBS_SOURCE_DIR=$PWD/obs-src | |
| -DCMAKE_DISABLE_FIND_PACKAGE_PkgConfig=ON | |
| -DCMAKE_C_FLAGS="-I$(brew --prefix)/include" | |
| - name: Build | |
| run: cmake --build build --parallel | |
| - name: Verify isolation | |
| run: ./scripts/verify-plugin.sh build/obs-irl-source.so | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: obs-irl-source-macos-arm64 | |
| path: build/obs-irl-source.so |