HEVC的算数编码

2024-02-12 09:38
文章标签 编码 算数 hevc

本文主要是介绍HEVC的算数编码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【重头戏,视频编码中最难啃的硬骨头,或许没有之一。今天这个还是文献的阅读记录,后面几篇会深入挖掘它的参考文献和JCT-VC的相关提案,争取借这次机会彻底把视频编码中的算数编码搞懂。这次的参考文献是:High Throughput CABAC Entropy Coding in HEVC,IEEE TRANSACTIONS ON CIRCUITS AND SYSTEMS FOR VIDEO TECHNOLOGY, VOL. 22, NO. 12, DECEMBER 2012。】
HEVC的算数编码

H.264和HEVC采用了CABAC以极大幅度地提高了算法的压缩比率。由于H.264中所采用的算法存在较强的数据依赖性,因此算法的数据吞吐量收到一定的限制。在HEVC中采用的CABAC算法充分考虑了算法的压缩比率和并行化程度。经过优化的CABAC可以在保持相当高的压缩比率的同时,显著提高处理速度并降低了硬件处理的需求。

1、CABAC熵编码
熵编码是视频编码的最后一步和解码的第一步所使用的一种无损编码。熵编码所处理的对象,是在前期的预测、变换阶段所产生的一系列语法元素(Syntax Elements),包括预测模式和残差数据等。这些语法元素描述了CU,PU,TU和LF等多种语法元素的特性。对CU,有块结构信息以及帧内/帧间预测模式;对PU,描述了帧内预测模式和运动信息等;对TU,主要包含残差信息的变换系数等;LF语法元素在每一个最大编码单元LCU中传输一次,描述了环路滤波中SAO的类型和偏移量。CABAC主要包括三大步骤,即二值化、上下文建模和算数编码。
(1)二值化。
二值化的作用是将语法元素映射为二进制符号(bin)。HEVC中的二值化采用几种不同的方式,与H.264类似,主要有一元(Unary),截断一元(Truncated Unary),k阶指数哥伦布编码(EGK)和定长(Fixed Length)。这几种不同模式的区别体现在将某个无符号整数N二值化的结果的不同,具体如下图所示:
【HEVC学习与研究】19、HEVC的算数编码
该表中的例子表述了大部分情况所采用的二值化方法,另外可能存在多种方法的组合,以及一些特定化的二值化方法。在实际应用中,具体采用哪一种二值化模式取决于语法元素的类型,或者之前处理过的语法元素的值以及条带参数中的设置。
(2)上下文模型
CABAC之所以在压缩比率上可以取得巨大提高,关键就是因为上下文模型的引入为编码过程提供了精确的概率估计。CABAC采用的上下文模型是高度自适应的,不同二进制码元采用的模型不同,而且可以依据之前处理的二值化码流进行模型更新。每一个bin的上下文模型的选择依据包括语法元素类型、bin的位置、亮度/色度和相邻块信息等。CABAC的概率模型采用7bit结构,其中6bit的概率状态位和1bit的最大概率模型位,在HEVC中其概率模型更新方法与H.264的类似,而改进了上下文选择的逻辑以提高数据处理效率。
(3)算数编码
算数编码是一种基于区间的递归划分的熵编码方法。一个初始化为[0,1]的区间根据bin的概率分布划分为两个子区间,并且依照bin的取值选取两个区间之一。该区间更新为选择的子区间,并进行下一次分割,依此循环往复。为防止下溢出,当区间长度小于某个值时,停止递归并重新进行区间归一化。
在编码的过程中,可以使用概率估计(上下文编码)和等概率模式(旁路编码)。旁路编码中,区间划分由某个偏移量实现,而上下文编码的bin需查表。HEVC的编码过程与H.264类似。

2、CABAC的输出瓶颈
下图为CABAC解码器中的反馈环路。由该图中可以看出主要存在一下几种反馈机制:
(1)递归区间分割中的区间范围更新;(2)精确概率估计对上下文的更新;(3)上下文的选择依赖于语法元素的类型;(4)上下文的选择依赖于bin在语法元素中的位置。
【HEVC学习与研究】19、HEVC的算数编码
在上图中,1、2环路比较简单,因此对吞吐量没有造成过大影响。如果某一个bin的上下文依赖于并行处理的另一个bin,则会造成较大影响。随着并行bin个数的增加,“预测运算”量将会呈指数增长。因此,吞吐量的瓶颈主要在于上下文选择过程中的依赖性。

