依 R5 五輪決策把 visionA-local 從「Wails 內嵌 Next.js」重構為「Wails
本機伺服器控制台 + 瀏覽器 Web UI」模式(類比 Docker Desktop / Ollama)。
程式碼變動
- M8-1 砍 yt-dlp 全套(後端 resolver / URL handler / 前端 URL tab /
Makefile vendor / installer / bootstrap / CI workflow,-555 行)
- M8-2 砍 Mock 模式全套(driver/mock、mock_camera、Settings runtimeMode、
VISIONA_MOCK 環境變數,-528 行)
- M8-3 ffmpeg 從 GPL 切換到 LGPL 混合方案:Windows/Linux 用 BtbN 現成
LGPL binary,macOS 自 build minimal decoder-only 進 git
(vendor/ffmpeg/macos/ffmpeg 5.7MB + ffprobe 5.6MB,比 GPL 版省 85% 空間)
- M8-4 Wails Server Controller:state machine、log ring buffer 2000 行、
preferences.json atomic write、boot-id、Gin SkipPaths、shutdown 7+1 秒、
notify_*.go 三平台 OS 通知、watchServer 改 Error state 不 os.Exit
- M8-4b 啟動階段管線 R5-E:6 階段進度 event、20s soft / 60s hard timeout、
stage 5/6 skip 規則、sentinel file、RestartStartupSequence 5 步驟
- M8-5 Wails 控制台 vanilla HTML/JS/CSS(9 檔 ~2012 行)取代 M7-B splash:
state 視覺、log panel、startup progress panel、Stage 6 manual CTA
pulse、shutdown modal、Settings、Dark Mode、i18n 中英雙語
- M8-6 上傳影片副檔名擴充(mp4/avi/mov/mpeg/mpg)
- M8-7 Web UI Server Offline Overlay(role=alertdialog + focus trap +
wsEverConnected 容錯 + Page Visibility)
- M8-8 CORS middleware(127.0.0.1/localhost only + suffix attack 防護)+
ws/origin.go 獨立 WebSocket CheckOrigin 避 package cycle
- MAJ-4 server:shutdown-imminent WebSocket broadcast 機制
(/ws/system endpoint + notifyShutdownImminent helper)
- M8-9 Boot-ID + 瀏覽器 tab 自動重連(sessionStorage loop guard)
品質
- ~105+ 新 unit test + race detector (-count=2) 全綠
- 10 個 milestone 全部通過 Reviewer 審查
- 三方 v2 + v2.1 文件(PRD / Design Spec / TDD)+ 交叉互審紀錄
收錄在 .autoflow/
交付前待處理(M8-10)
- 重跑 make payload-macos 把舊 GPL 77MB binary 換成新 LGPL
- 三平台 end-to-end build 驗證
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
22 KiB
v2/ffmpeg-lgpl.md — ffmpeg LGPL 打包策略
所屬:TDD v2 §2.2 決策依據:R5-6(LGPL 方案 B 混合)、R5-6a(macOS decoder-only ~20 MB)、R5-6b(macOS binary commit 到 repo)、R5-6c(三平台都打包 ffprobe) 對應 milestone:M8-3 前置研究:
/Users/jimchen/visionA/local-tool/.autoflow/04-architecture/ffmpeg-lgpl-research.md
1. 目的與範圍
把 v1 的「三平台 GPL ffmpeg build + VISIONA_ALLOW_GPL_FFMPEG=1 逃生門」換成 LGPL 方案 B(混合):
| 平台 | v1 來源 | v1 授權 | v2 來源 | v2 授權 | 存放位置 |
|---|---|---|---|---|---|
| macOS x86_64 | evermeet.cx / zip | GPL | 自 build(ffmpeg n7.1 + decoder-only configure) | LGPLv3 | vendor/ffmpeg/macos/(進 git) |
| Windows x86_64 | BtbN / …-win64-gpl.zip |
GPL | BtbN / …-win64-lgpl.zip |
LGPLv3 | vendor/ffmpeg/windows/(不進 git,Makefile 下載) |
| Linux x86_64 | johnvansickle static | GPL | BtbN / …-linux64-lgpl-7.1.tar.xz |
LGPLv3 | vendor/ffmpeg/linux/(不進 git,Makefile 下載) |
三平台都包 ffmpeg + ffprobe 兩支 binary(R5-6c)。
2. macOS:從源碼 build decoder-only(~20 MB)
2.1 選型理由
- 三平台只有 macOS x86_64 沒有現成的 LGPL static binary(完整分析見
ffmpeg-lgpl-research.md§2.3) - R5-6a 決定「最小 decoder-only build(~20 MB)」,configure 用
--disable-everything+ 主動 enable 需要的 decoder/demuxer - R5-6b 決定 binary 直接 commit 到
vendor/ffmpeg/macos/,避免開發者每次 build 都跑一遍編譯(單次 build ~15 分鐘)
2.2 需要的 feature set(對應「瀏覽器能吃的格式」)
PRD v2 支援的上傳影片副檔名:.mp4 / .avi / .mov / .mpeg / .mpg。對應的 ffmpeg configure 能力:
| 能力 | 必要項目 | 來源 |
|---|---|---|
| 容器解析 | demuxer=mov,avi,mpeg,mpegps,mpegts,matroska |
內建(LGPL) |
| 影像解碼 | decoder=h264,hevc,mpeg1video,mpeg2video,mpeg4,mjpeg,prores |
libavcodec native(LGPL) |
| 音訊解碼 | decoder=aac,mp2,mp3,pcm_s16le,pcm_s16be |
libavcodec native(LGPL) |
| pixel format 轉換 | filter=scale,format,fps |
libavfilter(LGPL) |
| 輸出為 image pipe | muxer=image2pipe / encoder=mjpeg |
libavcodec(LGPL;mjpeg encoder 不是 libx264,LGPL 安全) |
| 協議 | protocol=file |
夠用(只處理本地上傳檔) |
| parser | parser=h264,hevc,mpeg4video,mpegaudio,aac |
必要,否則有些 decoder 會 fail |
ffprobe:ffprobe 是 ffmpeg 主 source tree 的一部分,同一次 ./configure && make 會同時產出 ffmpeg 和 ffprobe,不用另外處理。
2.3 Makefile 新 target:vendor-ffmpeg-macos-build
新增到 Makefile(位置:現有 vendor-ffmpeg target 旁邊):
FFMPEG_VERSION := n7.1
FFMPEG_SRC_URL := https://github.com/FFmpeg/FFmpeg/archive/refs/tags/$(FFMPEG_VERSION).tar.gz
FFMPEG_SRC_SHA256 := <填 sha256,build 第一次時用 `shasum -a 256` 計算後記錄,之後每次 build 用 sha256sum 驗證>
# 這個 target 只有要升級 ffmpeg 時才跑一次;平常開發者不需要跑,
# 因為 vendor/ffmpeg/macos/ffmpeg 已經 commit 到 repo(R5-6b)。
vendor-ffmpeg-macos-build: ## 從源碼 build LGPL decoder-only ffmpeg for macOS x86_64(只有升級 ffmpeg 時才跑)
@if [ "$$(uname -s)" != "Darwin" ]; then \
echo "❌ vendor-ffmpeg-macos-build 只能在 macOS 上跑"; exit 1; \
fi
@command -v pkg-config >/dev/null 2>&1 || { echo "❌ 需要 pkg-config(brew install pkg-config)"; exit 1; }
@command -v yasm >/dev/null 2>&1 || command -v nasm >/dev/null 2>&1 || { echo "❌ 需要 yasm 或 nasm(brew install yasm)"; exit 1; }
@mkdir -p vendor/ffmpeg/macos build/ffmpeg-macos
@echo "==> 下載 ffmpeg source $(FFMPEG_VERSION)..."
curl -fL -o build/ffmpeg-macos/source.tar.gz "$(FFMPEG_SRC_URL)"
@echo "==> 驗證 source tarball sha256..."
@echo "$(FFMPEG_SRC_SHA256) build/ffmpeg-macos/source.tar.gz" | shasum -a 256 -c || { \
echo "❌ sha256 不符,請更新 FFMPEG_SRC_SHA256 或檢查來源"; exit 1; }
@rm -rf build/ffmpeg-macos/src
@mkdir -p build/ffmpeg-macos/src
tar xzf build/ffmpeg-macos/source.tar.gz -C build/ffmpeg-macos/src --strip-components=1
@echo "==> configure(decoder-only LGPL)..."
cd build/ffmpeg-macos/src && ./configure \
--prefix="$$(pwd)/../install" \
--enable-version3 \
--disable-debug \
--disable-doc \
--disable-ffplay \
--disable-network \
--disable-autodetect \
--disable-shared \
--enable-static \
--disable-everything \
--enable-small \
--enable-protocol=file,pipe \
--enable-demuxer=mov,avi,mpegps,mpegts,matroska,image2 \
--enable-decoder=h264,hevc,mpeg1video,mpeg2video,mpeg4,mjpeg,prores,vp8,vp9,aac,mp2,mp3,pcm_s16le,pcm_s16be \
--enable-parser=h264,hevc,mpeg4video,mpegaudio,aac \
--enable-filter=scale,format,fps,null,anull \
--enable-muxer=image2pipe,image2,null \
--enable-encoder=mjpeg \
--enable-swscale \
--enable-swresample \
--extra-cflags="-arch x86_64 -mmacosx-version-min=10.15" \
--extra-ldflags="-arch x86_64 -mmacosx-version-min=10.15 -Wl,-search_paths_first" \
--arch=x86_64 \
--target-os=darwin \
--cc="clang -arch x86_64"
cd build/ffmpeg-macos/src && make -j$$(sysctl -n hw.ncpu)
cd build/ffmpeg-macos/src && make install
@echo "==> 複製 ffmpeg + ffprobe 到 vendor/ffmpeg/macos/..."
cp build/ffmpeg-macos/install/bin/ffmpeg vendor/ffmpeg/macos/ffmpeg
cp build/ffmpeg-macos/install/bin/ffprobe vendor/ffmpeg/macos/ffprobe
@strip -S -x vendor/ffmpeg/macos/ffmpeg
@strip -S -x vendor/ffmpeg/macos/ffprobe
@chmod +x vendor/ffmpeg/macos/ffmpeg vendor/ffmpeg/macos/ffprobe
@echo "==> ad-hoc 簽章..."
codesign --force --sign - vendor/ffmpeg/macos/ffmpeg
codesign --force --sign - vendor/ffmpeg/macos/ffprobe
@echo "==> 驗證授權(configuration line 不含 --enable-gpl / libx264 / libx265)..."
@if vendor/ffmpeg/macos/ffmpeg -version 2>&1 | grep -E -- '--enable-gpl|libx264|libx265'; then \
echo "❌ LGPL 驗證失敗:build 不該出現 gpl / x264 / x265"; exit 1; \
fi
@echo "==> 複製 COPYING.LGPLv3 到 vendor/ffmpeg/macos/..."
cp build/ffmpeg-macos/src/COPYING.LGPLv3 vendor/ffmpeg/macos/COPYING.LGPLv3
@echo "==> ffmpeg 大小:$$(du -h vendor/ffmpeg/macos/ffmpeg | cut -f1)"
@echo "==> ffprobe 大小:$$(du -h vendor/ffmpeg/macos/ffprobe | cut -f1)"
@echo ""
@echo "✅ macOS LGPL ffmpeg build 完成。請:1) 更新 vendor/ffmpeg/macos/BUILD.md 的 binary sha256"
@echo " 2) git add vendor/ffmpeg/macos/{ffmpeg,ffprobe,COPYING.LGPLv3,BUILD.md}"
關鍵 flags 解釋:
| flag | 為什麼 |
|---|---|
--enable-version3 |
使用 LGPLv3(不是 v2.1),和 BtbN 對齊 |
--disable-debug / --disable-doc |
縮 binary |
--disable-network |
我們只處理本地檔案,網路 protocol(rtmp/rtsp/http)用不到,可關 |
--disable-autodetect |
不自動偵測系統上的外部 lib(libopus/libvpx 等);LGPL 合規稽核時更乾淨 |
--disable-shared --enable-static |
產出 self-contained binary,不依賴 macOS 上任何外部 lib |
--disable-everything |
先關全部,白名單 enable,確保不額外 link 任何東西 |
--enable-small |
優化大小而非速度,進一步縮 binary |
--enable-protocol=file,pipe |
只開 file:// 和 pipe(ffmpeg 內部 input/output),不開 http/rtsp |
--extra-cflags=-mmacosx-version-min=10.15 |
相容 macOS 10.15+(PRD v1 的 macOS 14/15 之外也能跑,無痛) |
2.4 vendor/ffmpeg/macos/BUILD.md(進 git,稽核用)
# macOS LGPL ffmpeg build record
This directory contains a pre-built LGPL ffmpeg + ffprobe binary for macOS x86_64.
## Reproducibility
- ffmpeg release: n7.1
- Source tarball: https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n7.1.tar.gz
- Source sha256: <填值>
- Build host: macOS 14.4, Xcode Command Line Tools 15.3 (clang 1500.3.9.4)
- Build date: 2026-04-14
- Build flags: 見 `Makefile` 的 `vendor-ffmpeg-macos-build` target
## Binary sha256
- ffmpeg: <填值>
- ffprobe: <填值>
## License
LGPLv3 — 完整授權條款見 `COPYING.LGPLv3`(與 binary 同目錄)。
## How to rebuild
make vendor-ffmpeg-macos-build
會:
1. 從 GitHub 下載 ffmpeg source tarball(n7.1)
2. 驗證 sha256
3. configure(只啟用 decoder/demuxer/filter 白名單)
4. make
5. 複製 ffmpeg + ffprobe 到這個目錄
6. strip + ad-hoc codesign
7. 驗證 `ffmpeg -version` 不含 `--enable-gpl` / `libx264` / `libx265`
Build 完成後請手動更新本檔的 Binary sha256 區塊,並 git commit。
## Verification
確認授權
vendor/ffmpeg/macos/ffmpeg -version | grep -E -- '--enable-gpl|libx264|libx265'
預期:沒有任何輸出
確認能解 5 種格式
for f in sample.mp4 sample.avi sample.mov sample.mpeg sample.mpg; do vendor/ffmpeg/macos/ffmpeg -hide_banner -i "$f" -f null - 2>&1 | tail -5 done
確認 Gatekeeper 可以過
spctl --assess --verbose vendor/ffmpeg/macos/ffmpeg
預期:accepted(ad-hoc signed)
2.5 現有 vendor-ffmpeg target 的處理
v1 現有的 Makefile:106-132 vendor-ffmpeg target 是從 evermeet.cx 下載 GPL build,整段刪除,改為:
vendor-ffmpeg: ## macOS:LGPL binary 已 commit 到 vendor/ffmpeg/macos/,此 target 只驗證存在
@if [ ! -f vendor/ffmpeg/macos/ffmpeg ]; then \
echo "❌ vendor/ffmpeg/macos/ffmpeg 不存在。請執行 'make vendor-ffmpeg-macos-build' 從源碼 build"; \
exit 1; \
fi
@if [ ! -f vendor/ffmpeg/macos/ffprobe ]; then \
echo "❌ vendor/ffmpeg/macos/ffprobe 不存在。請執行 'make vendor-ffmpeg-macos-build'"; \
exit 1; \
fi
@echo "==> vendor/ffmpeg/macos/ffmpeg 存在:$$(du -h vendor/ffmpeg/macos/ffmpeg | cut -f1)"
@echo "==> vendor/ffmpeg/macos/ffprobe 存在:$$(du -h vendor/ffmpeg/macos/ffprobe | cut -f1)"
@# 驗證 LGPL(沒有 --enable-gpl / libx264 / libx265)
@if vendor/ffmpeg/macos/ffmpeg -version 2>&1 | grep -qE -- '--enable-gpl|libx264|libx265'; then \
echo "❌ LGPL 驗證失敗"; exit 1; \
fi
@echo "==> LGPL 驗證通過"
注意:原本 vendor-ffmpeg 是把 binary 放在 vendor/ffmpeg/darwin/,v2 改為 vendor/ffmpeg/macos/(與 PRD 術語對齊 + 與 git commit 的目錄名一致)。payload 階段也要同步改(§5)。
3. Windows:換 BtbN LGPL(改一行 URL)
修改 Makefile:218:
# 原:
FFMPEG_URL_WINDOWS := https://github.com/BtbN/FFmpeg-Builds/releases/latest/download/ffmpeg-master-latest-win64-gpl.zip
# 改為:
FFMPEG_URL_WINDOWS := https://github.com/BtbN/FFmpeg-Builds/releases/latest/download/ffmpeg-n7.1-latest-win64-lgpl-7.1.zip
為什麼用 n7.1 穩定分支而非 master-latest:見 ffmpeg-lgpl-research.md §5.3,n7.1 綁定 7.1 release + 每日 backport bugfix,避免 master 的隨機 regression。
修改 Makefile:261-286 vendor-ffmpeg-windows target:
vendor-ffmpeg-windows: ## 下載 Windows LGPL ffmpeg + ffprobe → vendor/ffmpeg/windows/
@mkdir -p vendor/ffmpeg/windows
@if [ -f vendor/ffmpeg/windows/ffmpeg.exe ] && [ -f vendor/ffmpeg/windows/ffprobe.exe ]; then \
echo "==> ffmpeg.exe + ffprobe.exe 已存在,跳過"; \
else \
echo "==> 下載 BtbN LGPL ffmpeg (Windows, n7.1)..."; \
curl -fL -o vendor/ffmpeg/windows/ffmpeg-win.zip "$(FFMPEG_URL_WINDOWS)"; \
PY=""; \
for candidate in "$$VISIONA_PYTHON" "py -3" python3 python; do \
[ -z "$$candidate" ] && continue; \
if $$candidate --version >/dev/null 2>&1; then PY="$$candidate"; break; fi; \
done; \
[ -n "$$PY" ] || { echo "❌ 需要 python"; exit 1; }; \
$$PY -c "import zipfile; z=zipfile.ZipFile('vendor/ffmpeg/windows/ffmpeg-win.zip'); \
names=[n for n in z.namelist() if n.endswith('/bin/ffmpeg.exe') or n.endswith('/bin/ffprobe.exe') or n.endswith('/LICENSE.txt') or n.endswith('/COPYING.LGPLv3')]; \
import os; os.makedirs('vendor/ffmpeg/windows', exist_ok=True); \
for m in names: \
src = z.open(m); \
base = m.rsplit('/',1)[1]; \
dst = open(f'vendor/ffmpeg/windows/{base}', 'wb'); \
dst.write(src.read()); dst.close(); src.close(); \
print('extracted:', names)"; \
rm -f vendor/ffmpeg/windows/ffmpeg-win.zip; \
[ -f vendor/ffmpeg/windows/ffmpeg.exe ] || { echo "❌ ffmpeg.exe 沒被寫出"; exit 1; }; \
[ -f vendor/ffmpeg/windows/ffprobe.exe ] || { echo "❌ ffprobe.exe 沒被寫出"; exit 1; }; \
echo "==> ffmpeg.exe 大小:$$(du -h vendor/ffmpeg/windows/ffmpeg.exe | cut -f1)"; \
echo "==> ffprobe.exe 大小:$$(du -h vendor/ffmpeg/windows/ffprobe.exe | cut -f1)"; \
fi
4. Linux:換 BtbN LGPL(改一行 URL + 解壓路徑調整)
修改 Makefile:331:
# 原:
FFMPEG_URL_LINUX := https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
# 改為:
FFMPEG_URL_LINUX := https://github.com/BtbN/FFmpeg-Builds/releases/latest/download/ffmpeg-n7.1-latest-linux64-lgpl-7.1.tar.xz
修改 Makefile:362-379 vendor-ffmpeg-linux target:
vendor-ffmpeg-linux: ## 下載 Linux LGPL ffmpeg + ffprobe → vendor/ffmpeg/linux/
@mkdir -p vendor/ffmpeg/linux
@if [ -f vendor/ffmpeg/linux/ffmpeg ] && [ -f vendor/ffmpeg/linux/ffprobe ]; then \
echo "==> ffmpeg + ffprobe (Linux) 已存在,跳過"; \
else \
echo "==> 下載 BtbN LGPL ffmpeg (Linux, n7.1)..."; \
curl -fL -o /tmp/ffmpeg-linux.tar.xz "$(FFMPEG_URL_LINUX)"; \
mkdir -p /tmp/ffmpeg-linux-extract; \
tar xf /tmp/ffmpeg-linux.tar.xz -C /tmp/ffmpeg-linux-extract --strip-components=1; \
cp /tmp/ffmpeg-linux-extract/bin/ffmpeg vendor/ffmpeg/linux/; \
cp /tmp/ffmpeg-linux-extract/bin/ffprobe vendor/ffmpeg/linux/; \
cp /tmp/ffmpeg-linux-extract/LICENSE.txt vendor/ffmpeg/linux/LICENSE.txt 2>/dev/null || true; \
chmod +x vendor/ffmpeg/linux/ffmpeg vendor/ffmpeg/linux/ffprobe; \
rm -rf /tmp/ffmpeg-linux* ; \
echo "==> ffmpeg (Linux) 大小:$$(du -h vendor/ffmpeg/linux/ffmpeg | cut -f1)"; \
echo "==> ffprobe (Linux) 大小:$$(du -h vendor/ffmpeg/linux/ffprobe | cut -f1)"; \
fi
差別於 v1:
- URL 來源換掉
--strip-components從 1 改為 1(BtbN tar 的strip-components=1後頂層就是bin/,一樣)— 注意:BtbN 的 Linux tar 頂層目錄是ffmpeg-n7.1-latest-linux64-lgpl-7.1/,解壓後strip-components=1會進到bin/、doc/、lib/、include/、share/、LICENSE.txt、README.txt。cp /tmp/ffmpeg-linux-extract/bin/ffmpeg路徑正確- 同時抓
ffprobe - 複製
LICENSE.txt作為授權檔
5. Vendor directory layout
vendor/ffmpeg/
├── macos/ ← R5-6b:commit 到 git
│ ├── ffmpeg ← ~10 MB(進 git)
│ ├── ffprobe ← ~10 MB(進 git)
│ ├── COPYING.LGPLv3 ← 進 git
│ └── BUILD.md ← 進 git,reproducibility 稽核用
├── windows/ ← 不進 git,Makefile 下載
│ ├── ffmpeg.exe ← ~100 MB(BtbN LGPL 打包含很多 LGPL extra libs,未 strip)
│ ├── ffprobe.exe ← ~100 MB
│ ├── LICENSE.txt ← BtbN 自帶
│ └── COPYING.LGPLv3 ← BtbN 自帶
└── linux/ ← 不進 git,Makefile 下載
├── ffmpeg ← ~80 MB
├── ffprobe ← ~80 MB
└── LICENSE.txt ← BtbN 自帶
為什麼 Windows/Linux 不自 build 省體積? — BtbN LGPL 還 link 了 libopus / libvpx / libaom / libdav1d / libopenh264 / libmp3lame / libvorbis 等 LGPL-safe extra lib,binary 較大。對 Windows / Linux installer(~380 / 320 MB 現況)多出 50-100 MB 屬可接受範圍;要把 Windows/Linux 也降到 20 MB 就要跑三平台 CI matrix 自 build(方案 C,ffmpeg-lgpl-research.md §4.1 已分析,多花 1-1.5 人天,不划算)。
macOS 自 build 是不得不做(沒有現成 LGPL 來源),順便做到 20 MB 是 bonus。
6. .gitignore 更新
修改 .gitignore:
# ── 第三方依賴(由 make vendor-sync 下載,不進 git;第三輪決策 Q-D=D2) ──
/vendor/**
!/vendor/.gitkeep
!/vendor/README.md
+# R5-6b:macOS LGPL ffmpeg binary 進 git(沒有現成來源,自 build 成本高)
+!/vendor/ffmpeg/
+!/vendor/ffmpeg/macos/
+!/vendor/ffmpeg/macos/**
(! 規則的順序對 git 很敏感,這四行必須一起加;實測前需要用 git check-ignore vendor/ffmpeg/macos/ffmpeg 驗證)
注意:!/vendor/ffmpeg/macos/** 會取消忽略 macos/ 底下所有檔,包括未來可能意外丟進來的 .o 或 build artifact。為了防呆,BUILD.md 要明示「只 commit ffmpeg / ffprobe / COPYING.LGPLv3 / BUILD.md 四個檔」,程式碼 review 時檢查。
7. Payload 階段變化
修改 Makefile:182-203 payload-macos target:
-payload-macos: build-server vendor-python vendor-wheels vendor-ffmpeg vendor-ytdlp
+payload-macos: build-server vendor-python vendor-wheels vendor-ffmpeg
@echo "==> 建立 macOS payload..."
rm -rf payload/darwin
mkdir -p payload/darwin/bin payload/darwin/data payload/darwin/scripts payload/darwin/python payload/darwin/wheels
cp dist/visiona-local-server payload/darwin/bin/
- cp vendor/ffmpeg/darwin/ffmpeg payload/darwin/bin/
- cp vendor/yt-dlp/darwin/yt-dlp payload/darwin/bin/
- chmod +x payload/darwin/bin/ffmpeg payload/darwin/bin/yt-dlp
+ cp vendor/ffmpeg/macos/ffmpeg payload/darwin/bin/
+ cp vendor/ffmpeg/macos/ffprobe payload/darwin/bin/
+ cp vendor/ffmpeg/macos/COPYING.LGPLv3 payload/darwin/bin/ffmpeg-COPYING.LGPLv3
+ chmod +x payload/darwin/bin/ffmpeg payload/darwin/bin/ffprobe
Windows(payload-windows)與 Linux(payload-linux)同步:
# payload-windows
- cp vendor/ffmpeg/windows/ffmpeg.exe payload/windows/bin/
- cp vendor/yt-dlp/windows/yt-dlp.exe payload/windows/bin/
+ cp vendor/ffmpeg/windows/ffmpeg.exe payload/windows/bin/
+ cp vendor/ffmpeg/windows/ffprobe.exe payload/windows/bin/
+ cp vendor/ffmpeg/windows/COPYING.LGPLv3 payload/windows/bin/ffmpeg-COPYING.LGPLv3 2>/dev/null || true
# payload-linux
- @cp vendor/ffmpeg/linux/ffmpeg payload/linux/bin/ 2>/dev/null && chmod +x payload/linux/bin/ffmpeg || echo "!! WARN: ffmpeg 缺失"
- @cp vendor/yt-dlp/linux/yt-dlp payload/linux/bin/ 2>/dev/null && chmod +x payload/linux/bin/yt-dlp || echo "!! WARN: yt-dlp 缺失"
+ @cp vendor/ffmpeg/linux/ffmpeg payload/linux/bin/ && chmod +x payload/linux/bin/ffmpeg
+ @cp vendor/ffmpeg/linux/ffprobe payload/linux/bin/ && chmod +x payload/linux/bin/ffprobe
+ @cp vendor/ffmpeg/linux/LICENSE.txt payload/linux/bin/ffmpeg-LICENSE.txt 2>/dev/null || true
vendor-ytdlp* / vendor/yt-dlp/ 整塊砍除(見 v2/deletions.md §4)。
8. 授權檔案在 installer 中的呈現
每個 installer 都要附上 ffmpeg 的 LGPL 條款與 source 對應指引。
macOS:installer/macos/(目前沒有這個目錄,dmgbuild 直接從 .app 建)— 把 ffmpeg-COPYING.LGPLv3 放在 .app/Contents/Resources/bin/ 底下(已透過 payload-macos 自動 cp),加上 About dialog 裡的 link(v2 後續 design agent 設計)。
Windows Inno Setup:在 installer/windows/visiona-local.iss 的 [Files] 段加一行:
Source: "..\..\payload\windows\bin\ffmpeg.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
-Source: "..\..\payload\windows\bin\yt-dlp.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
+Source: "..\..\payload\windows\bin\ffprobe.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
+Source: "..\..\payload\windows\bin\ffmpeg-COPYING.LGPLv3"; DestDir: "{app}\bin"; Flags: ignoreversion
Linux AppImage:installer/linux/build-appimage.sh 第 61-62 行原本迭代 ffmpeg / yt-dlp,改為 ffmpeg / ffprobe,並額外 copy ffmpeg-LICENSE.txt 到 AppDir/usr/share/doc/visiona-local/。
9. 取得 LGPL source 的 offer
LGPLv3 要求散發者提供對應原始碼。兩種做法:
- Written offer(省空間):在 About dialog / Help menu / PRD 公告處提供 URL:
- macOS LGPL build →
https://github.com/<org>/visiona-localrepo 的vendor/ffmpeg/macos/BUILD.md指向 ffmpeg n7.1 source tarball 與確切 configure flags(任何人可依此重現 build) - Windows / Linux BtbN build →
https://github.com/BtbN/FFmpeg-Builds(BtbN 的 source 對應)
- macOS LGPL build →
- Bundle source:不採用 — 會讓 installer 多幾十 MB
選 1。詳細文字由 PMM / PM Agent 寫成 About dialog 內容;本 TDD 只需確認技術可行。
10. 驗收條件
| 檢查 | 指令 | 預期 |
|---|---|---|
| macOS ffmpeg 為 LGPL | vendor/ffmpeg/macos/ffmpeg -version | grep -- --enable-gpl |
無輸出 |
| macOS ffmpeg 不含 libx264 | vendor/ffmpeg/macos/ffmpeg -version | grep -- libx264 |
無輸出 |
| macOS ffmpeg 大小 < 25 MB | du -h vendor/ffmpeg/macos/ffmpeg |
< 25 MB |
| macOS ffprobe 存在 | test -f vendor/ffmpeg/macos/ffprobe && echo ok |
ok |
| macOS Gatekeeper | spctl --assess --verbose vendor/ffmpeg/macos/ffmpeg |
accepted |
| 可解 mp4 | vendor/ffmpeg/macos/ffmpeg -i sample.mp4 -f null - |
正常完成 |
| 可解 avi | 同上 | 正常完成 |
| 可解 mov | 同上 | 正常完成 |
| 可解 mpeg/mpg | 同上 | 正常完成 |
| Windows LGPL | ffmpeg.exe -version | findstr -- --enable-gpl |
無輸出 |
| Linux LGPL | 同上 | 無輸出 |
| installer 含 COPYING.LGPLv3 | 裝完後檢查 <install-dir>/bin/ffmpeg-COPYING.LGPLv3 存在 |
存在 |
11. 待確認
- ffmpeg
--disable-network會不會影響既有的NewVideoSourceFromURL/ RTSP 路徑? — v1 的camera/video_source.go:86-88有NewVideoSourceFromURLWithSeek吃 URL。v2 砍掉 yt-dlp 後是否還保留 URL 推論路徑?查v2/deletions.md:URL 推論整條砍(R5-7 前置,StartFromURLhandler 砍),但NewVideoSourceFromURL函式本身可能還有其他呼叫者。M8-1 執行時要先 grep 確認,若確實沒其他呼叫者就一起砍;若有就要保留--enable-protocol=http,https之類。Architect 建議 M8-1 執行前先做這個 grep 掃描並回報。 - ffmpeg n7.1 的 sha256 — 第一次 build 時由開發者執行
shasum -a 256 build/ffmpeg-macos/source.tar.gz後填進 Makefile + BUILD.md,之後每次 build 用它驗證。 - codesign ad-hoc 在 notarize 階段 — 目前全案採 ad-hoc sign 沒做 notarize。若未來要 notarize,ffmpeg + ffprobe 屬於 app bundle 內的執行檔,會跟著
.app一起送,不需單獨處理。