單元 5 · 第一個鏡頭跑起來

argus_camera / v4l2-ctl

Argus 拍照與預覽

argus_camera
argus_camera --mode 0 --capture-auto 1 --duration 1
argus_camera --preview 1 --mode 0
第一步驗證:argus_camera 出圖 = 感測器→tegra ISP→輸出鏈路通。

V4L2 / GStreamer

v4l2-ctl 與 gst
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=NV12
gst-launch-1.0 v4l2src device=/dev/video0 ! videoconvert ! autovideosink

常見失敗

症狀方向
argus 列不到相機DTB / tegracam / serdes(GMSL)
出圖黑曝光 0、感測器沒輸出
畫面綠/紫格式/色彩空間錯

5.7 深入:取流的完整驗證

OV9281 取流驗證
# 確認 media 管線
media-ctl -p -d /dev/media0
# 取一幀
v4l2-ctl -d /dev/video0 --stream-mmap=1 --stream-count=1 --stream-to=f.yuv
# 檢查格式
v4l2-ctl -d /dev/video0 --list-formats-ext
通過標準:取到一幀 = 感測器→CSI→video 鏈路通。接著才談調校。

5.8 練習

  1. 跑完整取流流程,確認格式。
  2. 記錄支援的 fourcc 清單。
看完這單元你應該能說出:
  • argus_camera 拍照/預覽。
  • v4l2-ctl / GStreamer 取流。
  • 「出圖 = 鏈路通」驗證。
  • 三種常見失敗方向。

5.9 深入原理:argus_camera 的參數含義

參數含義典型值
--mode N選 DTB mode(解析度/幀率)0 = 預設
--capture-auto N自動連拍 N 張1
--duration N取流秒數1
--preview 1螢幕預覽0/1
--raw-file f.raw輸出 RAW(回顧單元 8)
為什麼 Argus 出圖是「第一步」:Argus 走完整 NVIDIA 相機棧(感測器→CSI→VI→ISP→輸出),它出得了圖代表底層全通;接著才輪到調校。反過來,若 V4L2/GStreamer 能取但 Argus 不能,問題多半在 ISP/韌體對接而非感測器。

5.10 Worked Example:完整取流並檢查影像

OV9281 取 10 幀 NV12 並用 ffmpeg 檢查
# 取 10 幀 NV12(1280x720)
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=NV12 \
    --stream-mmap=10 --stream-count=10 --stream-to=caps.yuv
# 檢查是否「全黑」或「全灰」(用 ffprobe 或直接看大小)
ls -l caps.yuv                      # 720p NV12 = 1280*720*3/2 = 1,382,400 B/幀
ffmpeg -f rawvideo -pix_fmt nv12 -s 1280x720 -i caps.yuv -frames:v 1 out.png

幀大小正確但影像全黑 → 曝光/增益問題(回顧單元 10);大小錯誤 → 格式/時序問題。

5.11 疑難排解決策樹:出圖失敗

決策樹
1. v4l2-ctl --list-devices 有 video0?
   ├─ 無 ─→ 驅動/DTB(回顧單元 4)
   └─ 有 ┐
2. media-ctl 管線完整(感測器→CSI→VI)?
   ├─ 斷 ─→ 管線連結設定(media-ctl -l)
   └─ 完整 ┐
3. 取流,檢查幀大小:
   ├─ 錯 ─→ fourcc / width / height 宣告
   └─ 對 ┐
4. 影像內容:
   ├─ 全黑 → 曝光 0 / 感測器沒輸出 / 鏡頭蓋
   ├─ 綠紫 → pixel format 或色彩空間
   └─ 正常 → ✅ 準備調校

5.12 常見錯誤 / 陷阱

陷阱 ①:V4L2 的 --set-fmt-video 指定了不支援的格式時,驅動會「接受但實際沒改」——用 --get-fmt-video 回讀確認。
陷阱 ②:NV12 是「已處理」輸出;要分析感測器原始品質必須取 RAW(單元 8),不能拿 NV12 談雜訊/黑位。
陷阱 ③:GStreamer 管線卡住不一定是相機問題,可能只是沒有 sync=false 或 decodebin 緩衝。

5.13 練習

  1. 用 argus_camera 連拍 3 張,檢查檔案存在與大小。
  2. 用 v4l2-ctl 取一幀,驗證幀大小公式。
  3. 故意設錯 pixelformat,觀察錯誤訊息並記錄。

5.14 進階:V4L2 記憶體映射(mmap)與幀緩衝

取流前,V4L2 驅動配置幀緩衝(buffer),userspace 透過 mmap 直接讀取,避免每幀複製。理解三個狀態:QUEUED(排隊給硬體)→ DONE(硬體填好)→ DEQUEUED(使用者拿走)

