LL-Flux:RTSP流视频链路延迟优化
Pipeline

图1-RTSP视频流流程图
RTP/RTSP
RTSP = 控制协议(control protocol)
RTP = 承载媒体数据的实时传输协议(transport protocol)
RTP
实时传输协议(Real-time Transport Protocol),为数据提供了具有实时特征的端对端传送服务,用于实时传输数据。该协议提供的信息包括:时间戳(用于同步)、序列号(用于丢包和重排序检测)、以及负载格式(用于说明数据的编码格式)。
RTSP
实时流传输协议(Real Time Streaming Protocol,RTSP),TCP/IP协议.该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。RTSP在体系结构上位于RTP和RTCP之上,它使用TCP或UDP完成数据传输。
延迟原因分析:
- 缓冲区(Jitter Buffer)大小不同 → 延迟不同;
- 解码器实现不同 → 延迟不同;
- 是否等待时钟同步;
- RTP depayload 的策略不同
RTSP协议图:

图2-RTSP协议图
视频编码/解码
- 编码 (Encode):把原始视频压缩成体积更小的数据(H.264/H.265/MJPEG)
- 解码 (Decode):把压缩后的数据还原成可显示的图像帧(YUV/RGB)
视频编码格式
| 格式 | 类型 | 特点 | 带宽需求 |
|---|---|---|---|
| H.264(AVC) | 有损视频编码(帧内+帧间) | 压缩效率高、延迟中等 | 4–8 Mbps |
| H.265(HEVC) | 有损视频编码(帧内+帧间),H.264 的升级版 | 压缩效率更高(节省带宽) | 2–5 Mbps |
| MJPEG(Motion JPEG) | 一系列 JPEG 图片组成的视频 | 每帧独立,无帧间预测 → 低延迟 | 100–300 Mbps |
解码方式
VLC
VLC 使用 FFmpeg 解码器,直接打开一个 RTSP 链接,自带较大的 jitter buffer / caching。许多缓存、时间同步都封装在内部,难以完全关闭。
###GStreamer
用于创建流媒体应用程序的框架,更加开源。GStreamer提供用于多媒体应用程序的API, 插件架构, 流水线架构, 流水线架构, 媒体类型处理/协商机制, 同步机制等等。gstreamer基于glib实现,用C语言来实现面向对象思维。

图3-GStreamer
高性能
- 使用GLib的GSlice分配器。
- 插件之间极其轻量级的链接。数据可以以最小的开销在管道中传输。插件之间的数据传递只涉及典型管道中的指针取消引用。
- 提供一种直接在目标内存上工作的机制。例如,插件可以直接写入X服务器的共享内存空间。缓冲区也可以指向任意内存,例如声卡的内部硬件缓冲区。
- 写入时重新计数和复制最大限度地减少 memcpy 的使用。子缓冲区有效地将缓冲区拆分为可管理的部分。
- 专用流线程,调度由内核处理。
- 通过使用专门的插件允许硬件加速。
- 使用带有插件规范的插件注册表,以便可以延迟插件加载,直到实际使用插件。
基础概念
元素(Elements):
element 是执行某个媒体处理步骤的“功能模块”。每个 element 只做一件事,比如读取视频、拆包、解码、转换格式或输出画面。把多个 element 顺序连接起来,就形成一条完整的数据处理流水线(pipeline),数据会从源头一路经过这些模块处理后最终被播放或保存。
一个功能模块,例如:
元件 功能 rtspsrc RTSP 拉流 rtph265depay RTP 去封包 avdec_h265 H.265 解码(来自 FFmpeg) videoconvert 视频格式转换 x264enc H.264 编码 autovideosink 显示 Pads:
Pad 是 GStreamer 元素的输入/输出接口:,用来把元件连接起来让数据从一个元件流向另一个。每个 Pad 有自己能处理的数据类型(Caps),只有当两个 Pad 的类型兼容时才能连接,从而保证解码、转换、播放等处理模块之间的数据能够正确流动。数据在 pipeline 中是通过这些 Pad 单向流动的。
- src pad(输出)
- sink pad(输入)
元素之间用 pad 连接成 pipeline。
elementA.src → elementB.sinkCaps:
描述媒体格式,确保上下游格式匹配如:
|
Bin and Pipeline(管线):
Bin 是一组元素(element)的容器,本身也被当作一个元素来使用。它的作用是把多个元素打包成一个整体,让应用程序更容易管理复杂的 pipeline,例如一次性控制整个子系统的状态或统一接收内部元素产生的消息。
Pipeline 是最高级的 Bin,负责启动数据流、同步所有元素并管理媒体处理过程。Pipeline是多个元素的一条处理链路,即写的命令。例如:
gst-launch-1.0 rtspsrc ! rtph265depay ! avdec_h265 ! autovideosink

