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

12 KiB
Raw Permalink Blame History

Reviewer 審查 M8-3 ffmpeg LGPL 切換2026-04-15

對照文件:

  • TDD spec/Users/jimchen/visionA/local-tool/.autoflow/04-architecture/v2/ffmpeg-lgpl.md
  • Research/Users/jimchen/visionA/local-tool/.autoflow/04-architecture/ffmpeg-lgpl-research.md
  • BUILD.md/Users/jimchen/visionA/local-tool/vendor/ffmpeg/macos/BUILD.md

摘要

項目 結論
總結論 通過1 Minor + 2 Suggestion + 3 待處理事項)
LGPL 合規 三平台齊備macOS 自 build decoder-onlyWindows/Linux BtbN n7.1 LGPL
Binary 大小減量 macOS 77 MB → 11.32 MB含 ffprobe減量約 85%
阻擋 M8-10 不阻擋,所有硬性條件均通過

A. Makefile 變更正確性

對照 Makefile:1-449 ↔ TDD §2.3/§3/§418 項檢查全過:

# 驗證項 結果 位置
1 FFMPEG_VERSION=n7.1 + sha256 常數 Makefile:73-77
2 vendor-ffmpeg 退化為「驗證存在 + LGPL guard」 Makefile:112-130
3 vendor-ffmpeg-macos-build 僅限 Darwin + nasm/yasm Makefile:136-140
4 下載 tarball + sha256 驗證 + fail 印實際 sha Makefile:142-148
5 configure 21 個 flag 與 TDD §2.3 逐字對齊 Makefile:152-178
6 --disable-everything + decoder 白名單 h264/hevc/mpeg1/2video/mpeg4/mjpeg/prores/vp8/vp9/aac/mp2/mp3/pcm_* Makefile:167
7 demuxer 白名單 mov,avi,mpegps,mpegts,matroska,image2 Makefile:166
8 strip + ad-hoc codesign Makefile:184-189
9 build 後 LGPL grep guard Makefile:190-193
10 複製 COPYING.LGPLv3 Makefile:194-195
11 FFMPEG_URL_WINDOWS → BtbN n7.1 LGPL zip Makefile:277
12 FFMPEG_URL_LINUX → BtbN n7.1 LGPL tar.xz Makefile:387
13 vendor-ffmpeg-windows 解壓 ffmpeg.exe + ffprobe.exe + LICENSE + COPYING.LGPLv3 Makefile:319-348
14 vendor-ffmpeg-linux 解壓 ffmpeg + ffprobe + LICENSEstrip-components=1 Makefile:417-434
15 payload-macos 複製 ffmpeg + ffprobe + ffmpeg-COPYING.LGPLv3 Makefile:244-247
16 payload-windows 複製 ffprobe.exe + LICENSE/COPYINGskipifsourcedoesntexist Makefile:358-362
17 payload-linux 複製 ffprobe + ffmpeg-LICENSE.txt Makefile:444-446
18 payload-macos:241rm -rf payload/darwin 清舊 Makefile:241

五 decoder + 五 demuxer 白名單對照 TDD 驗收條件 §10h264/hevc/mpeg2video/mpeg4/aacmov-mp4/avi/mpeg/mpegts/matroska全數涵蓋。


B. Binary 正確性(親自驗證)

$ ls -la vendor/ffmpeg/macos/
-rw-r--r--   10500 BUILD.md
-rw-r--r--    7651 COPYING.LGPLv3
-rwxr-xr-x 6007520 ffmpeg    (5.73 MB)
-rwxr-xr-x 5865568 ffprobe   (5.59 MB)

sha256 與 BUILD.md lines 26-30 100% 吻合

c3cb9f1dad66730267c12fca92c6344d2f8939ab227889caac33005f8947992c  ffmpeg
bd388fb4372ed5f7e44ee331a51be6383d702fb2c067bf562cabbdfbdd8b0c5e  ffprobe
da7eabb7bafdf7d3ae5e9f223aa5bdc1eece45ac569dc21b3b037520b4464768  COPYING.LGPLv3

ffmpeg -version configuration

  • --enable-gpl、無 libx264、無 libx265
  • --enable-version3--disable-network--disable-autodetect--enable-static--disable-everything

Decoder 驗證ffmpeg -decoders | grep -E ' (h264|hevc|aac|mpeg2video|mpeg4) ' 五個全中。

Demuxer 驗證ffmpeg -demuxers 顯示 avi / matroska,webm / mov,mp4,m4a,3gp,3g2,mj2 / mpeg / mpegts 五個全中。

otool -L 動態依賴

/usr/lib/libSystem.B.dylib
/System/Library/Frameworks/CoreFoundation.framework/.../CoreFoundation
/System/Library/Frameworks/CoreVideo.framework/.../CoreVideo
/System/Library/Frameworks/CoreMedia.framework/.../CoreMedia

ffprobe 相同四項。無任何第三方 dylibx264/x265/vpx/opus/aom 都不在),符合 LGPL static self-contained。

ffprobe -version:可執行,顯示同一 configuration。

