RTSP交互流程
C表示rtsp客户端,S表示rtsp服务端
C->S:OPTION request //询问S有哪些指令可用
S->C:OPTION response //S回应信息中包括提供的所有可用指令
C->S:DESCRIBE request //要求得到S提供的媒体初始化描述信息
S->C:DESCRIBE response //S回应媒体初始化描述信息,主要是sdp
C->S:SETUP request //设置会话的属性,以及传输模式,提醒S建立会话
S->C:SETUP response //S建立会话,返回会话标识符,以及会话相关信息
C->S:PLAY request //C请求播放
S->C:PLAY response //S回应该请求的信息
S->C:发送流媒体数据
C->S:TEARDOWN request //C请求关闭会话
S->C:TEARDOWN response //S回应该请求
OPTION方法
- 方法格式如下所示,OPTION方法由客户端发起,格式为:
OPTION URL RTSP版本号
CSeq: CSeq号(每发一条方法加一)
User-Agent:
- 服务端给反馈,格式为:
RTSP版本号 状态码 状态字段
CSeq: 服务端发的CSeq号
Date: 时间 时区
Public: 可用方法

DESCRIBE方法
- DESCRIBE方法由客户端发起,带鉴权的RTSP需要除OPTION方法外每次都发鉴权信息DESCRIBE方法要发送两次,一次是不带鉴权的格式为:
DESCRIBE URL RTSP版本号
CSeq: CSeq号(每发一条方法加一)
User-Agent:
Accept:
- 服务端由于需要鉴权,所以以realm和nonce质询,realm是用户自定义字符串,nonce是包括\0长度为33的随机小写字母和数字组成的字符串
- 格式为:
RTSP版本号 状态码 状态字段
CSeq: 服务端发的CSeq号
Date: 时间 时区
WWW-Authenticate: Digest realm=" ", nonce=""

- 客户端收到第一次DESCRIBE的反馈后发送第二次DESCRIBE方法,并添加鉴权信息
- 格式为:
DESCRIBE URL RTSP版本号
CSeq: CSeq号(每发一条方法加一)
Authorization: Digest username="", realm=" ", nonce="", uri=" ", response=" "
User-Agent:
Accept:
- 服务端根据收到的信息判断鉴权信息是否正确。若不正确,则发送和不带鉴权的反馈一样的反馈。若正确则拼接SDP消息,格式为:
RTSP版本号 状态码 状态字段
CSeq: 服务端发的CSeq号
Date: 时间 时区
Content-Base: URL(用于拼接具体通道号URL的主URL,注意结尾带/)
Content-Type: 客户端发来的Accept
Content-Length: SDP包长度
v=0 //SDP版本号
o=- 1558173732855598 1 IN IP4 192.168.0.46 //[username] [session id] [version] [network type] [address type] [ip address]。 [username]没有,就填-。[session id]填写NTP时间戳。[version]填1。[network type] 一般为IN 。[address type]一般为IP4 。[ip address]填服务端IP地址。
s=IChinaE IPC Camera Stream//[session name ]按照用户自定义需求填写
i=stream1//[session info]按照相机url填写,通道几就写stream几,不同相机url不同
t=0 0//[start time] [end time] 实时流都填0
a=tool:LIVE555 Streaming Media v2010.07.29//a字段是可选字段,这6个a字段除了x-qt-text-inf要根据不同的通道号改变,其他都是固定不变的,也是live555添加的,为了安全起见先固定加上这些字段
a=type:broadcast
a=control:*
a=range:npt=0-
a=x-qt-text-nam:IChinaE IPC Camera Stream
a=x-qt-text-inf:stream1
m=video 0 RTP/AVP 96//[media] [port] [transport] [fmt list] 。[media] vedio或audio 。[port]先默认填0 。[transport]先默认填RTP/AVP。[fmt list]表示这路数据的编码类型,0-95是已定义好的编码类型,如果是这些类型,则填写相应的编号,否则,填写其他值并在rtpmap中指定编码类型
c=IN IP4 0.0.0.0//默认这样填
b=AS:12000//[modifier]CT(总带宽)或AS(单个媒体的最大带宽)。[bandwidth]带宽值
a=rtpmap:96 H264/90000//若m的[fmt list]填写了自定义编号,则在这里指定自定义编号的编码类型和时钟速率,h264为90000
a=fmtp:96 packetization-mode=1;profile-level-id=64002A;sprop-parameter-sets=Z2QAKq2EAQwgCGEAQwgCGEAQwgCEO1A8ARPyzcBAQECAAAAAAQ==,aO48sA==//指定对应编号的通道的信息。[packetization-mode]为1代表I帧要拆成多个包发送,默认填1 。[profile-level-id]重要程度,[ sprop-parameter-sets]pps和sps,计算方法下边给出。
a=control:track1//代表这一路码流的通道号,不同相机这个也不同
m=audio 0 RTP/AVP 0//余下信息同上
c=IN IP4 0.0.0.0
b=AS:64
a=control:track2

