工作不仅仅只是ctrl+V 或者ctrl+C,还有总结与思考。RTP的协议介绍挺多,但是我也没耐心去看,目前也没有直接用RTP去实现播放。
前言
最近在看了下RTP的相关代码,需要做如下的总结:
如下图所示:假设有两个线程,一个线程往缓冲区里写RTP包,一个线程是读取这个RTP包。假设存储空间是一个环形缓冲区,所有的信息都是用一个结构体描述,如:当前的写地址,写包index,读包index,以及对应每index包的对应的内存地址,一共可以存储LEN个包,即由长度为len的数组维系着。一个视频帧有可能由多个RTP包组成。往平台发送视频时,往往首先要找到I帧,对于生产者来说,在他写每个rtp包的时候,会将每一index包的地址放在那个数组中。
形成一个环状索引的一般公式是这样的:
index= (index + 1)% LEN
一、RTP目前需要知道的
首先还是得知道RTP的头,他的前12字节是固定的,CSRC可以有多个或者0个。
解释如下:
字段 | 描述 |
---|---|
V | 2 bits,RTP协议的版本号,V=2 |
P | 填充标志,占1位,如果P=1,则该RTP包的尾部包含附加的填充字节,作用是为了字节对齐,填充字节的数量保存在最后一个字节中。曾经在音频格式的aac格式下出现。 |
X | 扩展位:占1位,如果X=1,则RTP固定头部后面就跟有一个扩展头部,即上面的CSRC信息 |
CC | CSRC计数器(CC):占4位,指示 CSRC标识符的数量。当X=1的时候需要关注下,但是感觉很少情况遇到 |
M | 标记位(M):占1位,当M=1时,对于视频流, 它表示一帧的结束,而对于音频,则表示一次谈话的开始。 |
PT | 载荷类型:占7位,标识了RTP载荷的类型,比如是视频还是音频类型 |
SN | 序列号:占16位,发送方在每发送完一个RTP包后就将该域的值增加1,接收方可以由该域检测包的丢失及恢复包序列。序列号的初始值是随机的。 |
timestamp | 时间戳:占32位,记录了该包中数据的第一个字节的采样时刻。在一次会话开始时,时间戳初始化成一个初始值(随机生成)。即使在没有信号发送时,时间戳的数值也要随时间而不断地增加。时间戳是去除抖动和实现同步不可缺少的。 |
SSRC | 同步源标识符:占32位,用来表示RTP包的类型,每次开启新的流会话该值都会变化 |
CSRC | 特约信源:每个CSRC标识符占32位,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。 |
注:基本的RTP说明并不定义任何头扩展本身,如果遇到X=1,需要特殊处理
二、RTP头需要注意的
1.PT
负载类型主要用来告诉接收端(或者播放器)传输的是哪种类型的媒体(例如G.729,H.264,MPEG-4等),这样接收端(或者播放器)才知道了数据流的格式,才会调用适当的编解码器去解码或者播放,这就是负载类型的主要作用。
2.时间戳
时间戳反映了RTP分组中的数据的第一个字节的采样时刻。
首先,了解几个基本概念:
时间戳单位:时间戳计算的单位不是秒之类的单位,而是由采样频率所代替的单位,这样做的目的就是 为了是时间戳单位更为精准。比如说一个音频的采样频率为8000Hz,那么我们可以把时间戳单位设为1 / 8000。
时间戳增量:相邻两个RTP包之间的时间差(以时间 戳单位为基准)。
采样频率: 每秒钟抽取样本的次数,例如音频的采样率一般为8000Hz
帧率: 每秒传输或者显示帧数,例如25f/s
例如,对于8kHz采样的话音信号,若每隔20ms构成一个数据块。
则一个数据块中包含有160个样本(0.02×8000=160)。因此每发送一个RTP分组,其时间戳的值就增加160。
如果采样频率为90000Hz,则由上面讨论可知,时间戳单位为1/90000。
我们就假设1s钟被划分了90000个时间块,那么,如果每秒发送25 帧,那么,每一个帧的发送占多少个时间块呢?当然是 90000/25 = 3600。因此,我们根据定义“时间戳增量是发送第二个RTP包相距发送第一个RTP包时的时间间隔”,故时间戳增量应该为3600。
以上都是网页节选,具体用到采样频率,应该是和播放器有关。
总结
以上就是关于RTP头的介绍。