RTP之H264封包和解包

RTP之H264封包和解包


目录

  1. H264打包RTP的方法
    1. 打包方式之Single NAL Unit
    2. 打包方式之FU-A
      1. FU indication
      2. FU header

1. H264打包RTP的方法

  1. RTP的特点不仅仅⽀持承载在UDP上,这样利于低延迟⾳视频数据的传输,另外⼀个特点是它允许通过其它协议接收端和发送端协商⾳视频数据的封装和编解码格式,这样固定头的playload type字段就⽐较灵活。截⽌⽬前为⽌,RTP是我⻅过传输⾳视频数据类型最多的,具体参考:https://en.wikipedia.org/wiki/RTP_payload_formats
  2. 以H264裸码流NALU为例,进⾏H264的打包,其中H264打包的详细⽅法要参考RFC6184⽂档。
  3. H.264标准协议定义了两种不同的类型:⼀种是VCL即Video Coding Layer , ⼀ 种 是 NAL 即Network Abstraction Layer。其中前者就是编码器吐出来的原始编码数据,没有考虑传输和存储问题。后⾯这种就是为了展现H.264的⽹络亲和性,对VCL输出的slice⽚数据进⾏了封装为NALUs(NAL Units),然后再封装为RTP包进⾏传输,这些都是H.264的基础,⻅后续⽂章。
  4. NALU的基本格式是:NALU Header + NALU Data,其中NALU的头由⼀个字节组成如下所示:
 +---------------+
 |0|1|2|3|4|5|6|7|
 +-+-+-+-+-+-+-+-+
 |F|NRI|   Type  |
 +---------------+
  1. 其中
    1. F (1bit):如果是坏帧,则置1,其余H.264固定为0。
    2. NRI(2 bit):⽤来指示该NALU 的重要性等级。值越⼤,表示当前NALU越重要。具体⼤于0 时取何值,没有具体规定。
      例如:如果是00,则表示此帧即使丢失了,也不影响解码;其他值则表示此帧如果丢失了,会影响解码,这个字段指明了该NALU的重要性,但是实际我们不太关⼼这个字段。
    3. Nalu_Type(5 bit):NAL Unit的类型,这个值指明了NALU的类型,其中NALU的类型⻅下表