鉴权的规则
response = md5(md5(username:realm:password):nonce:md5(method:url));
profile-level-id,pps和sps计算规则(H264码流)
- 若码流中有0x00,0x00,0x00,0x01,0x*8则从0x*8算起为pps,pps长度为4字节。
- 若码流中有0x00,0x00,0x00,0x01,0x*7则从0x*7算起为sps,sps长度为sps位置减去pps的头00000001的位置

- 得到sps和pps原始值后分别经过base64转码得到BufSps和BufPps
- profile_level_id = (buf_sps[1]<<16) | (buf_sps[2]<<8) | buf_sps[3];取16进制前6位
- sps和pps用逗号隔开当做sprop-parameter-sets。
SETUP方法
- ETUP方法用于设置数据流的传输方式,端口,以及数据类型。所以要几路数据就要发几个SETUP。
- 当SETUP设置了传输方式为UDP时,服务端要根据客户端参数中设置的a-b端口号为RTP创建a端口的UDP链接,为RTCP创建b端口的UDP链接。
- 当SETUP设置了传输方式为TCP时,服务端使用和RTSP相同的端口向客户端发送音视频数据。client_port设置的值仅用于TCP区分是RTP还是RTCP
- 方法格式如下所示,SETUP方法由客户端发起,格式为:
SETUP URL RTSP版本号
CSeq: CSeq号(每发一条方法加一)
Transport: 连接方式;unicast;client_port=端口号或识别码
User-Agent:
- 服务端给反馈,格式为:
RTSP版本号 状态码 状态字段
CSeq: 服务端发的CSeq号
Date: 时间 时区
Transport: 连接方式;unicast;destination=客户端IP;source=服务端IP;服务端和客户端的端口号或识别码
Session: 8位16进制随机数,相同会话的session相同

PLAY方法
- PLAY方法用于开始指定session的数据的传输。
- 方法格式如下所示,PLAY方法由客户端发起,格式为:
PLAY URL RTSP版本号
CSeq: CSeq号(每发一条方法加一)
Session:
Range: npt=0.000-(实时流的ntp时间为0.000-,否则格式为起始时间-结束时间)
User-Agent:
- 服务端收到消息后给反馈,并开始用RTCP/RTP传输数据,反馈包格式为:
RTSP版本号 状态码 状态字段
CSeq: 服务端发的CSeq号
Date: 时间 时区
Range: npt=0.000-
Session:
RTP-Info: url=;seq=;rtptime=,url=;seq=;rtptime=
(因为一般都是音视频两路数据,所以会有两组反馈数据)

TEARDOWN方法
- 方法格式如下所示,TEARDOWN方法由客户端发起,格式为:
TEARDOWN URL RTSP版本号
CSeq: CSeq号(每发一条方法加一)
Session:和之前命令的session保持一致
User-Agent:
- 服务端给反馈,格式为:
RTSP版本号 状态码 状态字段
CSeq: 服务端发的CSeq号
Date: 时间 时区