指令狀態變化
--stream-mmap=N配置 N 個 mmap 緩衝
--stream-count=N取 N 幀後停止
--stream-to=file把 dequeued 幀寫檔
除錯意義:若 buffer 不足或硬體來不及填,會掉幀或 timeout——「取 N 幀得到少於 N 幀」通常是頻寬或時序問題(回顧單元 11 幀率/頻寬)。

5.15 快速參考:出圖指令小抄

最常用的三條
argus_camera --mode 0 --capture-auto 1 --duration 1     # Argus 出圖
v4l2-ctl -d /dev/video0 --stream-mmap=1 --stream-count=1 --stream-to=f.yuv
gst-launch-1.0 v4l2src device=/dev/video0 ! fakesink

5.16 看完本單元該記住的三件事

出圖成功 = 感測器 → CSI → ISP → 輸出全通。
三種工具(argus / v4l2-ctl / GStreamer)代表三種使用方式,都要會。
出圖後第一件事是「驗證影像正常」,才進入調校。

5.17 深入原理:GStreamer 管線的 buffer 與 sync

GStreamer 的 v4l2src 抓 V4L2 buffer 後沿管線流動。常見卡住原因不是相機,而是 sync:顯示端等 vsync,可能讓管線「等」到看起來像凍住。

除錯用的 GStreamer 管線
# fakesink:純吃 buffer,不顯示,測吞吐最快
gst-launch-1.0 v4l2src device=/dev/video0 ! fakesink
# 加上 sync=false 避免 vsync 卡住
gst-launch-1.0 v4l2src device=/dev/video0 ! \
  videoconvert ! autovideosink sync=false
判斷:v4l2src ! fakesink 能跑而顯示端卡 → 是 sync/顯示問題,不是相機問題。

5.18 看完本單元該記住的三件事

Argus 出圖 = 鏈路通的終極證明。
v4l2-ctl 是最小工具,GStreamer 是靈活工具。
卡住先分「相機」還是「顯示/sync」。

延伸閱讀

5.10 進階真實情境 Worked Example:用 GStreamer 管線做即時影像處理 Pipeline

場景:你需要在 Orin Nano 上做到「擷取 → ISP 處理 → 即時顯示 → 同時錄影」的完整 pipeline。

GStreamer 多路輸出 pipeline
# 擷取 NV12(ISP 處理後)→ 分流:一路顯示、一路存檔
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
  'video/x-raw(memory:NVMM), format=NV12, width=1920, height=1080, framerate=30/1' ! \
  tee name=t \
  t. ! queue ! nvvidconv ! 'video/x-raw(memory:NVMM), format=NV12' ! \
     nveglglessink \
  t. ! queue ! nvvidconv ! 'video/x-raw(memory:NVMM), format=NV12' ! \
     nvv4l2h264enc ! h264parse ! mp4mux ! filesink location=output.mp4
# - tee 分流:一進多出
# - queue:緩衝防止 block
# - nvvidconv:格式/尺寸轉換(GPU 硬體加速)

設計決策:nvarguscamerasrc 而非 v4l2src:前者走 NVIDIA ISP 完整管線,後者取原始 V4L2 輸出。tee 元件在 NVIDIA 的 GStreamer plugin 中是 GPU 級分流,不佔 CPU。

5.11 深入原理擴充:Argus 的 session / stream / request 模型

Argus API 的核心不是「拍照」,而是「排程」:每個 frame 是一個 request,多個 request 排在 stream 裡,stream 屬於一個 session