Nalu_TypeNALU内容备注
0未指定
1⾮IDR图像编码的slice⽐如普通I、P、B帧
2编码slice数据划分A2类型时,只传递⽚中最重要的信息,如⽚头,⽚中宏块的预测模式等;⼀般不会⽤到;
3编码slice数据划分B3类型是只传输残差;⼀般不会⽤到;
4编码slice数据划分C4时则只可以传输残差中的AC系数;⼀般不会⽤到;
5IDR图像中的编码sliceIDR帧,IDR⼀定是I帧但是I帧不⼀定是IDR帧。
6SEI补充增强信息单元可以存⼀些私有数据等;
7SPS 序列参数集编码的参数配置
8PPS 图像参数集编码的参数配置
9接⼊单元定界符
10序列结束
11码流结束
12填充数据
24STAP-A Single-time aggregation packet单⼀时间聚合包模式,意味着⼀个RTP包可以传输多个NALU,但是这些NALU的编码时间要⼀样才能聚合到⼀个RTP。
25STAP-B Single-time aggregation packet单⼀时间聚合包模式,⽐STAP-B多⼀个DON
26MTAP 16 Muti-time aggregation packet多个时间聚合包模式:意味着⼀个RTP包可以传输多个NALU,但是这些NALU的编码时间有可能不⼀样。
27MTAP 24 Muti-time aggregation packet多个时间的聚合包模式
28FU-A Fragmentation unit分包模式:当⼀个RTP容纳不下⼀个NALU时,就需要FUs这种格式。
29 FU-BFragmention unit分包模式
30-31未指定,保留
  1. 参考⽂档:https://tools.ietf.org/html/rfc6184
  2. 我们看到1-11就是NALU的单个包类型,但是⼀个NALU的⼤⼩是不⼀样的,如果是⾮视频数据的SPS PPS才⼗⼏个字节,对于IDR帧,则有可能⼏⼗KB。
  3. 这样把NALU打包到RTP⽅式就很多,分为:
    1. ⼀个RTP包承载⼀个NALU;
    2. 多个NALU合并到⼀个RTP;
    3. ⼀个⼤的NALU切分成多个RTP
  4. 同时由于时间戳的问题,就有了24-29⼏种类型。
  5. 但是对于发送端组RTP包的⼀⽅来说,尽可能找简单的打包⽅式。对于接受端则需要适配各种发送端的打包⽅式,因为⽆法决定输⼊源的打包⽅式。这⾥先分享下我们的打包⽅式,⽐较简单(打包的时候不要搞太复杂的模式):
    1. 我们对于NALU的⻓度<=1400(rtp payload size)的则采⽤的是单⼀NALU打包到单⼀的RTP包中;
    2. 我们对于NALU的⻓度>1400的则采⽤了FU-A的⽅式进⾏了打包,这种就是把⼀个⼤的NALU进⾏了切分,最后接收⽅则进⾏了合并,把多个RTP包合并成⼀个完整的NALU即可;
    3. 为什么NALU的⻓度⼤于1400字节就要进⾏FU-A切⽚,是因为底层MTU⼤⼩值固定为1500,从传输效率讲,这⾥⽤1400作为切分条件。
  6. 同时我们发现现在视频监控领域摄像头通过RTP 传输码流的打包⽅式都是基本这种,这种打包⽅案简单容易实现,⼜满⾜需要。
    在这里插入图片描述
  7. 28、29、30三个RTP分别传输的SPS、PPS、SEI这三种NALU,其中⼀个NALU分到⼀个RTP包,这是单⼀打包⽅式;
  8. 31、32三个RTP包分别传输了IDR帧的NALU单元,由于⽐较⼤,发送⽅采⽤了FU-A的打包⽅式;
  9. 上图还显示了SPS、PPS、SEI的RTP包固定头,Seq初始值不为0,为随机值,并且⼀个RTP包就顺序+1,这跟上⾯分析的⼀致;
  10. 上⾯SPS、PPS、SEI本身不涉及时间戳,但是这⾥头填充为和⾃⼰后⾯的第⼀个RTP保持⼀致,同样IDR的NALU切分的不同RTP包时间戳也是⼀样的;
  11. RTP一般一个包的大小是140bbyte左右,指的是RTP payload,不包含RTP header
  12. udp每个包有大小限制,MTU一般是1500byte,sendto一次不能发送超过1500byte的数据
  13. RTP包有大小之分
    1. SPS:25byte左右
    2. PPS:5byte左右
    3. SEI:600byte左右
    4. I帧:1080p为200K字节左右,一个RTP包发送不完一个I帧
  14. 同一个NALU划分成多个RTP包进行发送,比如I帧拆分成多个RTP包
  15. 一个RTP包也可以发送多个NALU,比如:sps和pps、sei帧一起发送,很多时候,为了简化程序,sps,pps,sei帧还是发送独立的包。
  16. 那么到底将单⼀的NALU打包到RTP或者把⽐较⼤的NLAU打包到多个RTP即FU-A⽅式是怎么操作的呢?
1. 打包方式之Single NAL Unit
  1. 就是⼀个RTP包打包⼀个单独的NALU⽅式,其实最好理解,就是在RTP固定头后⾯直接填充NLAU单元数据即可,即:
  2. RTP Header + NALU Header + NALU Data; (不包括startcode)
  3. 进⾏抓包和写⽂件,我们发现写⽂件的SPS和抓包RTP包固定头后⾯的负载完全是⼀致的,写⽂件中的SPS:
  4. 抓包中的RTP固定头后⾯的SEI:
    在这里插入图片描述