RTP线程
- 服务端收到客户端的PLAY方法后给反馈,并开始用RTCP/RTP传输数据,
- RTSP中的RTP包由三部分组成
- RSTP头(只在SETUP设置了TCP传输模式的时候添加)
- 格式为:
![]()
-
RSTP头
M:8位,固定设置为0x24
C:8位,通道号,和SETUP中设置的通道号对应
L:16位,不包括RTSP头,直到载荷结束的总字节数
-
RTP头
RTP头格式如下所示

- V:此域定义了 RTP 的版本,默认设为2
- P:填充位,默认设为0
- X:扩展位,默认设为0
- CC:CSRC 计数包含了跟在固定头后面 CSRC 识别符的数目,默认设为0
- M:表示这一帧是否已经是最后一帧,0表示非最后一帧,1表示最后一帧
- PT:此域定义了负载的格式,跟DESCRIBE方法中的负载类型保持一致。

- sequence number:每发送一个 RTP 数据包,序列号加 1,接收端可以据此检测丢包和重建包序列。序列号的初始值是随机的(不可预测)。
- timestamp:初始值是一个随机32bit数据,增量和采样率和数据发送的频率有关。算法为
- 设当前时间的struct timeval 为tv ,32位随机数为t_base
unsigned int t_sec = (freq*tv.tv_sec);
timestamp = t_sec + (unsigned int)((2.0* freq *tv.tv_usec + 1000000.0)/2000000) + t_base
- SSRC:设为32bit随机值,相同通道的数据SSRC相同,不同通道的数据SSRC不同
- CSRC:表示扩展的CSRC列表,一般忽略这位。
-
负载
- 音频负载
直接把数据接到CSRC后边作为载荷即可。
- H264负载
- 检测H264包头0x000001,或0x00000001
- 选择传输类型。
如果帧长大于MTU长度,则使用FU-A方式分片发送
如果帧长小于MTU长度,则使用单一NAL单元模式一次发送
- 去掉包头,在包头的位置添加NALU头,sps和pps也要发,只不过可以选择在I帧里一起发,也可以拆开发
- 单一NAL模式:

- FU-A分片模式

F:默认设置成0
NRI:默认设置为3
Type:NAL单元模式设置为1,FU-A分片模式设置为28
FU header只在FU-A模式下才有
S:start 如果这一包数据是这一帧数据的开始包,则设为1,否则设为0
E:end 如果这一包数据是这一帧数据的结束包,则设为1,否则设为0
R:reseived 默认设为0
Type:设为和FU indicator中相同的值,帧实际类型,PPS,SPS :7 I帧:1
RTCP线程
- RTCP协议用于控制RTP包的发送与停止等,包类型包括:
- SR:发送者报告,描述作为活跃发送者成员的发送和接收统计数字;
- RR:接收者报告,描述非活跃发送者成员的接收统计数字;
- SDES:源描述项,其中包括规范名 CNAME。
- BYE:表明参与者将结束会话。
- APP:应用描述功能。(暂时没用)
- 根据抓包和RFC文档规定,我们要将多个 RTCP 包形成一个复合 RTCP 包。在底层协议(如 UDP)中,通常都是将复合包作为一个包传输的。
- 每个 RTCP 复合包必须以 SR 或 RR 包开头。
- 每个 RTP 参与者在一个报告间隔内应只发送一个 RTCP 复合包,固定的时间间隔建议为 5 秒。
-
SR协议格式:

