jim800121chen 8cd5751ce3 feat(local-tool): M8 重構 — Wails 控制台 + 瀏覽器 Web UI(R5 決策)
依 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>
2026-04-15 17:57:54 +08:00

22 KiB
Raw Blame History

v2/ffmpeg-lgpl.md — ffmpeg LGPL 打包策略

所屬TDD v2 §2.2 決策依據R5-6LGPL 方案 B 混合、R5-6amacOS decoder-only ~20 MB、R5-6bmacOS binary commit 到 repo、R5-6c三平台都打包 ffprobe 對應 milestoneM8-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 自 buildffmpeg 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/(不進 gitMakefile 下載)
Linux x86_64 johnvansickle static GPL BtbN / …-linux64-lgpl-7.1.tar.xz LGPLv3 vendor/ffmpeg/linux/(不進 gitMakefile 下載)

三平台都包 ffmpeg + ffprobe 兩支 binaryR5-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 MBconfigure 用 --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 nativeLGPL
音訊解碼 decoder=aac,mp2,mp3,pcm_s16le,pcm_s16be libavcodec nativeLGPL
pixel format 轉換 filter=scale,format,fps libavfilterLGPL
輸出為 image pipe muxer=image2pipe / encoder=mjpeg libavcodecLGPLmjpeg encoder 不是 libx264LGPL 安全)
協議 protocol=file 夠用(只處理本地上傳檔)
parser parser=h264,hevc,mpeg4video,mpegaudio,aac 必要,否則有些 decoder 會 fail

ffprobeffprobe 是 ffmpeg 主 source tree 的一部分,同一次 ./configure && make 會同時產出 ffmpegffprobe,不用另外處理。

2.3 Makefile 新 targetvendor-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 := <填 sha256build 第一次時用 `shasum -a 256` 計算後記錄,之後每次 build 用 sha256sum 驗證>

# 這個 target 只有要升級 ffmpeg 時才跑一次;平常開發者不需要跑,
# 因為 vendor/ffmpeg/macos/ffmpeg 已經 commit 到 repoR5-6bvendor-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-configbrew install pkg-config"; exit 1; }
	@command -v yasm >/dev/null 2>&1 || command -v nasm >/dev/null 2>&1 || { echo "❌ 需要 yasm 或 nasmbrew 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 "==> configuredecoder-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 我們只處理本地檔案,網路 protocolrtmp/rtsp/http用不到可關
--disable-autodetect 不自動偵測系統上的外部 liblibopus/libvpx 等LGPL 合規稽核時更乾淨
--disable-shared --enable-static 產出 self-contained binary不依賴 macOS 上任何外部 lib
--disable-everything 先關全部,白名單 enable確保不額外 link 任何東西
--enable-small 優化大小而非速度,進一步縮 binary
--enable-protocol=file,pipe 只開 file:// 和 pipeffmpeg 內部 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 tarballn7.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

預期acceptedad-hoc signed

2.5 現有 vendor-ffmpeg target 的處理

v1 現有的 Makefile:106-132 vendor-ffmpeg target 是從 evermeet.cx 下載 GPL build整段刪除,改為:

vendor-ffmpeg: ## macOSLGPL 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.3n7.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 改為 1BtbN 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.txtREADME.txtcp /tmp/ffmpeg-linux-extract/bin/ffmpeg 路徑正確
  • 同時抓 ffprobe
  • 複製 LICENSE.txt 作為授權檔

5. Vendor directory layout

vendor/ffmpeg/
├── macos/                         ← R5-6bcommit 到 git
│   ├── ffmpeg                     ← ~10 MB進 git
│   ├── ffprobe                    ← ~10 MB進 git
│   ├── COPYING.LGPLv3             ← 進 git
│   └── BUILD.md                   ← 進 gitreproducibility 稽核用
├── windows/                       ← 不進 gitMakefile 下載
│   ├── ffmpeg.exe                 ← ~100 MBBtbN LGPL 打包含很多 LGPL extra libs未 strip
│   ├── ffprobe.exe                ← ~100 MB
│   ├── LICENSE.txt                ← BtbN 自帶
│   └── COPYING.LGPLv3             ← BtbN 自帶
└── linux/                         ← 不進 gitMakefile 下載
    ├── 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 libbinary 較大。對 Windows / Linux installer~380 / 320 MB 現況)多出 50-100 MB 屬可接受範圍;要把 Windows/Linux 也降到 20 MB 就要跑三平台 CI matrix 自 build方案 Cffmpeg-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-6bmacOS 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

Windowspayload-windows)與 Linuxpayload-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 對應指引。

macOSinstaller/macos/目前沒有這個目錄dmgbuild 直接從 .app 建)— 把 ffmpeg-COPYING.LGPLv3 放在 .app/Contents/Resources/bin/ 底下(已透過 payload-macos 自動 cp加上 About dialog 裡的 linkv2 後續 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 AppImageinstaller/linux/build-appimage.sh 第 61-62 行原本迭代 ffmpeg / yt-dlp,改為 ffmpeg / ffprobe,並額外 copy ffmpeg-LICENSE.txtAppDir/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-BuildsBtbN 的 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-88NewVideoSourceFromURLWithSeek 吃 URL。v2 砍掉 yt-dlp 後是否還保留 URL 推論路徑?查 v2/deletions.mdURL 推論整條砍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。若未來要 notarizeffmpeg + ffprobe 屬於 app bundle 內的執行檔,會跟著 .app 一起送,不需單獨處理。