您的位置:首页 > 其它

AVS-CABAC算法原理简介2

2014-09-23 15:54 246 查看
CABAC是H264的一种熵编码方案,相比如H264的另外一种熵编码方案CAVLC而言,在可接受的视频质量(30dB到38dB之间)内变化时,前者可节约平均9%到14%的码流。CABAC有以下几个特性:

1, 对多数符号使用了自适应概率模型。

2, 通过使用上下文关系,利用了符号相关性。

3, 限制为二进制算术编码(binary arithmetic coding),基于只用查表和移位方式的快速二进制算术编解码器。(CABAC本来是非常耗时的一种算法,在h264中应用了查表的方法,节约了很多的时间)

4, 399 种预定义的上下文模型,分成了各种不同的模型组,例如模型 14-20 用于帧间宏块类型的编码,模型的选择基于前面编码的信息(上下文关系),每个上下文模型适应实验分布。(每一种语法元素对应的上下文模式都是对应好了的,遵循一定得规则)

先大致介绍CABAC的实现过程,然后对一些技术做细节介绍

下面是CABAC的编码流程图



1,转化成二进制(Binarization)

CABAC使用二值算术编码,也就是说只对二进制的判决(0或者1)进行编码。非二进制符号(例如转换后的系数或者运动矢量)在编码前先要进行二进制转换。这一过程和变长编码(VLC)中将信息符号转化为变长编码一样,所不同的是,算术编码器在将信息送去传输之前还要进一步对这些二进制符号进行编码。 

2, 选择基于内容的模型:

“基于内容的模型”是二进制符号中一个或多个比特的概率模型。根据对先前已编码符号的统计,从可选模型中选择适当的概率模型。(根据与同一片中语法元素的类型,周围编码块的情况,编码过程中同一SE的值...有相应的规则,遵循即可)

3, 算术编码:

根据选择的概率模型对每个比特进行算数编码。

4, 更新模型

上图中的bypass coding是指对于一些特定语法元素的二进制比特符号,为了加快编码速度而不使用上下文模型的形式,也就没有相应的更新模式的过程

使用CABAC的熵编码方式在时间耗费方面大于CAVLC,为了达到一个折中,在实际编码中,并不是对所有的语法元素都使用CABAC编码方案,有许多表征视频序列本身固有参数特征的语法元素的熵编码还是使用CAVLC。下图是一些需要用CABAC编码的语法元素及对应的上下文模型索引。

在实际工程中一般头文件信息如图像帧头,序列头,片头等直接用哥伦布编码等

对于一些比较复杂的元素才会选择CABAC比如 参考帧信息,运动补偿MVD,宏块类型mb_type,宏块的帧内参考模式,宏块的CBP残差,宏块的量化参数,宏块的编码残差系数等






二进制化