- 版本(V):2 比特 RTP 版本识别符,在 RTCP 包内的意义与 RTP 包中的相同。此协议中定义的版本号为 2。
- 填充(P):1 比特 若设置填充比特,该 RTCP 包在末端包含一些附加填充比特,并不是控制信息的基本部分。填充的最后一个比特统计了多少个字节必须被忽略。填充可能会用于需要固定长度块的加密算法。默认设为0
- 接收报告块计数(RC):5 比特 该包中所含接收报告块的数目。零值有效。默认设为0
- 包类型(PT):8 比特 包含常数 200,用以识别这个为 SR 包
- length:16 比特 该 RTCP 包的长度(包括头和任何填充字节)减 1。其单位是 32 比特字
- SSRC:32 比特 SR 包发送者的同步源标识符。和RTP的SSRC一致
- NTP 时间戳:
- 高32位算法为:
struct timeval timeNow;
gettimeofday(&timeNow, NULL);
MSW = timeNow.tv_sec + 0x83AA7E80;//算出来的结果可能由于时区不同而差8小时
- 低32位算法为 :
double temp = (timeNow.tv_usec/15625.0)*0x04000000;
LSW = (unsigned int)(temp+0.5);
- RTP 时间戳:见RTP线程介绍
- 发送的报文数:32 比特 从开始传输到此 SR 包产生时该发送者发送的 RTP 数据包总数。若发送者改变 SSRC 识别符,该计数器重设。
- 发送的字节文数: 32 比特 从开始传输到此 SR 包产生时该发送者在 RTP 数据包发送的字节总数(不包括头和填充)。若发送者改变 SSRC 识别符,该计数器重设。
-
SDES协议格式

- 版本(V):默认设为 2。
- 填充(P):默认设为0
- 发送报告块计数(SC):默认设为1
- 包类型(PT):8 比特 包含常数 202,用以识别这个为 SDES包
- length:16 比特 该 RTCP 包的长度(包括头和任何填充字节)减 1。其单位是 32 比特字
- SSRC:32 比特 SR 包发送者的同步源标识符。和RTP的SSRC一致

- RTCP SDES 的SDES items组成图
- SDES items包括
- CNAME:8bit,默认设为1
- Length:8bit,user and domain name的长度,默认设为6
- user and domain name:默认设为(none) 0x28,0x6e,0x6f,0x6e,0x65,0x29
- Type:32bit默认设为0


- RTCP协议主要就是对这三种类型的协议的解析与发送,由于只发送复合包,所以每隔5秒发送一次SR和SDES的复合包
- 解析命令找包头后的PT,若PT为BYE,则证明收到BYE包。这部分流程不做说明
总结整套交互流程中的注意点
1.describe方法若有鉴权,则服务端会收到两次descibe,第一次是不带鉴权的,服务端以realm和nonce质询,第二次describe若鉴权通过,则返回sdp消息,注意sdp消息中不同相机的组包信息不同,要根据相机而定。
2.setup方法由客户端发起,有可能服务端在describe时告诉客户端有两路流,但客户端只请求一路流,比如vlc就会请求全部的流,但onvif工具会只请求视频
3.setup时确定rtp/.rtcp的发送方式是udp还是tcp。若是tcp则rtp/rtcp都从信令端口发送,而且rtp/rtcp要加4字节rtsp头。udp方式的端口号创建要求rtp是偶数端口,rtcp是它下一个端口
4.rtp/rtcp中的时间戳如果发送错误会导致vlc拉流失败
5.回放流中的play会带时间段,回放流还存在很多问题,有遗留问题欢迎交流
RTSP/RTP/RTCP协议详解与实践
本文详细介绍了RTSP交互流程,包括OPTION、DESCRIBE、SETUP、PLAY、TEARDOWN等方法及其响应,以及RTP线程和RTCP线程的工作原理。同时,解释了鉴权规则、H264码流的profile-level-id、pps和sps计算,以及RTCP中的SR、RR和SDES包的格式。通过对抓包数据的分析,阐述了时间戳的计算方法和RTCP包的组合发送策略。
4712

被折叠的 条评论
为什么被折叠?



