第6章 H.264的句法和语义
6.1 句法
在编码器输出的码流中,数据的基本单位是句法元素。每个句法元素由若干比特组成,它表示某个特定的物理意义,例如:宏块类型、量化参数等。句法表征句法元素的组织结构,语义阐述句法元素的具体含义。所有的视频编码标准都是通过定义句法和语义来规范编解码器的工作流程。
6.1.1 句法元素的分层结构
编码器输出的比特码流中,每个比特都隶属某个句法元素,也就是说,码流是由一个个句法元素依次衔接组成的,码流中除了句法元素外并不存在专门用于控制或同步的内容。在H.264定义的码流中,句法元素被组织成有层次的结构,分别描述各个层次的信息。图6.1表现了这种结构。
图6.1 句法元素的分层结构
句法元素的分层结构有助于更有效地节省码流。例如,在一个图像中,经常会在各个片之间有相同的数据,如果每个片都同时携带这些数据,势必会造成码流的浪费。更为有效的做法是将该图像的公共信息抽取出来,形成图像一级的句法元素,而在片级只携带该片自身独有的句法元素。在H.264中,句法元素被组织成序列、图像、片、宏块、子宏块5个层次。
H.264的分层结构是经过精心设计的,与以往的视频编码标准相比有很大的改进,这些改进主要针对传输中的错误掩藏,在有误码发生时可以提高图像重建的性能。在以往的标准中,分层的组织结构如图6.2所示,它们如同TCP/IP的结构,每一层都有头部,然后在每层的数据部分包含该层的数据。
图6.2 以往标准中句法元素的分层结构
在这样的结构中,每一层的头部和它的数据部分形成管理与被管理的强依赖关系,头部的句法元素是该层数据的核心,而一旦头部丢失,数据部分的信息几乎不可能再被正确地解码出来。尤其在序列层及图像层,由于网络中MTU(最大传输单元)大小的限制,不可能将整个层的句法元素全部放入同一个分组中,这个时候如果头部所在的分组丢失,该层其他分组即使能被正确接收也无法解码,造成资源浪费。
在H.264中,分层结构最大的不同是取消了序列层和图像层,并将原本属于序列和图像头部的大部分句法元素游离出来形成序列和图像两级参数集,其余的部分则放入片层。参数集是一个独立的数据单位,不依赖于参数集外的其他句法元素。图6.3描述了参数集与参数集外句法元素的关系,在图中我们可以看到,参数集只是在片层句法元素需要的时候被引用,而且,一个参数集并不对应某个特定的图像或序列,同一个序列参数集可以被多个序列中的图像参数集引用。同理,同一个图像参数集也可以被多个图像引用。只在编码器认为需要更新参数集的内容时,才会发送出新的参数集。在这种机制下,由于参数集是独立的,它可以被多次重发或者采用特殊技术加以保护。
图6.3 H.264中句法元素的分层结构
在图6.3的描述中,参数集与参数集外部的句法元素处于不同信道中,这是H.264的一个建议,我们可以使用更安全但成本更昂贵的通道来传输参数集,而使用成本低但不够可靠的信道传输其他句法元素,只需要保证片层中的某个句法元素需要引用某个参数集时,那个参数集已经到达解码器即可,也就是参数集在时间上必须先被传送。当然,在条件不允许的情况下,我们也可以采用妥协的办法:在同一个物理信道中传输所有的句法元素,但专门为参数集采用安全可靠的通信协议,如TCP。当然,H.264也允许我们为包括参数集在内的所有句法元素指定同样的通信协议,但这时所有参数集必须被多次重发,以保证解码器最终至少能接收到一个。在参数集和片使用同个物理信道的情况下,图6.3中的信道1和信道2应该被理解为逻辑上的信道,因为从逻辑上看,参数集与其他句法元素还是处于各自彼此独立的信道中。
H.264在片层增加了新的句法元素指明所引用的参数集的编号,同时因为取消了图像层,片成为了信道2中最上层的独立的数据单位,每个片必须自己携带关于所属图像的编号、大小等基本信息,这些信息在同一图像的每个片中都必须是一致的。在编码时,H.264的规范要求将参数集、片这些独立的数据单位尽可能各自完整地放入一个分组中进行传送。
从表面上看来,H.264关于参数集和片层的结构增加了编码后数据的冗余度(比如参数集必须多次重发,又如每个片都必须携带一部分相同的关于整个图像的信息,而这些数据完全是重复的),降低了编码效率,但这些技术的采用使得通信的鲁棒性大大增强,当数据传输中出现丢包时,能够将错误限制在最小范围,防止错误的扩散,解码后对错误的掩藏和恢复也能起到很好的作用。一个片的丢失将不会影响其他片的解码,还可以通过该片前后的片来恢复该片的数据。
H.264片层以下的句法元素的结构大体上和以往标准类似,但在相当多的细节上有所改进,所有改进的目的不外乎两个:在错误发生时防止错误扩散和减少冗余信息提高编码效率。这两者往往是矛盾的,H.264在这两者上的取舍显得颇具匠心,读者在6.3语义一节及第7章解码器原理中将会深刻体会到这些。
图6.3所示的码流的结构是一种简化的模型,这个模型已经能够正确工作,但还不够完善,不适合复杂的场合。在复杂的通信环境中,除了片和参数集外还需要其他的数据单位来提供额外的信息。图6.4描述了在复杂通信中的码流中可能出现的数据单位。如前文所述,参数集可以被抽取出来使用其他信道传输。
图6.4 H.264码流中的数据单位
在图6.4中我们看到,一个序列的第一个图像叫做IDR图像(即时解码刷新图像),IDR图像都是I图像。H.264引入IDR图像是为了解码的重同步,当解码器解码到IDR图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果在前一个序列的传输中发生重大错误,如严重的丢包或其他原因引起数据错位,在这里可以获得重新同步。IDR图像之后的图像永远不会引用IDR图像之前的图像的数据来解码。
要注意IDR图像和I图像的区别,IDR图像一定是I图像,但I图像不一定是IDR图像。一个序列中可以有很多的I图像,I图像之后的图像可以引用I图像之间的图像做运动参考。
在图6.4中,除了参数集与片外还有其他的数据单位,这些数据单位可以提供额外的数据或同步信息,这些数据单位也是一系列句法元素的集合。它们在解码过程中不是必需的,但却可以适当提高同步性能或定义图像的复杂特征。
6.1.2 句法的表示方法
1.句法元素与变量
编码器将数据编码为句法元素然后依次发送。在解码器端,通常要将句法元素作求值计算,得出一些中间数据,这些中间数据就是H.264定义的变量,如图6.5所示。
图6.5 从句法元素解出变量
在图6.5中,pic_width_in_mbs_minus1是解码器直接从码流中提取的句法元素,这个句法元素表征图像的宽度以宏块为单位。我们看到,为了提高编码效率,H.264将图像实际的宽度减去1后再传送。
PicWidthInMbs=pic_width_in_mbs_minus1+1
PicWidthInSamplesL=PicWidthInMbs×16
PicWidthInSamplesC=PicWidthInMbs×8
以上变量PicWidthInMbs表示图像以宏块为单位的宽,变量PicWidthInSamplesL、PicWidthInSamplesC分别表示图像的亮度、色度分量以像素为单位的宽。H.264定义这些变量是因为在后续句法元素的提取算法或图像的重建中需要用到它们的值。在H.264中,句法元素的名称是由小写字母和一系列的下划线组成,而变量名称由大小写字母组成,中间没有下划线。
2.语法
句法是句法元素的组织结构,而对一个结构的描述必然少不了对应的语法,语法提供判断、循环等必要的描述方法。H.264采用一种类C语法。
(1)判断
(2)循环
与C语言类似,H.264有三种循环体:
①
②
③
3.描述子
描述子是指从比特流提取句法元素的方法,即句法元素的解码算法,每个句法元素都有相对应的描述子。由于H.264编码的最后一步是熵编码,所以这里的描述子大多是熵编码的解码算法。H.264定义了如下几种描述子:
ae(v) | 基于上下文自适应的二进制算术熵编码; |
b(8) | 读进连续的8个比特; |
ce(v) | 基于上下文自适应的可变长熵编码; |
f(n) | 读进连续的n个比特; |
i(n)/i(v) | 读进连续的若干比特,并把它们解释为有符号整数; |
me(v) | 映射指数Golomb熵编码; |
se(v) | 有符号指数Golomb熵编码; |
te(v) | 截断指数Golomb熵编码; |
u(n)/u(v) | 读进连续的若干比特,并将它们解释为无符号整数; |
ue(v) | 无符号指数Golomb熵编码。 |
我们看到,描述子都在括号中带有一个参数,这个参数表示需要提取的比特数。当参数是n时,表明调用这个描述子的时候会指明n的值,也即该句法元素是定长编码的。当参数是v时,对应的句法元素是变长编码,这时有两种情况:i(v)和u(v)两个描述子的v由以前的句法元素指定,也就是说在前面会有句法元素指定当前句法元素的比特长度;除了这两个描述子外,其他描述子都是熵编码,它们的解码算法本身能够确定当前句法元素的比特长度。
6.2 句法表
句法表定义了H.264的句法,指明在码流中依次出现的句法元素及它们出现的条件、提取描述子等。就像前文所提,句法表是分层嵌套的。H.264的句法表见表6.1至表6.19。
表6.1 NAL层句法
表6.2 序列参数集层句法
表6.3 图像参数集层句法
表6.4 片层句法(不分区)
表6.5 片层A分区句法
表6.6 片层B分区句法
表6.7 片层C分区句法
表6.8 拖尾(trailing bits)句法
表6.9 片头句法
表6.10 参考帧队列重排序(reordering)句法
表6.11 加权预测句法
表6.12 参考帧队列标记(marking)句法
表6.13 片层数据句法
表6.14 宏块层句法
表6.15 宏块层预测句法
表6.16 子宏块预测句法
表6.17 残差句法
表6.18 CAVLC残差句法
表6.19 CABAC残差句法
在句法表中的C字段表示该句法元素的分类,这是为片分区服务的,句法元素分类的具体含义在表6.20中详细介绍。其中,Descriptor指定对应句法元素的描述子。
表6.20 nal_uint_type语义
6.3 语义
本节将对句法表中的句法元素作详细解释。
6.3.1 NAL层语义
在网络传输的环境下,编码器将每个NAL各自独立、完整地放入一个分组,由于分组都有头部,解码器可以很方便地检测出NAL的分界,依次取出NAL进行解码。为了节省码流,H.264没有另外在NAL的头部设立表示起始的句法元素,我们从表6.1可以看到这点。但是如果编码数据是储存在介质(如DVD光盘)上,由于NAL是依次紧密排列的,解码器将无法在数据流中分辨出每个NAL的起始位置和终止位置,所以必须要有另外的机制来解决这个问题。
针对这个问题,H.264草案的附录B中指明了一种简单又高效的方案。当数据流存储在介质上时,在每个NAL前添加起始码:0x000001。
在某些类型的介质上,为了寻址的方便,要求数据流在长度上对齐,或必须是某个常数的倍数。考虑到这种情况,H.264建议在起始码前添加若干字节的0来填充,直到该NAL的长度符合要求。
在这样的机制下,解码器在码流中检测起始码,作为一个NAL的起始标识,当检测到下一个起始码时当前NAL结束。H.264规定当检测到0x000000时也可以表征当前NAL的结束,这是因为连着的3个字节的0中的任何一个字节的0要么属于起始码,要么是起始码前面添加的0。
添加起始码是一个解决问题的很好的方法,但上面关于起始码的介绍还不完整,因为忽略了一个重要的问题:如果在NAL内部出现了0x000001或是0x000000的序列怎么办。毫无疑问这种情况是致命的,解码器将把这些本来不是起始码的字节序列当作起始码,而错误地认为这里往后是一个新的NAL的开始,进而造成解码数据的错位!而我们做的大量实验证明,NAL内部经常会出现这样的字节序列。
于是H.264提出了另外一种机制,叫做“防止竞争”,在编码器编码完一个NAL时,应该检测是否出现图6.6左侧中的四个字节序列,以防止它们和起始码竞争。如果检测到这些序列存在,编码器将在最后一个字节前插入一个新的字节:0x03,从而使它们变成图6.6右测的样子。当解码器在NAL内部检测到有0x000003的序列时,将把0x03抛弃,恢复原始数据。
图6.6中的前两个序列我们前文中已经提到,第三个0x000002是作保留用,而第四个0x000003是为了保证解码器能正常工作,因为我们刚才提到,解码器恢复原始数据的方法是检测到0x000003就抛弃其中的0x03,这样当出现原始数据为0x000003时会破坏数据,所以必须也应该给这个序列插入0x03。
图6.6 NAL内部为防止与起始码竞争插入0x03
我们可以从句法表6.1中看到解码器在NAL层的处理步骤,其中变量NumBytesInNALunit是解码器计算出来的,解码器在逐个字节地读一个NAL时并不同时对它解码,而是要通过起始码机制将整个NAL读进,计算出长度后再开始解码。
forbidden_zero_bit 等于0
nal_ref_idc 指示当前NAL的优先级。取值范围为0~3,值越高,表示当前NAL越重要,越需要优先受到保护。H.264规定如果当前NAL是一个序列参数集,或一个图像参数集,或属于参考图像的片或片分区等重要的数据单位时,本句法元素必须大于0。但在大于0时具体该取何值,并没有进一步的规定,通信双方可以灵活地制定策略。当nal_unit_type等于5时,nal_ref_idc大于0;nal_unit_type等于6、9、10、11或12时,nal_ref_idc等于0。
nal_unit_type 指明当前NAL unit的类型,具体类型的定义见表6.20。
nal_unit_type=5时,表示当前NAL是IDR图像的一个片,在这种情况下,IDR图像中的每个片的nal_unit_type都应该等于5。注意片分区不可用于IDR图像。
rbsp_byte[i] RBSP的第i个字节。RBSP指原始字节载荷,它是NAL单元的数据部分的封装格式,封装的数据来自SODB(原始数据比特流)。SODB是编码后的原始数据,SODB经封装为RBSP后放入NAL的数据部分。下面介绍一个RBSP的生成顺序。
从SODB到RBSP的生成过程如下所述。
(1)如果SODB内容是空的,生成的RBSP也是空的。
(2)否则,RBSP由如下的方式生成:
①RBSP的第一个字节直接取自SODB的第1~8个比特(RBSP字节内的比特按照从左到右对应为从高到低的顺序排列),以此类推,RBSP其余的每个字节都直接取自SODB的相应比特;
②RBSP的最后一个字节包含SODB的最后几个比特,及如下的rbsp_trailing_bits(),
rbsp_trailing_bits()的第一个比特是1,接下来填充0,直到字节对齐(填充0的目的也是为了字节对齐);
③最后添加若干个cabac_zero_word(其值等于0x0000)。
emulation_prevention_three_byte NAL内部为防止与起始码竞争而引入的填充字节,值为0x03。
6.3.2 序列参数集语义
profile_idc、level_idc 指明所用profile、level。
constraint_set0_flag 等于1时表示必须遵从本章参考文献[1]中附录A.2.1所指明的所有制约条件,等于0时表示不必遵从所有条件。
constraint_set1_flag 等于1时表示必须遵从本章参考文献[1]中附录A.2.2所指明的所有制约条件,等于0时表示不必遵从所有条件。
constraint_set2_flag 等于1时表示必须遵从本章参考文献[1]中附录A.2.3所指明的所有制约条件,等于0时表示不必遵从所有条件。
注意:当constraint_set0_flag、constraint_set1_flag、constraint_set2_flag中有两个以上等于1时,本章参考文献[1]中附录A.2中的所有制约条件都要被遵从。
reserved_zero_5bits 在目前的标准中本句法元素必须等于0,其他的值保留做将来用,解码器应该忽略本句法元素的值。
seq_parameter_set_id 指明本序列参数集的id号,这个id号将被picture参数集引用,本句法元素的值应该在[0, 31]。
注意:当编码器需要产生新的序列参数集时,应该使用新的seq_parameter_set_id,即使用新的序列参数集,而不是去改变原来的参数集中的内容。
log2_max_frame_num_minus4 这个句法元素主要是为读取另一个句法元素frame_num服务的,frame_num是最重要的句法元素之一,它标识所属图像的解码顺序。可以在句法表看到,fram-num的解码函数是ue(v),函数中的v在这里指定:
v=log2_max_frame_num_minus4+4
从另一个角度看,这个句法元素同时也指明了frame_num的所能达到的最大值:
MaxFrameNum=2(log2_max_frame_num_minus4+4)
变量MaxFrameNum表示frame_num的最大值,在后文中可以看到,在解码过程中,它也是一个非常重要的变量。
值得注意的是frame_num是循环计数的,即当它到达MaxFrameNum后又从0重新开始新一轮的计数。解码器必须要有机制检测这种循环,不然会引起类似千年虫的问题,在图像的顺序上造成混乱。第7章会详细讲述H.264检测这种循环的机制。
pic_order_cnt_type 指明了POC(Picture Order Count)的编码方法、POC标识图像的播放顺序。由于H.264使用了B帧预测,使得图像的解码顺序并不一定等于播放顺序,但它们之间存在一定的映射关系。POC可以由frame-num通过映射关系计算得来,也可以索性由编码器显式地传送。H.264中一共定义了3种POC的编码方法,这个句法元素就是用来通知解码器该用哪种方法来计算POC。pic_order_cnt_type的取值范围是[0,2]。
在如下的视频序列中本句法元素不应该等于2:
(1)一个非参考帧的接入单元后面紧跟着一个非参考图像(指参考帧或参考场)的接入单元;
(2)两个分别包含互补非参考场对的接入单元后面紧跟着一个非参考图像的接入单元;
(3)一个非参考场的接入单元后面紧跟着另外一个非参考场,并且这两个场不能构成一个互补场对。
log2_max_pic_order_cnt_lsb_minus4 指明了变量MaxPicOrderCntLsb的值:
MaxPicOrderCntLsb=2(log2_max_pic_order_cnt_lsb_minus4+4)
该变量在pic_order_cnt_type=0时使用。
delta_pic_order_always_zero_flag 等于1时,句法元素delta_pic_order_cnt[0]和delta_pic_order_cnt[1]不在片头出现,并且它们的值默认为0;本句法元素等于0时,上述的两个句法元素将在片头出现。
offset_for_non_ref_pic 被用来计算非参考帧或场的picture order count,本句法元素的值应该在[-231, 231-1]范围内。
offset_for_top_to_bottom_field 被用来计算图像帧中的底场的picture order count,本句法元素的值应该在[-231, 231-1]范围内。
num_ref_frames_in_pic_order_cnt_cycle 被用来解码picture order count,本句法元素的值应该在[0,255]范围内。
offset_for_ref___frame[i] 在picture order count type=1时用,用于解码POC,本句法元素对循环num_ref_frames_in_pic_order_cycle中的每一个元素指定一个偏移。
num_ref_frames 指定参考帧队列可能达到的最大长度,解码器依照这个句法元素的值开辟存储区,这个存储区用于存放已解码的参考帧,H.264规定最多可用16个参考帧,本句法元素的值最大为16。值得注意的是这个长度以帧为单位,如果在场模式下,应该相应地扩展一倍。
gaps_in_frame_num_value_allowed_flag 这个句法元素等于1时,表示允许句法元素frame_num可以不连续。当传输信道堵塞严重时,编码器来不及将编码后的图像全部发出,这时允许丢弃若干帧图像。在正常情况下每一帧图像都有依次连续的frame_num值,解码器检查到如果frame_num不连续,便能确定有图像被编码器丢弃。这时,解码器必须启动错误掩藏的机制来近似地恢复这些图像,因为这些图像有可能被后续图像用作参考帧。
当这个句法元素等于0时,表不允许frame_num不连续,即编码器在任何情况下都不能丢弃图像。这时,H.264允许解码器可以不去检查frame_num的连续性以减少计算量。这种情况下如果依然发生frame_num不连续,表示在传输中发生丢包,解码器会通过其他机制检测到丢包的发生,然后启动错误掩藏的恢复图像。
pic_width_in_mbs_minus1 本句法元素加1后指明图像宽度,以宏块为单位:
PicWidthInMbs=pic_width_in_mbs_minus1+1
通过这个句法元素解码器可以计算得到亮度分量以像素为单位的图像宽度:
PicWidthInSamplesL=PicWidthInMbs×16
从而也可以得到色度分量以像素为单位的图像宽度:
PicWidthInSamplesC=PicWidthInMbs×8
以上变量PicWidthInSamplesL、PicWidthInSamplesC 分别表示图像的亮度、色度分量以像素为单位的宽。
H.264将图像的大小在序列参数集中定义,意味着可以在通信过程中随着序列参数集动态地改变图像的大小,在后文中可以看到,甚至可以将传送的图像剪裁后输出。
pic_height_in_map_units_minus1 本句法元素加1后指明图像高度:
PicHeightInMapUnits=pic_height_in_map_units_minus1+1
PicSizeInMapUnits=PicWidthInMbs×PicHeightInMapUnits
图像的高度的计算要比宽度的计算复杂,因为一个图像可以是帧也可以是场,从这个句法元素可以在帧模式和场模式下分别计算出亮度、色度的高。值得注意的是,这里以map_unit为单位,map_unit的含义由后文叙述。
frame_mbs_only_flag 本句法元素等于1时,表示本序列中所有图像的编码模式都是帧,没有其他编码模式存在;本句法元素等于0时,表示本序列中图像的编码模式可能是帧,也可能是场或帧场自适应,某个图像具体是哪一种要由其他句法元素决定。
结合map_unit的含义,这里给出上一个句法元素pic_height_in_map_units_minus1的进一步解析步骤。
当frame_mbs_only_flag等于1,pic_height_in_map_units_minus1指的是一个picture中帧的高度;当frame_mbs_only_flag等于0,pic_heght_in_map_units_minus1指的是一个picture中场的高度,所以可以得到如下以宏块为单位的图像高度:
FrameHeightInMbs=(2-frame_mbs_only_flag)×PicHeightInMapUnits
mb_adaptive_frame_field_flag 指明本序列是否属于帧场自适应模式。mb_adaptive_frame_field_flag等于1时,表明在本序列中的图像如果不是场模式就是帧场自适应模式;等于0时,表示本序列中的图像如果不是场模式就是帧模式。
全部是帧,对应于frame_mbs_only_flag=1的情况。
帧和场共存。frame_mbs_only_flag=0, mb_adaptive_frame_field_flag=0
帧场自适应和场共存。frame_mbs_only_flag=0, mb_adaptive_frame_field_flag=1
值得注意的是,帧和帧场自适应不能共存在一个序列中。
direct_8x8_inference_flag 用于指明B片的直接和skip模式下运动矢量的预测方法。
frame_cropping_flag 用于指明解码器是否要将图像裁剪后输出,如果是的话,后面紧跟着的四个句法元素分别指出左、右、上、下裁剪的宽度。
frame_crop_left_offset, frame_crop_right_offset, frame_crop_bottom_offset, frame_crop_bottom_offset 如上一句法元素所述。
vui_parameters_present_flag 指明vui子结构是否出现在码流中,vui的码流结构在本章参考文献[1]中的附录指明,用以表征视频格式等额外信息。
6.3.3 图像参数集语义
pic_parameter_set_id 用以指定本参数集的序号,该序号在各片的片头被引用。
seq_parameter_set_id 指明本图像参数集所引用的序列参数集的序号。
entropy_coding_mode_flag 指明熵编码的选择。本句法元素为0时,表示熵编码使用CAVLC;本句法元素为1时表示熵编码使用CABAC。
pic_order_present_flag POC的3种计算方法在片层还各需要用一些句法元素作为参数。本句法元素等于1时,表示在片头会有句法元素指明这些参数;本句法元素等于0时,表示片头不会给出这些参数,这些参数使用默认值。
num_slice_groups_minus1 本句法元素加1后指明图像中片组的个数。H.264中没有专门的句法元素用于指明是否使用片组模式,当本句法元素等于0时(即只有一个片组),表示不使用片组模式,后面也不会跟有用于计算片组映射的句法元素。
slice_group_map_type 规定了片组的映射类型,取值范围为[0,6]。片组的取值对应的映射类型可参见表5.2。
map_units的定义如下。
(1)当frame_mbs_only_flag等于1时,map_units指的就是宏块。
(2)当frame_mbs_only_falg等于0时,又有以下几种情况:
①帧场自适应模式时,map_units指的是宏块对;
②场模式时,map_units指的是宏块;
③帧模式时,map_units指的是与帧场自适应帧中的宏块对类似,垂直相邻的两个连续宏块的组合体。
run_length_minus1[i] 用以指明当片组类型等于0时,每个片组连续的map_units个数。
top_left[i],bottom_right[i] 用以指明当片组类型等于2时,矩形区域的左上及右下位置。
slice_group_change_direction_flag 当片组类型等于3、4、5时,本句法元素与下一个句法元素一起指明确切的片组映射类型。
slice_group_change_rate_minus1 用以指明变量SliceGroupChangeRate。本句法元素表示一个片组的大小从一个图像到下一个的改变的倍数,以map_units为单位。
pic_size_in_map_units_minus1 在片组类型等于6时,用以指明图像以map_units为单位的大小。
slice_group_id[i] 在片组类型等于6时,用以指明某个map_units属于哪个片组。
num_ref_idx_l0_active_minus1 加1后指明目前参考帧队列的长度,即有多少个参考帧(包括短期和长期)。值得注意的是,当目前解码图像是场模式下,参考帧队列的长度应该是本句法元素再乘以2,因为场模式下各帧必须被分解以场对形式存在(这里所说的场模式包括图像的场及帧场自适应下的处于场模式的宏块对)。本句法元素的值有可能在片头被重载。
读者可能还记得在序列参数集中有句法元素num_ref_frames也是跟参考帧队列有关,它们的区别是:num_ref_frames指明参考帧队列的最大值,解码器用它的值来分配内存空间;num_ref_idx_l0_active_minus1指明在这个队列中当前实际的、已存在的参考帧的数目,这从它的名字“active”中也可以看出来。
这个句法元素是H.264中最重要的句法元素之一,在第7章我们可以看到,编码器要通知解码器某个运动矢量所指向的是哪个参考图像时,并不是直接传送该图像的编号,而是传送该图像在参考帧队列中的序号。这个序号并不是在码流中传送的,而是编码器和解码器同步地、用相同的方法将参考图像放入队列,从而获得一个序号。这个队列在每解一个图像时,甚至是每个片后都会动态地更新。维护参考帧队列是编解码器十分重要的工作,而本句法元素是维护参考帧队列的重要依据。参考帧队列的复杂的维护机制也正是H.264重要且很有特色的组成部分。
num_ref_idx_l1_active_minus1 与上一个句法元素的语义一致,只是本句法元素用于list1,而上一句法元素用于list0。
weighted_pred_flag 用以指明是否允许P和SP片的加权预测,如果允许,在片头会出现用以计算加权预测的句法元素。
weighted_bipred_idc 用以指明是否允许B片的加权预测。本句法元素等于0时表示使用默认加权预测模式,等于1时表示使用显式加权预测模式,等于2时表示使用隐式加权预测模式。
pic_init_qp_minus26 取值范围为[-26,+25],加26后用以指明亮度分量的量化参数的初始值。在H.264中,量化参数分3个级别给出:图像参数集、片头、宏块。在图像参数集给出的是一个初始值。
pic_init_qs_minus26 与上一个句法元素语义一致,只是用于SP和SI。
chroma_qp_index_offset 色度分量的量化参数是根据亮度分量的量化参数计算出来的,本句法元素用以指明计算时用到的参数。
deblocking_filter_control_present_flag 编码器可以通过句法元素显式地控制去块滤波的强度,本句法元素指明是在片头是否会有句法元素传递这个控制信息。如果本句法元素等于0,那些用于传递滤波强度的句法元素不会出现,解码器将独立地计算出滤波强度。
constrained_intra_pred_flag 在P和B片中,帧内编码的宏块的邻近宏块可能是采用的帧间编码。当本句法元素等于1时,表示帧内编码的宏块不能用帧间编码的宏块的像素作为自己的预测,即帧内编码的宏块只能用邻近帧内编码的宏块的像素作为自己的预测;而本句法元素等于0时,表示不存在这种限制。
redundant_pic_cnt_present_flag 指明是否会出现redundant_pic_cnt 句法元素。
6.3.4 片头语义
first_mb_in_slice 片中的第一个宏块的地址,片通过这个句法元素来标定它自己的地址。
要注意的是,在帧场自适应模式下,宏块都是成对出现的,这时本句法元素表示的是第几个宏块对,对应的第一个宏块的真实地址应该是2×first_mb_in_slice。
slice_type 指明片的类型,具体语义见表6.21。
表6.21 slice_type语义
IDR图像时,slice_type等于2、4、7、9。
pic_parameter_set_id 图像参数集的索引号,取值范围为[0,255]。
frame_num 每个参考帧都有一个依次连续的frame_num作为它们的标识,这指明了各图像的解码顺序。frame_num所能达到了最大值由前文序列参数集中的句法元素log2_max_frame_num_minus4推出。事实上我们在表中可以看到,frame_num的出现没有if语句限定条件,这表明非参考帧的片头也会出现frame_num。只是当该个图像是参考帧时,它所携带的这个句法元素在解码时才有意义。见表6.22所示的例子。
表6.22 某个序列的frame_num值
注:该系列中B帧一律不作为参考帧,而P帧一律作为参考帧。
H.264对frame_num的值作了如下规定:当参数集中的句法元素gaps_in_frame_num_value_allowed_flag等于0时,每个图像的frame_num值是其前一个参考帧的frame_num值加1。这句话包含有两层意思。
(1)当gaps_in_frame_num_value_allowed_flag等于0时,即frame_num连续的情况下,每个图像的frame_num由前一个参考帧图像对应的值加1,着重点是“前一个参考帧”。在表6.22中,第3个图像是B帧,按照定义,它的frame_nun值应是前一个参考帧,即第2个图像对应的值加1,即为2;第4个图像是P帧,由于该序列B帧都不作为参考帧,所以对于该图像来说,定义中所谓的“前一个参考帧”,仍旧是指的第2个图像,所以对于第4个图像来说,它的frame_num的取值和第3个图像一样,也为2。相同的情况也发生在第6和第8帧上。
前面我们曾经提到,对于非参考帧来说,它的frame_num值在解码过程中是没有意义的,因为frame_num值是参考帧特有的,它的主要作用是在该图像被其他图像引用作运动补偿的参考时提供一个标识。但H.264并没有在非参考帧图像中取消这一句法元素,原因是在POC的第二种和第三种解码方法中可以通过非参考帧的frame_num值计算出它们的POC值,在第7章中会详细讲述这个问题。
(2)当gaps_in_frame_num_value_allowed_flag等于1,前文已经提到,这时若网络拥塞,编码器可以将编码后的若干图像丢弃,而不用另行通知解码器。在这种情况下,解码器必须有机制将缺失的frame_num及所对应的图像填补,否则后续图像若将运动矢量指向缺失的图像将会产生解码错误。
field_pic_flag 这是在片层标识图像编码模式的唯一一个句法元素。所谓的编码模式是指的帧编码、场编码、帧场自适应编码。当这个句法元素取值为1时属于场编码,0时为非场编码。
序列参数集中的句法元素frame_mbs_only_flag和mb_adaptive_frame_field_flag再加上本句法元素共同决定图像的编码模式,如图6.7所示。
图6.7 图像编码模式的判断流程
在序列参数集中,我们已经能够计算出图像的高和宽,但需要指出的是,这个高是指该序列中图像的帧的高度,而一个实际的图像可能是帧也可能是场,对于图像的实际高度,应进一步作如下处理:
PicHeightInMbs=FrameHeightInMbs /(1+field_pic_flag)
从而我们可以得到在解码器端所用到的其他与图像大小有关的变量。
亮度分量:PicHeightInSamplesL=PicHeightInMbs×16
色度分量:PicHeightInSamplesC=PicHeightInMbs×8
PicSizeInMbs=PicWidthInMbs×PicHeightInMbs
前文已提到,frame_num是参考帧的标识,但是在解码器中,并不是直接引用的frame_num值,而是引用由frame_num 进一步计算出来的变量PicNum的值,第7章会详细讲述由frame_num映射到PicNum的算法。这里介绍在该算法中用到的两个变量MaxPicNum和CurrPicNum。
(1)MaxPicNum
表征PicNum的最大值。PicNum和frame_num一样,也是嵌在循环中,当达到这个最大值时,PicNum将从0开始重新计数。
如果field_pic_flag=0, MaxPicNum=MaxFrameNum
否则,MaxPicNum=2×MaxFrameNum
(2)CurrPicNum
当前图像的PicNum值。在计算PicNum的过程中,当前图像的PicNum值是由frame_num直接算出(在第7章中会看到,在解某个图像时,要将已经解码的各参考帧的PicNum重新计算一遍,新的值参考当前图像的PicNum值得来)。
如果field_pic_flag=0, CurrPicNum=frame_num
否则,CurrPicNum=2×frame_num+1
Frame_num是对帧编号的,也就是说,如果在场模式下,同属一个场对的顶场和底场两个图像的frame_num的值是相同的。在帧或帧场自适应模式下,就直接将图像的frame_num赋给PicNum;而在场模式下,将2×frame_num和2×frame_num+1两个值分别赋给两个场。2×frame_num+1这个值永远被赋给当前场,解码到当前场对的下一个场时,刚才被赋为2×frame_num+1的场的PicNum值被重新计算为2×frame_num,而将2×frame_num+1赋给新的当前场。
bottom_field_flag 等于1时表示当前图像是属于底场,等于0时表示当前图像是属于顶场。
idr_pic_id IDR图像的标识。不同的IDR图像有不同的idr_pic_id值。值得注意的是,IDR图像不等价于I图像,只有在作为IDR图像的I帧才有这个句法元素。在场模式下,IDR帧的两个场有相同的idr_pic_id值。idr_pic_id的取值范围是[0,65535],和frame_num类似,当它的值超出这个范围时,它会以循环的方式重新开始计数。
pic_order_cnt_lsb 在POC的第一种算法中本句法元素来计算POC值,在POC的第一种算法中是显式地传递POC的值,而其他两种算法是通过frame_num来映射POC的值。注意这个句法元素的读取函数是u(v),这个v的值是序列参数集的句法元素log2_max_pic_order_cnt_lsb_minus4加4个比特而得到。pic_order_cnt_lsb的取值范围是[0, MaxPicOrderCntLsb -1]。
delta_pic_order_cnt_bottom 如果是在场模式下,场对中的两个场都各自被构造为一个图像,它们有各自的POC算法来分别计算两个场的POC值,也就是一个场对拥有一对POC值;而在是帧模式或是帧场自适应模式下,一个图像只能根据片头的句法元素计算出一个POC值。根据H.264的规定,在序列中有可能出现场的情况,即frame_mbs_only_flag不为1时,每个帧或帧场自适应的图像在解码完后必须分解为两个场,以供后续图像中的场作为参考图像。所以当frame_mb_only_flag不为1时,帧或帧场自适应中包含的两个场也必须有各自的POC值。在第7章中我们会看到,通过本句法元素,可以在已经解开的帧或帧场自适应图像的POC基础上新映射一个POC值,并把它赋给底场。当然,像句法表指出的那样,这个句法元素只用在POC的第一个算法中。
delta_pic_order_cnt[0],delta_pic_order_cnt[1]:
前文已经提到,POC的第二和第三种算法是从frame_num映射得来,这两个句法元素用于映射算法。delta_pic_order_cnt[0]用于帧编码方式下的底场和场编码方式的场,delta_pic_order_cnt[1]用于帧编码方式下的顶场。在第7章会详细讲述POC的3种算法。
redundant_pic_cnt 冗余片的id号,取值范围为[0,127]。
direct_spatial_mv_pred_flag 指出在B图像的直接预测的模式下,用时间预测还是用空间预测。1表示空间预测,0表示时间预测。
num_ref_idx_active_override_flag 在图像参数集中我们看到已经出现句法元素num_ref_idx_l0_active_minus1和num_ref_idx_l1_active_minus1指定当前参考帧队列中实际可用的参考帧的数目。在片头可以重载这对句法元素,以给某特定图像更大的灵活度。这个句法元素就是指明片头是否会重载,如果该句法元素等于1,下面会出现新的num_ref_idx_l0_active_minus1和num_ref_idx_l1_active_minus1值。
num_ref_idx_l0_active_minus1、num_ref_idx_l1_active_minus1 如上个句法元素中所介绍,这是重载的num_ref_idx_l0_active_minus1及num_ref_idx_l1_active_minus1。
cabac_init_idc 给出cabac初始化时表格的选择,取值范围为[0,2]。
slice_qp_delta 指出用于当前片的所有宏块的量化参数的初始值QPY:
SliceQPY=26+pic_init_qp_minus26+slice_qp_delta
QPY的取值范围是[0,51]。
我们前文已经提到,H.264中量化参数是分图像参数集、片头、宏块头三层给出的,前两层各自给出一个偏移值,这个句法元素就是片层的偏移。
sp_for_switch_flag 指出SP帧中的p宏块的解码方式是否是switching模式,第7章有详细的说明。
slice_qs_delta 与slice_qp_delta的与语义相似,用在SI和SP中,由下式计算:
QSY=26+pic_init_qs_minus26+slice_qs_delta
QSY的取值是[0,51]。
disable_deblocking_filter_idc H.264规定一套可以在解码器端独立地计算图像中各边界的滤波强度进行滤波的算法。除了解码器独立计算之外,编码器也可以传递句法元素来干涉滤波强度,这个句法元素指定了在块的边界是否要用滤波,同时指明那个块的边界不用块滤波。
slice_alpha_c0_offset_div2 给出用于增强α和tC0的偏移值:
FilterOffsetA=slice_alpha_c0_offset_div2 << 1
slice_alpha_c0_offset_div2值的范围是[-6,+6]。
slice_beta_offset_div2 给出用于增强α和tC0的偏移值:
FilterOffsetB=slice_beta_offset_div2 << 1
slice_beta_offset_div2值的范围是[-6,+6]。
slice_group_change_cycle 当片组的类型是3、4、5时,由句法元素可获得片组中map_units的数目:
MapUnitsInSliceGroup0=Min(slice_group_change_cycle×SliceGroupChangeRate, PicSizeIn MapUnits)
slice_group_change_cycle由Ceil(Log2(PicSizeInMapUnits÷SliceGroupChangeRate+1))位比特表示
slice_group_change_cycle值的范围是[0,Ceil(PicSizeInMapUnits÷SliceGroupChangeRate)]。
其中,Ceil(x)函数返回不小于x的最小整数。
6.3.5 参考图像序列重排序的语义
每一个使用帧间预测的图像都会引用前面已解码的图像作为参考帧。如前文所述,编码器给每个参考帧都会分配一个唯一性的标识,即句法元素frame_num。但是,当编码器要指定当前图像的参考图像时,并不是直接指定该图像的frame_num值,而是使用通过下面步骤最终得出的ref_id号,如图6.8所示。
图6.8 由frame_num到ref_id
其中,从frame_num到变换到变量PicNum主要是考虑到场模式的需要,当序列中允许出现场时,每个非场的图像(帧或帧场自适应)解码后必须分解为一个场对,从而需要为它们分解后的两个场各自指定一个标识;进一步从PicNum到ref_id是为了能节省码流,因为PicNum的值通常都比较大,而在帧间预测时,需要为每个运动矢量都指明相对应的参考帧的标识,如果这个标识选用PicNum,开销就会比较大,所以H.264又将PicNum映射为一个更小的变量ref_id。在编码器和解码器都同步地维护一个参考帧队列,每解码一个片就将该队列刷新一次,把各图像按照特定的规则进行排序,排序后各图像在队列中的序号就是该图像的ref_id值。在下文中,我们可以看到在宏块层表示参考图像的标识就是ref_id,在第7章我们会详细讲述队列的初始化、排序等维护算法。维护队列时两个重要操作:重排序(Reordering)和标记(Marking)所用到的句法元素。
说明:句法元素的后缀名带有“10”指的是第一个参数列表;句法元素的后缀名带有“11”指的是第二个参数列表(用在B帧预测中)。
ref_pic_list_reordering_flag_l0 指明是否进行重排序操作。这个句法元素等于1时,表明紧跟着会有一系列句法元素用于参考帧队列的重排序。
ref_pic_list_reordering_flag_l1 与上个句法元素的语义相同,只是本句法元素用于参考帧队列L1。
reordering_of_pic_nums_idc 与句法元素abs_diff_pic_num_minus1或long_term_pic_num配合,指明执行哪种重排序操作,具体语义见表6.23。
表6.23 重排序操作
abs_diff_pic_num_minus1 在对短期参考帧重排序时指明重排序图像与当前图像预测值的差值,取值范围是[0, MaxPicNum-1],见表6.23。
long_term_pic_num 在对长期参考帧重排序时指明重排序图像。见表6.23。
从上文可以看到,每组reordering_of_pic_nums_idc、abs_diff_pic_num_minus1或reordering_of_pic_nums_idc、long_term_pic_num只能对一个图像操作,而通常情况下都需要对一组图像重排序,所以在码流中一般会有个循环,反复出现这些重排序的句法元素,如图6.9所示,循环直到reordering_of_pic_nums_idc等于3结束,我们在表6.22中也可以看到这种情况。
图6.9 重排序流程
6.3.6 加权预测的语义
加权预测句法元素的语义如下:
luma_log2_weight_denom 给出参考帧列表中参考图像所有亮度的加权系数,取值范围是[0,7]。
chroma_log2_weight_denom 给出参考帧列表中参考图像所有色度的加权系数,取值范围是[0,7]。
luma_weight_10_flag 其值等于1时,指的是在参考图像列表0中的亮度的加权系数存在;等于0时,在参考图像列表0中的亮度的加权系数不存在。
luma_weight_10[i] 用参考序列0预测亮度值时,所用的加权系数,取值范围是[-128,127]。如果luma_weight_10_flag is=0,对于RefPicList0[i]的luma_weight_10[i]=2luma_log2_weight_denom。
luma_offset_10[i] 用参考序列0预测亮度值时,所用的加权系数的额外偏移。luma_offset_10[i] 的取值范围是[–128,127]。如果luma_weight_10_flag=0,对于RefPicList0[i]的luma_offset_10[i]=0。
chroma_weight_10_flag、chroma_weight_10[i][j]、chroma_offset_10[i][j]与上述三个类似,不同的是这三个句法元素是用在色度预测。
luma_weight_11_flag、luma_weight_11、luma_offset_11、chroma_weight_11_flag、chroma_weight_11、chroma_offset_11等句法元素与luma_weight_10_flag、luma_weight_10、luma_offset_10、chroma_weight_10_flag、chroma_weight_10、chroma_offset_10的语义相似,不同点是这几个句法元素是用在参考图像列表1中。
6.3.7 参考图像序列标记(Marking)操作的语义
前文介绍的重排序(Reordering)操作是对参考帧队列重新排序,而标记(Marking)操作负责将参考图像移入或移出参考帧队列。
no_output_of_prior_pics_flag 仅在当前图像是IDR图像时出现这个句法元素,指明是否要将前面已解码的图像全部输出。
long_term_reference_flag 与上个图像一样,仅在当前图像是IDR图像时出现这一句法元素。这个句法元素指明是否使用长期参考这个机制。如果取值为1,表明使用长期参考,并且每个IDR图像被解码后自动成为长期参考帧;否则取值为0,IDR图像被解码后自动成为短期参考帧。
adaptive_ref_pic_marking_mode_flag 指明标记(Marking)操作的模式,具体语义见表6.24。
表6.24 标记(Marking)模式
memory_management_control_operation 在自适应标记(Marking)模式中,指明本次操作的具体内容,具体语义见表6.25。
表6.25 标记(Marking)操作
difference_of_pic_nums_minus1 当memory_management_control_operation等于3或1时,由这个句法元素可以计算得到需要操作的图像在短期参考队列中的序号。参考帧队列中必须存在这个图像。
long_term_pic_num 当memory_management_control_operation值等于2时,从此句法元素中得到所要操作的长期参考图像的序号。
long_term_frame_idx 当memory_management_control_operation等于3或6,分配一个长期参考帧的序号给一个图像。
max_long_term_frame_idx_plus1 此句法元素的值减1,指明长期参考队列的最大数目。max_long_term_frame_idx_plus1的取值范围是[0,num_ref_frames]。
6.3.8 片数据的语义
片数据句法的语义如下:
cabac_alignment_one_bit 当熵编码模式是CABAC时,此时要求数据字节对齐,即数据从下一个字节的第一个比特开始,如果还没有字节对齐,将出现若干个cabac_alignment_one_bit作为填充。
mb_skip_run 当图像采用帧间预测编码时,H.264允许在图像平坦的区域使用“跳跃”块,“跳跃”块本身不携带任何数据,解码器通过周围已重建的宏块的数据来恢复“跳跃”块。当熵编码为CAVLC或CABAC时,“跳跃”块的表示方法不同。当entropy_coding_mode_flag为1,即熵编码为CABAC时,是每个“跳跃”块都会有句法元素mb_skip_flag指明;当entropy_coding_mode_flag等于0,即熵编码为CAVLC时,用一种行程的方法给出紧连着的“跳跃”块的数目,即句法元素mb_skip_run。mb_skip_run的取值范围[0,PicSizeInMbs - CurrMbAddr]。
mb_skip_flag 指明当前宏块是否是跳跃编码模式的宏块。
mb_field_decoding_flag 在帧场自适应图像中,指明当前宏块所属的宏块对是帧模式还是场模式。mb_field_decoding_flag等于0,则当前宏块对是帧宏块对;等于1,该宏块对是一个场宏块对。如果一个宏块对的两个宏块句法结构中都没有出现这个句法元素,即它们都是“跳跃”块时,本句法元素由以下决定:
(1)如果这个宏块对与相邻的、左边的宏块对属于同一个片时,这个宏块对的mb_field_decoding_flag的值等于左边的宏块对的mb_field_decoding_flag的值;
(2)否则,这个宏块对的mb_field_decoding_flag的值等于上边同属于一个片的宏块对的mb_field_decoding_flag的值;
(3)如果当前宏块对的左边和上方都没有邻居宏块对,这个宏块对的mb_field_decoding_flag的值等于0,即帧模式。
end_of_slice_flag 指明是否到了片的结尾。
6.3.9 宏块层的语义
mb_type 指明当前宏块的类型。H.264规定,不同的片中允许出现的宏块类型也不同。在各种片类型中允许出现的宏块种类见表6.26。
表6.26 各种片中允许出现的宏块类型
可以看到,I片中只允许出现I宏块,而P片中既可以出现P宏块也可以出现I宏块。也就是说,在帧间预测的图像中也可以包括帧内预测的图像。其他片也有类似情况。
更进一步来看,H.264也定义了比以往视频编码标准更多的宏块类型。具体来说,在帧间预测模式下,宏块可以有7种运动矢量的划分方法。在帧内预测模式下,如果是帧内16×16预测,宏块有4种预测方法,即4种类型;如果是帧内4×4预测,这时每个4×4块可以有9种预测方法,整个宏块共有144种类型。
mb_type并不能描述以上所有有关宏块类型的信息。mb_type作为出现在宏块层的第一个句法元素,它描述跟整个宏块有关的基本的类型信息。在不同的片中,mb_type的定义是不同的,下面我们分别讨论I、P、B片中这个句法元素的意义。
(1)I片中的mb_type,具体语义见表6.27。
表6.27 I片中的mb_type
表中,Intra_4×4表示使用帧内4×4预测,Intra_16×16表示使用帧内16×16预测。当使用帧内16×16时,类型名称由了如下的结构组成:
I_16×16_x_y_z
其中,x对应于表中“帧内16×16的预测模式”字段的值,y对应于表中“色度CBP”字段的值,z对应于表中“亮度CBP”的值。
①帧内16×16的预测模式:当使用帧内16×16预测时,指定使用何种预测方式,帧内16×16共有4种预测模式,第7章中会详细介绍这些预测模式的算法。
②CodedBlockPatternLuma:指定当前宏块色度分量的CBP,CBP(CodedBlockPattern)是指子宏块残差的编码方案。该变量详细语义见coded_block_pattern条目。
③亮度CBP:指定当前宏块亮度分量的CBP,详细语义见coded_block_pattern条目。
我们看到,帧内16×16宏块类型的mb_type语义原比其他宏块类型的复杂,这是因为当使用帧内16×16时,整个宏块是一个统一的整体,宏块中各子宏块、4×4小块的预测模式信息都是相同的,所以可以把这些信息放入mb_type,以减少码流。其他宏块类型的这些信息必须在各子块中另外用句法元素指明。
(2)P片中的mb_type,具体语义见表6.28。
表6.28 P片中的mb_type
在表6.28中,Pred_L0表示用参考列表L0,即前向预测。P片中的宏块类型可参见表6.28和表6.27。当mb_type值为0~4时,mb_type的含义见表6.28;当mb_type值为5~30时,mb_type的含义见表6.27,用mb_type值减5所得值来进行查找。预测模式(mb_type,n)预测模式是mb_type的函数,n是宏块的第n个分区。
(3)B片中的mb_type,其具体语义见表6.29。
表6.29 B片中的mb_type
B片中的宏块类型可参见表6.29和表6.27。如果当前宏块是属于B片且mb_type值为0~22,mb_type的含义见表6.29;当mb_type值为23~48时,mb_type的含义见表6.27,用mb_type值减23所得值来进行查找。
表中,Pred_L0表示使用L0,即前向预测;Pred_L1表示使用L1,即后向预测;Bipred表示双向预测;Direct表示直接预测模式。预测模式(mb_type,n)是mb_type的函数,n是宏块的第n个分区。
pcm_alignment_zero_bit 其值等于0。
pcm_byte[i] 像素值。前256个pcm_byte[i]的值代表亮度像素的值,下一个(256×(ChromaFormatFactor-1))/2个pcm_byte[i]的值代表Cb分量的值。最后一个(256×(Chroma FormatFactor-1))/2个pcm_byte[i]的值代表Cr分量的值。
coded_block_pattern 即CBP,指亮度和色度分量的各小块的残差的编码方案,所谓编码方案有以下几种:
(1)所有残差(包括DC、AC)都编码;
(2)只对DC系数编码;
(3)所有残差(包括DC、AC)都不编码。
这个句法元素同时隐含了一个宏块中亮度、色度分量的CBP,所以第一步必须先分别解出各分量各自CBP的值。其中,两个色度分量的CBP是相同的。变量CodedBlockPatternLuma是亮度分量的CBP,变量CodedBlocPatternChroma是色度分量的CBP。
对于非Intra_16×16的宏块类型:
CodedBlockPatternLuma=coded_block_pattern% 16
CodedBlockPatternChroma=coded_block_pattern / 16
对于Intra_16×16宏块类型,CodedBlockPatternLuma 和CodedBlockPatternChroma 的值不是由本句法元素给出,而是通过mb_type得到。
①CodedBlockPatternLuma:是一个16位的变量,其中只有最低四位有定义。由于非Intra_16×16的宏块不单独编码DC系数,所以这个变量只指明两种编码方案:残差全部编码或全部不编码。变量的最低位比特从最低位开始,每一位对应一个子宏块,该位等于1时表明对应子宏块残差系数被传送;该位等于0时表明对应子宏块残差全部不被传送,解码器把这些残差系数赋为0。
②CodedBlockPatternChroma:当值为0、1、2时有定义,见表6.30。
表6.30 CodedBlockPatternChroma的定义
mb_qp_delta 在宏块层中的量化参数的偏移值。mb_qp_delta值的范围是[-26,+25]。量化参数是在图像参数集、片头、宏块分三层给出的,最终用于解码的量化参数由以下公式得到:
QPY=(QPY,PREV+mb_qp_delta+52)% 52
其中,QPY,PREV是当前宏块按照解码顺序排列的前一个宏块的量化参数,我们可以看到,mb_qp_delta所指示的偏移是前后两个宏块之间的偏移。片中第一个宏块的QPY,PREV是由下式给出:
QPY,PREV=26+pic_init_qp_minus26+slice_qp_delta
6.3.10 宏块预测的语义
prev_intra4×4_pred_mode_flag[luma4×4BlkIdx] rem_intra4×4_pred_mode[luma4×4BlkIdx]
帧内预测模式也是可以预测的,句法元素prev_intra4×4_pred_mode_flag用来指明帧内预测中亮度分量的预测模式的预测值是否是实际预测模式。如果是,就不需另外再传预测模式;如果不是,就由rem_intra4×4_pred_mode指定实际预测模式。
intra_chroma_pred_mode 在帧内预测时指定色度的预测模式,具体语义见表6.31。
表6.31 intra_chroma_pred_mode的语义
ref_idx_10[mbPartIdx] 用参考帧列表L0进行预测时,即前向预测时,参考图像在参考帧列表中的序号。其中mbPartIdx是宏块分区的序号。
如果当前宏块是非场宏块,则ref_idx_10[mbPartIdx]值的范围是[0, num_ref_idx_10_active_minus1]。
如果当前宏块是场宏块(宏块所在图像是场,当图像是帧场自适应时当前宏块处于场编码的宏块对),ref_idx_10[mbPartIdx]值的范围是0到2×num_ref_idx_10_active_minus1+1,如前所述,此时参考帧队列的帧都将拆成场,故参考队列长度加倍。
ref_idx_11[mbPartIdx] 语义同上,只是这个句法元素用于参考帧列表L1,即后向预测。
mvd_10[mbPartIdx][0][compIdx] 运动矢量的预测值和实际值之间的差。mbPartIdx是宏块分区的序号。compIdx=0时为水平运动矢量,compIdx=1时为垂直运动矢量。
mvd_11[mbPartIdx][0][compIdx] 语义同上,只是这个句法元素用于L1,即后向预测。
6.3.11 子宏块预测的语义
子宏块预测的句法元素的语法如下:
sub_mb_type[mbPartIdx] 指明子宏块的预测类型,在不同的宏块类型中,这个句法元素的语义不一样。
(1)P宏块
P宏块中的子宏块类型见表6.32。
表6.32 P宏块中的子宏块类型
(2)B宏块
B宏块中的子宏块类型见表6.33。
表6.33 B宏块中的子宏块类型
ref_idx_10[mbPartIdx] 与6.3.10节中定义的ref_idx_10相同。
ref_idx_11[mbPartIdx] 与6.3.10节中定义的ref_idx_11相同。
mvd_10[mbPartIdx][subMbPartIdx][compIdx] 与6.3.10节中定义mvd_10相同,除了subMbPartIdx(子宏块中的索引值)。
mvd_11[mbPartIdx][subMbPartIdx][compIdx] 同上,用于L1。
6.3.12 用CAVLC方式编码的残差数据的语义
coeff_token 指明了非零系数的个数,拖尾系数的个数。
trailing_ones_sign_flag 拖尾系数的正负符号。
如果trailing_ones_sign_flag=0,相应的拖尾系数是+1;
如果trailing_ones_sign_flag=1,相应的拖尾系数是-1。
level_prefix和level_suffix分别表示非零系数值的前缀和后缀。
total_zeros 系数中0的总个数。
run_before 在非零系数之前连续零的个数。
6.3.13 用CABAC方式编码的残差数据的语义
coded_block_flag 指出当前块是否包含非零系数。
如果coded_block_flag=0,这个块不包含非零系数;
如果coded_block_flag=1,这个块包含非零系数。
significant_coeff_flag[i] 指出在位置为i处的变换系数是否为零。
如果significant_coeff_flag[i]=0,在位置为i处的变换系数为零;
如果significant_coeff_flag[i]=1,在位置为i处的变换系数不为零。
last_significant_coeff_flag[i] 表示当前位置i处的变换系数是否为块中最后一个非零系数。
如果last_significant_coeff_flag[i]=1,这个块中随后的系数都为零;
否则,这个块中随后的系数中还有其他的非零系数.
coeff_abs_level_minus1[i] 系数的绝对值减1。
coeff_sign_flag[i] 系数的符号位。
coeff_sign_flag=0,正数;
coeff_sign_flag=1,负数。
6.4 总结
H.264 的句法是经过精心设计的,构成句法的各句法元素既相互依赖又相互独立。依赖是为了减少冗余信息,提高编码效率;而独立是为了使通信更加可靠,在错误发生时限制错误的扩散。但是,依赖和独立又是矛盾的,往往要在它们之间作取舍。在实现H.264的编解码器时,同样有速度和健壮性这样一组矛盾的关系,既要在现有硬件平台上提高编解码的速度,又要作充分的安全检查,建立异常处理机制。如果能详细考察句法元素间的依赖与独立关系,充分利用H.264各句法元素间本身的内在联系与安全机制,便能够设计出既快速,又安全、健壮的编解码算法。
参考文献
[1]Draft ITU-T recommendation and final draft international standard of joint video specification(ITU-T Rec. H.264/ISO/IEC 14 496-10 AVC. In Joint Video Team (JVT) of ISO/IEC MPEG and ITU-T VCEG, JVTG050,2003.
[2]T. Wiegand, G. J. Sullivan, G. Bjøntegaard, A. Luthra. Overview of the H.264/AVC Video Coding Standard. IEEE Trans. Circuits Syst. Video Technol., vol. 13, pp. 560–576, July 2003.
[3]S. Wenger. H.264/AVC over IP. IEEE Trans. Circuits Syst. Video Technol., vol. 13, pp. 645–656, July 2003.
[4]T. Stockhammer, M. M. Hannuksela, T. Wiegand. H.264/AVC in wireless environments. IEEE Trans. Circuits Syst. Video Technol., vol. 13, pp. 657–673, July 2003.
[5]T. Wedi. Motion compensation in H.264/AVC. IEEE Trans. Circuits Syst. Video Technol., vol. 13, pp. 577–586, July 2003.
[6]M. Flierl, B. Girod. Generalized B pictures and the draft JVT/H.264 video compression standard. IEEE Trans. Circuits Syst. Video Technol.,vol. 13, pp. 587–597, July 2003.
[7]T. Wiegand, H. Schwarz, A. Joch, F. Kossentini, G. J. Sullivan. Rate-constrained coder control and comparison of video coding standards. IEEE Trans. Circuits Syst. Video Technol., vol. 13, pp. 688–703, July 2003.
[8]Schafer Ralf, Wiegand Thomas, Schwarz Heiko. The emerging H.264/AVC Standard EBU Technical Review. Jan.2003.
[9]M. Karczewicz, R. Kurçeren. The SP and SI frames design for H.264/AVC. IEEE Trans. Circuits Syst. Video Technol., vol. 13, pp. 637–644, July 2003.
[10]H. Malvar, A. Hallapuro, M. Karczewicz, L. Kerofsky. Low-Complexity transform and quantization in H.264/AVC. IEEE Trans. Circuits Syst. Video Technol., vol. 13, pp. 598–603, July 2003.
[11]J. Ribas-Corbera, P. A. Chou, S. Regunathan. A generalized hypothetical reference decoder for H.264/AVC. IEEE Trans. Circuits Syst. Video Technol., vol. 13, pp. 674–687, July 2003.
[12]Mathias Wien. Variable Block-Size Transforms for H.264/AVC. IEEE Trans. Circuits Syst. Video Technol., vol. 13, pp. 604–613, July 2003.
[13]Michael Horowitz, Anthony Joch, Faouzi Kossentini. H.264/AVC Baseline Profile Decoder Complexity Analysis. IEEE Trans. Circuits Syst. Video Technol., vol. 13, pp. 704–716, July 2003.