- feature-device-mgmt-tdd.md + api-device-mgmt.md(B 設備管理 TDD) - feature-model-sharing-tdd.md + api-model-sharing.md + PRD feature + 設計規格(C 模型共享三方規劃) - adr-020-ffmpeg-camera-indev.md(camera 三平台 indev) - PRD.md / TDD.md 索引增補 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
11 KiB
ADR-020: vendor ffmpeg 加回 camera input device(indev)— 三平台 avfoundation / dshow / v4l2
狀態
Proposed。
待「三平台 ffmpeg rebuild / 驗證 +
buildCaptureArgs補 Linux 分支 + 三平台實機驗(需實體攝影機)」全數完成後,轉 Accepted。 使用者目前僅有 macOS 機器可測,Windows / Linux 標為「待實機驗證」。
日期
2026-08-02
作者
Architect Agent
相關
- 根因評估:
local-tool/.autoflow/05-implementation/camera-ffmpeg-avfoundation-eval.md - 打破的前提:v2 TDD §2(decoder-only ffmpeg 決策)、
vendor/ffmpeg/macos/BUILD.md - 相關實作:
local-tool/server/internal/camera/ffmpeg_camera.go、ffmpeg_detect.go
1. 背景與範圍 (Context)
1.1 觸發問題
camera 即時推論在真機報錯(camera 修 bug 讓「吞錯誤」不再發生後,底層錯誤終於浮現):
failed to open camera (index=0): camera did not start:
ffmpeg exited before producing a frame: ffmpeg stream ended: EOF
...
Unknown input format: 'avfoundation'
Error opening input file 0:none
Unknown input format: 'avfoundation' = 這顆 ffmpeg binary 沒有編進 avfoundation input device(indev)。
1.2 根因(已 100% 確認,非推測)
camera 抓實體攝影機是 Go 端 os/exec 起 ffmpeg subprocess(非 Python),指令形如 ffmpeg -f avfoundation -i "0:none" ... -f image2pipe -vcodec mjpeg -,ffmpeg 把攝影機輸出成連續 MJPEG stream 到 stdout,Go 端掃 JPEG SOI/EOI marker 切 frame。
問題在 vendor 的 macOS ffmpeg 是「decoder-only」自 build(v2 TDD §2 決策、vendor/ffmpeg/macos/BUILD.md),configure flags 為縮體積 --disable-everything,白名單只 re-enable 了「解碼既有檔案」需要的元件:
--disable-everything
--enable-protocol=file,pipe
--enable-demuxer=mov,avi,mpegps,mpegts,matroska,image2
--enable-decoder=h264,hevc,...,mjpeg,...
--enable-parser=... --enable-filter=... --enable-muxer=image2pipe,image2,null
--enable-encoder=mjpeg
--disable-network
白名單裡完全沒有任何 --enable-indev=...。 --disable-everything 一併關掉所有 input device,而白名單沒把 camera 需要的 indev 加回來 → avfoundation 認不得 → camera 開不了。
1.3 為什麼只有 camera 壞、影片 / 圖片 / 批次正常
| 功能 | 用到的 ffmpeg 能力 | 白名單有無 | 結果 |
|---|---|---|---|
| 影片 / 圖片 / 批次推論 | demuxer + decoder(解碼既有檔案) | ✅ 有 | 正常 |
| camera 即時推論 | indev(從實體裝置抓 raw frame) | ❌ 沒有 | 壞 |
這是純「build 白名單漏了 indev」的問題,不是程式碼邏輯錯。
1.4 跨平台現況(讀 code 確認)
camera 三平台共用同一套 MJPEG pipe 抓取架構,但每平台用不同 indev:
| 平台 | 抓取 indev | ffmpeg 來源 | ffmpeg indev 現況 | camera code 現況 |
|---|---|---|---|---|
| macOS | avfoundation |
自 build decoder-only | ❌ 缺 avfoundation(根因) | ✅ 完整 |
| Windows | dshow |
BtbN n7.1 完整 LGPL build | ⚠️ 大概率已含 dshow(待實機驗) | ✅ 完整(dshow 路徑齊全) |
| Linux | v4l2(應為) |
BtbN n7.1 完整 LGPL build | ⚠️ 大概率已含 v4l2(待實機驗) | ❌ 缺 Linux 分支 |
附帶 code bug(獨立於 ffmpeg):buildCaptureArgs(ffmpeg_camera.go)的 switch runtime.GOOS 只有 windows 與 default,default 分支用 avfoundation。Linux 會誤落 default → 對 Linux 攝影機用 avfoundation → 必錯。即使 macOS ffmpeg 修好,Linux camera 仍會壞。
2. 決策 (Decision)
採方案 A:rebuild / 驗證三平台 ffmpeg 加回對應 indev,並補 Linux camera code 分支。
2.1 三平台 ffmpeg indev
| 平台 | 動作 | 具體 |
|---|---|---|
| macOS | rebuild 加 indev | vendor-ffmpeg-macos-build 的 configure 加 --enable-indev=avfoundation;rebuild;重算 sha256;更新 BUILD.md;commit 新 binary |
| Windows | 驗證(大概率零改動) | 實機 ffmpeg -f dshow -list_devices true -i dummy 確認 BtbN build 已含 dshow;若缺才需換含 dshow 的 build |
| Linux | 驗證(大概率零改動) | 實機 ffmpeg -devices 確認 BtbN build 已含 v4l2;若缺才需換 build 或補 --enable-indev=v4l2 |
BtbN 官方 LGPL 完整 build(
win64-lgpl/linux64-lgpl)預設含 dshow / v4l2 indev,故 Windows / Linux 預期零 ffmpeg 改動、只需實機驗證。macOS 是自 build 精簡版,是唯一確定要 rebuild 的。
2.2 補 Linux camera code 分支(獨立必補項)
buildCaptureArgs(ffmpeg_camera.go)與 ListFFmpegDevices(ffmpeg_detect.go)補 Linux 分支,三平台 capture args 對照:
| 平台 | 列裝置 | 抓 frame(capture args) |
|---|---|---|
| macOS | -f avfoundation -list_devices true -i "" |
-f avfoundation -i "<index>:none" |
| Windows | -f dshow -list_devices true -i dummy |
-f dshow -i video="<name>" |
| Linux(新增) | -f v4l2 -list_devices true -i "" 或列舉 /dev/video* |
-f v4l2 -i /dev/video<N> |
三平台後段皆接
-f image2pipe -vcodec mjpeg -q:v 5 -an -,MJPEG pipe 架構不動。
3. 考慮過的替代方案 (Alternatives Considered)
| 方案 | 優點 | 缺點 | 排除原因 |
|---|---|---|---|
| A. rebuild 加 indev(採用) | 成本最低(macOS 加一行 flag);不推翻 decoder-only;LGPL 乾淨;架構不動 | 需 rebuild macOS binary + 補 Linux code 分支 | — |
| B. 換完整版 ffmpeg | 省事、一次到位所有格式 | 體積爆增(40–70MB vs 現 5.7MB);推翻 v2 TDD §2 decoder-only;macOS 無現成 LGPL static 完整 build(正是當初自 build 的理由) | 唯一好處「省事」在 A 只加一個 flag 前提下不成立 |
| C. camera 改用平台原生 API(AVFoundation / Media Foundation / V4L2 ioctl + cgo) | 不依賴 ffmpeg subprocess | 三平台各寫一套原生 + cgo,複雜度爆炸 = 重寫 camera 子系統 | 解「build flag 少一行」不該砍掉可用的抓取架構 |
| D. macOS 專用第二顆含 avfoundation 的 ffmpeg | 主 binary 維持純解碼 | 多一顆 binary + 兩套 build 維護 | A 加一個 flag 就能讓同一顆 binary 兼顧(indev 增量 < 0.5MB),D 無意義 |
4. 後果 (Consequences)
4.1 打破的既有前提
本 ADR 打破 v2 TDD §2 decoder-only「不含 indev」的前提。原決策的假設是「local-tool 只處理本地檔案解碼」,但 camera 即時推論需要從實體裝置抓 frame(indev),該假設對 camera 情境不成立。本 ADR 確立新契約:
camera indev 是 ffmpeg build 白名單的必要一部分。 未來升級 ffmpeg 版本 rebuild 時,三平台的 indev(avfoundation / dshow / v4l2)不得再遺漏。
4.2 體積影響
| 平台 | 增量 | 說明 |
|---|---|---|
| macOS | < 0.5 MB(現 5.7MB) | avfoundation indev 是薄封裝,呼叫系統 AVFoundation / CoreMedia framework(otool -L 已顯示 binary 已 link 這些 framework),不自帶 codec |
| Windows / Linux | 0(若零改動) | BtbN build 已含 indev,不重 build |
4.3 LGPL 合規
- avfoundation / dshow / v4l2 皆為 LGPL-safe indev,不引入任何 GPL 元件。
- macOS 維持
--enable-version3(LGPL v3),rebuild 後仍須通過既有驗證(ffmpeg -version不含--enable-gpl/libx264/libx265)。 - Windows / Linux 沿用 BtbN LGPL build,合規不變。
4.4 三平台 indev 對照(契約,供未來 rebuild 參照)
| 平台 | indev | ffmpeg 來源 | build 需求 |
|---|---|---|---|
| macOS | avfoundation | 自 build decoder-only | configure 白名單須含 --enable-indev=avfoundation |
| Windows | dshow | BtbN 完整 LGPL build | 沿用 upstream(含 dshow) |
| Linux | v4l2 | BtbN 完整 LGPL build | 沿用 upstream(含 v4l2) |
4.5 風險
- 低。macOS 改的是 build flag + 補一個 OS 分支(Linux code),不動 MJPEG pipe 抓取架構。
- 主要不確定性在「Windows / Linux BtbN build 是否已含 indev」,透過實機
-list_devices/-devices驗證即可消除;若不含則退化為「換 build」(+1h)。
5. 合規性 Checklist
實作與轉 Accepted 前須全數完成:
- macOS ffmpeg rebuild:configure 加
--enable-indev=avfoundation、rebuild、重算 sha256、更新vendor/ffmpeg/macos/BUILD.md(含新 configure line / sha256 / 大小)、commit 新 binary - macOS LGPL 驗證:rebuild 後
ffmpeg -version不含--enable-gpl/libx264/libx265;ffmpeg -devices列出 avfoundation - Windows dshow 驗證:實機
ffmpeg -f dshow -list_devices true -i dummy有列裝置(若缺 → 換含 dshow 的 build) - Linux v4l2 驗證:實機
ffmpeg -devices含 v4l2(若缺 → 換 build 或補 flag) buildCaptureArgs補 Linux 分支:ffmpeg_camera.go+ffmpeg_detect.go加case "linux": -f v4l2(列裝置 + 抓 frame)- 三平台實機驗:各平台接實體攝影機,camera 即時推論從「開不了」變「出 frame」
- 體積 / LGPL 確認:macOS binary 增量 < 0.5MB、LGPL v3 合規未破
- v2 TDD ffmpeg 章節交叉引用(增補不覆蓋):註記「camera indev 為 build 白名單必要部分、三平台 indev 對照見 ADR-020」
- 與 Tech Lead / 使用者確認
- 成本影響已評估(體積增量微、無新增基礎設施成本)
6. WP 拆解(供 Orchestrator 排期)
| WP | 內容 | 派誰 | 需實機 | 前置 | 估時 |
|---|---|---|---|---|---|
| WP-1 | macOS:configure 加 --enable-indev=avfoundation、rebuild、重算 sha256、更新 BUILD.md、commit binary |
devops(build/vendor) | macOS(使用者有) | — | 1–1.5h(含 ~3 分 rebuild) |
| WP-2 | buildCaptureArgs / ListFFmpegDevices 補 Linux v4l2 分支(三平台 capture args 對照) |
backend(Go camera code) | 否(可先寫、Linux 驗證階段測) | — | 1–1.5h |
| WP-3 | Windows:實機 -f dshow -list_devices 驗證 dshow;若缺才換 build |
devops | Windows(待實機) | — | 0.5h(順利)/ +1h(換 build) |
| WP-4 | Linux:實機驗證 v4l2 + camera 即時推論測試 | devops + backend | Linux(待實機) | WP-2 | 1–1.5h |
| WP-5 | v2 TDD ffmpeg 章節交叉引用(增補);ADR-020 轉 Accepted | architect | 否(待 WP-1~4 完成) | WP-1~4 | 0.5h |
平行 / 接力:WP-1(macOS ffmpeg)與 WP-2(Linux code)可平行(互不相依、不同檔)。WP-3(Windows 驗)獨立可平行。WP-4(Linux 驗)接力 WP-2。WP-5 收尾,等前四個。 關鍵路徑:WP-2 → WP-4 → WP-5(Linux 驗需先有 code 分支)。 使用者只有 macOS:WP-1 可立即做並驗證;WP-3 / WP-4 的實機驗證需 Windows / Linux 機器,標為「待實機」,先寫好 code / build 再擇機驗。
7. 等級與後續
- 等級:M 級(跨多檔 + 跨三平台 + 動 vendor build 策略,但非新 user story / 新架構)。
- 後續:ADR 定稿後由 Orchestrator 派 devops(ffmpeg rebuild / 驗證)+ backend(Linux camera code 分支)落地。camera 不阻擋 B+C 主線,可獨立排期。