官方中文文档:
📎H.264_ITU官方中文版.pdf
官方下载地址:
https://www.itu.int/rec/T-REC-H.264/en
JM源码:
https://iphome.hhi.de/suehring/tml/download/
博客参考学习:H.264官方软件JM源代码简单分析-解码器ldecod(转载)-CSDN博客
H.264——使用H.264视频编解码器JM进行YUV图像序列的编解码_jm10.0图像处理-CSDN博客
雷神h264源码参考实现学习
https://github.com/leixiaohua1020/h264_analysis
yuvplayer:
https://github.com/fermay/YUVplayer
4、缩写词(abbreviations):
为了本建议书 | 国际标准的目的,以下缩写词适用:
- 1、CABAC : Context-based Adaptive Binary Arithmetic coding(基于上下文的自适应二进制算术编码)
- 2、CAVLC: Context-based Adaptive Variable length coding(基于上下文的自适应变长编码)
- 3、CBR : Constant Bit Rate(恒定比特率)
- 4、CPB: Coded Picture Buffer(编码图像缓冲区):指的是在视频编码过程中用于存储已经编码完成的图像帧的数据缓冲区。编码后的图像帧首先被存储在这个缓冲区中,随后可以按顺序发送到网络或写入到文件中,或者用于其他视频处理操作。编码图像缓冲区的作用包括:
- 暂存编码数据:为编码器提供足够的时间来处理和编码视频帧,而不受网络传输或存储设备写入速度的限制。
- 平滑输出:在编码过程中可能会有不同帧大小和编码时间的变化,编码图像缓冲区可以平滑这些变化,保持输出的一致性。
- 错误恢复:在网络传输中,编码图像缓冲区有助于实现错误恢复机制,比如通过重传或使用错误隐藏技术。
- 延迟控制:在需要控制播放延迟的应用中,编码图像缓冲区的大小和填充策略会影响整体的延迟。
- 5、DPB:Decoded Picture Buffer(解码图像缓冲区),是视频处理中的一个术语,指的是在视频解码过程中用于暂存已经解码但尚未显示的图像帧的内存区域。解码图像缓冲区的主要作用包括:
- 时间缓冲:由于视频帧的解码时间可能不是均匀的,解码图像缓冲区可以平滑解码过程中的时间波动,确保视频播放的连续性和流畅性。
- 处理延迟:在解码过程中可能会有延迟,解码图像缓冲区可以存储已经解码好的帧,直到它们需要被显示时再送至显示设备。
- 错误隐藏:如果解码过程中出现错误,解码图像缓冲区可以提供一种机制,用先前正确解码的帧来替代损坏的帧,从而隐藏错误对观看体验的影响。
- 同步和定时:解码图像缓冲区有助于视频播放的同步,确保视频帧按照正确的顺序和时间间隔显示。
- 提高用户体验:通过合理管理解码图像缓冲区,可以减少播放过程中的卡顿和中断,提高用户的观看体验。
- 7、DUT: Decoder under test(正在测试的解码器)
- 8、FIFO: First-In, First-Out(先进先出)
- 9、HRD : Hypotherical Reference Decoder(假想参考解码器)
- 10、HSS: Hypothetical stream Scheduler(假想流调度器)
- 11、IDR: Instantaneous Decoding Refresh 即时解码刷新帧
- 12、LSB : Least Significant Bit 最低有效位
- 13、MB : Macroblock 宏块
- 14、MBAFF : Macroblock-Adaptive frame-field coding 宏块自适应帧场编码
- 15、MSB : Most Significant Bit 最高有效位
- 16、MVC : Multiview video coding 多视点视频编码:指的是一种视频编码技术,用于处理和编码由多个摄像机捕获的多个视角的视频数据,以支持3D视频或虚拟现实(VR)体验。
- 17、MVCD : Multiview video coding with depth 带有深度信息的多视点视频编码: 这种技术不仅编码多个视角的视频数据,还包括与这些视角相关的深度信息,用于增强3D效果或实现更高级的图像处理和分析功能。
- 18、NAL : Network Abstraction Layer 网络抽象层
- 19、RBSP: Raw Byte Sequence Payload 原始字节序列负载,指的是在网络通信或数据传输中,未经压缩或加密的原始数据序列。
- 20、SEI : Supplemental Enhancement Information 补充增强信息
- 21、SODB : String of Data Bits 数据比特串
- 22、SVC:Scalable video coding 可扩展视频编码
- 23、UUID : univeral unique identifier 通用唯一识别码
- 24、VBR : variable bit rate 可变比特率
- 25、vcl : video conding layer 视频编码层
- 26、vlc : variable length coding 变长编码
- 27、vui : video usability information 视频可用性信息
7、4、semantics(语义):
与这些结构内的语法元素及其语法结构相关的语义在本条款中被指定。当语法元素的语义通过表格或一组表格来指定时,除非在本建议 | 国际标准中有其他规定,否则表中未指定的任何值都不应出现在比特流中。
7、4、1: NAL unit semantics(网络抽象层单元的语义):
NAL(network abstraction layer)
注意1 - VCL(视频编码层)被指定用于高效地表示视频数据的内容。NAL(网络抽象层)被指定用于格式化这些数据,并以适合在各种通信信道或存储介质上传输的方式提供头部信息。所有数据都包含在NAL单元中,每个NAL单元包含整数个字节。NAL单元指定了一个通用格式,用于面向包和比特流系统。在面向包传输和字节流格式中,NAL单元的格式是相同的,除了在字节流格式中,每个NAL单元可以由一个起始码前缀和额外的填充字节前导。
NumBytesInNALunit
指定了NAL单元的大小,以字节为单位。这个值是解码NAL单元所必需的。为了能够推断NumBytesInNALunit
,需要某种形式的NAL单元边界的界定。一种这样的界定方法在附录B中针对字节流格式进行了规定。其他界定方法可能在本建议书|国际标准之外进行了规定。
forbidden_zero_bit
应该等于 0。
nal_ref_idc
不等于 0 表示NAL单元的内容包含序列参数集、序列参数集扩展、子集序列参数集、图像参数集、参考图像的切片、参考图像的切片数据分区,或者是一个参考图像切片前的前缀NAL单元。 对于符合附录A中指定的一个或多个配置文件并且使用第2至9条款中指定的解码过程解码的编码视频序列,如果包含切片或切片数据分区的NAL单元的nal_ref_idc
等于0,则表示该切片或切片数据分区是非参考图像的一部分。 对于序列参数集或序列参数集扩展或子集序列参数集或图像参数集NAL单元,nal_ref_idc
不应该等于 0。当特定图像的一个NAL单元的nal_ref_idc
等于0且nal_unit_type
在1到4(含)范围内时,该图像所有nal_unit_type
在1到4(含)范围内的NAL单元的nal_ref_idc
也应该等于 0。 对于nal_unit_type
等于5的NAL单元,nal_ref_idc
不应该等于 0。 对于nal_unit_type
等于6、9、10、11或12的所有NAL单元,nal_ref_idc
应该等于 0。
nal_unit_type
指定了NAL单元中包含的RBSP(原始字节序列载荷)数据结构的类型,如表7-1所规定。 表7-1中标记为"C"的列列出了可能在NAL单元中出现的语法元素的类别。此外,根据RBSP数据结构的语法和语义,也可能存在语法类别为"All"的语法元素。任何特定列出类别的语法元素的存在或缺失,由相关RBSP数据结构的语法和语义确定。除非RBSP数据结构中至少存在一个语法元素,其语法元素类别值等于nal_unit_type
的值且不归类为"All",否则nal_unit_type
不应等于3或4。
对于符合附录A中指定的一个或多个配置文件并且使用第2至9条款中指定的解码过程解码的编码视频序列,VCL(视频编码层)和非VCL NAL单元在表7-1中标记为"附录A NAL单元类型类别"的列中指定。对于符合附录G中指定的一个或多个配置文件并且使用附录G中指定的解码过程解码的编码视频序列,以及符合附录H中指定的一个或多个配置文件并且使用附录H中指定的解码过程解码的编码视频序列,VCL和非VCL NAL单元在表7-1中标记为"附录G和附录H NAL单元类型类别"的列中指定。nal_unit_type
等于14的"后缀依赖"项规定如下:
- 如果按照解码顺序直接跟随
nal_unit_type
等于 14 的NAL单元的NAL单元具有nal_unit_type
等于 1 或 5,则nal_unit_type
等于 14 的NAL单元是VCL NAL单元。 - 否则(即按照解码顺序直接跟随
nal_unit_type
等于 14 的NAL单元的NAL单元,其nal_unit_type
不等于 1 或 5),nal_unit_type
等于 14 的NAL单元是非VCL NAL单元。解码器应忽略(从比特流中移除并丢弃)nal_unit_type
等于 14 的NAL单元以及按照解码顺序直接跟随nal_unit_type
等于 14 的NAL单元的NAL单元。
当编码视频序列中存在nal_unit_type
等于 13 或 19 的NAL单元时,解码器应执行为这些NAL单元指定的(可选的)解码过程,或者应忽略(从比特流中移除并丢弃)这些NAL单元的内容。 符合附录A中指定的一个或多个配置文件而不是附录G或H中指定的配置文件的解码器,应忽略(从比特流中移除并丢弃)所有nal_unit_type
等于 14、15 或 20 的NAL单元的内容。
使用nal_unit_type
等于 0 或在 24 到 31(含)范围内的NAL单元,不应对本建议书|国际标准中指定的解码过程产生影响。 注意 2 — 应用可能根据需要使用NAL单元类型 0 和 24 到 31。本建议书|国际标准中没有为这些nal_unit_type
值指定解码过程。由于不同的应用可能对NAL单元类型 0 和 24 到 31 使用不同的目的,因此在设计生成nal_unit_type
等于 0 或在 24 到 31(含)范围内的NAL单元的编码器时,以及在设计解释nal_unit_type
等于 0 或在 24 到 31(含)范围内的NAL单元内容的解码器时,必须特别小心。
解码器应忽略(从比特流中移除并丢弃)所有使用nal_unit_type
保留值的NAL单元的内容。 注意 3 — 这项要求允许对本建议书|国际标准进行兼容扩展的定义。 注意 4 — 在本建议书|国际标准以前的版本中,NAL单元类型13..15和19..20(或这些NAL单元类型的子集)是保留的,并没有为具有这些nal_unit_type
值的NAL单元指定解码过程。在本建议书|国际标准后来的版本中,当前保留的nal_unit_type
值可能会变为非保留,并且可能会为这些nal_unit_type
值指定解码过程。编码器应该考虑到在本建议书|国际标准以前的版本中保留的nal_unit_type
值可能会被解码器忽略。
在文本中,编码切片NAL单元统一指代一个非IDR图像NAL单元的编码切片或一个IDR图像NAL单元的编码切片。变量IdrPicFlag定义为 IdrPicFlag=(nal_unit_type==5)?1:0IdrPicFlag=(nal_unit_type==5)?1:0(公式7-1) 当一个NAL单元的nal_unit_type
值等于5,且包含某个特定图像的切片时,该图像中不应包含nal_unit_type
在1到4(含)范围内的NAL单元。对于符合附录A中指定的一个或多个配置文件并且使用第2至9条款中指定的解码过程解码的编码视频序列,这样的图像被称为IDR图像。 注意5 — IDR图像不能使用切片数据分区。
svc_extension_flag
表示在语法结构中接下来是否会跟随 nal_unit_header_svc_extension()
或 nal_unit_header_mvc_extension()
。 当 svc_extension_flag
不存在时,推断其值为0。 对于符合附录G中指定的一个或多个配置文件的编码视频序列,svc_extension_flag
的值应等于1。符合附录G中指定的一个或多个配置文件的解码器应忽略(从比特流中移除并丢弃)nal_unit_type
等于14或20,且 svc_extension_flag
等于0的NAL单元。 对于符合附录H中指定的一个或多个配置文件的编码视频序列,svc_extension_flag
的值应等于0。符合附录H中指定的一个或多个配置文件的解码器应忽略(从比特流中移除并丢弃)nal_unit_type
等于14或20,且 svc_extension_flag
等于1的NAL单元。 对于符合附录I中指定的一个或多个配置文件的编码视频序列,svc_extension_flag
的值应等于0。符合附录I中指定的一个或多个配置文件的解码器应忽略(从比特流中移除并丢弃)nal_unit_type
等于14、20或21,且 svc_extension_flag
等于1的NAL单元。 对于符合附录J中指定的一个或多个配置文件的编码视频序列,svc_extension_flag
的值应等于0。符合附录J中指定的一个或多个配置文件的解码器应忽略(从比特流中移除并丢弃)nal_unit_type
等于14或20,且 svc_extension_flag
等于1的NAL单元。
avc_3d_extension_flag
用于指示NAL单元当 nal_unit_type
等于21时,语法结构中接下来是否会跟随 nal_unit_header_mvc_extension()
或 nal_unit_header_3davc_extension()
。 当 avc_3d_extension_flag
不存在时,推断其值为0。 DepthFlag
的值按照以下方式指定:
对于符合附录I中指定的一个或多个配置文件的编码视频序列,avc_3d_extension_flag
的值应等于0。符合附录I中指定的一个或多个配置文件的解码器应忽略(从比特流中移除并丢弃)nal_unit_type
等于21且 avc_3d_extension_flag
等于1的NAL单元。
rbsp_byte[i]
是RBSP(Raw Byte Sequence Payload, RBSP)中的第i个字节。RBSP被指定为如下的有序字节序列。 RBSP包含一个SODB,"Sequence of Data Bits",即数据位序列,如下所述:
- 如果SODB为空(即长度为零位),则RBSP也为空。
- 否则,RBSP按照以下方式包含SODB:
- (1)RBSP的第一个字节包含SODB的第一个(最重要,最左边的)八位;RBSP的下一个字节包含SODB的接下来的八位,以此类推,直到SODB剩余不足八位。
- (2)rbsp_trailing_bits() 语法结构在SODB之后存在,如下所示:
- i、最终RBSP字节的第一个(最重要,最左边的)位包含SODB的剩余位(如果有的话)。
- ii、接下来的位由一个等于1的单独位组成(即,rbsp_stop_one_bit)。
- iii、当rbsp_stop_one_bit不是字节对齐字节中的最后一个位时,会存在一个或多个值为零的位(即,rbsp_alignment_zero_bit的实例),以实现字节对齐。
- (3)在RBSP的末尾的rbsp_trailing_bits()之后,某些RBSP中可能会存在一个或多个等于0x0000的cabac_zero_word 16位语法元素。
具有这些RBSP属性的语法结构在语法表中使用"_rbsp"后缀来表示。这些结构应作为rbsp_byte[i]数据字节的内容在NAL单元中携带。RBSP语法结构与NAL单元的关联应按照表7-1的规定。
注6 - 当RBSP的边界已知时,解码器可以通过连接RBSP的字节的位,并丢弃等于1的最后一个(最不显著,最右边)的rbsp_stop_one_bit,以及丢弃其后的所有等于0的(更不显著,更靠右的)位,从RBSP中提取SODB。解码过程所需的数据包含在RBSP的SODB部分。
emulation_prevention_three_byte 是一个等于0x03的字节。当NAL单元中存在 emulation_prevention_three_byte 时,解码过程应将其丢弃。 NAL单元的最后一个字节不能等于0x00。 在NAL单元内,以下三字节序列在任何字节对齐的位置都不应出现:
在NAL单元内,除了以下序列之外,任何以0x000003开头的四字节序列都不应出现在任何字节对齐的位置:
注7 - 当nal_unit_type等于0时,在编码器的设计中必须特别小心,以避免在NAL单元语法结构的开头出现上述列出的三字节和四字节模式,因为语法元素emulation_prevention_three_byte不能是NAL单元的第三个字节。
附录B
B、1:字节流NAL unit 语法和语义
B、1、1、字节流NAL unit 语法:
B、1、2、字节流Nal unit 语义:
字节流中的NAL单元的顺序应遵循字节流中包含的NAL单元的解码顺序(参见第7.4.1.2条)。每个字节流NAL单元的内容与包含在字节流NAL单元中的NAL单元相同的访问单元相关联(参见第7.4.1.2.3条)。
转换成白话来理解:
在视频编码过程中,原始视频数据被编码成一系列NAL单元。这些NAL单元在字节流中出现的顺序应该遵循它们解码的顺序。也就是说,解码器应该按照NAL单元在字节流中出现的顺序来解码它们。访问单元是视频编码中的一个概念,指的是可以独立解码的一系列NAL单元的集合。一个访问单元通常包含一个或多个视频帧。每个字节流NAL单元的内容应该与它所包含的NAL单元相同的访问单元相关联。这意味着,如果一个NAL单元是某个访问单元的一部分,那么在字节流中,这个NAL单元的所有数据都应该与那个访问单元的其他数据一起被处理。
- leading_zero_8bits is a byte equal to 0x00 :注意——
leading_zero_8bits
语法元素只能出现在比特流的第一个字节流NAL单元中,因为(如B.1.1条款的语法图所示)任何跟随NAL单元语法结构并且位于四字节序列0x00000001(应被解释为一个字节零值后跟一个三字节的开始码前缀)之前的等于0x00的字节,将被认为是trailing_zero_8bits
语法元素,它们是前面字节流NAL单元的一部分。 - zero_byte 是一个字节,等于0x00, 当以下任一条件为真时,应存在
zero_byte
语法元素:
- 1、在NAL单元(nal_unit())中的nal_unit_type
等于7(序列参数集)或8(图像参数集)时。
- 2、字节流NAL单元的语法结构包含了解码顺序中的第一个NAL单元的访问单元,如第7.4.1.2.3条款所规定。
- start_code_prefix_one_3bytes: 这是一个固定值的3字节序列,等于0x000001。这个语法元素被称为起始码前缀。
- trailing_zero_8bits 是一个字节等于0x00.
B、2、字节流Nal unit 解码过程:
这个过程的输入是一系列有序的字节流,由一系列字节流NAL单元的语法结构组成。
这个过程的输出是由一系列NAL单元语法结构组成的序列。
在解码过程的开始,解码器将其在字节流中的当前位置初始化为字节流的开头。然后,它提取并丢弃每个存在的leading_zero_8bits
语法元素,每次将字节流中的当前位置向前移动一个字节,直到字节流中的当前位置使得比特流中的下四个字节形成0x00000001的四字节序列。
这段话转换一下来理解:
- 初始化解码位置:在解码过程开始时,解码器将当前位置设置为字节流的开始。
- 处理leading_zero_8bits:解码器会检查并提取字节流中可能出现的
leading_zero_8bits
语法元素(如果存在)。这些元素是字节流中NAL单元之前的零字节,解码器需要识别并丢弃它们。 - 向前移动:每次提取并丢弃
leading_zero_8bits
后,解码器将当前位置向前移动一个字节。 - 识别起始码:解码器继续这一过程,直到它识别到比特流中接下来的四个字节形成特定的四字节序列0x00000001。这个序列通常用作NAL单元的起始码前缀,标志着一个NAL单元的开始。
- 重复解码过程:一旦解码器识别到NAL单元的起始码,它将开始提取和解码NAL单元的语法结构。解码器会重复这一过程,直到:
-
- 遇到字节流的结尾(通过未指定的方式确定,可能是指文件的结尾或特定的结束标志)。
- 所有NAL单元都被解码完毕。
- 解码结束:当解码器处理完字节流中的最后一个NAL单元后,解码过程结束。
然后,解码器反复执行以下逐步过程,以提取并解码字节流中的每个NAL单元语法结构,直到遇到字节流的结尾(通过未指定的方式确定),并且字节流中的最后一个NAL单元已被解码:
- 1、当比特流中的下四个字节形成0x00000001的四字节序列时,字节流中的下一个字节(这是一个zero_byte
语法元素)被提取并丢弃,并将字节流中的当前位置设置为丢弃此字节后的字节的位置。
- 2、字节流中的下一个三字节序列(这是一个start_code_prefix_one_3bytes
)被提取并丢弃,并将字节流中的当前位置设置为跟随这个三字节序列的字节的位置。
- 3、NumBytesInNALunit
被设置为从字节流中当前位置开始的字节数,直到但不包括任何以下情况发生的位置前的最后一字节:
- (1)一个随后的字节对齐的三字节序列等于0x000000。
-(2)一个随后的字节对齐的三字节序列等于0x000001.
-(3)字节流的结尾,通过未指定的方式确定。
- 4、从比特流中移除 NumBytesInNALunit
字节,并将字节流中的当前位置向前推进 NumBytesInNALunit
字节。这一系列字节是 nal_unit(NumBytesInNALunit)
,并使用NAL单元解码过程进行解码。
- 5、当字节流中的当前位置不在字节流的结尾(通过未指定的方式确定),并且字节流中的下一个字节序列不以0x000001的三字节序列开始,且字节流中的下一个字节序列不以0x00000001的四字节序列开始时,解码器提取并丢弃每个trailing_zero_8bits
语法元素,每次将字节流中的当前位置向前移动一个字节,直到字节流中的当前位置使得字节流中的下一个字节序列形成0x00000001的四字节序列,或者遇到了字节流的结尾(通过未指定的方式确定)。
B3、解码器字节对齐恢复(信息性说明)
本条款不构成本建议书|国际标准的不可分割部分。 许多应用以一种内在字节对齐的方式向解码器提供数据,因此无需使用本条款中描述的面向比特的字节对齐检测程序。
当解码器能够确定比特流中数据的位置是否字节对齐时,就说解码器与比特流字节对齐。当解码器与编码器的字节流没有字节对齐时,解码器可能会检查传入的比特流中是否存在二进制模式'00000000 00000000 00000000 00000001'(31个连续的0比特后跟1个1比特)。紧随这一模式之后的比特是一个对齐字节的第一个比特,跟随起始码前缀。一旦检测到这种模式,解码器将与编码器字节对齐,并定位在字节流中的一个NAL单元的开始。
一旦与编码器字节对齐,解码器可以检查传入的字节流中后续的三字节序列0x000001和0x000003。 当检测到三字节序列0x000001时,这是一个起始码前缀。 当检测到三字节序列0x000003时,第三个字节(0x03)是一个emulation_prevention_three_byte
,应按照第7.4.1条款的规定丢弃。 当检测到比特流语法中的错误(例如,forbidden_zero_bit
的非零值或第7.4.1条款中禁止的三字节或四字节序列之一),解码器可能会考虑检测到的条件为字节对齐可能已丢失的指示,并可能丢弃所有比特流数据,直到在比特流的后面位置检测到字节对齐,如本条款中所述。