2. 打包方式之FU-A
  1. 这种打包⽅式也不复杂,为了解释清楚,需要了解下⾯两个数据包头即FU indicator和Fu header
1. FU indication
 +---------------+
 |0|1|2|3|4|5|6|7|
 +-+-+-+-+-+-+-+-+
 |F|NRI|   Type  |
 +---------------+
  1. 这⾥⾯的的F和NRI已经在NALU的Header解释清楚了,就是NALU头的前⾯三个bit位,后⾯的TYPE就是NALU的FU-A类型28,这样在RTP固定头后⾯第⼀字节的后⾯5bit提取出来就确认了该RTP包承载的不是⼀个完整的NALU,是其⼀部分。
  2. 那么问题来了,⼀个NALU切分成多个RTP包传输,那么到底从哪⼉开始哪⼉结束呢?可能有⼈说RTP包固定头不是有mark标记么,注意区分那个是以帧图像的结束标记,这⾥要确定是NALU结束的标记,其次NALU的类型呢?那么就需要RTP固定12字节后⾯的Fu Header来进⾏区分。
2. FU header
 +---------------+
 |0|1|2|3|4|5|6|7|
 +-+-+-+-+-+-+-+-+
 |S|E|R|   Type  |
 +---------------+
  1. 字段解释:

    1. S: 1 bit,当设置成1,开始位指示分⽚NAL单元的开始。当跟随的FU荷载不是分⽚NAL单元荷载的开始,开始位设为0。
    2. E: 1 bit,当设置成1, 结束位指示分⽚NAL单元的结束,即, 荷载的最后字节也是分⽚NAL单元的最后⼀个字节,当跟随的FU荷载不是分⽚NAL单元的最后分⽚,结束位设置为0。也就是说⼀个NALU切⽚时,第⼀个切⽚的SE是10,然后中间的切⽚是00,最后⼀个切⽚时01。
    3. R: 1 bit,保留位必须设置为0,接收者必须忽略该位。
    4. Type: 5 bits:此处的Type就是NALU头中的Type,取1-23的那个值,表示 NAL单元荷载类型定义。
  2. 综上所述:

  3. 对于⽐较⼤的NLAU进⾏FU-A切⽚时,其中NALU的Header字段在RTP打包时划分为两个字节

    1. NALU header的前3bit为RTP固定头后⾯第⼀个字节FU-indication的前3bit,后⾯5bit后⾯跟了FU-A打包这种类型28;
    2. NALU header的后⾯5bit变成了RTP固定头第⼆字节的后⾯5bit,其中前3bit标识了分⽚的开始和结束
  4. 为了验证这种打包⽅式,我们同样进⾏了写⽂件和抓包,对第⼀个IDR帧的NLAU采取的这种分⽚进⾏了研究。

  5. 第⼀个IDR帧的NALU第⼀个切⽚:
    在这里插入图片描述

FU indication
⼗六机制:0x7C
⼆进制:0111 1100
FU header
⼗六进制:0x85
⼆进制:1000 0101
这⾥的SE是10,则说明该RTP包承载的NALU的第⼀个切⽚
  1. 这样我们提取FU indication字节的前3bit位和Fu header字节后5bit位则为0110 0101即0x65这刚好符合IDR帧的NALU Header定义,后⾯的88 84 00 2f等⼆进制就是NALU的DATA字段。
  2. 第⼀个IDR帧的NALU第⼆个切⽚:
    在这里插入图片描述
FU indication
⼗六机制:0x7C
⼆进制:0111 1100
FU header
⼗六进制:0x05
⼆进制:0000 0101
这⾥的SE是00,则说明该RTP包承载的NALU的中间切⽚。
  1. 按照同样⽅法提取,则NALU Header的⼆进制为0110 0101即0x65,同样说明是IDR帧类型,类似这种的中间切⽚有很多,从31-56RTP包都是中间切⽚,直到最后⼀个NALU的切⽚。
  2. 第⼀个IDR帧的NALU最后⼀个切⽚:
    10.
