argus_camera / v4l2-ctl
argus_camera --mode 0 --capture-auto 1 --duration 1 argus_camera --preview 1 --mode 0
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、感測器沒輸出 |
| 畫面綠/紫 | 格式/色彩空間錯 |
# 確認 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
| 參數 | 含義 | 典型值 |
|---|---|---|
--mode N | 選 DTB mode(解析度/幀率) | 0 = 預設 |
--capture-auto N | 自動連拍 N 張 | 1 |
--duration N | 取流秒數 | 1 |
--preview 1 | 螢幕預覽 | 0/1 |
--raw-file f.raw | 輸出 RAW(回顧單元 8) | — |
# 取 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);大小錯誤 → 格式/時序問題。
1. v4l2-ctl --list-devices 有 video0? ├─ 無 ─→ 驅動/DTB(回顧單元 4) └─ 有 ┐ 2. media-ctl 管線完整(感測器→CSI→VI)? ├─ 斷 ─→ 管線連結設定(media-ctl -l) └─ 完整 ┐ 3. 取流,檢查幀大小: ├─ 錯 ─→ fourcc / width / height 宣告 └─ 對 ┐ 4. 影像內容: ├─ 全黑 → 曝光 0 / 感測器沒輸出 / 鏡頭蓋 ├─ 綠紫 → pixel format 或色彩空間 └─ 正常 → ✅ 準備調校
--set-fmt-video 指定了不支援的格式時,驅動會「接受但實際沒改」——用 --get-fmt-video 回讀確認。sync=false 或 decodebin 緩衝。取流前,V4L2 驅動配置幀緩衝(buffer),userspace 透過 mmap 直接讀取,避免每幀複製。理解三個狀態:QUEUED(排隊給硬體)→ DONE(硬體填好)→ DEQUEUED(使用者拿走)。
| 指令 | 狀態變化 |
|---|---|
--stream-mmap=N | 配置 N 個 mmap 緩衝 |
--stream-count=N | 取 N 幀後停止 |
--stream-to=file | 把 dequeued 幀寫檔 |
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 ! fakesinkGStreamer 的 v4l2src 抓 V4L2 buffer 後沿管線流動。常見卡住原因不是相機,而是 sync:顯示端等 vsync,可能讓管線「等」到看起來像凍住。
# 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/顯示問題,不是相機問題。場景:你需要在 Orin Nano 上做到「擷取 → ISP 處理 → 即時顯示 → 同時錄影」的完整 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。
Argus API 的核心不是「拍照」,而是「排程」:每個 frame 是一個 request,多個 request 排在 stream 裡,stream 屬於一個 session。
| 概念 | 說明 | 常見誤解 |
|---|---|---|
| Session | 一組相機的使用環境 | 以為可以跨 session 共享 buffer(不行) |
| Stream | 一個輸出格式的幀序列 | 以為一個 session 只能有一個 stream(可多個) |
| Request | 一幀的 ISP 設定 + 輸出 buffer | 以為 request 是同步的(實際是非同步排程) |
| Event | ISP 回傳的狀態(AE 收斂、幀完成…) | 以為不處理 event 也沒事(可能導致 buffer 洩漏) |
request->disable()` 或沒呼叫 EventQueue::waitForEvent(),buffer 會慢慢耗盡直到 OOM。| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| 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 測試 |
v4l2src 與 nvarguscamerasrc 的延遲差異:在 pipeline 中加入 identity 元件記錄 timestamp,計算從 sensor 到 sink 的端到端延遲。場景:生產線每台設備裝完都要人工跑 argus / v4l2 驗證出圖,太慢且容易漏。專案目標:寫一個自動化驗證腳本,一次跑完「Argus 出圖 → V4L2 取幀 → GStreamer 串流 → 幀大小 / 內容檢查」,輸出 pass/fail 報告。
#!/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 輸出。幀大小與內容檢查可以攔下「出圖成功但全黑」的隱形失敗。
v4l2-ctl --list-devices → 確認 videoN 存在。media-ctl -p → 管線完整。v4l2-ctl -d /dev/video0 --list-formats-ext → 記錄 fourcc / 尺寸。--stream-mmap=1 --stream-count=1 --stream-to=f.raw → 驗證幀大小公式。| 面向 | Orin Nano | RPi5 | Orange Pi | Thor |
|---|---|---|---|---|
| 出圖指令 | argus_camera | rpicam-still | v4l2-ctl | argus / Holoscan |
| 串流 | gst nvarguscamerasrc | libcamera-vid | gst v4l2src | gst + Holoscan |
| RAW | --raw-file | --raw | --stream-to | --raw-file |
| 預覽 | --preview(EGL) | --viewfinder | gst autovideosink | EGL / Holoscan |
| 底層 | 全部走 V4L2 / media API — 知識共通 | |||
| 步驟 | Command | 驗證目標 | 預期結果 |
|---|---|---|---|
| 1. 設模式 | argus_camera --camera-id 0 --mode 0 | 選擇正確 mode | mode 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 範圍 |
#!/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') "
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 曝光範圍 └─ 否 ─→ 輸出格式/色彩空間錯誤
1. "Session create failed"? ├─ 是 ┐ │ 2. 有其他 Argus 程序在跑? │ ├─ 是 → kill 舊程序 │ └─ 否 → ISP bandwidth 超限(一次開太多路?) └─ 否 ┐ 2. "No cameras available"? ├─ 是 → driver 沒 probe 成功(回單元 4) └─ 否 → 驅動版本與 Argus API 版本不匹配
v4l2-ctl --list-devices → /dev/video0 存在。/tmp/frame_test;確認寫入權限。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。ls -l /tmp/frame_test/*.raw → 預期 width × height × 2 bytes。np.fromfile(raw, uint16).mean() → 應在 100-600 範圍。| 面向 | Orin Nano | RPi5 | Orange Pi | Thor | 推薦 |
|---|---|---|---|---|---|
| 出圖工具 | argus_camera | rpicam / libcamera | v4l2-ctl | argus / Holoscan | 各有首選 |
| RAW 輸出 | --file-type raw | --raw / libcamera-raw | --stream-to | Holoscan 管線 | 格式相同 |
| 曝光控制 | --exposure-value | --shutter (µs) | V4L2 controls | SensorMode | 單位不同 |
| 增益控制 | --gain-value | --gain | V4L2 controls | SensorMode | 全平台可調 |
| 亮度分析 | Python numpy 全平台共用 | 平台無關 | |||
| Argus 版本 | JetPack 版本決定 | 無 Argus | 無 Argus | 同 Orin | 注意 API 版本 |
| 第一幀里程碑 | 出圖 + 大小正確 + 亮度合理 | 全平台相同 | |||