3、HEVC的CABAC所做的改进
为提高数据的吞吐量,HEVC主要在前期的CABAC的基础上做了如下改进:
(1)减少上下文编码的bin数量;上下文编码所带来的数据依赖性限制了数据吞吐量,而旁路编码由于没有因为上下文选择带来的数据依赖问题所以更适于并行处理。另外,由于不需要查表,旁路模式的算数编码过程也更为简单。
(2)聚合旁路编码的bin;比特流中连续出现的一串旁路编码bin可以在同一个循环中进行处理。
(3)聚合相同上下文的bin;参考相同上下文的bin聚合在一起,可以减少“预测运算”,同时减少上下文切换次数。
(4)减少上下文选择的依赖性;由于上下文选择过程中的数据依赖性,循环解码多个bin需要大量“预测操作”;减少此类依赖性可以简化上下文选择的过程并减少“预测操作”数量。
(5)减少bin的总量;主要考虑降低算数编码本身的负载;
(6)减少解析的依赖性;尽量隔离CABAC解析同其他所有的处理过程;
(7)减少内存需求;减少内存的需求也就是降低了内存的存取时间;

4、编码预测单元PU
PU中主要包含了帧内和帧间预测信息,并取得了比H.264更高的编码效率。
(1)对运动信息的编码
该部分主要包括减少解析块合并的依赖、减少运动矢量预测的依赖、减少上下文编码bin和减小内存需求。
①减小块合并的依赖:
HEVC中的块合并功能可以通过时空邻域信息获取预测方向、参考索引和运动矢量等运动信息。在该模式中,merge_idx表示该从哪一个候选中获取运动信息,该变量采用截断一元编码。理论上其最大长度cMax应设为PU中用于合并的候选列表的长度。但是这需要建立列表以获取表长度,增加解析过程的依赖性。另外,建立候选块列表所需的运算量也相当大,因此该方法效果不佳。
在HEVC中cMax在条带头中标记,并不依赖与表的长度。为了弥补定长cMax带来的效率损失,在表长度不足的情况下,将联合/零合并候选块加入表中。
②减小运动矢量预测的依赖:
在未开启块合并模式下,运动矢量由邻域块的MV进行预测,并通过MVP和MVD记录。在H.264中采用了单一MV预测,采用左、上和右上三个方向的邻域块的中值作为运动矢量预测值;在HEVC中采用了“先进运动矢量预测”(AMVP)的方法,从时间和空间邻域中选定多个候选块数据,经过优化处理,保留两个较优的候选块。mvp−l0−flag标识哪一个候选的MV选作了MVP,并且即使列表中只有一个候选块该标识也会存在。默认候选为0矢量,因此列表永不为空。
③减少上下文编码的bin:HEVC中,上下文编码的bin被极大减少,对MVD的编码,只有前两个bin是上下文编码,其余是一阶指数哥伦布编码bin的旁路编码。
④减少内存需求:HEVC通过改进上下文选择的逻辑,减少了行缓存大小。通过对比每个邻域块的MV信息和阈值16的比较来选择上下文,可以将每个邻域块的MV缓存需求减少1bit。
⑤聚合旁路编码bin:mvd的x和y分量的旁路编码bin将聚合在一起进行处理,以最大化快速旁路编码的效率。
(2)帧内模式的编码
HEVC采用了新的最大概率模式提高编码效率,采用定长为3的由左、上邻域块构建的候选表(可以加入DC、平面等候补选择)。如果采用最大概率模式,使用mpm_idx变量说明采用了哪一个候选。
与帧间模式的编码类似,CABAC编码帧内信息曹勇了减少上下文编码bin和聚合旁路编码bin等技术。