FU indication
⼗六机制:0x7C
⼆进制:0111 1100
FU header
⼗六进制:0x45
⼆进制:0100 0101
这⾥的SE是01,则说明该RTP包承载的NALU的最后⼀个切⽚
  1. 当然通过抓包你还可以到IDR帧时⽐较⼤的,⽽后⾯的P帧就相对⽐较⼩,因为⼀个NALU切⽚4次就完了,同样能看到时间戳的变化值等信息。
  2. 我们可以看到发送端⼀般采⽤Single NAL Unit和FU-A打包⽅式就基本可以将H264数据发送到接收端了,对于AAC⾳频来说,直接将ADTS头部去掉以1024字节组成⼀帧直接塞到RTP即可,打包并不难。
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: AAC(Advanced Audio Coding)是一种基于MPEG-2标准的音频压缩编码格式,它采用了高效的压缩算法,能够在保留较高音质的同时减小文件大小。RTP(Real-time Transport Protocol)是一种实时传输音视频数据的协议,用于在互联网上传输音视频流。 AAC封包和解是将AAC音频数据封装成RTP数据,并在接收端将RTP数据解包还原成AAC音频数据的过程。 在进行AAC封包时,需要首先将原始的AAC音频数据按照RTP格式进行封装。封包的过程括以下几个步骤: 1. 分片:将原始的AAC音频数据分成较小的数据块,以便在网络上传输。 2. 添加RTP头部:为每个数据块添加RTP头部,括序列号、时间戳等信息,用于接收端进行数据恢复。 3. 添加RTP扩展头部(可选):添加一些额外的信息,如源地址、目的地址等。 4. 添加UDP头部:将封装好的RTP数据添加UDP头部,以便进行网络传输。 在进行AAC解包时,需要将接收到的RTP数据解析还原成原始的AAC音频数据。解包的过程括以下几个步骤: 1. 去除UDP头部:将接收到的数据去除UDP头部,获取RTP数据。 2. 解析RTP头部:解析RTP头部获取序列号、时间戳等信息。 3. 去除RTP头部:将RTP头部去除,获取原始的AAC音频数据块。 4. 还原AAC音频数据:将获取到的音频数据块还原成原始的AAC音频数据。 封包和解使得AAC音频数据能够以RTP数据的形式在网络上进行实时传输和接收,保证了音频数据的完整性和一定程度的实时性。这对于需要进行音频传输的应用场景非常有用,如实时语音通话、音频会议等。 ### 回答2: RTP(实时传输协议)是一种用于实时数据传输的协议,可以将音频、视频和其他多媒体数据封装并实时传输。AAC(Advanced Audio Coding)是一种高级音频编码格式,能够提供较高的音质和较低的数据率。 在将AAC封装成RTP时,需要进行以下步骤: 1. 分割AAC帧:AAC编码的音频数据通常以帧的形式存储,需要将这些帧进行分割,以便封装成RTP。 2. 添加RTP头部:根据RTP协议的规范,需要为每个AAC帧添加RTP头部,括序列号、时间戳和同步源等信息。 3. 打RTP:将添加了RTP头部的AAC帧按照一定的顺序和格式打RTP,可以使用UDP协议进行传输。 解包RTP中的AAC音频数据时,需要进行以下步骤: 1. 解析RTP头部:从接收到的RTP中提取出RTP头部的信息,括序列号、时间戳和同步源等。 2. 解析AAC帧:根据AAC编码的格式,将RTP中的数据解析成原始的AAC帧。 3. 合并帧数据:如果收到多个RTP含有同一帧中的不同部分数据,需要将这些部分数据进行合并,还原出完整的AAC帧。 4. 进行解码:将还原出的AAC帧进行解码,得到音频数据。 5. 进一步处理:可以对解码后的音频数据进行后续处理,如播放、存储或传输。 通过上述封包和解的过程,我们能够将AAC音频数据封装成RTP进行实时传输,并在接收端解析和解RTP,得到原始的AAC音频数据进行后续处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值