依 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>
462 lines
22 KiB
Markdown
462 lines
22 KiB
Markdown
# 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 旁邊):
|
||
|
||
```makefile
|
||
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,稽核用)
|
||
|
||
```markdown
|
||
# 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,**整段刪除**,改為:
|
||
|
||
```makefile
|
||
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`:
|
||
|
||
```makefile
|
||
# 原:
|
||
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:
|
||
|
||
```makefile
|
||
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`:
|
||
|
||
```makefile
|
||
# 原:
|
||
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:
|
||
|
||
```makefile
|
||
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`:
|
||
|
||
```diff
|
||
# ── 第三方依賴(由 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:
|
||
|
||
```diff
|
||
-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`)同步:
|
||
|
||
```diff
|
||
# 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]` 段加一行:
|
||
|
||
```diff
|
||
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 要求散發者提供對應原始碼。兩種做法:
|
||
|
||
1. **Written offer**(省空間):在 About dialog / Help menu / PRD 公告處提供 URL:
|
||
- macOS LGPL build → `https://github.com/<org>/visiona-local` repo 的 `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 對應)
|
||
2. **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. 待確認
|
||
|
||
1. **ffmpeg `--disable-network` 會不會影響既有的 `NewVideoSourceFromURL` / RTSP 路徑?** — v1 的 `camera/video_source.go:86-88` 有 `NewVideoSourceFromURLWithSeek` 吃 URL。v2 砍掉 yt-dlp 後是否還保留 URL 推論路徑?查 `v2/deletions.md`:URL 推論整條砍(R5-7 前置,`StartFromURL` handler 砍),**但 `NewVideoSourceFromURL` 函式本身可能還有其他呼叫者**。M8-1 執行時要先 grep 確認,若確實沒其他呼叫者就一起砍;若有就要保留 `--enable-protocol=http,https` 之類。**Architect 建議 M8-1 執行前先做這個 grep 掃描並回報**。
|
||
2. **ffmpeg n7.1 的 sha256** — 第一次 build 時由開發者執行 `shasum -a 256 build/ffmpeg-macos/source.tar.gz` 後填進 Makefile + BUILD.md,之後每次 build 用它驗證。
|
||
3. **codesign ad-hoc 在 notarize 階段** — 目前全案採 ad-hoc sign 沒做 notarize。若未來要 notarize,ffmpeg + ffprobe 屬於 app bundle 內的執行檔,會跟著 `.app` 一起送,不需單獨處理。
|