概念說明常見誤解
Session一組相機的使用環境以為可以跨 session 共享 buffer(不行)
Stream一個輸出格式的幀序列以為一個 session 只能有一個 stream(可多個)
Request一幀的 ISP 設定 + 輸出 buffer以為 request 是同步的(實際是非同步排程)
EventISP 回傳的狀態(AE 收斂、幀完成…)以為不處理 event 也沒事(可能導致 buffer 洩漏)
陷阱:「argus_camera 拍一張照片就好」背後其實是 Argus 自動管理 session + stream + request queue。若你用 libargus 自建 pipeline,忘記 request->disable()` 或沒呼叫 EventQueue::waitForEvent(),buffer 會慢慢耗盡直到 OOM。

5.12 診斷式疑難排解表

症狀可能原因解決方案
gst-launch-1.0 串流後畫面停住不動下游元件 block(例如 nveglglessink 開了視窗但被遮住)-v 看哪個 element 的 queue 滿了;確認下游有正常消費 buffer
argus_camera 回傳 "Camera initialization failed"ISP 資源被其他程序佔用 或 sensor mode 不支援kill 其他 camera 程序;用 argus_camera --list-sensors 確認支援 mode
GStreamer pipeline 報 "nvarguscamerasrc: Caps negotiation failed"下游要求的 format 與 camera 輸出不相容在 nvarguscamerasrc 後加 capsfilter 明確指定 format
錄影檔案播放時跳幀或音畫不同步h264 encode 速度跟不上擷取速度降低擷取解析度或幀率;確認 nvv4l2h264enc 使用硬體編碼器
v4l2-ctl 能出圖但 gst-launch 無法連接GStreamer plugin 未安裝 或 版本不符確認 gstreamer1.0-plugins-bad/good/ugly 已安裝;gst-inspect-1.0 nvarguscamerasrc 測試

5.13 進階挑戰題

  1. 用 GStreamer 建立一個 pipeline:從 OV9281 擷取 1280x800 灰階,送到 Python 腳本做即時邊緣偵測(用 OpenCV),再把結果顯示在 EGL 視窗上。
  2. 比較 v4l2srcnvarguscamerasrc 的延遲差異:在 pipeline 中加入 identity 元件記錄 timestamp,計算從 sensor 到 sink 的端到端延遲。
  3. 撰寫一個 argus_camera 的 wrapper script,自動偵測目前連接了幾顆感測器、支援哪些 mode,並讓使用者選一顆開拍。

5.14 專案級端到端 Worked Example:自動化出圖驗證腳本專案

場景:生產線每台設備裝完都要人工跑 argus / v4l2 驗證出圖,太慢且容易漏。專案目標:寫一個自動化驗證腳本,一次跑完「Argus 出圖 → V4L2 取幀 → GStreamer 串流 → 幀大小 / 內容檢查」,輸出 pass/fail 報告。

capture_verify.sh
#!/bin/bash
set -e
CAM=${1:-0}
echo "== [1/4] Argus 出圖 =="
argus_camera --mode 0 --capture-auto 1 --duration 1 || { echo "FAIL: argus"; exit 1; }
echo "== [2/4] V4L2 取幀 =="
v4l2-ctl -d /dev/video$CAM --stream-mmap=1 --stream-count=1 --stream-to=cap.raw
SIZE=$(stat -f%z cap.raw)
echo "檔案大小: $SIZE bytes"
echo "== [3/4] GStreamer 串流 3 秒 =="
timeout 3 gst-launch-1.0 v4l2src device=/dev/video$CAM ! fakesink || { echo "FAIL: gst"; exit 1; }
echo "== [4/4] 內容檢查(全黑?)=="
python3 - <<'EOF'
import numpy as np
raw = np.fromfile('cap.raw', dtype=np.uint8)
print('mean', round(raw.mean(),1), 'max', int(raw.max()))
assert raw.mean() > 5, "FAIL: 全黑"
print("PASS")
EOF

專案輸出:capture_verify.sh(單機驗證)+ 可接 CI 的 pass/fail 輸出。幀大小與內容檢查可以攔下「出圖成功但全黑」的隱形失敗。

5.15 量測/驗證 SOP:出圖驗證

  1. 列舉v4l2-ctl --list-devices → 確認 videoN 存在。
  2. 拓撲media-ctl -p → 管線完整。
  3. 格式v4l2-ctl -d /dev/video0 --list-formats-ext → 記錄 fourcc / 尺寸。
  4. 取幀--stream-mmap=1 --stream-count=1 --stream-to=f.raw → 驗證幀大小公式。
  5. 內容:取 RAW 檢查 mean / max,排除「全黑」。
  6. 多工具交叉:Argus 出圖 + GStreamer 串流,確認三種工具都通。
驗收指標:三種工具都出圖、幀大小正確、內容非全黑、非綠紫。

5.16 平台間對照:出圖工具

面向Orin NanoRPi5Orange PiThor
出圖指令argus_camerarpicam-stillv4l2-ctlargus / Holoscan
串流gst nvarguscamerasrclibcamera-vidgst v4l2srcgst + Holoscan
RAW--raw-file--raw--stream-to--raw-file
預覽--preview(EGL)--viewfindergst autovideosinkEGL / Holoscan
底層全部走 V4L2 / media API — 知識共通
重點:「出圖 = 鏈路通」的驗證哲學四平台通用;指令不同但驗證三件套(列舉 / 取幀 / 內容)可平移。

5.17 互動式檢核清單:出圖驗收

5.17 Register 位元級完整工作流:Argus 設定曝光 + 出圖驗證

步驟Command驗證目標預期結果
1. 設模式argus_camera --camera-id 0 --mode 0選擇正確 modemode 0 載入成功
2. 設曝光--exposure-value 0.016手動曝光曝光設為 16ms
3. 設增益--gain-value 4.0手動增益增益設為 4x
4. 擷取--capture-auto 1 --duration 1取 1 幀輸出 .raw 檔案
5. 驗證大小ls -l *.raw檔案大小width × height × 2
6. 亮度確認Python mean() 計算非全黑/全白mean 在 100-600 範圍
Argus 完整 Pipeline:出圖 → 驗證 → 判斷
#!/bin/bash
# argus_first_frame.sh — 第一幀完整驗證

echo "=== Step 1: List cameras ==="
argus_camera --list-cameras
echo ""

echo "=== Step 2: Capture with manual exposure ==="
argus_camera --camera-id 0 --mode 0 \
  --exposure-value 0.016 --gain-value 4.0 \
  --capture-auto 1 --duration 1 --file-type raw \
  --output-dir /tmp/frame_test

echo "=== Step 3: Verify output ==="
RAW_FILE=$(find /tmp/frame_test -name "*.raw" | head -1)
if [ -z "$RAW_FILE" ]; then
  echo "FAIL: No RAW file generated"
  exit 1
fi

SIZE=$(stat -f%z "$RAW_FILE" 2>/dev/null || stat --format=%s "$RAW_FILE")
echo "RAW file: $RAW_FILE"
echo "Size: $SIZE bytes"

# OV9281 mode 0: 1280x800, 10-bit → 1280*800*2 = 2,048,000
EXPECTED=2048000
if [ "$SIZE" -eq "$EXPECTED" ]; then
  echo "SIZE CHECK: PASS (expected $EXPECTED)"
else
  echo "SIZE CHECK: FAIL (expected $EXPECTED, got $SIZE)"
fi

echo "=== Step 4: Brightness check ==="
python3 -c "
import numpy as np, sys
data = np.fromfile('$RAW_FILE', dtype=np.uint16)
print(f'mean={data.mean():.1f} min={data.min()} max={data.max()}')
if data.mean() < 10: print('VERDICT: TOO DARK — check exposure/mode')
elif data.mean() > 600: print('VERDICT: TOO BRIGHT — check gain')
else: print('VERDICT: OK')
"

5.18 多層疑難排解決策樹

決策樹 A:Argus 出全黑
1. v4l2-ctl --stream-mmap=1 --stream-count=1 --stream-to=raw 取到檔?
   ├─ 否 ─→ 退回感測器驅動問題(見單元 4)
   └─ 是 ┐
2. argus_camera 有 output?(-o /tmp/test)
   ├─ 有 但 0 bytes ─→ argus 設定錯誤(mode 或 fourcc)
   ├─ 無 任何輸出 ─→ argus 輸出路徑權限問題
   └─ 有且有大小 ┐
3. RAW 數據 mean < 10?
   ├─ 是 ─→ 曝光未生效(ATE 模式?)→ 檢查 mode 曝光範圍
   └─ 否 ─→ 輸出格式/色彩空間錯誤
決策樹 B:Argus 開會話失敗
1. "Session create failed"?
   ├─ 是 ┐
   │   2. 有其他 Argus 程序在跑?
   │      ├─ 是 → kill 舊程序
   │      └─ 否 → ISP bandwidth 超限(一次開太多路?)
   └─ 否 ┐
2. "No cameras available"?
   ├─ 是 → driver 沒 probe 成功(回單元 4)
   └─ 否 → 驅動版本與 Argus API 版本不匹配

5.19 量測驗證完整 SOP

  1. 前置確認v4l2-ctl --list-devices → /dev/video0 存在。
  2. argus 輸出目錄:建立 /tmp/frame_test;確認寫入權限。
  3. 手動曝光出圖argus_camera --camera-id 0 --mode 0 --exposure-value 0.016 --gain-value 4.0 --capture-auto 1 --duration 1 --file-type raw -o /tmp/frame_test
  4. RAW 尺寸ls -l /tmp/frame_test/*.raw → 預期 width × height × 2 bytes。
  5. 亮度檢查:Python np.fromfile(raw, uint16).mean() → 應在 100-600 範圍。
  6. 白卡測試:拍攝 X-Rite 灰卡,取 RAW → 檢查三通道均勻度。
  7. 亮度穩定性:手動曝光下連續取 30 幀,量每幀 mean ± std;std < 2 表示亮度穩定。
判讀標準:RAW 大小正確 + mean 在合理範圍 + 三通道均勻 + 30 幀亮度穩定 = 「我的第一張相機圖片」里程碑達成。

5.20 四平台终极對照

面向Orin NanoRPi5Orange PiThor推薦
出圖工具argus_camerarpicam / libcamerav4l2-ctlargus / Holoscan各有首選
RAW 輸出--file-type raw--raw / libcamera-raw--stream-toHoloscan 管線格式相同
曝光控制--exposure-value--shutter (µs)V4L2 controlsSensorMode單位不同
增益控制--gain-value--gainV4L2 controlsSensorMode全平台可調
亮度分析Python numpy 全平台共用平台無關
Argus 版本JetPack 版本決定無 Argus無 Argus同 Orin注意 API 版本
第一幀里程碑出圖 + 大小正確 + 亮度合理全平台相同

5.21 完整 Bring-up 專案 Checklist