RTSP 协议详解
当我们谈到 RTSP 的时候,其实不仅仅是 RTSP 协议本身,我们其实不可避免会谈到以下几个协议:
- RTP (Real-time Transport Protocol):真正用来传输音频视频的协议,一般是建立在 UDP 协议的基础上,特别需要注意的是,它使用偶数端口1;
- RTCP (Real-time Control Protocol):RTP 的姊妹协议,通过周期性发送统计信息,提供服务质量(QoS)的反馈,它使用的端口是奇数,而且就是 RTP 端口 +12;
- SDP (Session Description Protocol):是应用层的一个协议,也可以说事一个格式,跟 HTML、JSON 之类的算是同一类(在今天的文章里就简单带过了)3;
这里相信你也能看出一些内容了,比如其实 RTSP 协议本身不负责播放,只负责交互控制,RTP 以及 RTCP 才是真正的视频传输。
下面我们将其中的详细内容展开来说说,并且会用实际的例子来说明。
几个协议的详细介绍
在 Web 开发的时候,我们经常会使用到各种 HTTP 抓包工具,但是,作为一个有追求的工程师,你应该学会使用 WireShark,这是一款强大免费的网络抓包分析工具,它可以让我们看清楚,我们每天在使用的协议究竟是什么样的。
打开 WireShark (安装的过程就略过了,相信你可以自己搞定的),选择你电脑正在使用的网络端口,比如 Linux 可能是 eth0,Mac 是 en0 ,双击就能进入抓包。
接着在 WireShark 的筛选栏里,填入 rtsp || rtcp || rtp
这样,我们就能够把一些无关的协议过滤掉。
在继续之前,你还需要准备的是,一个 RTSP 服务器,我这里准备的是一个网络摄像头,另外就是本地的 RTSP 播放器,比如我就是用 VLC 来播放的。如果你身边暂时没有可用的,也可以临时造一个,可以看看 rtsp-simple-server 里面介绍的。
当然,还有客户端,我们可以直接用各种播放器(如 VLC)来播放 RTSP 视频源,或者你可以使用命令行, 比如 FFMpeg 的 ffplay:
1 | ffplay rtsp://192.168.1.100/live |
如果你跟我一样使用 VLC:点击打开媒体 -> 网络,然后在 URL 中填入视频源,点击打开就开始播放了,过几秒钟后点击停止播放。
整体通信过程总览
下面两张图就是我用 VLC 播放以及停止之间发生的网络通信抓包,其中 192.168.2.31 是网络摄像头,而 192.168.2.115 则是我的电脑,即播放器所在的电脑。
需要注意到的部分:
- 这次忽略了暂停(PAUSE),以及其它比如 GET_PARAMETER,SET_PARAMETER;
- 在 PLAY 请求的回复之前,我们看到了一个 RTCP 以及 RTP 请求,这说明,在回复之前,播放源已经开始传输播放数据;
- 在后续不断的 RTP 中,有些数据包带有 Mark 字样,这是由于视频数据过大造成了分包;
RTSP 协议
接下来,让我们通过实际抓包的内容来作具体说明。
OPTIONS 请求
首先,客户端会发送一个与 HTTP 协议很类似的 RTSP 协议到 192.168.1.100 的 554 端口,是一个 OPTIONS 请求,即列出这个播放源可用的请求,注意 CSeq,每个 RTSP 请求都会带上,这样,服务端的回应就会跟客户端一一对应起来(这不就是 HTTP)。
然后服务器就会回应:
如上,服务器告诉客户端,可以使用 DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE 等几个请求。
DESCRIBE 请求
现在,客户端发送 DESCRIBE 请求:
服务器会用 SDP 格式的内容回应:
WireShark 的一个非常友好的部分在于,它会把协议的说明描述显示出来,SDP 看不懂?它会很清楚地告诉你,另外,SDP 详细的协议解释清看 维基上的说明 。
这里注意下 rtpmap:96 H264/90000
这一行,这里表示这个视频源是用 H264 编码,采样频率是 90000 。
如上,服务器会展示出,这个视频源的实际视频内容是 MP4 格式的,视频在 0 通道,音频在 1 通道。
SETUP 请求
现在,我们到了 SETUP 步骤,相当于初始化(如果播放源既有音频又有视频,那么需要 SETUP 两次):
这里解释下 Transport 的内容:
- RTP/AVP:表示 RTP A/V Profile,其实后面省略了 UDP,如果是 RTP/AVP/TCP 则表示 RTP 使用 TCP 进行传输;
- unicast:表示单播,与组播(multicast)进行区别,即一对一进行传输,而不是一对多;
- client_port=57246-57247:表示客户端打开了 57246 以及 57247 端口,分别进行 RTP 以及 RTSP 进行数据传输;
记下来就是服务端回应:
这里需要注意下 Session,这是接下来的播放控制请求都会带上的,用来区别不同的播放请求。
PLAY 请求
接下来就是正式的请求了:
其中的 Range 表示播放时间的范围,而上图的 npt=0.000-
表示这是一个实时的视频源。
服务端会回应一个带有 RTP-Info 的头,其中的 seq 以及 rtptime 的信息都用来指示 RTP 包的信息。
如果你注意下上面的总览,你会发现服务端在接收到 PLAY 请求的同时,就开啊是发送 RTP 以及 RTCP 数据进行真正的播放了。
TEARDOWN 请求
即停止播放请求,这里很简单,就不详述了。
RTCP 协议
相比于 RTSP 的 文本协议,RTCP 属于二进制协议,它的协议头如下2:
- Version: 版本号,与 RTP 中的版本号一致,目前为 2;
- P (Padding): 用来表示 RTP 包是否包含填充字节(比如加密的 RTP 包会用到);
- RC (Reception report count): 统计信息,接收
- PT (Packet type) : 包的类型,目前有发送者报告(SR)、接收者报告(RR)、SDES(源描述)、BYE(结束)、APP(应用自定义);
- Length: 当前包的长度;
- SSRC: 同步源标识;
拿出实际例子,我们会发现服务端接受到 PLAY 请求后,紧接着就发送了一个 RTCP Sender Report:
从中需要注意的一点在于,它有两个时间戳,一个是 NTP (Network Time Protocol) 时间戳,用 8 个字节来表示的绝对时间,另一个则是 RTP 时间戳,这是相对时间,可以用来计算 RTP 包的时间,具体的计算规则是用两个 RTP 时间戳的差值除以视频采样频率,再加上这里的绝对时间,就是当前 RTP 包的绝对时间了。(不知道采样频率?回头去看看上面 RTSP 的 DESCRIBE 请求的回复。)
RTP 协议
RTP 也属于二进制协议,它的协议头如下1:
- Version: 版本号,同 RTCP;
- P (Padding): 同 RTCP;
- X (Extension): 表示是否有拓展包头;
- CC (CSRC count): CSRC 个数;
- M (Marker): 标志位,比如可以用来标志视频帧的边界;
- PT (Payload type): 包内容类型,具体类型非常多,想了解的可以看 rfc3551;
- Sequence number: 序号,防止丢包以及包乱序;
- Timestamp: 时间戳,与上面 RTCP 时间戳相关;
- SSRC: 同步源标识;
- CSRC: 贡献源标识;
- Header extension: 可拓展的包头;
我们选取第一个 RTP 包来看,我们可以看到,内容类型是 96,也就是 H264。
总结
RTSP 协议本身不复杂,下一篇我们来说说关于 RTSP 的实践。
Ref
- Real-time Transport Protocol
- RTP Control Protocol
- Session Description Protocol
- Real Time Streaming Protocol
- rfc2326 Real Time Streaming Protocol (RTSP)
- rfc3550 RTP: A Transport Protocol for Real-Time Applications
- rfc3551 RTP Profile for Audio and Video Conferences with Minimal Control
首发于 Github issues: https://github.com/xizhibei/blog/issues/152 ,欢迎 Star 以及 Watch
本文采用 署名-非商业性使用-相同方式共享(BY-NC-SA)进行许可作者:习之北 (@xizhibei)
原链接:https://blog.xizhibei.me/zh-cn/2020/10/26/rtsp-explain/