codesign -vffmpeg + ffprobe 皆 exit 0ad-hoc signing 通過)。


C. .gitignore 雙層

Inner local-tool/.gitignore:6-15

/vendor/**
!/vendor/.gitkeep
!/vendor/README.md
!/vendor/ffmpeg/
!/vendor/ffmpeg/macos/
!/vendor/ffmpeg/macos/**

Outer visionA/.gitignore:20-27:同樣四行 un-ignore + local-tool/vendor/** 為基底。

git check-ignore 驗證:

路徑 inner repo outer repo
vendor/ffmpeg/macos/ffmpeg exit 1未 ignore exit 1
vendor/ffmpeg/macos/BUILD.md exit 1 exit 1
vendor/ffmpeg/windows/ffmpeg.exe exit 0ignored exit 0
vendor/ffmpeg/linux/ffmpeg exit 0 exit 0

git status --ignored vendor/ 顯示:

  • ?? vendor/ffmpeg/macos/untrackedgit add
  • !! vendor/ffmpeg/{linux,windows}/!! vendor/{python,wheels,yt-dlp}/ignored

雙層規則正確outer repo local-tool/vendor/ 仍為整個 untracked需在交付前 git add — 屬待處理事項而非實作錯誤。


D. BUILD.md 可重現性

BUILD.md295 行)完整度:

欄位 有無
ffmpeg release n7.1 + source URL + sha256
Build hostmacOS 14.7.6Apple clang 16.0.0
Toolchainnasm 3.01、brew 5.1.6、Xcode CLT
Configure flags 完整複製貼上
Binary sha256三項
Binary 大小bytes + 人類可讀)
Build 耗時2 分 44 秒user 559s/sys 56s
實測驗證輸出ffmpeg -version / decoder / demuxer / otool / codesign 節錄)
Rebuild 指令 make vendor-ffmpeg-macos-build
Commit 清單(僅允許 ffmpeg/ffprobe/COPYING/BUILD.md 四檔)

兩年後重現評估可以。source tarball URL + sha256 固定、configure flags 可直貼、系統依賴明列、Makefile 本身就是 reproducibility script。唯一風險是 Homebrew nasm/clang 版本漂移,但 ffmpeg 7.1 對 toolchain 包容度高,不預期 break。


E. GPL flag 清除 grep

全 repo grep VISIONA_ALLOW_GPL_FFMPEG / --enable-gpl / libx264 / libx265

類別 殘存位置 評估
.autoflow/*progress/TDD/research/spec 允許(歷史紀錄)
Makefile:126,190-193 guard 驗證邏輯
vendor/ffmpeg/macos/BUILD.md 驗證輸出說明
build/ffmpeg-macos/src/* upstream source tarball 解壓產物 (非專案碼)
scripts/bootstrap-{windows,linux}.* 已改為 LGPL v3 build 標語
.github/workflows/build.yml 零殘留
installer/** 零殘留
server/**.go + visiona-local/**.go 零殘留

GPL flag 完全清除,只剩文件類歷史 + guard 邏輯。


F. Installer / Bootstrap / CI

  • Windows Inno Setup installer/windows/visiona-local.iss:74-79:含 ffmpeg.exe + ffprobe.exe + ffmpeg-LICENSE.txt + ffmpeg-COPYING.LGPLv3後兩者用 skipifsourcedoesntexist fallback
  • Linux AppImage installer/linux/build-appimage.sh:61-76for tool in ffmpeg ffprobe 迴圈 + 把 ffmpeg-LICENSE.txt 放到 AppDir/usr/share/doc/visiona-local/
  • macOS:無獨立 installerpayload-macos 直接把 COPYING.LGPLv3 複製到 payload/darwin/bin/ffmpeg-COPYING.LGPLv3,經 stage-macos 進 .app/Contents/Resources/bin/
  • bootstrap-windows.ps1:71 / bootstrap-linux.sh:58:只剩 LGPL 提示語,無 GPL flag
  • .github/workflows/build.yml:只保留 vendor-ffmpeg-windowsline 135vendor-ffmpeg-linuxline 232呼叫無 env var 設定

G. Payload 流程相容性 + 真實 decode 測試

G.1 server runtime 相容性

server/main.go:88-93VISIONA_BUNDLE_BIN_DIR prepend 到 PATHserver/internal/deps/checker.go:23-94resolveTool 優先在 $VISIONA_BUNDLE_BIN_DIR/<name> 找;visiona-local/app.go:482-484 Wails shell 啟動 server 時注入 VISIONA_BUNDLE_BIN_DIR = locateBundleBinDir()macOS→Contents/Resources/binWindows/Linux→<exe>/bin,開發→cwd/payload/<os>/bin)。

payload-macos Makefile:244-245ffmpeg + ffprobe 放到 payload/darwin/bin/stage-macos 會完整複製到 bundle Resources。server/internal/camera/video_source.go:24exec.Command("ffprobe", ...) 依賴 basename lookup加入 ffprobe 後完全相容。

G.2 實際 decode 測試

先用系統 ffmpeg 產生 h264 mp4/usr/local/bin/ffmpeg -f lavfi -i "testsrc=duration=1:size=320x240:rate=10" -c:v libx264 ... /tmp/testsrc.mp4

LGPL ffmpeg 解碼 → mjpeg

$ ./vendor/ffmpeg/macos/ffmpeg -i /tmp/testsrc.mp4 \
    -frames:v 1 -f image2pipe -vcodec mjpeg -q:v 5 /tmp/test_out.jpg
Stream #0:0(und): Video: mjpeg, yuv444p, 320x240, 10 fps ...
frame=    1 fps=0.0 q=5.0 Lsize=       9KiB
$ file /tmp/test_out.jpg
/tmp/test_out.jpg: JPEG image data, JFIF standard 1.02, ..., 320x240

LGPL ffprobe probe h264 stream

$ ./vendor/ffmpeg/macos/ffprobe -v error -show_streams /tmp/testsrc.mp4
codec_name=h264  codec_type=video  width=320  height=240  pix_fmt=yuv444p

真實 decode 路徑通過server extract first-frame 流程可直接使用。

G.3 payload/darwin/bin/ 當前為舊 GPL 77 MB binary

$ shasum -a 256 payload/darwin/bin/ffmpeg
b68f795f7fb4528daf697f57a2b6780846a1ae762a71907e994442ad103ee88f

非 M8-3 實作錯誤payload-macos 尚未在 M8-3 後重跑。Makefile:241rm -rf payload/darwinstage-macos:265rm -rf visiona-local/build/darwin/Resources 會自動清乾淨。列入待處理。


H. Size 比較

項目 舊 GPL 新 LGPL 差異
macOS ffmpeg ~77 MBprogress.md M6-1 紀錄) 5.73 MB 71.3 MB92%
macOS ffprobe 未附 5.59 MB 新增
macOS 合計 ~77 MB 11.32 MB 65.7 MB85%

macOS 成果超越 TDD §2.1「~20 MB」目標--disable-everything + 白名單策略效益顯著。Windows/Linux BtbN LGPL build 大小待 M8-10 CI runner 下載後驗證。


I. 問題清單

Critical / Major

無。

Minor

# 位置 問題 建議
1 vendor/ffmpeg/macos/BUILD.md:186-194 §Verification §5 預期 spctl --assess --verbose 為「accepted」不準確實測 ad-hoc signed binary 在 macOS 14.7 下被 rejectedexit 3。Gatekeeper 由 outer .app bundle signing 決定,不對內嵌 binary 單獨 assess 把該步驟改為 codesign -vexit 0 即可並註記「Gatekeeper 最終由 outer .app bundle signing 決定」

Suggestion

# 位置 建議
1 Makefile:126-130 vendor-ffmpeg target 可多驗 shasum -a 256 對照 BUILD.md 記錄,防 binary 被意外覆蓋 / 損毀非必要git 已保護)
2 Makefile:361-362 payload-windows 兩份授權檔都用 skipifsourcedoesntexist,若 BtbN zip 內 LICENSE.txt 與 COPYING.LGPLv3 同時缺失installer 會無授權檔交付。建議補「至少其中一個存在」assertion

待處理(非 M8-3 scope但影響 release

  1. outer repo git add/Users/jimchen/visionA/git status 仍顯示 local-tool/vendor/ 為整個 untracked。交付前須 git add local-tool/vendor/ffmpeg/macos/{ffmpeg,ffprobe,COPYING.LGPLv3,BUILD.md} 並 commit。
  2. payload/darwin/bin/ffmpeg 仍為舊 GPL 77 MB binary:下次 make payload-macos 會自動清。M8-10 前應重跑。
  3. vendor/yt-dlp/ 目錄仍在:屬 M8-2 清理範圍,非 M8-3。

J. 結論

M8-3 ffmpeg LGPL 切換: 通過。

核心成果確認:

  • Makefile 三平台變更逐字對齊 TDD §2-§4
  • macOS binary 親測 LGPL 合規(無 gpl/x264/x265有 version3、五 decoder + 五 demuxer 全中、只依賴 macOS 系統 framework
  • sha256 與 BUILD.md 100% 吻合
  • 實測 h264 mp4 decode → mjpeg JPEG 成功ffprobe probe 成功
  • 雙層 .gitignore inner + outer 規則均正確
  • BUILD.md 完整可重現(兩年後可 rebuild
  • GPL flag 在程式碼 / installer / bootstrap / CI 完全清除
  • Installer Windows/Linux 含 ffprobe + 授權檔
  • Size 減量 85%

僅 1 MinorBUILD.md 的 spctl 預期描述錯誤)+ 2 Suggestion + 3 待處理事項,不阻擋 M8-10。

Orchestrator 建議:

  1. Minor #1BUILD.md spctl 描述修正)列為 M8-3 尾巴,由 Architect/DevOps 補
  2. M8-10 CI 交付前執行 outer repo git add + commit
  3. M8-10 時確保 make payload-macos + stage-macos 重跑清掉舊 GPL payload