5、编码变换单元TU
在CABAC中,变换系数的位置以“关键度表”的形式编码,关键度表表明了非零系数的位置。系数的level信息只在大于1的系数信息中包含,而所有非零系数信息都包含系数的符号。
(1)关键度表:
在H.264中,会传递一个标志位significant_coeff_flat(SCF)来指示每一个非零系数(采用之字形扫描),随后会传递一个标志last_significant_coeff_flag指示当前是否是最后一个SCF。对4×4和8×8TU中不同位置以及bin是否表示SCF和LSCF,采用不同的上下文。SCF和LSCF是交错分布的,因此在上下文选择过程中,H.264的算法存在大量的二进制依赖关系。
为了减小这种依赖关系,HEVC采用了减少参考邻域的做法,在HM模型不同的阶段,采用了10、8、6、5个等不同的参考邻域。在HM2.0及其以前的版本中,由于关键度表采用之字形扫描,所以取消对角方向的块作为参考邻域会造成比较明显的影响。
在HM4.0模型中,采用了对角线扫描的方式处理SCF。此方法对编码效率有一定的影响,但是却解除了SCF处理中的依赖关系。在HM7.0中,对16×16和32×32TU进行了分割处理,将TU分割成了4×4的子块,并引入了coded_sub_block_flag这个参数。在HM8.0中8×8TU也被分割成了4×4子块,因此之后所有的TU都是基于4×4子块组成的。
在对8×8、16×16和32×32TU的处理中,每个块都被划分为DC、低频区和高频区三部分,每部分都采用不同的上下文。同时为了节约内存,16×16和32×32的SCF共享内存空间。
对于处理帧内预测的CU时,引入了一种“依赖模式系数扫描”(MDCS),根据帧内预测模式选择水平、垂直和对角线扫描。
“最末位”编码:
由于H.264的SCF和LSCF相互交错,它们之间存在较强的相互依赖性。主要解决方法有:将数个SCF组合,并为这N个SCF传递一个LSCF;或者避免将SCF和LSCF交替出现;以及将一个LSCF分离成x,y两个分量传输。“最末位”由一个前缀和后缀两部分组成。前缀对x和y分别采用cMax的截断一元编码码,以TU的宽度和高度为上下文;后缀采用定长旁路编码。
编码子块标志位(CSBF):
每一个TU被分割成4×4大小的子块。CSBF用于标识某个子块是否包含非零系数。若该参数为1,则该子块中含有SCF;反之,若子块中仅仅包含0系数,则不存在SCF的值。该方法在HM7.0中扩展,用以降低16×16和32×32TU的上下文选择中的依赖性,并且在HM8.0中应用到了8×8TU中。同时,分别采用了四种模式,将不同位置的邻域子块中的元素同上下文模型的选择结合,以解除对其的依赖性。
(2)系数的等级和符号
在H.264中,系数等级由两部分组成。前14位由截断一元二值化生成,采用上下文编码,剩余位由0阶指数哥伦布编码产生,采用旁路编码。在系数等级编码完成后,采用旁路编码处理系数的符号。
①等级编码:
在HEVC中,系数等级仅仅有前两位(coeff_abs_level_greater1_flag和coeff_abs_level_greater2_flag)采用上下文编码,剩余部分(coeff_abs_level_ramaining)采用旁路编码。这样可以极大程度地降低了整个CABAC中上下文编码的码子数量。coeff_abs_level_ramaining的前缀的二值化方法采用一元码,后缀则采用定长码,码长取决于前缀的值。同时,定长码子的数目还依赖于cRiceParam这个参数,该参数根据之前的非零系数的等级变化。coeff_abs_level_ramaining的最大取值为32.
对于每一个4×4子块而言,每一个子块最多包含8个coeff_abs_level_greater1_flag和1个coeff_abs_level_greater2_flag。减少这两个flag的数量将有效减少上下文的的数量。
对系数等级进行上下文选择,主要经过以下步骤:
1)对子块中的16个系数进行扫描;——>2)根据前一个子块中大于1的系数的个数,为当前子块选定上下文集合;——>3)根据当前块内的1系数,在集合中选择上下文模型。
在HM3.0中,每个上下文集合包含5个上下文,共6种集合备选;低频/非低频部分,亮度/色度分量,以及coeff_abs_level_greater1_flag和coeff_abs_level_greater2_flag均需要不同的上下文,因此共需要120种不同的上下文模型。而发展到了HM6.0,所需的上下文模型减少到了仅需要30个。
②符号编码:
每一个4×4子块内的16个系数的符号被聚合在一起处理,这些系数的符号位码元位于coeff−abs−level−remaining的码元之前,并且在该元素解码完成之后可以立刻获取。
除此之外,还采用了数据隐藏的方法提高编码的效率。若一个子块内非0系数的个数超过了某一阈值,则符号位可由非零系数个数的奇偶性推测。

