3. DeepStream架构与核心插件
DeepStream 并不是一套从零构建的推理框架,而是建立在 GStreamer 之上的流式视频分析 SDK。理解 DeepStream 的关键,是先理解 GStreamer 的“管道—元素—Pad”模型,再看 NVIDIA 如何用一批专用插件把解码、批处理、推理、跟踪、绘制和输出串成一条可扩展的分析流水线。本节围绕这条流水线的拓扑结构、核心插件职责、批处理机制与元数据总线展开。
GStreamer基础:管道、元素与Pad
GStreamer 用“元素(Element)”作为最小功能单元,多个元素通过“Pad”连接成“管道(Pipeline)”。Pad 有方向:src pad 输出数据,sink pad 接收数据;只有 src 与 sink 的 caps(能力描述,如 video/x-raw、format=NV12、width=1920、height=1080)兼容时才能连接成功。数据以 GstBuffer 为单位在管道中流动,缓冲区携带时间戳、时长和内存指针。DeepStream 的插件全部遵循这一模型,因此可以用 gst-launch-1.0 快速验证,也可以用 C/C++ 或 Python 构建动态管道。
一个典型的最小 DeepStream 管道形态如下:
filesrc → qtdemux → h264parse → nvv4l2decoder → streammux
→ nvinfer → nvtracker → nvdsosd → nvv4l2h264enc → filesink
其中 nvv4l2decoder 负责硬解码,streammux 负责批处理,nvinfer 负责推理,nvtracker 负责目标跟踪,nvdsosd 负责在帧上叠加检测框和标签,最后编码或直接送显。管道中的每个元素都可以通过 GstElement 属性进行配置,例如 nvinfer 的 config-file-path、streammux 的 batch-size 和 width/height。
DeepStream插件拓扑:从源到宿的完整链路
DeepStream 的插件拓扑可以按职责划分为五段:源与解码、批处理、推理与跟踪、可视化、输出。源可以是文件、RTSP、摄像头或 CSI 传感器;解码通常使用 nvv4l2decoder 或 nvv4l2decoder 配合 nvv4l2h264enc。批处理由 nvstreammux 完成,它把多路输入帧按 batch-size 聚合成一个批次张量,供后续推理使用。推理与跟踪由 nvinfer、nvinferserver、nvtracker 承担。可视化由 nvdsosd 完成,它读取元数据中的对象坐标并绘制到帧上。输出可以是显示、文件、RTSP 推流或消息代理。
需要特别注意的是,DeepStream 的插件之间传递的不只是视频帧,还有元数据(NvDsBatchMeta)。nvinfer 在推理后把检测结果写入元数据,nvtracker 在跟踪后补充对象 ID,nvdsosd 读取这些元数据完成绘制。因此,插件拓扑不仅是数据流,也是元数据流。
source-bin与streammux:多路输入的汇聚点
在多路视频场景中,每一路源通常被封装成一个 source-bin。source-bin 是一个 GstBin,内部包含该路源的解码、解析和必要的预处理元素,对外只暴露一个 src pad。这样做的价值在于:主管道只需要把多个 source-bin 的 src pad 分别请求(request)到 nvstreammux 的 sink pad 上,就能实现“一路一 bin、动态增删”的灵活拓扑。
nvstreammux 是 DeepStream 的批处理核心。它接收多路输入,按 batch-size 把帧聚合成一个批次张量。关键参数包括:batch-size(批次大小)、width/height(输出帧尺寸)、live-source(是否为实时源)、batched-push-timeout(批处理超时)。当输入路数少于 batch-size 时,streammux 会等待超时或填充空帧,因此 batch-size 的设置需要与输入路数、延迟要求匹配。例如 4 路 1080p 输入、batch-size=4 时,推理引擎一次处理 4 帧;若 batch-size=8 而只有 4 路输入,则会出现等待或空帧填充,反而增加延迟。
nvinfer、nvtracker与nvdsosd:推理、跟踪与绘制
nvinfer 是 DeepStream 的推理插件,支持 TensorRT 引擎、ONNX、Caffe 等模型格式。它通过 config-file-path 指向配置文件,配置文件中定义模型路径、输入尺寸、类别数、后处理类型(如检测、分类、分割)等。nvinfer 的 interval 参数控制跳帧推理:interval=0 表示每帧推理,interval=1 表示隔帧推理,以此类推。跳帧可以降低 GPU 负载,但会牺牲跟踪的连续性。
nvtracker 负责多目标跟踪,常用算法包括 NvDCF、DeepSORT、IOU 等。它读取 nvinfer 输出的检测框,为每个目标分配稳定的 track ID,并把跟踪结果写回元数据。nvtracker 的关键参数有 ll-lib-file(跟踪库路径)、tracker-width/tracker-height(跟踪器工作分辨率)、gpu-id 等。跟踪器的工作分辨率不必等于原视频分辨率,适当降低可以提升速度。
nvdsosd 是屏幕显示插件,它从元数据中读取对象框、标签、置信度和 track ID,并叠加到视频帧上。process-mode 决定 OSD 是在 GPU 还是 CPU 上处理;display-bbox、display-text 控制是否绘制框和文字。nvdsosd 通常放在编码或显示之前,是调试和演示时最直观的观察点。
sink类型与元数据总线
DeepStream 的 sink 类型决定了分析结果的去向。常见的 sink 包括:nveglglessink(本地显示)、nvv4l2h264enc + filesink(保存为 MP4)、nvv4l2h264enc + rtph264pay + udpsink(RTSP 推流)、nvmsgbroker(把元数据发送到 Kafka、MQTT 等消息代理)。选择 sink 时需要考虑是否需要保留视频、是否需要结构化元数据、以及目标平台的显示能力。
元数据总线是 DeepStream 区别于普通 GStreamer 管道的关键。NvDsBatchMeta 随 GstBuffer 在管道中传递,包含 frame_meta、object_meta、classifier_meta、tracker_meta、display_meta 等层级。nvinfer 写入检测结果,nvtracker 写入跟踪 ID,nvdsosd 读取并绘制,nvmsgbroker 读取并发送。开发者也可以通过 probe(探针)在任意 pad 上挂载回调,读取或修改元数据。例如在 nvinfer 的 src pad 上挂 probe,可以获取每帧的检测框坐标和类别,用于自定义业务逻辑。