RTSP协议详解(一)

来源:互联网 发布:八卦软件下载 编辑:程序博客网 时间:2024/05/21 04:25

1.    Overview

RTSPReal Time Streaming Protocol),RFC2326,实时流传输协议,是TCP/IP协议体系中的一个应用层协议,该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。

                                                   

   图1 RTSP的主要结构

图1中第一层是RTSP协议的主要构成部分,包括RTP, RTCP,以及RTSP本身。第二层则是上一层协议将会通过哪些协议发送出去,包括UDP和TCP,图中RTP和RTCP对应的是UDP,其实RTP和RTCP也是可以通过TCP进行发送的。

所以想要学习RTSP则必须先学习RTP和RTCP(RTCP可以忽略),因为RTSP仅仅是一个交互协议,并不负责数据的传输任务,而RTP协议则承担着数据传输的任务。

2.   RTP(Real-timeTransport Protocol,实时传输协议

网上关于RTP协议的文章很多,但是真正能全部讲通透的并不多,而且他们多数是利用开源代码编写个demo,但是开源代码对于刚开始学的朋友显得略微有些难以理解。好啦,不废话,进入正题。

一般不管什么协议都是由head和body两部分构成,RTP也不例外。RTP的head如图2所示。


2RTPhead

每行是32bits,由此可以直观看到每个表示部分所占的位数。简单介绍一下:

V(version)2 bitsRTP的版本,这里统一为2

P(padding)1 bit,如果置1,在packet的末尾被填充,填充有时是方便一些针对固定长度的算法的封装,一般直接置为0

X(extension)1 bit,如果置1,在RTPHeader会跟着一个headerextension,一般直接置为0

CC(CSRC count): 4 bits,表示头部后contributingsources的个数,一般直接置为0

M(marker): 1 bit,标志着是否为一帧的结束

PT(playload type): 7 bits,表示所传输的多媒体的类型,本文中的H.264的类型为96

sequence number: 16 bits,每个RTPpacketsequencenumber会自动加1,以便接收端检测丢包情况

timestamp: 32 bits,时间戳

SSRC: 32 bits,同步源的id,没两个同步源的id不能相同

CSRC: 上文说到,个数由CC指定,范围是0-15,直接忽略,不写入码流

 

       本文,并没有像其他文章一样定义一个结构体,然后给每个字段分配多少个bit。好啦,直接看代码吧

 

static void send_rtp_data(RTPMux *rtpMux, const uint8_t *buf1, int len, int m){/**    0*    0 1 2 3 4 5 6 7*   +-+-+-+-+-+-+-+-+*   |V=2|P|X|   CC  |*   +---------------+*   P = 0, X =0, CC = 0*/uint8_t *sendBuf = (uint8_t *)malloc(len*sizeof(uint8_t));uint8_t v_p_x_cc = RTPVERSION << 6;memcpy(sendBuf, &v_p_x_cc, 1);/**    0*    0 1 2 3 4 5 6 7*   +-+-+-+-+-+-+-+-+*   |M|     PT      |*   +---------------+*   M标志着是否为一帧的结束, PT则为payload type*/uint8_t m_pt = rtpMux->m_payloadType & 0x7f | ((uint8_t)m << 7);memcpy(sendBuf + 1, &m_pt, 1);//2字节的sequence number,每次发送一个rtp包则加1uint16_t seq = smallToBig_2(rtpMux->m_seq);memcpy(sendBuf + 2, &seq, 2);rtpMux->m_seq++;//4字节timestampuint32_t timestamp = smallToBig_4(rtpMux->m_curTimestamp);memcpy(sendBuf + 4, ×tamp, 4);//4字节的信源标识符SSRCuint32_t ssrc = smallToBig_4(rtpMux->m_ssrc);memcpy(sendBuf + 8, &ssrc, 4);}

上述代码就是RTP协议的12bytes头,相信这个对大家都不难理解吧,因为楼主电脑写文件的时候采用的是小端模式,所以需要将小端模式转换为大端模式,则上述代码中smallToBig_2和smallToBig_4就是分别代表着将2byte和4byte的数据由小端模式转换到大端模式的宏。

RTP协议的head部分已经解释完毕,那么现在该RTP的body部分了。

RTP协议的body部分可以分为三种模式:单包模式,聚合包模式以及分片模式

(1)单包模式:(本文是以H.264作为荷载的)

以H.264作为荷载为例,一个视频在编码完成后,将会以一个个的NAL(网络适配层)存储着,那么RTP中的单包就是将H.264中的单个NAL单元作为一个独立的RTP包进行封装、发送,其封包规则如下:


图3 RTP单包模式的body部分

F(forbidden): 1bit,禁止位,一般为0

NRI: 2bit,表示此包的重要性

Type:5bit,表示此包所包含的NAL单元是什么类型的,例如:IDR, SEI, SPS, PPS等

第一个字节之后则存放的是NAL的第一个字节之后的数据。

对于单包模式来说,直接把H.264的NAL单元写入就OK了,因为H.264的第一个byte与RTP包的第一个byte是一样的,然后在其前面加上RTP head,就是一个完整的RTP包了。

(2)FU-A分片模式

由于在网络传输过程中,每个包能包含的最大字节数是有限制的,一般为1400字节,那么当我们使用单包模式的时候,单个包的字节数大于1400,在网络传输中这种包会被丢弃的,所以,对于H.264中比较大的NAL单元,我们采用FU-A分片模式来进行封装,其封包规则如下:


图4 RTP FU-A分片模式


图5. FU indicator和FU header

跟单包模式有所区别,主要是其头包括FU indicator和FU header两部分,共两字节,含义如下:

F(forbidden): 1bit,禁止位,一般为0

NRI: 2bit,表示此包的重要性

Type:5bit,表示此FU-A包为什么类型,一般此处为28

S:1bit,是否为分片NAL的开始,也就是说这个FU-A包是不是当前NAL的第一个FU-A包

E:1bit,是否为分片NAL的结尾,也就是说这个FU-A包是不是当前NAL的最后一个FU-A包

R:1bit保留为,必须设置为0

TYPE:5bit,表示此NAL类型,例如:IDR, SEI, SPS, PPS等

由于FU-A分片包的特殊规则,那么FU-A分片包必须满足下列一些条件:

(1)RTP head + FU-A indicator + FU-A header + FU-A payload < 1400字节,即此RTP包的大小要小于网络传输的限制

(2)FU-A payload(1) + FU-A payload(2) +........+ FU-A payload(n) = NAL - 1,即连续的N个FU-A包的payload构成一个NAL包(不包括NAL的head部分(1字节))

RTP协议好像也就这么多了吧,下面是源码地址,此源码采用了ffmpeg库作为编码库,然后将实时编好的每一帧发送到本机127.0.0.1上,客户端采用的是VLC,记得要用SDP打开,SDP我就不多说了,我会在源码中给出,还在审核~~~。我会在接下来的博客里详细述说一下RTSP,以及给出一份自己写的并不是很完善的代码。

http://download.csdn.net/detail/nvniaobi/9676397



1 0
原创粉丝点击