Skip to content

Commit 737a65c

Browse files
committed
Build Windows FFmpeg with pinned dependency sources and runtime verification
1 parent ad5ad60 commit 737a65c

8 files changed

Lines changed: 588 additions & 0 deletions

File tree

‎.gitattributes‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@
1818
# Keep the upstream FFmpeg notices byte-for-byte for the pinned SHA-256 checks.
1919
scripts/runtime/ffmpeg/COPYING.GPLv3.txt -text
2020
scripts/runtime/ffmpeg/UPSTREAM-README.txt -text -whitespace
21+
# Preserve the verified bundled notices exactly as emitted by the runtime build.
22+
scripts/runtime/ffmpeg-bundled/*.txt -text -whitespace
23+
scripts/runtime/ffmpeg-bundled/SOURCES.md -text
24+
*.sh text eol=lf
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Build media runtime
2+
3+
on:
4+
workflow_dispatch:
5+
6+
permissions:
7+
contents: read
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-24.04
12+
timeout-minutes: 45
13+
steps:
14+
- uses: actions/checkout@v4
15+
- name: Install cross compiler and build tools
16+
run: |
17+
sudo apt-get update
18+
sudo apt-get install -y --no-install-recommends \
19+
build-essential curl ca-certificates xz-utils python3 meson ninja-build \
20+
pkg-config nasm autoconf automake libtool \
21+
gcc-mingw-w64-x86-64-posix g++-mingw-w64-x86-64-posix \
22+
binutils-mingw-w64-x86-64 mingw-w64-tools
23+
- name: Build and package pinned sources
24+
run: bash scripts/runtime/build/build.sh "$RUNNER_TEMP/ufriend-ffmpeg-build" "$GITHUB_WORKSPACE/local/runtime-build-output"
25+
- uses: actions/upload-artifact@v4
26+
if: always()
27+
with:
28+
name: ffmpeg-runtime-build
29+
path: |
30+
local/runtime-build-output/*.zip
31+
local/runtime-build-output/*.tar.xz
32+
local/runtime-build-output/*.json
33+
local/runtime-build-output/build.log
34+
if-no-files-found: error
35+
retention-days: 14
36+
37+
verify-windows:
38+
needs: build
39+
runs-on: windows-latest
40+
timeout-minutes: 15
41+
steps:
42+
- uses: actions/checkout@v4
43+
- uses: actions/download-artifact@v4
44+
with:
45+
name: ffmpeg-runtime-build
46+
path: local/runtime-build-output
47+
- name: Exercise static Windows executables
48+
shell: pwsh
49+
run: ./scripts/runtime/build/verify-runtime.ps1 -ArtifactDirectory ./local/runtime-build-output
50+
- uses: actions/upload-artifact@v4
51+
if: always()
52+
with:
53+
name: ffmpeg-runtime-verified
54+
path: |
55+
local/runtime-build-output/*.zip
56+
local/runtime-build-output/*.tar.xz
57+
local/runtime-build-output/*.json
58+
if-no-files-found: error
59+
retention-days: 14

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ yarn-error.log*
2828
/docs/product/
2929
/docs/development/*
3030
!/docs/development/FFMPEG_RUNTIME.md
31+
!/docs/development/MEDIA_RUNTIME_BUILD.md
3132

3233
# Keep only the artwork required by the icon build
3334
/design/logo-options/*
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# UFriend's Windows FFmpeg build
2+
3+
This recipe builds FFmpeg 8.1.2 with the `ufriend1` suffix from seven pinned
4+
source archives. It includes x264, LAME, libass, FreeType, FriBidi and HarfBuzz.
5+
The native FFmpeg codecs, formats and filters are kept where their prerequisites
6+
are available. libass discovers installed Windows fonts through DirectWrite/GDI.
7+
Network access, fontconfig, extra codec libraries and hardware SDKs are disabled.
8+
9+
The GitHub Actions workflow builds on Ubuntu 24.04, rejects any PE imports outside
10+
Windows system DLLs, then runs both executables on Windows. The Windows job encodes
11+
and decodes H.264/AAC, burns UTF-8 subtitles using DirectWrite, inspects metadata
12+
with ffprobe, and prepares an MP3 segment plus CSV in the same format the app uses.
13+
A compiled payload is not a verified release until that Windows job passes.
14+
15+
Install the generic build tools on Ubuntu 24.04:
16+
17+
```sh
18+
sudo apt-get update
19+
sudo apt-get install --no-install-recommends build-essential curl ca-certificates \
20+
xz-utils python3 meson ninja-build pkg-config nasm autoconf automake libtool \
21+
gcc-mingw-w64-x86-64-posix g++-mingw-w64-x86-64-posix \
22+
binutils-mingw-w64-x86-64 mingw-w64-tools
23+
bash recipe/build.sh "$PWD/new-work" "$PWD/new-output" "$PWD/sources"
24+
```
25+
26+
For a repository checkout, use `scripts/runtime/build/build.sh` in place of
27+
`recipe/build.sh` and omit the final argument to download the pinned inputs. The
28+
work and output directories must not already exist. The source package contains
29+
all seven original input archives and can rebuild without fetching those inputs.
30+
Build tools still need to be installed. Their exact versions and copyright files
31+
are retained in `configuration/toolchain.txt` and `licenses/toolchain/`.
32+
33+
No upstream source patch is applied. Generated build files and compiler flags
34+
are retained in `configuration/`. `build.sh` regenerates prefix-dependent files
35+
for the chosen work directory. The runtime and source package include their
36+
shared source inventory and build information; `build-receipt.json` binds both
37+
archives by SHA-256. `windows-verification.json` records actual execution results.
38+
39+
The executables are GPL-3.0-or-later. The source package accompanies the binary
40+
under GPL section 6(d). Unmodified general-purpose tools and Windows system
41+
libraries are not part of the application source archive. Their applicable
42+
notices, including compiler runtime exceptions, are preserved. FreeType is used
43+
under the FreeType License. The build does not relicense UFriend's separate app.

‎scripts/runtime/build/build.sh‎

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/usr/bin/env bash
2+
# Build only in new directories. The optional third argument is an offline
3+
# directory containing the exact source archives from sources.lock.json.
4+
set -euo pipefail
5+
RECIPE_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
6+
WORK_ROOT="$(realpath -m -- "${1:?Pass a new build directory}")"
7+
OUTPUT_ROOT="$(realpath -m -- "${2:?Pass a new output directory}")"
8+
SOURCE_CACHE="${3:-}"
9+
if [[ -e "$WORK_ROOT" || -e "$OUTPUT_ROOT" ]]; then
10+
echo 'Build and output directories must not already exist.' >&2
11+
exit 1
12+
fi
13+
mkdir -p "$WORK_ROOT" "$OUTPUT_ROOT"
14+
exec > >(tee "$OUTPUT_ROOT/build.log") 2>&1
15+
export LC_ALL=C TZ=UTC SOURCE_DATE_EPOCH=1782568800
16+
export CROSS=x86_64-w64-mingw32
17+
export CC="$CROSS-gcc-posix" CXX="$CROSS-g++-posix"
18+
export AR="$CROSS-ar" RANLIB="$CROSS-ranlib" STRIP="$CROSS-strip"
19+
export CFLAGS='-O2 -pipe -fno-ident' CXXFLAGS='-O2 -pipe -fno-ident'
20+
export LDFLAGS='-static -static-libgcc -static-libstdc++ -Wl,--no-insert-timestamp'
21+
PREFIX="$WORK_ROOT/prefix"
22+
export PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig"
23+
export PKG_CONFIG_PATH='' PKG_CONFIG_SYSROOT_DIR=''
24+
JOBS="${JOBS:-$(nproc)}"
25+
mkdir -p "$PREFIX" "$WORK_ROOT/configuration" "$WORK_ROOT/toolchain-licenses"
26+
python3 "$RECIPE_DIR/package.py" fetch "$WORK_ROOT" "$SOURCE_CACHE"
27+
28+
cat > "$WORK_ROOT/cross.ini" <<EOF
29+
[binaries]
30+
c = '$CC'
31+
cpp = '$CXX'
32+
ar = '$AR'
33+
strip = '$STRIP'
34+
windres = '$CROSS-windres'
35+
pkg-config = 'pkg-config'
36+
[properties]
37+
needs_exe_wrapper = true
38+
pkg_config_libdir = ['$PKG_CONFIG_LIBDIR']
39+
[host_machine]
40+
system = 'windows'
41+
cpu_family = 'x86_64'
42+
cpu = 'x86_64'
43+
endian = 'little'
44+
EOF
45+
cp "$WORK_ROOT/cross.ini" "$WORK_ROOT/configuration/cross.ini"
46+
{
47+
"$CC" --version
48+
"$CXX" --version
49+
"$CROSS-ld" --version
50+
meson --version
51+
ninja --version
52+
nasm -v
53+
python3 --version
54+
dpkg-query -W -f='${binary:Package}\t${Version}\t${source:Package}\t${source:Version}\n' \
55+
gcc-mingw-w64-x86-64-posix g++-mingw-w64-x86-64-posix \
56+
mingw-w64-common mingw-w64-x86-64-dev
57+
} > "$WORK_ROOT/configuration/toolchain.txt"
58+
for package in gcc-mingw-w64-x86-64-posix g++-mingw-w64-x86-64-posix mingw-w64-common mingw-w64-x86-64-dev; do
59+
cp -L "/usr/share/doc/$package/copyright" "$WORK_ROOT/toolchain-licenses/$package.txt"
60+
done
61+
62+
meson_build() {
63+
local name="$1"; shift
64+
meson setup "$WORK_ROOT/build-$name" "$WORK_ROOT/src/$name" \
65+
--cross-file "$WORK_ROOT/cross.ini" --prefix "$PREFIX" --libdir lib \
66+
--buildtype release --default-library static --wrap-mode nofallback \
67+
-Dauto_features=disabled "$@"
68+
ninja -C "$WORK_ROOT/build-$name" -j "$JOBS"
69+
ninja -C "$WORK_ROOT/build-$name" install
70+
cp "$WORK_ROOT/build-$name/meson-info/intro-buildoptions.json" \
71+
"$WORK_ROOT/configuration/$name-buildoptions.json"
72+
}
73+
meson_build freetype -Dharfbuzz=disabled -Dbrotli=disabled -Dbzip2=disabled -Dpng=disabled -Dzlib=none -Dtests=disabled
74+
meson_build fribidi -Ddocs=false -Dbin=false -Dtests=false
75+
meson_build harfbuzz -Dglib=disabled -Dgobject=disabled -Dcairo=disabled -Dicu=disabled \
76+
-Dfreetype=disabled -Dgraphite2=disabled -Dtests=disabled -Dutilities=disabled \
77+
-Ddocs=disabled -Dintrospection=disabled -Dwith_libstdcxx=false
78+
meson_build libass -Ddirectwrite=enabled -Dfontconfig=disabled -Dcoretext=disabled \
79+
-Dlibunibreak=disabled -Dtest=disabled -Dcompare=disabled -Dprofile=disabled \
80+
-Dfuzz=disabled -Dcheckasm=disabled -Dasm=enabled
81+
82+
(
83+
cd "$WORK_ROOT/src/x264"
84+
./configure --prefix="$PREFIX" --host="$CROSS" --cross-prefix="$CROSS-" \
85+
--enable-static --disable-cli --disable-opencl --disable-lavf --disable-swscale
86+
make -j "$JOBS"
87+
make install
88+
cp config.mak "$WORK_ROOT/configuration/x264-config.mak"
89+
)
90+
(
91+
cd "$WORK_ROOT/src/lame"
92+
./configure --prefix="$PREFIX" --host="$CROSS" \
93+
--enable-static --disable-shared --disable-frontend --disable-decoder --disable-cpml
94+
make -j "$JOBS"
95+
make install
96+
cp config.log "$WORK_ROOT/configuration/lame-config.log"
97+
)
98+
(
99+
cd "$WORK_ROOT/src/ffmpeg"
100+
./configure --prefix="$PREFIX" --target-os=mingw32 --arch=x86_64 \
101+
--cross-prefix="$CROSS-" --cc="$CC" --cxx="$CXX" --ar="$AR" --ranlib="$RANLIB" \
102+
--pkg-config=pkg-config --pkg-config-flags=--static \
103+
--extra-cflags="$CFLAGS -I$PREFIX/include" --extra-cxxflags="$CXXFLAGS -I$PREFIX/include" \
104+
--extra-ldflags="$LDFLAGS -L$PREFIX/lib" \
105+
--extra-version=ufriend1 --enable-gpl --enable-version3 \
106+
--enable-static --disable-shared --disable-autodetect --disable-doc --disable-debug \
107+
--disable-ffplay --disable-network --disable-pthreads --enable-w32threads \
108+
--enable-libass --enable-libx264 --enable-libmp3lame
109+
make -j "$JOBS"
110+
make install
111+
cp ffbuild/config.mak ffbuild/config.log config.h "$WORK_ROOT/configuration/"
112+
)
113+
python3 "$RECIPE_DIR/package.py" package "$WORK_ROOT" "$OUTPUT_ROOT"

0 commit comments

Comments
 (0)