简单介绍
RTSP(Real Time Streamin Protocol)
,是TCP/IP
协议体系中的一个应用层协议,由哥伦比亚大学、网景和RealNetworks
公司提交的IETF RFC
标准。该协议定义了一对多应用程序如何有效地通过IP
网络传输多媒体数据。RTSP
在体系结构上位于RTP和RTCP之上,使用TCP或UDP完成数据传输。
RTP(Real-time Transport Protocol)
,由IETF
地多媒体传输工作小组1996年在RFC1880
中公布。RTP
协议详细说明了在network上传递音频和视频的标准数据包格式。它创建在UDP
协议上。RTCP(Real-time ControlProtocol)
,是和RTP
一起工作的控制协议,主要功能是为数据传输提供服务质量反馈。
根据上述介绍,可以得知RTSP、RTP和RTCP三个协议分别负责的内容如下图所示:
实时传输协议RTP
**RTP**
为语音、图像、传真等多种需要实时传输的流媒体数据提供端到端的实时传输服务,但不保证服务质量,服务质量由RTCP
来提供。
流媒体,指的是Internet上使用流式传输技术的时基媒体。与常见的下载方式不同,流式传输的特点是边下载边观看,无需等到音频或视频数据全部下载完成后在播放。
RTP协议的工作原理
RTP
和RTCP
位于传输层,运行在UDP
协议之上。UDP
协议具有实时性好,数据传输延时低等特点,且可以利用UDP
的多路复用、校验和服务。
RTP报文分析
RTP
数据协议负责对流媒体数据进行封包并实现流媒体数据的实时传输,每个RTP
数据packet
都由header
和payload
两部分组成,其中header
的前12
个字节的含义是固定的,而payload
可以是音频或者视频数据。
其中RTP packet
的header
定义和含义如下所示:
RTP封包
当应用程序建立一个RTP
会话时,应用程序将确定一对目的传输地址。目的传输地址由一个网络地址和一对端口组成,RTP
数据发向偶数的UDP
端口,而对应的控制信号RTCP
数据发给相邻的奇数UDP
端口,这样就构成一个UDP
端口对。RTP
协议从上层接收流媒体信息码流,封装成RTP
数据包,然后将其发往UDP
端口对中偶数端口。
下面以H264视频数据为例,介绍RTP如何封装H264数据。H264有三种打包方式如下:
- 单NALU打包:一个RTP packet包含一个完整的NALU;
- 聚合打包:对应较小的NALU,一个RTP报可包含多个完整的NALU;
- 分片打包:对于较大的NALU,一个NALU可以分为多个RTP packet发送;
每一个RTP packet都包含一个RTP header和 payload,但是不同的打包方式下,除了header和payload之外,还包含了一些其他东西。
- 单NALU打包
所谓单NALU打包就是将一整个NALU的数据放入RTP包的载荷中,这是最简单的一种方式。
- 分片打包
每个RTP包都有大小限制的,因为RTP一般都是使用UDP发送,UDP没有流量控制,所以要限制每一次 发送的大小,所以如果一个NALU的太大,就需要分成多个RTP包发送。
分片打包下,RTP中除了header和payload之外,在payload开始之前还有两个字节的信息,如下所 示:
第一个字节,称为FU Indicator,其格式如下:
其中高三位,与NAL头的高三位相同,后五位为Type,值为28,表示该RTP packet的分片类型。
Type Packet Type name
---------------------------------------------------------
0 undefined -
1-23 NAL unit Single NAL unit packet per H.264
24 STAP-A Single-time aggregation packet
25 STAP-B Single-time aggregation packet
26 MTAP16 Multi-time aggregation packet
27 MTAP24 Multi-time aggregation packet
28 FU-A Fragmentation unit
29 FU-B Fragmentation unit
30-31 undefined
第二个字节,称为FU Header,其格式如下:
其中,第一位:S,表示该 RTP packet为NALU分片的第一个包,第二位:E,表示该 RTP packet为NALU分片的最后一个包,第三位:保留位,必须设置为0,最后五位:NALU的Type信息。
因此,对于RTP封装H264流数据,在不同打包方式下,RTP数据包的内容如下图所示:
RTP解包
RTP
解包,对于H264
数据而言,指的是接收到一个RTP packet
,首先需要判断RTP
打包方式是单NALU打包还是分片打包,然后在packet payload
中获取得到H264
的NAL
数据,并加上0x00000001
起始字节一并写进文件中即可。
RTSP的pipeline
Gstreamer对于RTP和RTSP具有良好的支持。在实际的视觉任务中,都需要通过RTSP获取到实时数据,然后使用深度学习模型对其进行分析。深度学习推理框架Deepstream基于Gstreamer搭建而成,因此对RTSP的pipeline进行分析非常有必要。
pipeline
在Deepstream
的环境下,通过如下的命令可以实现拉取RTSP
流,然后使用模型对数据进行分析,然后识别的结果保存成一张张连续的图像数据。
gst-launch-1.0 rtspsrc location=rtsp://10.9.4.133/30012 ! rtph264depay ! h264parse ! nvv4l2decoder ! m.sink_0 nvstreammux name=m batch-size=1 width=1920 height=1080 ! nvinfer config-file-path=/opt/nvidia/deepstream/deepstream-6.0/samples/configs/deepstream-app/config_infer_primary.txt batch-size=4 unique-id=1 ! nvmultistreamtiler rows=1 columns=1 width=1920 height=1080 ! nvvideoconvert ! nvdsosd display-bbox=0 display-text=0 ! nvvideoconvert ! jpegenc ! multifilesink location=test%d.jpg
pipeline可视化
对于上述的pipeline,可以通过如下的步骤导出pipeline的结构图,具体如下:
- 安装dot
sudo apt-get install graphviz
- 设置文件输出环境变量
export GST_DEBUG_DUMP_DOT_DIR=/tmp/
- 运行
pipeline
新建终端,拷贝上述的命令,修改实际的RTSP地址,运行命令。在上述指定的路径下,此时会生成很 多dot
文件,如下图所示:
$ ls /tmp
0.00.00.238129310-gst-launch.NULL_READY.dot
0.00.00.247064574-gst-launch.READY_PAUSED.dot
0.00.00.632677398-gst-launch.PAUSED_PLAYING.dot
0.00.05.464861472-gst-launch.PLAYING_PAUSED.dot
0.00.05.484623147-gst-launch.PAUSED_READY.dot
- 生成
pipeline
结构图
dot -Tpng 0.00.05.464861472-gst-launch.PLAYING_PAUSED.dot > aa.png
dot -Tpdf 0.00.05.464861472-gst-launch.PLAYING_PAUSED.dot > aa.pdf
相关的elements介绍
pipeline
的结构如下图所示,由于上述命令的pipeline
结构比较复杂,这里主要提出了参与RTSP
的部分elements
。
rtpjitterbuffer
This element reorders and removes duplicate RTP packets as they are received from a network source.
该元素重新排序并删除从网络源接收到的重复 RTP 数据包。
该element需要RTP payload的clock-rate信息,用于评估delay延迟。
如果接收到packet时间比较迟,则会触发一个GstRTPPacketLost event。通过该event,depayloader或者其他element可以创建concealment数据或者一些其他逻辑来处理丢失的数据packet。
jitterbuffer 结合输入buffer的DTS属性和PTP packet中的rtptime属性来初始化输出buffer的PTS属性。
jitterbuffer通过初步计算一个packet何时到达,如果一个packet到达时间过迟,可以向上游发送一个GstRTPRetransmissionRequest event(重传)。
This element will automatically be used inside rtpbin.(RtpBuffer)
rtph264depay
Extracts H264 video from RTP packets
从RTP
数据包中提取H264
视频,也就是我们上面介绍的RTP
解包过程。在该element
的实现中,gst_rtp_h264_depay_process
函数中实现了RTP
数据包的解包工作。
丢包模拟
流媒体数据通过RTSP协议传输在实际场景下,由于网络、带宽等原因,数据在传输过程中存在丢包(RTP packet)导致解码得到的图像数据存在花屏,而对于视觉算法而言,花屏就会导致误检降低检测性能,因此需要尽可能避免花屏的出现。
在这一小节中,首先介绍如何人为制造花屏数据,以便进行后续花屏检测的测试工作。在Linux平台下,提供一个流量控制工具TC,能够模拟一些异常的网络情况,例如网络延时长、丢包、网络地址连接不通等。
TC工具的主要用法如下:
传输延迟
- 将设备eth0网卡的传输设置为延迟100毫秒发送
tc qdisc add dev eth0 root netem delay 100ms
- 将传输设置为延迟100ms ± 10ms
tc qdisc add dev eth0 root netem delay 100ms 10ms
模拟网络丢包
- 随机丢掉1%的数据包
tc qdisc add dev eth0 root netem loss 1%
- 随机丢掉1%的数据包,成功率为30%
tc qdisc add dev eth0 root netem loss 1% 30%
模拟包重复
- 随机产生1%的重复数据包
tc qdisc add dev eth0 root netem duplicate 1%
模拟包损坏
- 随机产生 0.2% 的损坏的数据包
tc qdisc add dev eth0 root netem corrupt 0.2%
模拟包乱序
- 有 25% 的数据包(50%相关)会被立即发送,其他的延迟10 秒
tc qdisc change dev eth0 root netem delay 10ms reorder 25% 50%
删除规则
sudo tc qdisc del dev eth0 root
显示规则
sudo tc -s qdisc ls dev eth0
利用TC实现花屏
RTSP传输数据过程中,花屏造成的主要原因是RTP packet内部数据丢失造成,因此通过TC工具的模拟队丢包命令即可得到花屏数据。
- 模型丢包
首先在一台机器上将视频数据完成RTSP推理,然后输入如下模拟丢包命令:
# 在当前设备上模拟丢包5%
tc qdisc add dev eth0 root netem loss 5%
# 查看当前设备已经运行的TC命令
sudo tc -s qdisc ls dev eth0
- 运行命令,拉取RTSP流
输入如下命令,拉取RTSP流,得到每一帧的图像数据
gst-launch-1.0 rtspsrc location=rtsp://10.9.4.133/30012 ! rtph264depay ! h264parse ! nvv4l2decoder ! m.sink_0 nvstreammux name=m batch-size=1 width=1920 height=1080 ! nvinfer config-file-path=/opt/nvidia/deepstream/deepstream-6.0/samples/configs/deepstream-app/config_infer_primary.txt batch-size=4 unique-id=1 ! nvmultistreamtiler rows=1 columns=1 width=1920 height=1080 ! nvvideoconvert ! nvdsosd display-bbox=0 display-text=0 ! nvvideoconvert ! jpegenc ! multifilesink location=test%d.jpg
- 查看花屏数据
花屏检测
造成花屏的本质原因是数据传输过程中RTP
包丢失,也即RTP packet
中header
的seqnum
不连续,因此花屏检测的思路如下:
1. 接收RTP packet
,与上一个packet
的seqnum
对比,判断seqnum
是否连续;
2. 如果seqnum
不连续,判断接收到的RTP packet
的NAL Type
,判断是否为关键帧;
3. 如果不是关键帧,则将该RTP packet
的数据抛弃;
4. 一直抛弃数据,直到下一个关键帧,才开始重启处理数据;
上述花屏检测的业务逻辑可以在**rtph264depay element**
的源码中实现,上述过程存在一个问题,由于花屏会丢弃一些数据,导致画面帧可能不连续~~~
参考链接
- https://zhuanlan.zhihu.com/p/72917813
- https://blog.csdn.net/u013554213/article/details/98078955
- https://developer.aliyun.com/article/243398