封装RTP码流

 RTP header格式组成,见下图:
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |V=2|P|X|  CC   |M|     PT      |       sequence number         |
单一NAL单元模式:2                1     96        htons(g_rtspClients[is].seqnum++)     
分片封包模式[0]: 2                0     96        htons(g_rtspClients[is].seqnum++)          
分片封包模式[n]: 2                1     96        htons(g_rtspClients[is].seqnum++)             
分片封包模式[N]: 2                0     96        htons(g_rtspClients[is].seqnum++)                      
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           timestamp                           |
                   htonl(g_rtspClients[is].tsvid)
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           synchronization source (SSRC) identifier            |
                                  10
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   |            contributing source (CSRC) identifiers             |
   |                             ....                              |
   
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    注:没有写的表示等于0;
      分片封包模式[0]:第一个包;          
分片封包模式[n]:中间的包;           
分片封包模式[N]:最后一个包;   
   
   各个字段代表含义如下:


V:版本号,一般为2;
P:填充字段标识;
X:扩展头标识;


CC:CSRC计数,4比特


M:标志 1bit,在传输h264时表示h264 nalu的最后一包
PT:负载类型 7 bits, H264类型为96,荷载类型的赋值或者通过profile或者通过动态方式
SN:序列号16 bits
Timestamp:时间戳32bits,如果为视频的话,应该设置为1/9000,音频为1/8000,如果NAL单元没有
           他自己的时间属性(即,parameter set and SEI NAL units),RTP时戳设置成访问单元主
           编码图像的RTP时戳。
SSRC:32bits,用以识别同步源。
CSRC列表:0到15项,每项32比特,CSRC列表识别在此包中负载的所有贡献源。识别符的数目在CC域中
          给定。若有贡献源多于15个,仅识别15个。CSRC识别符由混合器插入,并列出所有贡献源的
          SSRC识别符。例如语音包,混合产生新包的所有源的SSRC标识符都被列出,这样可以在接收
          端正确指示参与者。    
   
   
contributing source (CSRC) identifiers 的组成:如下:
    [StartCode] [NALU Header] [NALU Payload]
    关于NALU使用RTP包进行发送可能的类型有:
1. 单一 NAL 单元模式(NALU的长度小于 MTU 大小的包)
    即一个 RTP 包仅由一个完整的 NALU 组成。这种情况下 RTP NAL 头类型字段和原始的H.264的NALU 
头类型字段是一样的。
    对于 NALU的长度小于 MTU 大小的包,一般采用单一 NAL 单元模式。对于一个原始的H.264 NALU 单元常
由 [StartCode] [NALU Header] [NALU Payload] 三部分组成,其中 Start Code 用于标示这是一个NALU 
单元的开始,必须是"00 00 00 01" 或"00 00 01",
    NALU 头仅一个字节,其后都是 NALU 单元内容。打包时去除 "00 00 01" 或"00 00 00 01" 的开始码,把
其他数据封包的 RTP 包即可,有如下例子:
[00 0000 01 67 42 A0 1E 23 56 0E 2F ... ]
封装成 RTP 包将如下:
[ RTPHeader ] [ 67 42 A0 1E 23 56 0E 2F ]
(在这里要说明的是,如果客户端是通用的播放器,比如VLC或者JM的话需要将前导码去掉,但是如果使用的是
ffmpeg在客户端解码的话,发送前不需要去掉前导码,去掉之后可能会导致ffmpeg解码错误)。
   
NALU Header:
    0           
    0 1 2 3 4 5 6 7 |
   +-+-+-+-+-+-+-+-+|
   |F|NRI|   TYPE   |
   |0| 0 |    0     |                  
   +-+-+-+-+-+-+-+-+|
   
    H.264Payload 格式定义了三种不同的基本的负载(Payload)结构,接收端可能通过RTP Payload的第一个
    字节来识别它们。这一个字节类似NALU 头的格式,而这个头结构的NAL 单元类型字段则指出了代表的是
    哪一种结构,这个字节的结构如下:
F        1比特
NRI      2比特
Type     5比特


可以看出它和H.264 的NALU 头结构是一样的。


字段Type:这个RTP payload 中 NAL 单元的类型。 这个字段和 H.264 中类型字段的区别是,当type的
值为24-31表示这是一个特别格式的 NAL 单元,而H.264中,只取1-23是有效的值。
  2 3. 分片封包模式(NALU的长度大于 MTU 大小的包)
       用于把一个 NALU单元封装成多个 RTP 包。存在两种类型 FU-A 和 FU-B。类型值分别是 28 和 29。
       而当 NALU 的长度超过 MTU 时,就必须对 NALU 单元进行分片封包。 也称为Fragmentation Units(FUs)。
       将NALU拆分成小于MTU的数据包进行发送,如果使用的是VLC等网络播放器的话,需要设置FU header,如下图所示: 
       如果使用的是ffmpeg自行进行数据包接收与解码,则完全不必写FU header。
