【H.264/AVC视频编解码技术详解】二十二、熵编码(7):语法元素的CABAC解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shaqoneal/article/details/84637385

《H.264/AVC视频编解码技术详解》视频教程已经在“CSDN学院”上线,视频中详述了H.264的背景、标准协议和实现,并通过一个实战工程的形式对H.264的标准进行解析和实现,欢迎观看!

“纸上得来终觉浅,绝知此事要躬行”,只有自己按照标准文档以代码的形式操作一遍,才能对视频压缩编码标准的思想和方法有足够深刻的理解和体会!

链接地址:H.264/AVC视频编解码技术详解

GitHub代码地址:点击这里

在本系列的博文18中,我们讨论了算术编码的基本原理,以及实现一个简单的算术编码器内核的方法:

而在博文19和21中我们根据H.264对于CABAC的规定,讨论了语法元素二值化以及上下文概率模型的相关算法:

通过前面的研究我们已经了解,由于视频数据特殊的统计特性和对编码性能的高指标要求,CABAC的算法远远比博文18中描述的基本模型更加复杂。尽管如此,CABAC在算术编码的最核心层面依然遵循了博文18中所讲的根本原理,这一点在本文对标准协议文档的解读中也可以获得明确的证实。

一、CABAC解析(解码)的总流程

CABAC的解码过程定义与标准协议文档的9.3.3.2节。CABAC解码过程所需要的输入数据包括前一章所推导出的上下文模型索引ctxIdx、旁路模式标志bypassFlag,以及解码器引擎的状态。下图表示了CABAC解码过程的概念框图:

在上图中可以看出,根据参数的不同,CABAC解码总共可能有三种运行流程:

  • DecodeBypass: 当旁路模式标志bypassFlag为1时执行,表示旁路模式的解析过程;
  • DecodeDecision: 当bypassFlag为0且ctxIdx不为276时执行,表示CABAC解析过程;
  • DecodeTerminate: 当bypassFlag为0且ctxIdx==276时执行,表示解析终结码的过程;

在这三种执行流程中最重要的就是第二种——DecodeDecision。接下来本文将从DecodeDecision开始分析这三种解析过程。

二、CABAC算术编码的解码(解析)过程

本节描述的即是DecodeDecision部分的方法。这一部分也是CABAC算法中最为重要的部分,H.264的main、high profile中的多数语法元素都是通过该过程进行解析的。该部分在标准协议文档的9.3.3.2.1中定义。

从标准协议中的该节内容中可知,该过程所需要的数据有ctxIdx, codIRange 和 codIOffset,其中ctxIdx由前一章《CABAC的上下文概率模型》中的方法推导,codIRange 和 codIOffset的初始值由CABAC解码器引擎的初始化确定。输出的数据包括解析出来的语法元素比特位值binVal,以及更新过的codIRange 和 codIOffset。

该过程的整体流程如下图所示:

2.1 计算 codIRangeLPS

计算 codIRangeLPS 的过程遵循以下流程:

  1. 根据当前的codIRange值,计算qCodIRangeIdx的值:
    • qCodIRangeIdx =( codIRange >> 6 ) & 3
  2. 通过 qCodIRangeIdx 和 pStateIdx,计算 codIRangeLPS 的值:
    • 通过查表获取:codIRangeLPS = rangeTabLPS[ pStateIdx ][ qCodIRangeIdx ]
    • rangeTabLPS为预定义的表,在表9-44中指定;

2.2 更新 codIRange

更新 codIRange 的方法为:

codIRange = codIRange - codIRangeLPS;

更新完成后,判断 codIOffset,如果 codIOffset >= codIRange,输出比特位值binVal赋值为1 - valMPS,并且codIOffset自减去codIRange的值,然后codIRange的值赋值为codIRangeLPS;否则,输出比特位值binVal赋值为valMPS。

2.3 状态转移过程

在CABAC编码或解码语法元素的某一个bit,编码/解码器将随之更新编解码器的状态。状态转移过程定义于标准的9.3.3.2.1.1节。该过程根据当前的上下文模型索引和解码的比特值,来更新上下文模型索引以及LPS/MPS的定义。

状态转移过程可以下式表示:

if( binVal = = valMPS )
    pStateIdx = transIdxMPS( pStateIdx )
else {
    if( pStateIdx = = 0 ) {
        valMPS = 1 − valMPS   
    }
    pStateIdx = transIdxLPS( pStateIdx )
}

在编码过程中上下文模型索引的更新同样以查表的形式实现,该表格在9-45中规定。

2.4 归一化过程

在第18篇博文“算术编码的基本原理中”已经讨论过算术编码器的归一化。在H.264实际定义的CABAC算法中,归一化同样也是必备过程。CABAC的归一化过程定义于9.3.3.2.2节,流程图以下图表示:

进行归一化的本质含义是更新codIRange和codIOffset的值,所需要的数据包括当前CABAC的codIRange和codIOffset以及当前的二进制比特流数据。主要步骤为:

  • 判断如果codIRange不小于256,那么不需要进行归一化;
  • 如果codIRange小于256,则进行归一化过程,方法为:
    1. codIRange和codIOffset分别自乘以2;
    2. 在码流中读取 1 bit,并与codIOffset按位取或运算并更新到codIOffset;

三、CABAC的bypass解析方法

本节描述的是CABAC的DecodeBypass方法,即旁路解析模式,在bypass值设为1时执行。DecodeBypass相比DecodeDecision方法的特点是编码效率较低但运算远比DecodeDecision简单。与DecodeDecision过程相比,DecodeBypass不需要ctxIdx,只需要codIRange和codIOffset两个值。

DecodeBypass过程的流程图如下:

解析过程为:

  1. 首先codIOffset自增一倍,并且从码流中读取1 bit与之求按位或操作;
  2. codIOffset与codIRange对比:
    • 若codIOffset小于codIRange,输出二进制位0;
    • 否则,输出二进制位1,且codIOffset自减去codIRange的值;

四、CABAC的终止符解析

CABAC的终止符解析即DecodeTerminate过程,主要用于解析end_of_slice和ctxIdx值为276的元素。解析的方法类似于DecodeBypass过程,流程如下:

  1. 首先codIOffset自减2;
  2. codIOffset与codIRange对比:
    • 若codIOffset小于codIRange,输出二进制位0,并执行解码器的归一化过程;
    • 否则,输出二进制位1;

猜你喜欢

转载自blog.csdn.net/shaqoneal/article/details/84637385