🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## 概述 H.264标准协议定义了两种不同的类型: - 一种是VCL即Video Coding Layer,编码器吐出来的原始编码数据,没有考虑传输和存储问题 - 一种是NAL即Network Abstraction Layer,为了展现H.264的网络亲和性,对VCL输出的slice片数据进行了封装为NALUs(NAL Units),然后再封装为RTP包进行传输 ### NALU NALU Header + NALU Data,其中NALU的头由一个字节组成如下所示 ``` +-----------------+ |0|1|2 |3|4|5|6|7| +-+-+---+-+-+-+ |F| NRI |Type| +-----------------+ ``` - F(1 bit) 如果是坏帧,则置1,其余H.264固定为0。 - NRI(2 bit) 用来指示该NALU 的重要性等级。值越大,表示当前NALU越重要。具体大于0 时取何值,没有具体规定。例如:如果是00,则表示此帧即使丢失了,也不影响解码;其他值则表示此帧如果丢失了,会影响解码,这个字段指明了该NALU的重要性,但是实际我们不太关心这个字段。 - Nalu_Type(5 bit) NAL Unit的类型,这个值指明了NALU的类型, **其中NALU的类型见下表** |Nalu_Type|NALU内容|备注| |---|---|---| |0|未指定| | |1|非IDR图像编码的slice|比如普通I、P、B帧| |2|编码slice数据划分A|2类型时,只传递片中最重要的信息,如片头,片中宏块的预测模式等;一般不会用到;| |3|编码slice数据划分B|3类型是只传输残差;一般不会用到;| |4|编码slice数据划分C|4时则只可以传输残差中的AC系数;一般不会用到;| |5 |IDR图像中的编码slice |IDR帧,IDR一定是I帧但是I帧不一定是IDR帧。| |6 |SEI补充增强信息单元 |可以存一些私有数据等;| |7 |SPS 序列参数集 |编码的参数配置| |8 |PPS 图像参数集 |编码的参数配置| |9 |接入单元定界符 || |10 |序列结束|| |11 |码流结束|| |12 |填充数据|| |24 |STAP-ASingle-time aggregation packet |单一时间聚合包模式,意味着一个RTP包可以传输多个NALU,但是这些NALU的编码时间要一样才能聚合到一个RTP。| |25 |STAP-BSingle-time aggregation packet| |26 |MTAP 16Muti-time aggregation packet |多个时间聚合包模式:意味着一个RTP包可以传输多个NALU,但是这些NALU的编码时间有可能不一样。| |27 |MTAP 24Muti-time aggregation packet| |28 |FU-AFragmentation unit |切包模式:当一个RTP容纳不下一个NALU时,就需要FUs这种格式。| |29 |FU-BFragmention unit| |30-31 |未指定,保留| 我们看到1-11就是NALU的单个包类型,但是一个NALU的大小是不一样的,如果是非视频数据的SPS PPS才十几个字节,对于IDR帧,则有可能几十KB。这样把NALU打包到RTP方式就很多:分为一个RTP包承载一个NALU,多个NALU合并到一个RTP,一个大的NALU切分成多个RTP。同时由于时间戳的问题,就有了24-29几种类型 <BR/> 但是对于发送端组RTP包的一方来说,尽可能找简单的打包方式: 1. 我们对于NALU的长度<1400的则采用的是单一NALU打包到单一的RTP包中; 2. 我们对于NALU的长度>=1400的则采用了FU-A的方式进行了打包,这种就是把一个大的NALU进行了切分,最后接收方则进行了合并,把多个RTP包合并成一个完整的NALU即可; 3. 至于为什么NALU的长度大于1400字节就要进行FU-A切片,是因为底层MTU大小值固定为1500,从传输效率讲,这里用1400作为切分条件 抓包分析 ![](../images/screenshot_1662474304454.png)