H.264格式

H.264是把原始的yuv文件编码成码流的文件。

H.264是由一系列startcode加NALU构成的

startcode NALU startcode NALU …… startcode NALU startcode NALU

RBSP = SODB + RBSP trailing bits
NALU = NAL header(1 byte) + RBSP
H.264 = Start Code Prefix(3 bytes) + NALU + Start Code Prefix(3 bytes) + NALU +…

startcode

起始码分两种:
0x00000001(4Byte)表示NALU对应的Slice为一帧的开始
0x000001(3Byte)

NALU

NAL header(1 byte) + RBSP = NALU
NAL headerbit0-bit4表示nal type(type见下表),bit5-bit6表示nal参考级别,bit7必须为0

nal_unit:
{
forbidden_zero_bit (1 bit)
nal_ref_idc (2 bits)
nal_unit_type (5 bits)
RBSP(Raw Byte Sequence Payloads)
}
如果一个包含一个条带或条带数据分割的NAL 单元的nal_ref_idc 等于0 时,该条带或条带数据分割是一个非参考图像的一部分。
对于序列参数集或序列参数集扩展或图像参数集的NAL单元,nal_ref_idc不应等于0。当一个特定的图像的一个条带或条带数据分割NAL单元的nal_ref_idc等于0,该图像的所有条带或条带数据划分NAL单元都应该等于0。
IDR NAL单元的nal_ref_idc不应等于0,即nal_unit_type等于5的NAL单元。
所有nal_unit_type等于6、9、10、11或12的NAL单元其nal_ref_idc都应等于0。

当解码器性能不足需要丢帧时,nal_ref_idc可以作为判断能否丢帧的依据。如果nal_ref_idc为0,则可以丢弃。当该帧nal_unit_type等于6,9,10,11或12时,nal_ref_idc为0。部分非IDR帧的nal_ref_idc也为0,也可以丢弃。丢弃的同时也能保证不会花屏。

image.png

RBSP尾部

标准中描述了很多种的RBSP结构并且通过语法表现出来,RBSP语法主要规定了该结构由什么成员组成,各个成员如何组合,成员会占用几个bit。不过虽然RBSP结构有很多种,但是他们也有一个共同点:都有一个RBSP尾部。
RBSP尾部的语法如下:

  1. rbsp_trailing_bits( ) { C Descriptor
  2. rbsp_stop_one_bit /* equal to 1 */ All f(1)
  3. while( !byte_aligned( ) )
  4. rbsp_alignment_zero_bit /* equal to 0 */ All f(1)
  5. }

语法元素

  • rbsp_stop_one_bit 1位的1
  • rbsp_alignment_zero_bit 字节补零,目的是为了进行字节对齐

有一种特殊情况:如果采用的熵编码方式为CABAC,而且当前是实际图像内容相关的RBSP(名称包含slice的RBSP结构),那么会在RBSP尾部的后面添加1个或多个0x0000。语法表示如下:

  1. rbsp_slice_trailing_bits( ) { C Descriptor
  2. rbsp_trailing_bits( ) All
  3. if( entropy_coding_mode_flag )
  4. while( more_rbsp_trailing_data( ) )
  5. cabac_zero_word /* equal to 0x0000 */ All f(16)
  6. }

语法元素

  • cabac_zero_word 0x0000

image.png
RBSP中除了rbsp_trailing_bits以及rbsp_slice_trailing_bits,其余部分被统称为SODB(String Of Data Bits)。

NALU结构

image.png

H.264码流分层次结构

image.png

一些定义

可变长度

可变长度,以非0xFF结束
int _read_ff_coded_number(bs_t* b)
{
int n1 = 0;
int n2;
do
{
n2 = bs_read_u8(b);
n1 += n2;
} while (n2 == 0xff);
return n1;
}

GOP

GOP 是画面组,一个 GOP 是一组连续的画面。
GOP 一般有两个数字,如 M = 3,N = 12,M 制定 I 帧与 P 帧之间的距离,N 指定两个 I 帧之间的距离。那么现在的 GOP 结构是

I BBP BBP BBP BB I

增大图片组能有效的减少编码后的视频体积,但是也会降低视频质量,至于怎么取舍,得看需求了。

工具

streameye
H.264 Visa

解码参考代码

https://github.com/jiayayao/h264_analysis/blob/master/NALParse.cpp

参考

https://www.cnblogs.com/TaigaCon/p/5215448.html
https://blog.csdn.net/shaqoneal/article/details/52080975