这篇关于HEVC的算数编码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/702292

相关文章

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

form表单提交编码的问题

浏览器在form提交后,会生成一个HTTP的头部信息"content-type",标准规定其形式为Content-type: application/x-www-form-urlencoded; charset=UTF-8        那么我们如果需要修改编码,不使用默认的,那么可以如下这样操作修改编码,来满足需求: hmtl代码:   <meta http-equiv="Conte

4-4.Andorid Camera 之简化编码模板(获取摄像头 ID、选择最优预览尺寸)

一、Camera 简化思路 在 Camera 的开发中,其实我们通常只关注打开相机、图像预览和关闭相机,其他的步骤我们不应该花费太多的精力 为此,应该提供一个工具类,它有处理相机的一些基本工具方法,包括获取摄像头 ID、选择最优预览尺寸以及打印相机参数信息 二、Camera 工具类 CameraIdResult.java public class CameraIdResult {

Python字符编码及应用

字符集概念 字符集就是一套文字符号及其编码的描述。从第一个计算机字符集ASCII开始,为了处理不同的文字,发明过几百种字符集,例如ASCII、USC、GBK、BIG5等,这些不同的字符集从收录到编码都各不相同。在编程中出现比较严重的问题是字符乱码。 几个概念 位:计算机的最小单位二进制中的一位,用二进制的0,1表示。 字节:八位组成一个字节。(位与字节有对应关系) 字符:我们肉眼可见的文字与符号。

在Eclipse环境下修改Tomcat编码的问题

问题: 由于BMS需要设置UTF-8编码,要不就会出现中文乱码问题; 一、项目保持UTF-8格式; 二、由于可能会多次移除项目、加载项目,不想每次都要修改tmp0\conf 原因: 如果在eclipse中配置了tomcat后,其实,tomcat所用的所有tomcat配置文件,都不是catalina_home/config下面的xml文件,而是在eclipse所创建的Serve

在Unity环境中使用UTF-8编码

为什么要讨论这个问题         为了避免乱码和更好的跨平台         我刚开始开发时是使用VS开发,Unity自身默认使用UTF-8 without BOM格式,但是在Unity中创建一个脚本,使用VS打开,VS自身默认使用GB2312(它应该是对应了你电脑的window版本默认选取了国标编码,或者是因为一些其他的原因)读取脚本,默认是看不到在VS中的编码格式,下面我介绍一种简单快

霍夫曼编码/译码器

赫夫曼树的应用 1、哈夫曼编码   在数据通信中,需要将传送的文字转换成二进制的字符串,用0,1码的不同排列来表示字符。例如,需传送的报文为“AFTER DATA EAR ARE ART AREA”,这里用到的字符集为“A,E,R,T,F,D”,各字母出现的次数为{8,4,5,3,1,1}。现要求为这些字母设计编码。要区别6个字母,最简单的二进制编码方式是等长编码,固定采用3位二进制,可分别用

Base64编码 及 在HTML中用Base编码直接显示图片或嵌入其他文件类型

1.为什么要用到BASE64编码的图片信息      Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一。Base64 主要不是加密,它主要的用途是把一些二进制数转成普通字符用于网络传输。由于一些二进制字符在传输协议中属于控制字符,不能直接传送需要转换一下。最常见的用途是作为电子邮件或WebService附件的传输编码.  2.base64编码定义    目前的internet

批量文件编码转换用python实现的utf8转gb2312,vscode设置特殊文件的默认打开编码

批量文件编码转换用python实现的utf8转gb2312, 任意编码之间的相互转换都是可以的.改一下下面的参数即可 convert.py文件内容如下 import osimport globimport chardet#检测文件编码类型def detect_file_encoding(file_path):with open(file_path, 'rb') as f:data = f