欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

NALU格式解析

程序员文章站 2022-03-17 14:59:57
...

NALU是压缩视频的基本单位,根据不同场景和传输机制NALU分为2种传输模式:分组流和字节流

分组流

分组流是基于RTP协议的方式,直接将NALU作为RTP分组的载荷部分。

字节流

字节流方式则是NALU按照解码顺序排列成字节流传输。由于NALU里没有NALU长度信息,所以如果NALU直接连接成字节流就无法区分不同的NALU,为了解决这个问题需要在每个NALU前添加起始码字段。在H.265标准的附录B中定义了相关规范。

NALU字节流生成过程:

  1. 在每个NALU前插入3字节起始码start_code_prefix_one_3bytes,其值为0x000001
  2. 如果NALU类型为VPS_NUT, SPS_NUT,PPS_NUT或者AU的第一个NALU,起始码前还要插入zero_byte,其值为0x00
  3. 在视频流的首个NALU的起始码(可能包含zero_byte)前插入leading_zero_8bits,其值为0x00。注意:leading_zero_8bits只能加在第一个NALU前,否则0x00后面跟上4字节0x00 00 00 01(zero_byte后跟上 leading_zero_8bits)会被认为是前一个NALU的trailing_zero_8bits
  4. 根据需要在每个NALU后面添加trailing_zero_8bits 作为填充数据,其值为0x00

字节流的语法格式如下表所示,通过该语法格式可以从字节流中提取NALU。可以看到通过查找起始码0x000001可以确定NALU的前边界,通过查找第一个0x00000001可以确定视频的前边界,通过查找0x00000001可以确定AU的前边界。

NALU格式解析

NALU

H.265中NALU由NALU header和NALU body两部分组成。

NALU Header

NALU头固定为2字节,其结构如下。

NALU格式解析

在ffmpeg中相关定义如下:

typedef struct H265RawNALUnitHeader {
    uint8_t forbidden_zero_bit;
    uint8_t nal_unit_type;
    uint8_t nuh_layer_id;
    uint8_t nuh_temporal_id_plus1;
} H265RawNALUnitHeader;
  • forbidden_zero_bit为1bit,其值应设置为0防止与MPEG-2起始码冲突。

  • nal_unit_type为6bit,取值范围为0-63,表示当前NALU的类型。

  • nuh_layer_id 为6bit,其值应为0。该字段保留给将来使用。

  • nuh_temporal_id_plus1 为3bit,其值减1为该NALU时域层标号。TemporalId = nuh_temporal_id_plus1 − 1

NALU的类型定义如下。

NALU格式解析

 

ffmpeg中关于NALU type的定义如下:

enum HEVCNALUnitType {
    HEVC_NAL_TRAIL_N    = 0,
    HEVC_NAL_TRAIL_R    = 1,
    HEVC_NAL_TSA_N      = 2,
    HEVC_NAL_TSA_R      = 3,
    HEVC_NAL_STSA_N     = 4,
    HEVC_NAL_STSA_R     = 5,
    HEVC_NAL_RADL_N     = 6,
    HEVC_NAL_RADL_R     = 7,
    HEVC_NAL_RASL_N     = 8,
    HEVC_NAL_RASL_R     = 9,
    HEVC_NAL_VCL_N10    = 10,
    HEVC_NAL_VCL_R11    = 11,
    HEVC_NAL_VCL_N12    = 12,
    HEVC_NAL_VCL_R13    = 13,
    HEVC_NAL_VCL_N14    = 14,
    HEVC_NAL_VCL_R15    = 15,
    HEVC_NAL_BLA_W_LP   = 16,
    HEVC_NAL_BLA_W_RADL = 17,
    HEVC_NAL_BLA_N_LP   = 18,
    HEVC_NAL_IDR_W_RADL = 19,
    HEVC_NAL_IDR_N_LP   = 20,
    HEVC_NAL_CRA_NUT    = 21,
    HEVC_NAL_IRAP_VCL22 = 22,
    HEVC_NAL_IRAP_VCL23 = 23,
    HEVC_NAL_RSV_VCL24  = 24,
    HEVC_NAL_RSV_VCL25  = 25,
    HEVC_NAL_RSV_VCL26  = 26,
    HEVC_NAL_RSV_VCL27  = 27,
    HEVC_NAL_RSV_VCL28  = 28,
    HEVC_NAL_RSV_VCL29  = 29,
    HEVC_NAL_RSV_VCL30  = 30,
    HEVC_NAL_RSV_VCL31  = 31,
    HEVC_NAL_VPS        = 32,
    HEVC_NAL_SPS        = 33,
    HEVC_NAL_PPS        = 34,
    HEVC_NAL_AUD        = 35,
    HEVC_NAL_EOS_NUT    = 36,
    HEVC_NAL_EOB_NUT    = 37,
    HEVC_NAL_FD_NUT     = 38,
    HEVC_NAL_SEI_PREFIX = 39,
    HEVC_NAL_SEI_SUFFIX = 40,
    HEVC_NAL_RSV_NVCL41 = 41,
    HEVC_NAL_RSV_NVCL42 = 42,
    HEVC_NAL_RSV_NVCL43 = 43,
    HEVC_NAL_RSV_NVCL44 = 44,
    HEVC_NAL_RSV_NVCL45 = 45,
    HEVC_NAL_RSV_NVCL46 = 46,
    HEVC_NAL_RSV_NVCL47 = 47,
    HEVC_NAL_UNSPEC48   = 48,
    HEVC_NAL_UNSPEC49   = 49,
    HEVC_NAL_UNSPEC50   = 50,
    HEVC_NAL_UNSPEC51   = 51,
    HEVC_NAL_UNSPEC52   = 52,
    HEVC_NAL_UNSPEC53   = 53,
    HEVC_NAL_UNSPEC54   = 54,
    HEVC_NAL_UNSPEC55   = 55,
    HEVC_NAL_UNSPEC56   = 56,
    HEVC_NAL_UNSPEC57   = 57,
    HEVC_NAL_UNSPEC58   = 58,
    HEVC_NAL_UNSPEC59   = 59,
    HEVC_NAL_UNSPEC60   = 60,
    HEVC_NAL_UNSPEC61   = 61,
    HEVC_NAL_UNSPEC62   = 62,
    HEVC_NAL_UNSPEC63   = 63,
};

NALU Body

由于NALU的长度必须是整数字节,所以生成NALU的比特流通常需要填充。视频编码生成的压缩比特流片段称为SODB(String of Data Bits),SODB可能不是正好是整数字节,需要在其后填充比特变成整字节,填充后的比特流称为原始字节载荷序列(Raw Byte Sequence Payload,RBSP)。

SODB生成RBSP过程如下:

  1. RBSP第1字节取SODB最左端8比特,第2字节取接下来8比特,以此类推直到SODB剩余内容不足8比特。
  2. RBSP下一字节首先包含SODB最后几个比特,然后添加比特1,如果该字节还不满8比特后面填充0。
  3. 后面可能加入若干16比特的cabac_zero_word作为填充比特,其值为0x00 00。

RBSP还不能直接作为NALU Body,因为RBSP中可能含有0x00 00 01,与起始码冲突,必须先进行冲突避免处理。

NALU格式解析

其中0x00 00 02是预留码。

关于NALU更详细的内容可以参考H.265相关标准文档。

感兴趣的可以关注微信公众号Video Coding

NALU格式解析

 

相关标签: NALU HEVC H.265