包括基本方案和串接方案。
Unary Binarization对于x>=0的无符号整数值,由x个”1”和一个终结符合”0”组成。
Truncated Unary Binarization(TU:给定一个参数S,对于编码符号x,0<=x<=S有效,如果x>S,则取x=S,对于x<S时,二进制串由Unary Binarization 方案给出,对于x=S,Unary Binarization 方案中的那个终结符号”0”被忽略,此时输出二进制串为x个”1”。
kth order Exp-Golom(EGK) Binarization:由一个前缀和一个后缀码字串接而成,

对于给定x,下面是产生一个k阶指数格雷码的算法

while(1){
//unary prfix part of EGK
if (x>=(1<<k)){
put(1)
x=x-(1<<k)
k++
} else {
put(0)    //terminating “0” of prefix part
while(k--) //binary suffix part of EGK
put((x>>k)&0x01)
break
}
}


Fixed-Length(FL)Binarization给定一个参数S,对于编码语法元素x,必须满足0<=x<S,输出二进制串为十进制值x对应的二进制数。
Concatenation of Basic Binarization串接方案,有以下几种组合:
1,编码coded block pattern时,cbp代表了六个8x8块的编码系数情况(4个亮度,2个色度,具体会在后面讲到),这时候,以4-bit的FL方案产生的二进制串作为前缀表征亮度部分,以S=2的TU方案产生的二进制串作为后缀表征色度部分。

2,Unary/kth order Exp-Golomb(UEGK),这种串接方式应用于mvd和变换系数的绝对值的二进制化。对于mvd, 前缀是S=9,x=min(|mvd|,9)的TU方式。当|mvd|>9时,后缀是x=|mvd|-9的EG3的方案输出的二进制串,mvd的符号为正时用”1”表征,为负时用”0”表征,当0<|mvd|<9时,后缀仅由表征mvd符号的比特生成。

3,对于变换系数绝对值的二进制化,前缀采用S=14的TU方式,后缀采用EG0方式,注意此时二进制化的语法元素coeff_abs_value_minus1=abs_level-1,对于abs_level=0的情况,我们用一个significance map将其处理了。这和二进制化mvd比较相似,但此时并没有处理符号,符号是后面要单独处理的。

具体针对每一种语法元素会有相应的规则,我也没有具体对这些规则进行总结,但是上面的情况已经包含了大部分二进制话的情况了

上下文模型

假设对已编码符号有一个预定义的集T,即所谓的上下文模版,有一个上下文的相关集C={0,1,…,C-1}给出,这个上下文是通过操作在T上的一个模型函数F:T--->C所定义的。对每一个即将要编码的符号x,可以利用它的已经编码的相邻符号 的概率模型来估计一个条件概率p(x|F(z)),在CABAC中,符号是二进制形式,而且通过选择少数的上下文C使得算法变得更为简单。

CABAC中有四种上下文模型的设计方式:

第1种类型的模型必须根据它相邻的已编码的语法元素构成,一般是其左边和上边的对应语法元素来建立相应的概率模型,对当前语法元素进行模型预测。

第2种模型仅局限于对宏块类型和子宏块类型的应用,其中第n比特的概率模型的选定要参考前面已编码n-1比特所采用的模型。

第3种和第4种模型仅用于残余数据的编码,这两种模型都依赖编码块的类型,其中第3种模型依赖的不是已编码的系数,而是系数在扫描路径中的位置。第4种模型则要计算该比特所在系数之前已编码的系数数目。在CABAC中除了这些条件上下文模型之外,还有一些固定概率模型,它们对待编码的比特提供固定的概率预测,已编码比特的模型不加以应用。

在编码中针对不同的语法元素遵循相关的规则,选择对应的语法模式就好了

首先需要在程序中定义一些语法元素的模型

typedef struct {
BiContextType mb_type_contexts [4][NUM_MB_TYPE_CTX];
BiContextType pdir_contexts    [4][NUM_INTER_DIR_CTX];
BiContextType amp_contexts     [3][NUM_AMP_CTX];
BiContextType b8_type_contexts [2][NUM_B8_TYPE_CTX];
BiContextType mv_res_contexts  [2][NUM_MV_RES_CTX];
BiContextType ref_no_contexts  [2][NUM_REF_NO_CTX];
BiContextType delta_qp_contexts[NUM_DELTA_QP_CTX];

} MotionInfoContexts;

typedef struct {
BiContextType  ipr_contexts [NUM_IPR_CTX];
BiContextType  cipr_contexts[NUM_CIPR_CTX];
BiContextType  cbp_contexts [3][NUM_CBP_CTX];
BiContextType  one_contexts [NUM_BLOCK_TYPES][NUM_ONE_CTX];
BiContextType  abs_contexts [NUM_BLOCK_TYPES][NUM_ABS_CTX];
BiContextType  map_contexts [NUM_BLOCK_TYPES][NUM_MAP_CTX];
BiContextType  last_contexts[NUM_BLOCK_TYPES][NUM_LAST_CTX];
BiContextType  split_contexts [NUM_BLOCK_TYPES][NUM_SPLIT_CTX];
BiContextType  tu_contexts [NUM_BLOCK_TYPES][NUM_TU_CTX];
} TextureInfoContexts;


具体的数据结构根据具体情况而定

if (!biari_decode_symbol(dep_dp, &ctx->mv_res_contexts[k][act_ctx])) {
act_sym = 0;
} else if (!biari_decode_symbol(dep_dp, &ctx->mv_res_contexts[k][3])) {
act_sym = 1;
} else if (!biari_decode_symbol(dep_dp, &ctx->mv_res_contexts[k][4])) {
act_sym = 2;
} else if (!biari_decode_symbol(dep_dp, &ctx->mv_res_contexts[k][5])) {  //1110
act_sym = 0;


上面就是我们在解mvd时选择语法模型的一个视图

A. 概率模型的更新

 


上面是LPS的概率状态转移图,概率的状态转移遵循以下原则

为了减少乘法运算带来的复杂度,将概率转移转化为概率索引的转移,又将的转移用两个数组表示出来

const UChar g_aucACNextStateMPS64[64] =

{1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,  21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,

41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,62,63};

   

const UChar g_aucACNextStateLPS64[64] =

{  0, 0, 1, 2, 2, 4, 4, 5, 6, 7,8, 9, 9,11,11,12,13,13,15,15,  16,16,18,18,19,19,21,21,22,22,23,24,24,25,26,26,27,27,28,29,

    29,30,30,30,31,32,32,33,33,33,34,34,35,35,35,36,36,36,37,37,37,38,38,63};

   

由数组可看出,当前字符为MPL时,LPS的状态索引只是简单地加1

但当前字符为LPS的时候,的改变就复杂多了。

需要注意的是,当在=62处,在这里LPS的概率到达最小,或者说MPS的最大概率到达,如果这时候即将编码的仍然是一个MPS,则概率索引值62将不会改变,除非有一个LPS出现,这时候按照LPS的状态转移规则进行转移,我们可以看到,这时候状态63实际上是没有用到的。当在=0的时候,当前即将编码符号仍然是LPS,则状态索引不变,但模型的MPS值将要改变,这就导致了随后的LPS与MPS定义的交换

在AVS当中,CABAC的原理和h264的原理有很多相似的地方,比如流程框架图基本是一样的,在二进制化和上下文选择上可能选用的规则有所不同,但是大体上是吻合的,但是在最后的概率更新上有很大的不同

在AVS中,因为在概率更新中用到了较多的乘法,因此AVS中将运算转化到对数域

详情可参考《AVS技术创新报告》一书,讲解的还算详细

typedef struct {
unsigned int  LG_PMPS;
unsigned char MPS;
unsigned char cycno;
} BiContextType;


是AVS中的算数编码的一个基本数据结构

对数域上的大概率取值(10bit)

MPS:目前大概是1,or 0(1 bit)

cycno: 当前语法元素转换为二进制流进行算数编码时的码字循环情况,这个数据和概率更新有着明显的关系
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  h264 AVS CABAC