• H264封装格式:字节流格式(AnnexB)、AVCC 、RTP打包格式


    H.264的两种打包/封装方法:字节流AnnexB格式 AVCC格式
    放用于网络发送时,要封装成RTP格式

    1、AnnexB格式----用于实时播放

    处于H264文档附录B(Annex-B Byte stream format)中

    开始前缀(00000001或000001)+NALU数据  绝大部分编码器的默认输出格式
      一共有两种起始码start_code
       ①3字节0x000001  单帧多slice(即单帧多个NALU)之间间隔
       ②4字节0x00000001 帧之间,或者SPS等之前
    4字节类型的开始码在在连续的数据传输中非常有用,因为用字节来对齐、分割流数据,比如:用连续的31个bit0后接一个bit1来分割流数据,是很容易的。

    AnnexB格式每个NALU都包含起始码,且通常会周期性的在关键帧之前重复SPS和PPS
      所以解码器可以从视频流随机点开始进行解码,实时的流格式

    2、AVCC—用于存储

    解码器配置参数在一开始就配置好了,系统可以很容易的识别NALU的边界,不需要额外的起始码,减少了资源的浪费,同时可以在播放时调到视频的中间位置。这种格式通常被用于可以被随机访问的多媒体数据,如存储在硬盘的文件。MP4、MKV通常用AVCC格式来存储。

    AVCC格式不使用起始码作为NALU的分界,这种格式在每个NALU前都加上一个大端格式的前缀(1、2、4字节,代表NALU长度)

    所以在解析AVCC格式的时候需要将指定的前缀字节数的值保存在一个头部对象中,这个都通常称为extradata或者sequence header。同时,SPS和PPS数据也需要保存在extradata或者叫’sequence header’中。
    H.264 extradata / sequence header’语法如下:

    bits      
    8   version ( always 0x01 )  
    8   avc profile ( sps[0][1] )  
    8   avc compatibility ( sps[0][2] )  
    8   avc level ( sps[0][3] )  
    6   reserved ( all bits on )  
    2   NALULengthSizeMinusOne  变量告诉我们用几个字节来存储NALU的长度(前缀:1、2或4)
    // 【第5字节的后2位】这个值是(前缀长度-1),如果值=3,那前缀就是4,因为4-1=3  
      值=0 对应前缀1字节 对应每个NALU包最大长度255字节
      值=1 对应前缀2字节 对应每个NALU包最大长度64K
      值=3 对应前缀4字节 使用最多
    3   reserved ( all bits on )  
    5   number of SPS NALUs (usually 1)  repeated once per SPS:  
    16 SPS size  
    N 	variable   SPS NALU data  
    8 	number of PPS NALUs (usually 1)   repeated once per PPS  
    16 PPS size  
    N 	variable PPS NALU data  
    
    使用上面的例子,那么AVCC extradata看起来像是这样的:
    0x0000 | 01 64 00 0A FF E1 00 19 67 64 00 0A AC 72 84 44  
    0x0010 | 26 84 00 00 03 00 04 00 00 03 00 CA 3C 48 96 11  
    0x0020 | 80 01 07 68 E8 43 8F 13 21 30  
      你会发现SPS和PPS被存储在了非NALU包中(out of band带外),即独立于基本流数据。
      这些数据的存储和传输是文件容器的任务,超出了本文的范畴。
    •  

    虽然AVCC格式不使用起始码,但防竞争字节还是有的。

    防字节竞争处理(Annxb和AVCC均有):RBSPEBSP
    >用起始码定位NALU边界存在一个问题,即NALU中可能存在与起始码相同的数据。
    >为了防止这个问题,在构建NALU时,需要在数据中的0x000000,0x000001,0x000002,0x000003中插入防竞争字节(Emulation Prevention Bytes)0x03,使其变为:
    0x000000 = 0x0000 03 00
    0x000001 = 0x0000 03 01
    0x000002 = 0x0000 03 02
    0x000003 = 0x0000 03 03
    解码器在检测到0x000003时,将0x03抛弃,恢复原始数据。

    3、RTP封装=12字节固定RTP包头 + 载荷(NALU)

    在这里插入图片描述

    V:	RTP协议的版本号,当前协议版本号为2。
    P:	填充标志,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。
    X:	扩展标志,如果X=1,则在RTP报头后跟有一个扩展报头
    CC:	CSRC计数器,指示CSRC 标识符的个数。
    
    M:	标记位(不同载荷含义不同,视频标记一帧的最后一个分片slice则=1,其他=0)
    PT:	载荷类型RTP_PAYLOAD_RTSP 如GSM音频、JPEM图像等。例如H264=96
    序列号: 用于标识发送者所发送的 RTP 报文的序列号,每发送一个报文,序号增加 1
    
    时间戳:	时间戳反映了该 RTP 报文的第一个八位组的采样时刻。 接受者使用时间戳来计算延迟和抖动, 并进行同步控制。
    
    SSRC:同步信源标识符 区分是在和谁通信。值随机选择,参加同一视频会议的两个同步信源的SSRC要相同。
    //特约信源(CSRC)标识符:每个CSRC标识符占32位,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。

    针对IP网络的RTP打包方式。为原始的NAL打包格式,就是开始的若干字节(1,2,4字节)是NAL的长度,而不是start_code,此时必须借助某个全局的数据来获得编码器的profile,level,PPS,SPS等信息才可以解码。

    RTP 协议实际上是由实时传输协议RTP(Real-time Transport Protocol)和实时传输控制协议RTCP(Real-time Transport Control Protocol)两部分组成。
      RTP 协议基于多播或单播网络为用户提供连续媒体数据的实时传输服务;  
      RTCP 协议是 RTP 协议的控制部分,用于实时监控数据传输质量,为系统提供拥塞控制和流控制。

    原始码流NALU格式

    3.0 RTP单次发送有上限2种RTP打包:拆包or不拆包

    在IP网络中,当要传输的IP报文大小超过【最大传输单元MTU】时就会产生IP分片情况。(若交给底层协议拆包容易出问题→主动拆分NALU再打包成RTP包后发送)

    3.1 不分包进行RTP打包:nalu_head(不分包时的包头)

    在这里插入图片描述
    即NALU自身原本的nalu_header
    在这里插入图片描述

    1-12是NALU数据类型
    24-31是RTP打包头类型

    一个NALU_header解读:
    在这里插入图片描述

    3.2 分包进行RTP打包:FU_indicator和FU_head(RTP分包时的包头)

    H264的RTP中有三种不同的封包模式(Single NAL,Non-interleaved,Interleaved)
    通过SDP参数中指定,如:
    m=video 49170 RTP/AVP 98
    a=rtpmap:98 H264/90000
    a=fmtp:98 profile-level-id=42A01E; packetization-mode=1; sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==
    
    
    1、packetization-mode决定封包模式:
      1、单一NAL单元模式( Single NAL unit mode):packetization-mode = 0 或者无此字段时缺省
      2、非交错模式(Non-interleaved mode): packetization-mode = 1
      3、交错模式(Interleaved mode): packetization-mode = 2
    
    
    2、sprop-parameter-sets: SPS,PPS
    这个参数可以用于传输 H.264 的序列参数集和图像参数 NAL 单元. 这个参数的值采用 Base64 进行编码. 不同的参数集间用","号隔开。
    //若不用Base64则可能会有数据丢失
    
    3、profile-level-id:
    这个参数用于指示 H.264 流的 profile 类型和级别. 由 Base16(十六进制) 表示的 3 个字节. 第一个字节表示 H.264 的 Profile 类型, 第三个字节表示 H.264 的 Profile 级别

    3种打包模式–7种打包方式对应关系在这里插入图片描述
    另一种看待角度:
    ①single NAL unit packet 单包(1个RTP包:1个NALU)
    ②aggregation packets  聚合(组合)包(1个RTP包:多个NALU,提高传输效率),需要解包时在重组。
      ①STAP (Single-time aggregation packet)
        STAP-A
        STAP-B
      ② MTAP (Multi-time aggregation packet)
        MTAP16
        MTAP24
    ③Fragmentation Unit  拆包处理【一个NALU→多包 NALU>最大传输单元MTU】
        FU-A  //非交错模式
        FU-B  //交错模式
    1、单一NALU的RTP包:
    在这里插入图片描述
    2、组合NALU的RTP包:
    在这里插入图片描述
    3、分片NALU的RTP包:
    在这里插入图片描述

    2、FU-A的分片格式
    数据比较大的H264视频包,被RTP分片发送。12字节的RTP头后面跟随的就是FU-A分片:
    在这里插入图片描述

    FU_indicator:
    F  禁止位
    NRI 重要标识位即拆包的nalu自身的NRI
    type RTP打包头类型,FU-A时type=28

    FU_header:
    S  开始位 1表示分片NAL单元的开始,反之=0
    E  结束位 1表示分片NAL单元的结束,反之=0。
    R  保留位 必须为0,接收者必须忽略该位。
    type NALU数据类型 NALU_header

    拆包和解包:
    发送端—拆包:NAL_header与分片后的FU的单元头有如下关系:
         NAL_header前三位为FU_indicator的前三位
         NAL_header后五位为FU_header的后五位
    接收端—解包:将所有的分片包组合还原成原始的NAl包
         nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)

     
  • 相关阅读:
    ArrayList源码剖析
    Java集合框架
    Java数据结构和算法(十五)——无权无向图
    Java数据结构和算法(十四)——堆
    Java数据结构和算法(十三)——哈希表
    Java数据结构和算法(十二)——2-3-4树
    Java数据结构和算法(十一)——红黑树
    Java数据结构和算法(十)——二叉树
    Java数据结构和算法(九)——高级排序
    [刷题] Leetcode算法 (2020-2-27)
  • 原文地址:https://www.cnblogs.com/lidabo/p/15840382.html
Copyright © 2020-2023  润新知