NALU格式解析

66 篇文章 23 订阅
28 篇文章 3 订阅

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

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

NALU Header

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

在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的类型定义如下。

 

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,与起始码冲突,必须先进行冲突避免处理。

其中0x00 00 02是预留码。

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

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

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值