其实在后面的实际操作中会发现,SPS、PPS都是非常小,不到一百个字节,都是单个的NAl进行打包发送,而I帧一般都比较大,会采用分包发送,一般也是FU-A方式分片,其中MTU一般是1500个字节。FFmpeg中都有现成的源程序可以参考的。

  对于H264的I帧、P帧等主要是FU(分片)发送,那么FU到底是怎样一个过程呢。


      相同NAL单元的分片必须使用递增的RTP序号连续顺序发送(第一和最后分片之间没有其他的RTP包)。相似, NAL单元必须按照RTP顺序号的顺序装配。FUs不可以嵌套。即 一个FU 不可以包含另一个FU。运送FU的RTP时戳被设置成分片NALU的NALU的时刻。


      FU-A的RTP荷载格式:


        0                                              1                                             2                                            3
        0   1   2  3   4  5  6   7  8   9   0  1  2  3  4   5   6   7   8  9   0  1   2  3  4   5  6   7   8  9  0   1
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |       FU indicator          |      FU header             |                                                                            |
      +--+--+--+--+--+--+--+--+--+--+--+-+--+--+--+--+                                                                             |
      |                                                                                                                                                         |
      |                                                             FU payload                                                                        |
      |                                                                                                                                                         |
      |                                                                             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |                                                                                :...OPTIONAL RTP padding                       |
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+




FU indicator :  1字节的分片单元指示
      +---------------+
       |0|1|2|3|4|5|6|7|
      +-+-+-+-+-+-+-+
                                                                                      |F|NRI|  Type   |
分片封包模式[0]:                                               |0| 0 |   28    |
分片封包模式[n]:                                               |0| 0 |   28    |
分片封包模式[N]:                                               |0| 0 |   28    |
      +---------------+
NRI: 2 bits, 00值指示NAL单元的内容不用于重建影响图像的帧间图像预测.这样的NAL单元可以被丢弃而不用冒影响图像完整性的风险。大于00的值指示NAL单元的解码要求维护引用图像的完整性。
注意:任何非零的NRI在H.264 解码器的处理是相同的。因此,接收者在传送NAL单元给解码器时不必操作NRI的值。NRI值必须根据分片NAL单元的NRI值设置。H.264编码器必须根据H.264规范设置NRI值。
当nal_unit_type 范围的是1到12。特别是,H.264规范要求对于nal_unit_type为6,9,10,11,12的NAL单元的NRI的值应该为0。
对于nal_unit_type等于7,8 (指示顺序参数集或图像参数集)的NAL单元,H.264编码器应该设置NRI为11 (二进制格式)。
对于nal_unit_type等于5的主编码图像的编码片NAL单元(指示编码片属于一个IDR图像), H.264编码器应设置NRI为11。


FU header:  1字节的分片单元头
      +---------------+
      |0|1|2|3|4|5|6|7|
     +-+-+-+-+-+-+-+
      |S|E|R|  Type   |
分片封包模式[0]:                                                     |1|0|0|    0    |
分片封包模式[n]:                       |0|0|0|    0    |
分片封包模式[N]:                               |0|1|0|    0    |
      +---------------+
S: (1 bit)
   当设置成1,开始位指示分片NAL单元的开始。当跟随的FU荷载不是分片NAL单元荷载的开始,开始位设为0。
E: (1 bit)
   当设置成1,结束位指示分片NAL单元的结束,即荷载的最后字节也是分片NAL单元的最后一个字节。
   当跟随的FU荷载不是分片NAL单元的最后分片,结束位设置为0。
R: (1 bit)
    保留位必须设置为0,接收者必须忽略该位。
Type: (5 bit)
       NAL单元荷载类型定义。


FU payload : 分片单元荷载。



  下面再进一步解释一下时间戳增量是怎么计算出来的:

       对于PAL制式的视频而言,每秒摄像头会采集 25 帧 数据,那么,每采集到 1帧 耗时 1/25 s ,如果我们设计为1个RTP包只包含1帧数据,并且一次发送1帧,那么,要想网络流量均匀,则时间戳增量应该设计为 1/25 s .  而在一般的RTP协议的实现中,时间戳单位不是 秒(s),而约定为采样频率的倒数,由于一般视频的采样频率是 90000,故时间戳单位为 1/90000 s,因此,实际的时间戳增量 = 时间戳增量 ( 1/25 s ) / 时间戳单位(1/90000 s) = 3600 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值