3. 视频采集与摄像头接入

在 Jetson 上做视频分析,第一步不是模型推理,而是把视频“稳定、低延迟、可控帧率”地送进内存。Jetson 提供了三类典型视频源:CSI 摄像头(MIPI 直连 ISP)、USB 摄像头(UVC 走 USB 总线)、IP 摄像头(RTSP over 网络)。它们的数据路径、延迟特性、CPU 占用和可用的硬件加速能力完全不同,选错接入方式往往会让后续推理“卡在采集上”。本节围绕这三类源,讲清接入方式、GStreamer 管道基础,以及多路管理与帧率控制的实际做法。

三类视频源的数据路径与选型

CSI 摄像头通过 MIPI CSI-2 接口直接连到 Jetson 的 ISP(图像信号处理器),原始 Bayer 数据在片上完成去马赛克、白平衡、曝光等处理,再交给 VIC/NVENC 或直接进入内存。它的优势是延迟低、CPU 占用小、可硬件加速,适合固定安装的工业检测、机器人视觉。USB 摄像头走 UVC 协议,数据经 USB 控制器进入内存,格式多为 MJPEG 或 YUYV,解码通常由 CPU 或 GPU 承担,优点是即插即用、成本低,缺点是带宽和延迟受 USB 总线影响,多路时容易掉帧。IP 摄像头输出 RTSP 流,数据经网络到达 Jetson,需要先做 RTP 解包、H.264/H.265 解码,再进入分析管道,优点是布线灵活、可远程,缺点是引入网络抖动,必须做缓冲与丢帧策略。

三类视频源到 Jetson 分析管道的接入路径 CSI 摄像头 MIPI CSI-2 / Bayer 低延迟 · 硬件 ISP USB 摄像头 UVC / MJPEG·YUYV 即插即用 · 受总线带宽 IP 摄像头 RTSP RTP / H.264·H.265 远程 · 网络抖动 接入与预处理 ISP / 去马赛克 / 白平衡 CSI 路径 MJPEG 解码 / 格式转换 USB 路径 RTP 解包 / H.264 解码 RTSP 路径 统一为 NVMM / GstBuffer appsink 或 nvvidconv 输出 BGR/RGB 供推理 多路管理与帧率控制 每路独立 GstPipeline + 队列 videorate 限帧 / drop 策略 时间戳对齐 · 推理节流 输出:检测框 / 事件 / 告警 关键:CSI 走硬件 ISP,USB 需软解,RTSP 需网络缓冲;三者最终统一为 GstBuffer 进入分析层

GStreamer 管道基础:从 source 到 appsink

GStreamer 用“管道(pipeline)”描述数据流,基本结构是 source → filter → sink。在 Jetson 上,常用元素包括:nvarguscamerasrc(CSI)、v4l2src(USB)、rtspsrc(RTSP)、nvv4l2decoder(硬解)、nvvidconv(格式/尺寸转换)、videorate(限帧)、appsink(把帧交给 Python/C++ 程序)。下面给出三条可直接参考的示例管道(参数为示例值,需按实际设备调整)。

# CSI 摄像头:1280x720@30fps,输出 BGR 给 OpenCV
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
  'video/x-raw(memory:NVMM),width=1280,height=720,framerate=30/1' ! \
  nvvidconv ! 'video/x-raw,format=BGRx' ! videoconvert ! \
  appsink drop=1 max-buffers=2

# USB 摄像头:MJPEG 解码后限帧到 15fps
gst-launch-1.0 v4l2src device=/dev/video0 ! \
  'image/jpeg,width=1280,height=720,framerate=30/1' ! \
  jpegdec ! videorate ! 'video/x-raw,framerate=15/1' ! \
  videoconvert ! appsink drop=1

# RTSP 流:低延迟解码,仅保留最新帧
gst-launch-1.0 rtspsrc location=rtsp://192.168.1.64:554/stream1 latency=200 ! \
  rtph264depay ! h264parse ! nvv4l2decoder ! \
  nvvidconv ! 'video/x-raw,format=BGRx' ! videoconvert ! \
  appsink drop=1 max-buffers=1 sync=false

几个关键点:appsink 的 drop=1 表示队列满时丢弃旧帧,避免延迟累积;max-buffers=1 配合 sync=false 让程序总是拿到最新帧,适合实时分析;latency=200 是 RTSP 的抖动缓冲(毫秒),网络差时可适当增大,但会增加延迟。若用 Python,可通过 cv2.VideoCapture(pipeline, cv2.CAP_GSTREAMER) 直接打开上述管道字符串。

多路视频源管理与帧率控制

多路接入的核心矛盾是“总吞吐”与“单路实时性”。假设 4 路 1080p@30fps,总帧率 120fps,若每帧都做完整推理,Jetson Orin Nano 很难跟上。实际做法是:每路用独立线程或独立 pipeline 采集,采集与推理解耦;推理端按“抽帧”策略处理,例如每路只取 5fps 送入模型,其余帧丢弃。这样 4 路总推理负载降到 20fps,实时性反而更好。

帧率控制有三种常用手段:一是用 videorate 在管道内限帧,例如 videorate ! video/x-raw,framerate=10/1;二是在应用层用时间戳判断,距上次推理不足 100ms 就跳过;三是用 appsink 的 drop 与 max-buffers 控制缓冲深度。三者可组合使用。判断采集是否健康,可观察三个指标:实际帧率是否接近设定值、端到端延迟是否稳定、appsink 是否频繁丢帧。若实际帧率远低于设定,优先检查 USB 带宽、RTSP 网络丢包或解码是否落在 CPU 上。

建议为每路视频源单独记录:设备节点/URL、分辨率、目标帧率、实际帧率、延迟、丢帧数。多路调试时,这组数据能快速定位是采集瓶颈还是推理瓶颈。
RTSP 流不要用 sync=true 等待时钟同步,否则容易累积延迟;USB 多路时尽量使用 MJPEG 而非 YUYV,因为 YUYV 未压缩,带宽占用是 MJPEG 的数倍。

最后给出一个多路管理的参考结构:主线程负责启动 N 路 pipeline,每路一个采集线程把最新帧写入线程安全的“最新帧槽”;推理线程轮询各路的帧槽,按设定帧率取帧、推理、输出结果。这样即使某一路短暂卡顿,也不会阻塞其他路,整体系统更稳健。