@@ -138,6 +138,238 @@ jobs:
138138 save-if : ${{ startsWith(github.ref_name, 'release/') || github.ref_name == 'develop' }}
139139 workspaces : application\ui\src-tauri -> target
140140
141+ # Build custom ffmpeg
142+
143+ - name : Install MSYS2 (for FFmpeg build tools)
144+ uses : msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2.32.0
145+ with :
146+ msystem : UCRT64
147+ update : true
148+ install : >-
149+ base-devel
150+ mingw-w64-ucrt-x86_64-toolchain
151+ mingw-w64-ucrt-x86_64-cmake
152+ mingw-w64-ucrt-x86_64-nasm
153+ mingw-w64-ucrt-x86_64-pkg-config
154+ mingw-w64-ucrt-x86_64-meson
155+ mingw-w64-ucrt-x86_64-ninja
156+ mingw-w64-ucrt-x86_64-libvpx
157+ mingw-w64-ucrt-x86_64-opus
158+ git
159+ diffutils
160+ make
161+
162+ - name : Configure custom prefix
163+ shell : msys2 {0}
164+ run : |
165+ set -euo pipefail
166+ PREFIX="/c/ffmpeg-build"
167+ mkdir -p "$PREFIX"
168+ echo "PREFIX=$PREFIX" >> $GITHUB_ENV
169+ echo "PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig:${PKG_CONFIG_PATH:-}" >> $GITHUB_ENV
170+
171+ - name : Build OpenH264 from source
172+ shell : msys2 {0}
173+ env :
174+ OPENH264_COMMIT : " e3f5b10438e2bacc155cf54578222bd4236c9f06"
175+ run : |
176+ set -euo pipefail
177+ export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
178+
179+ git init openh264
180+ cd openh264
181+ git remote add origin https://github.com/cisco/openh264.git
182+ git fetch --depth 1 origin "${OPENH264_COMMIT}"
183+ git checkout FETCH_HEAD
184+
185+ make -j$(nproc) \
186+ PREFIX="$PREFIX" \
187+ BUILDTYPE=Release \
188+ OS=mingw_nt \
189+ ARCH=x86_64 \
190+ install
191+
192+ # Verify install
193+ pkg-config --modversion openh264
194+
195+ - name : Build SVT-AV1 from source
196+ shell : msys2 {0}
197+ env :
198+ SVT_AV1_COMMIT : " e7fcc226994c87b76b66389545eb73a844f13002"
199+ run : |
200+ set -euo pipefail
201+ export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
202+
203+ git init svtav1
204+ cd svtav1
205+ git remote add origin https://gitlab.com/AOMediaCodec/SVT-AV1.git
206+ git fetch --depth 1 origin "${SVT_AV1_COMMIT}"
207+ git checkout FETCH_HEAD
208+
209+ cmake -B build -G "Ninja" \
210+ -DCMAKE_INSTALL_PREFIX="$PREFIX" \
211+ -DCMAKE_BUILD_TYPE=Release \
212+ -DBUILD_SHARED_LIBS=ON \
213+ -DBUILD_TESTING=OFF \
214+ -DBUILD_APPS=OFF \
215+ -DBUILD_DEC=ON \
216+ -DBUILD_ENC=ON
217+
218+ cmake --build build -j$(nproc)
219+ cmake --install build
220+
221+ # Verify install
222+ pkg-config --modversion SvtAv1Enc
223+
224+ - name : Build libvpl (oneVPL) from source
225+ shell : msys2 {0}
226+ env :
227+ LIBVPL_COMMIT : " 778a66d6c6537f08eabb91955dbbf1bce3812894"
228+ run : |
229+ set -euo pipefail
230+ export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
231+
232+ git init libvpl
233+ cd libvpl
234+ git remote add origin https://github.com/intel/libvpl.git
235+ git fetch --depth 1 origin "${LIBVPL_COMMIT}"
236+ git checkout FETCH_HEAD
237+
238+ cmake -B build -G "Ninja" \
239+ -DCMAKE_INSTALL_PREFIX="$PREFIX" \
240+ -DCMAKE_BUILD_TYPE=Release \
241+ -DBUILD_SHARED_LIBS=ON \
242+ -DBUILD_TESTS=OFF \
243+ -DBUILD_EXAMPLES=OFF \
244+ -DBUILD_TOOLS=OFF
245+
246+ cmake --build build -j$(nproc)
247+ cmake --install build
248+
249+ # Verify install
250+ pkg-config --modversion vpl
251+
252+ - name : Build FFmpeg from source
253+ shell : msys2 {0}
254+ env :
255+ FFMPEG_COMMIT : " 00d1f41b2eb070803a927c6132c240e14142d0b9"
256+ run : |
257+ set -euo pipefail
258+ export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
259+
260+ export CFLAGS="-I$PREFIX/include"
261+ export LDFLAGS="-L$PREFIX/lib -L$PREFIX/lib64"
262+
263+ # Clone and checkout FFmpeg source
264+ git init ffmpeg
265+ cd ffmpeg
266+ git remote add origin https://github.com/FFmpeg/FFmpeg.git
267+ git fetch --depth 1 origin "${FFMPEG_COMMIT}"
268+ git checkout FETCH_HEAD
269+
270+ ./configure \
271+ --prefix="$PREFIX" \
272+ --extra-libs="-lpthread -lm" \
273+ --enable-libvpl \
274+ --enable-shared \
275+ --enable-libsvtav1 \
276+ --enable-libopenh264 \
277+ --enable-libvpx
278+
279+ make -j$(nproc)
280+ make install
281+
282+ # Verify headers and libraries are installed
283+ ls "$PREFIX/include/libavcodec/avcodec.h"
284+ ls "$PREFIX/lib/pkgconfig/libavcodec.pc"
285+ pkg-config --modversion libavcodec libavformat libswscale
286+ "$PREFIX/bin/ffmpeg" -version
287+ "$PREFIX/bin/ffmpeg" -hide_banner -encoders | grep qsv
288+ "$PREFIX/bin/ffmpeg" -hide_banner -h encoder=h264_qsv
289+
290+ - name : Copy runtime DLLs into FFmpeg prefix
291+ shell : msys2 {0}
292+ run : |
293+ set -euo pipefail
294+ # Copy MinGW runtime DLLs and transitive dependencies into FFmpeg bin dir
295+ for dll in libgcc_s_seh-1.dll libwinpthread-1.dll libstdc++-6.dll \
296+ libiconv-2.dll liblzma-5.dll zlib1.dll libbz2-1.dll; do
297+ if [ -f "/ucrt64/bin/$dll" ]; then
298+ cp "/ucrt64/bin/$dll" "$PREFIX/bin/"
299+ echo "Copied $dll to $PREFIX/bin/"
300+ fi
301+ done
302+ # Also copy codec runtime DLLs that FFmpeg depends on
303+ for pattern in libvpx-*.dll libopus-*.dll; do
304+ for f in /ucrt64/bin/$pattern; do
305+ if [ -f "$f" ]; then
306+ cp "$f" "$PREFIX/bin/"
307+ echo "Copied $(basename $f) to $PREFIX/bin/"
308+ fi
309+ done
310+ done
311+
312+ - name : Set up MSVC developer environment
313+ uses : ilammy/msvc-dev-cmd@7315a94840631165970262a99c72cfb48a65d25d # v1.13.0
314+ with :
315+ arch : x64
316+
317+ - name : Generate MSVC import libraries from FFmpeg DLLs
318+ run : |
319+ $BIN_PATH = "C:\ffmpeg-build\bin"
320+ $LIB_PATH = "C:\ffmpeg-build\lib"
321+ $ffmpegLibs = @("avformat", "avcodec", "avdevice", "avutil", "avfilter", "swscale", "swresample")
322+ foreach ($lib in $ffmpegLibs) {
323+ $dll = Get-ChildItem "$BIN_PATH\$lib*.dll" -ErrorAction SilentlyContinue | Select-Object -First 1
324+ if ($dll) {
325+ Write-Host "Generating $lib.lib from $($dll.Name)"
326+ $defFile = "$LIB_PATH\$lib.def"
327+ $libFile = "$LIB_PATH\$lib.lib"
328+ dumpbin /EXPORTS $dll.FullName /OUT:"$LIB_PATH\$lib.exports.txt"
329+ $defContent = "LIBRARY $($dll.Name)`nEXPORTS`n"
330+ Get-Content "$LIB_PATH\$lib.exports.txt" | ForEach-Object {
331+ if ($_ -match "^\s+\d+\s+[0-9A-Fa-f]+\s+[0-9A-Fa-f]+\s+(\S+)") {
332+ $defContent += " $($Matches[1])`n"
333+ }
334+ }
335+ Set-Content -Path $defFile -Value $defContent -NoNewline
336+ lib /machine:x64 /def:$defFile /out:$libFile /nologo
337+ if (Test-Path $libFile) {
338+ Write-Host " Created $libFile"
339+ } else {
340+ throw "Failed to create $libFile"
341+ }
342+ } else {
343+ Write-Host "WARNING: DLL not found for $lib at $BIN_PATH"
344+ }
345+ }
346+
347+ - name : Configure PyAV build environment
348+ run : |
349+ $FFMPEG_PREFIX = "C:\ffmpeg-build"
350+
351+ # Verify the headers exist
352+ if (-not (Test-Path "$FFMPEG_PREFIX\include\libavcodec\avcodec.h")) {
353+ throw "FFmpeg headers not found at $FFMPEG_PREFIX\include\libavcodec\avcodec.h"
354+ }
355+ Write-Host "FFmpeg headers verified at $FFMPEG_PREFIX\include"
356+
357+ # Set INCLUDE and LIB for MSVC compiler/linker
358+ $currentInclude = [System.Environment]::GetEnvironmentVariable("INCLUDE", "Process")
359+ $currentLib = [System.Environment]::GetEnvironmentVariable("LIB", "Process")
360+ Add-Content -Path $env:GITHUB_ENV -Value "INCLUDE=$FFMPEG_PREFIX\include;$currentInclude"
361+ Add-Content -Path $env:GITHUB_ENV -Value "LIB=$FFMPEG_PREFIX\lib;$currentLib"
362+
363+ # Tell uv to forward INCLUDE and LIB into isolated build environments
364+ Add-Content -Path $env:GITHUB_ENV -Value "UV_BUILD_ENV_VARS=INCLUDE,LIB"
365+
366+ # Add to PATH so DLLs are findable during build
367+ Add-Content -Path $env:GITHUB_PATH -Value "$FFMPEG_PREFIX\bin"
368+ Add-Content -Path $env:GITHUB_PATH -Value "C:\msys64\ucrt64\bin"
369+
370+ # Force uv to build PyAV from source against our FFmpeg
371+ Add-Content -Path $env:GITHUB_ENV -Value "UV_NO_BINARY_PACKAGE=av"
372+
141373 # Build backend
142374
143375 - name : Prepare venv and install Python dependencies
@@ -147,6 +379,35 @@ jobs:
147379 DEVICE : ${{ inputs.device || 'xpu' }}
148380 run : just venv --accelerator "$env:DEVICE"
149381
382+ - name : Copy FFmpeg DLLs and patch PyAV for DLL loading
383+ working-directory : application/backend
384+ run : |
385+ $avDir = ".venv\Lib\site-packages\av"
386+ $ffmpegBin = "C:\ffmpeg-build\bin"
387+
388+ # Copy all FFmpeg DLLs into the av package directory
389+ Copy-Item "$ffmpegBin\*.dll" -Destination $avDir -Force
390+ Write-Host "Copied DLLs to $avDir"
391+
392+ # Patch av/__init__.py to add the DLL directory before importing _core
393+ $avInit = "$avDir\__init__.py"
394+ $original = Get-Content $avInit -Raw
395+ $patch = @'
396+ import os as _os, sys as _sys
397+ if _sys.platform == 'win32':
398+ _av_dir = _os.path.dirname(_os.path.abspath(__file__))
399+ _dll_dir_handle = _os.add_dll_directory(_av_dir)
400+ '@
401+ $patched = $patch + "`n" + $original
402+ Set-Content -Path $avInit -Value $patched -NoNewline
403+ Write-Host "Patched $avInit"
404+
405+
406+ - name : Verify PyAV import
407+ working-directory : application/backend
408+ run : |
409+ .\.venv\Scripts\python.exe -c "import av; print(f'PyAV {av.__version__} loaded successfully')"
410+
150411 - name : Build OpenAPI spec
151412 working-directory : application/backend
152413 run : just gen-api-spec -o .build/openapi-spec.json
0 commit comments