1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
<#
.SYNOPSIS
Download, verify and stage the ffmpeg/ffprobe MeshBay bundles by default.
.DESCRIPTION
MeshBay transcodes browser-incompatible video to H.264 (webrtc_server.py)
-- a real encode, not just remux/probe -- so only a GPL ffmpeg build works
here; libx264 is GPL, no LGPL-only build includes it. The gpl-shared
preset also carries h264_qsv and h264_nvenc, which hwaccel.py uses to put
that encode on the GPU where there is one; a build without them still
works and is simply slower, on the machines that can least afford it.
Asking an end user to separately install ffmpeg (`winget install ffmpeg`)
is not viable for a non-technical install: it needs network access and
winget/App Installer present at that exact moment, and fails silently
(streaming just does not work, with nothing pointing back at ffmpeg).
So this bundles it, verified, by default.
Source: BtbN/FFmpeg-Builds (github.com/BtbN/FFmpeg-Builds), the "gpl-shared"
Windows x86_64 preset -- ffmpeg.exe/ffprobe.exe plus the shared DLLs they
both link against, rather than two independent static binaries (which is
what very nearly doubled this: the "full" static build many devs already
have via winget is ~220 MB *per executable*). ffplay.exe is dropped: it is
an SDL2 video player, not something the daemon ever invokes.
Pinned to one dated release tag (autobuild-YYYY-MM-DD-HH-MM) rather than
the "latest" alias, which BtbN repoints to a new build on every run --
fine for a person fetching ffmpeg today, wrong for a build script that
must produce the same output next month. Checksum verified against the
release's own checksums.sha256, and the hash is pinned here too, so a
compromised or altered mirror is a hard failure, not a silent swap.
LICENSE-ffmpeg.txt is copied alongside ffmpeg.exe in the output -- ffmpeg
is unmodified, but it is still a GPLv3 binary MeshBay redistributes, and
that binary must carry its own license notice into the package.
.PARAMETER OutDir
Where to place ffmpeg.exe, ffprobe.exe, the DLLs and the license notice.
Typically packages/meshbay-client/node-runtime/ (default build-node-
runtime.ps1 target), so they end up wherever the daemon already looks --
that directory is on PATH once installed (W3/W4), so no code needs to name
ffmpeg's path explicitly.
.PARAMETER SkipCache
Re-download even if a verified copy already sits in the cache dir. Off by
default so repeated builds do not refetch 73 MB every time.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$OutDir,
[switch]$SkipCache
)
$ErrorActionPreference = "Stop"
# Pinned: one dated release, one asset, one hash. Re-pin deliberately (a new
# tag from https://github.com/BtbN/FFmpeg-Builds/releases, the exact asset
# name for that release -- it embeds ffmpeg's own git-describe, so it changes
# every time -- and the hash from that release's checksums.sha256) when
# ffmpeg needs an update. Never move this to the "latest" alias: it is
# reassigned on every BtbN auto-build and would make this script produce a
# different binary tomorrow with no change to this file.
$FFMPEG_TAG = "autobuild-2026-09-04-14-01"
$FFMPEG_ASSET = "ffmpeg-N-126404-g818e5d965b-win64-gpl-shared.zip"
$FFMPEG_SHA256 = "8575193e6a8d661a650e776f97b1379c14f6513d8fb1d650013e40916b758609"
$FFMPEG_URL = "https://github.com/BtbN/FFmpeg-Builds/releases/download/$FFMPEG_TAG/$FFMPEG_ASSET"
# What actually ships. Every DLL ffmpeg.exe/ffprobe.exe in this build link
# against, plus the two executables. ffplay.exe (an SDL2 player, ~17 MB) is
# deliberately left out -- collect_all-style "take everything" is right for
# the PyInstaller spec's Python deps, wrong here where the vendor zip bundles
# a whole extra program MeshBay never runs.
$KEEP_FILES = @(
"ffmpeg.exe", "ffprobe.exe",
"avcodec-63.dll", "avdevice-63.dll", "avfilter-12.dll", "avformat-63.dll",
"avutil-61.dll", "swresample-7.dll", "swscale-10.dll"
)
function Step($msg) { Write-Host "==> $msg" -ForegroundColor Cyan }
$cacheDir = Join-Path $env:LOCALAPPDATA "meshbay-build-cache"
New-Item -ItemType Directory -Force -Path $cacheDir | Out-Null
$zipPath = Join-Path $cacheDir $FFMPEG_ASSET
if ($SkipCache -or -not (Test-Path $zipPath) -or
(Get-FileHash $zipPath -Algorithm SHA256).Hash.ToLower() -ne $FFMPEG_SHA256) {
Step "downloading $FFMPEG_ASSET ($FFMPEG_TAG)"
$ua = "meshbay-build-script (+https://meshbay.org)"
Invoke-WebRequest -Uri $FFMPEG_URL -OutFile $zipPath -UseBasicParsing -UserAgent $ua
}
else {
Step "using cached $FFMPEG_ASSET"
}
$actual = (Get-FileHash $zipPath -Algorithm SHA256).Hash.ToLower()
if ($actual -ne $FFMPEG_SHA256) {
Remove-Item $zipPath -Force -ErrorAction SilentlyContinue
throw "ffmpeg download checksum mismatch: got $actual, expected $FFMPEG_SHA256 -- refusing to use it"
}
Step "checksum verified"
$extractDir = Join-Path $cacheDir "extracted"
Remove-Item $extractDir -Recurse -Force -ErrorAction SilentlyContinue
Expand-Archive -Path $zipPath -DestinationPath $extractDir
$binDir = Join-Path (Get-ChildItem $extractDir -Directory | Select-Object -First 1).FullName "bin"
if (-not (Test-Path $binDir)) { throw "expected bin\ under the extracted archive, found none" }
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
foreach ($name in $KEEP_FILES) {
$src = Join-Path $binDir $name
if (-not (Test-Path $src)) { throw "expected file missing from the ffmpeg build: $name" }
Copy-Item $src (Join-Path $OutDir $name) -Force
}
$noticeSrc = Join-Path $PSScriptRoot "LICENSE-ffmpeg.txt"
Copy-Item $noticeSrc (Join-Path $OutDir "LICENSE-ffmpeg.txt") -Force
Step "smoke test: encode + probe"
$smokeOut = Join-Path $env:TEMP "meshbay-ffmpeg-smoke.mp4"
Remove-Item $smokeOut -ErrorAction SilentlyContinue
& (Join-Path $OutDir "ffmpeg.exe") -hide_banner -loglevel error `
-f lavfi -i "testsrc=duration=1:size=320x240:rate=10" `
-c:v libx264 -pix_fmt yuv420p -y $smokeOut
if ($LASTEXITCODE -ne 0 -or -not (Test-Path $smokeOut)) {
throw "bundled ffmpeg failed to encode a test clip with libx264"
}
$codec = & (Join-Path $OutDir "ffprobe.exe") -hide_banner -v error `
-show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 $smokeOut
if ($codec.Trim() -ne "h264") { throw "expected h264, ffprobe reported '$codec'" }
Remove-Item $smokeOut -ErrorAction SilentlyContinue
$mb = "{0:N0} MB" -f ((Get-ChildItem $OutDir -File | Measure-Object Length -Sum).Sum / 1MB)
Write-Host "OK ffmpeg bundled to $OutDir ($mb)" -ForegroundColor Green
|