rtsp/rtp/rtcp协议详解,附带抓包讲解及时间戳计算方法等细节

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

rtsp/rtp/rtcp协议详解,附带抓包讲解及时间戳计算方法等细节_第1张图片

 

鉴权的规则

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相同

rtsp/rtp/rtcp协议详解,附带抓包讲解及时间戳计算方法等细节_第2张图片

 

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头格式如下所示

rtsp/rtp/rtcp协议详解,附带抓包讲解及时间戳计算方法等细节_第3张图片

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

rtsp/rtp/rtcp协议详解,附带抓包讲解及时间戳计算方法等细节_第4张图片

  • 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分片模式

rtsp/rtp/rtcp协议详解,附带抓包讲解及时间戳计算方法等细节_第5张图片

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包的发送与停止等,包类型包括:
    1. SR:发送者报告,描述作为活跃发送者成员的发送和接收统计数字;
    2. RR:接收者报告,描述非活跃发送者成员的接收统计数字;
    3. SDES:源描述项,其中包括规范名 CNAME。
    4. BYE:表明参与者将结束会话。
    5. APP:应用描述功能。(暂时没用)
  • 根据抓包和RFC文档规定,我们要将多个 RTCP 包形成一个复合 RTCP 包。在底层协议(如 UDP)中,通常都是将复合包作为一个包传输的。
  • 每个 RTCP 复合包必须以 SR RR 包开头。
  • 每个 RTP 参与者在一个报告间隔内应只发送一个 RTCP 复合包,固定的时间间隔建议为 5 秒。

​​​​​​​

  • SR协议格式:

rtsp/rtp/rtcp协议详解,附带抓包讲解及时间戳计算方法等细节_第6张图片

  • 版本(V)2 比特 RTP 版本识别符,在 RTCP 包内的意义与 RTP 包中的相同。此协议中定义的版本号为 2
  • 填充(P)1 比特 若设置填充比特,该 RTCP 包在末端包含一些附加填充比特,并不是控制信息的基本部分。填充的最后一个比特统计了多少个字节必须被忽略。填充可能会用于需要固定长度块的加密算法。默认设为0
  • 接收报告块计数(RC)5 比特 该包中所含接收报告块的数目。零值有效。默认设为0
  • 包类型(PT)8 比特 包含常数 200,用以识别这个为 SR
  • length16 比特 RTCP 包的长度(包括头和任何填充字节) 1。其单位是 32 比特字
  • SSRC32 比特 SR 包发送者的同步源标识符。和RTPSSRC一致
  • 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协议格式

rtsp/rtp/rtcp协议详解,附带抓包讲解及时间戳计算方法等细节_第7张图片

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

  • 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)