图4-GStreamer-Pipeline
Pad是一个element的输入/输出接口,分为src pad(生产数据)和sink pad(消费数据)两种。两个element必须通过pad才能连接起来,pad拥有当前element能处理数据类型的能力(capabilities),会在连接时通过比较src pad和sink pad中所支持的能力,来选择最恰当的数据类型用于传输,如果element不支持,程序会直接退出。在element通过pad连接成功后,数据会从上一个element的src pad传到下一个element的sink pad然后进行处理。当element支持多种数据处理能力时,我们可以通过Cap来指定数据类型.
通讯
GStreamer为应用程序和管道之间的通信和数据交换提供了多种机制。
Buffers 是用于在管道中的元素之间传递流数据的对象。缓冲区总是从源传输到接收器(下游)。
Events 是在元素之间或从应用程序发送到元素的对象。事件可以上游和下游传输。下游事件可以与数据流同步。
messages 是由element发出的消息,通过bus,以异步的方式被应用程序处理。通常用于传递errors, tags, state changes, buffering state, redirects等消息。消息处理是线程安全的。由于大部分消息是通过异步方式处理,所以会在应用程序里存在一点延迟,如果要及时的相应消息,需要在streaming线程捕获处理。
queries 查询允许应用程序从管道请求信息,如持续时间或当前播放位置。查询总是同步回答。元素也可以使用查询从其对等元素请求信息(如文件大小或持续时间)。它们可以在管道中两种方式使用,但上游查询更常见。

图5-GStreamer-communicate
相机测试
硬解码
在非jetson环境下不推荐
环境配置
在新版Uubuntu22.04下安装Gstramer,会安装高版本的Gstreamer就不会出现该问题(Windows下高版本也不会),只有Ubuntu20.04及以下版本才会出现。
- linux平台下的gstreamer安装
|
测试指令
|
- 下载gst-plugins-bad
查看gstreamer版本
|
ubuntu20.04的版本为1.16.3,下载gst-plugins-bad源码包
|
- 安装Nvidia的Video Codec SDK
gst-plugins-bad编译过程依赖的库及头文件,需要从NVIDIA官网下载,下载地址:NVIDIA VIDEO CODEC SDK - Get Started | NVIDIA Developerm
下载完成后并解压,将头文件和库文件拷贝至/usr/loocal下:
|
- 编译
在gst-plugins-bad目录下开启终端,运行以下命令,需要根据版本更改cuda。
查看cuda版本指令:
|
进入sys/nvdec目录进行编译硬解码
|
进入sys/nvdec目录进行编译硬编码
|
- 添加环境变量
|
- 测试
|
软解码
- TCP + latency=0 ; rtph265depay + h265parse + avdec_h265 ; videoconvert + autovideosink
|
delay = 220ms+
- TCP + latency=0 ; drop-on-latency=true ; sync=false
|
delay = 160ms+
- rtph265depay : RTP H.265 去封装,拼成连续 H.265 码流
- h265parse : H.265 码流解析器,分析码流,让 decoder 正常工作
- avdec_h265 : H.265 码流解码器,解码为 原始帧
- videoconvert : 像素格式转换器,转换像素格式 → RGB 等可显示格式
- autovideosink : 自动选择一个可用的视频输出设备显示到屏幕