CABAC/CAVLCin H.264

什么是熵编码?

熵编码压缩是一种无损压缩,其实现原理是使用新的编码来表示输入的数据,从而达到压缩的效果。常用的熵编码有游程编码,哈夫曼编码和CAVLC编码等。

CAVLC

CAVLC(Context Adaptive VariableLength Coding)是在H.264/MPEG-4AVC中使用的熵编码方式。在H.264中,CAVLC以zig-zag顺序用于对变换后的残差块进行编码。CAVLC是CABAC的替代品,虽然其压缩效率不如CABAC,但CAVLC实现简单,并且在所有的H.264profile中都支持。

CAVLC的编码过程如下:

  1. 计算非零系数(TotalCoeffs)和拖尾系数(TrailingOnes)的数目。

    拖尾系数指值为+1/-1的系数,最大数目为3。如果超过3个,那么只有最后三个被视为拖尾系数。拖尾系数的数目被赋值到变量TrailingOnes。
    非零系数包括所有的拖尾系数,其数目被赋值到变量TotalCoeffs)。

  2. 计算nC(numberCurrent,当前块值)。

    nC值由左边块的非零系数nA和上面块非零系数nB来确定,计算公式为:nC=round((nA+nB)/2);若nA存在nB不存在,则nC=nA;若nA不存在而nB存在,则nC=nB;若nA和nB都不存在,则nC=0。
    nC值用于选择VLC编码表,如下图所示。这里体现了上下文相关(contextadaptive)的特性,例如当nC值较小即周围块的非零系数较少时,就会选择比较短的码,从而实现了数据压缩。

  1. 查表获得coff_token的编码。

    根据之前编码和计算过程所得的变量TotalCoeffs、TrailingOnes和nC值可以查H.264标准附录CAVLC码表,即可得出coeff_token编码序列。

  2. 编码每个拖尾系数的符号,按zig-zag的逆序进行编码。

    每个符号用1个bit位来表示,0表示“+”,1表示“—”。
    当拖尾系数超过三个时只有最后三个被认定为拖尾系数,引词编码顺序为从后向前编码。

  3. 编码除拖尾系数之外非零系数的level(Levels)。

    每个非零系数的level包括sign和magnitude,扫描顺序是逆zig-zag序。

    level的编码由前缀(level_prefix)和后缀(level_suffix)组成。前缀的长度在0到6之间,后缀的长度则可通过下面的步骤来确定:

    将后缀初始化为0。(若非零系数的总数超过10且拖尾系数不到3,则初始化为1)。

    编码频率最高(即按扫描序最后)的除拖尾系数之外的非零系数。

    若这个系数的magnitude超过某个门槛值(threshold),则增加后缀的长度。下表是门槛值的列表:

  4. 编码最后一个非零系数之前0的个数(totalZeos)。

    TotalZeros指的是在最后一个非零系数前零的数目,此非零系数指的是按照正向扫描的最后一个非零系数
    根据TotalCoeffs值,H.264标准共提供了25个变长表格供查找,其中编码亮度数据时有15个表格供查找,编码色度DC2×2块(4:2:0格式)有3个表格、编码色度DC2×4块(4:2:2格式)有7个表格。

  5. 编码每个系数前面0的数目(run_before)。

    扫描顺序为zig-zag的逆序。
    若∑[run_before]== total_zeros,则不需再计算run_before
    扫描序中的最后一个元素不需要计算run_before
    每个run_before的VLC编码取决于run_before自身及未编码的0的个数ZerosLeft。例如若ZerosLeft== 2,那么run_before只可能是0,1或2,因此使用两个bit即可表示。

CAVLC之手把手教你编码

转自:http://blog.csdn.net/sunshine1314/article/details/1685948

这篇博客使用实例对上述过程做了详细的说明,尤其是有关Levels的计算方面做了重要的补充。下面是全文的转载:

首先声明本文并不是我写的,文章来自本人同学(Sunrise),都是一起做的H264,比较了解,文章内容都是自己整理的,比较可信,因此整理到一起,我也偷个懒哈

再次声明:文中用的标准是BS的正式标准,如果大家发现序号不对,参考着改过来就是了!

编码过程:
假设有一个4*4数据块
{
   0,   3,   -1,   0,
   0,   -1,   1,   0,
   1,   0,   0,   0,
   0,   0,    0,   0
}
数据重排列:0,3,0,1,-1,-1,0,1,0……

1)初始值设定:
非零系数的数目(TotalCoeffs) = 5;
拖尾系数的数目(TrailingOnes)= 3;
最后一个非零系数前零的数目(Total_zeros) = 3;
变量NC=1;
(说明:NC值的确定:色度的直流系数NC=-1;其他系数类型NC值是根据当前块左边4*4块的非零系数数目(NA)当前块上面4*4块的非零系数数目(NB)求得的,见毕厚杰书P120表6.10)
suffixLength = 0;
i = TotalCoeffs = 5;
2)编码coeff_token:
查标准(BS ISO/IEC 14496-10:2003)Table 9-5,可得:
If (TotalCoeffs == 5 && TrailingOnes == 3 && 0 <= NC < 2)
      coeff_token = 0000 100;
      Code = 0000 100;
3)编码所有TrailingOnes的符号:
逆序编码,三个拖尾系数的符号依次是+(0),-(1),-(1);
即:
TrailingOne sign[i--] = 0;
TrailingOne sign[i--] = 1;
TrailingOne sign[i--] = 1;
Code = 0000 1000 11;
4)编码除了拖尾系数以外非零系数幅值Levels:
过程如下:
(1)将有符号的Level[i]转换成无符号的levelCode;
如果Level[i]是正的,levelCode = (Level[i]<<1) – 2; 
如果Level[i]是负的,levelCode = - (Level[i]<<1) – 1;
(2)计算level_prefix:level_prefix = levelCode / (1<<suffixLength);
       查表9-6可得所对应的bit string;
(3)计算level_suffix:level_suffix = levelCode % (1<<suffixLength);
(4)根据suffixLength的值来确定后缀的长度;
(5)suffixLength updata:
If ( suffixLength == 0 )
suffixLength++;
         else if ( levelCode > (3<<suffixLength-1) && suffixLength <6)
            suffixLength++;

回到例子中,依然按照逆序,Level[i--] = 1;(此时i = 1)
levelCode = 0;level_prefix = 0;
查表9-6,可得level_prefix = 0时对应的bit string = 1;
因为suffixLength初始化为0,故该Level没有后缀;
因为suffixLength = 0,故suffixLength++;
Code = 0000 1000 111;
编码下一个Level:Level[0] = 3;
levelCode = 4;level_prefix = 2;查表得bit string = 001;
level_suffix = 0;suffixLength = 1;故码流为0010;
Code = 0000 1000 1110 010;
i = 0,编码Level结束。
5)编码最后一个非零系数前零的数目(TotalZeros):
   查表9-7,当TotalCoeffs = 5,total_zero = 3时,bit string = 111;
   Code = 0000 1000 1110 0101 11;
6)对每个非零系数前零的个数(RunBefore)进行编码:
i = TotalCoeffs = 5;ZerosLeft = Total_zeros = 3;查表9-10:
依然按照逆序编码
ZerosLeft =3, run_before = 1         run_before[4]=10;
ZerosLeft =2, run_before = 0         run_before[3]=1;
ZerosLeft =2, run_before = 0         run_before[2]=1;
ZerosLeft =2, run_before = 1         run_before[1]=01;
ZerosLeft =1, run_before = 1         run_before[0]不需要码流来表示
Code = 0000 1000 1110 0101 1110 1101;
编码完毕。

CABAC

简介

CABAC(ContextAdaptive Binary Arithmatic Coding)也是 H.264/MPEG-4AVC中使用的熵编码算法。CABAC在不同的上下文环境中使用不同的概率模型来编码。其编码过程大致是这样:首先,将欲编码的符号用二进制bit表示;然后对于每个bit,编码器选择一个合适的概率模型,并通过相邻元素的信息来优化这个概率模型;最后,使用算术编码压缩数据。

CABAC编码详情

CABAC编码之所以能取得很高的压缩比,是因为:a)根据每一个语法元素的上下文来选取预测模型;b)使用本地的统计数据来估计概率;c)使用算术编码而不是变长编码。编码一个符号需要经过下面几步:

  1. 二值化。CABAC使用的算术编码是基于二进制的算术编码,因此非二进制形式的编码首先要转化为二进制的形式表示。

下面的2、3、4步

  1. 选择上下文模型。“上下文模型”是指对二值化后的符号中的bit位进行编码时使用的概率模型。概率模型与最近编码的符号相关,会有多个概率模型可供选择。

  2. 算术编码。算术编码器根据第2步选择的概率模型对每个bit进行编码。需要注意的是每个bit的子范围只有两个数:0和1。

  3. 更新预测模型。根据实际编码的值来更新所选择的预测模型。例如,如果所编码的二进制bit为1,则预测模型中的1计数要增加。

编码过程

下面将以mxdx为例解释编码过程,mxdx是motionvector difference in the x-direction的简写,通过宏块的子块之间运算获得。

  1. 二值化。对于|mvdx|<9的数,使用下表进行编码,超过9的数使用Exp-Golomb编码。在这里,我们称编码后的第一个bit为bin1,第二个bit为bin2,以此推之,可以得到bin3,bin4等。

  1. 为每个bin选择一个上下文模型。bin1可以在三个模型之间进行选择,选择的依据是相邻的两个mxdx的绝对值之和,ek:

e= mxdxA+ mxdxB(A和B分别是当前块的上方块和左边块)

根据ek值从下表中为bin1选择上下文模型:

除bin1之外的其它bit的上下文模型的选择根据下表进行:

  1. 编码每个bin。所选的预测模型中有0和1的概率,从而为算术编码器提供了概率范围,算术编码器使用这个概率范围对此bin进行算术编码。

  2. 更新上下文模型。例如,若bin1使用上下文模型2,而bin1的值是1,那么上下文模型2中1的计数就要增加,1的概率和0的概率需要重新计算。当上下文模型中的总数超过门槛值后,0和1的计数就要除以某个值,从而使得新加入的0和1在模型中产生更大的影响。

CAVLC和CABAC简介相关推荐

  1. H264编码器13(CAVLC和CABAC简介)

    来自:https://blog.csdn.net/jubincn/article/details/6948334 CABAC/CAVLCin H.264 什么是熵编码? 熵编码压缩是一种无损压缩,其实 ...

  2. H.264/AVC 标准中CAVLC 和CABAC 熵编码算法研究

    http://www.paper.edu.cn/index.php/default/releasepaper/downPaper/200903-146

  3. 三. H.264简介

    一. H.264视频编码标准 H.264视频编码标准是ITU-T与MPEG合作产生的又一巨大成果,自颁布之日起就在业界产生了巨大影响.严格地讲,H.264标准是属于MPEG-4家族的一部分,即MPEG ...

  4. 【H.264/AVC视频编解码技术详解】三. H.264简介

    <H.264/AVC视频编解码技术详解>视频教程已经在"CSDN学院"上线,视频中详述了H.264的背景.标准协议和实现,并通过一个实战工程的形式对H.264的标准进行 ...

  5. 十三、熵编码算法(3):CAVLC原理

    GitHub代码地址:点击这里 上下文自适应的变长编码(Context-based Adaptive Variable Length Coding, CAVLC) 1. 引言 在前述的几章节的博文/视 ...

  6. 视频编解码(七):profilelevel简介、ffmpeg如何控制profilelevel、编码效率

    一. H264编码profile & level控制 作者:DayInAI   日期:20190123 背景知识 先科普一下profile&level.(这里讨论最常用的H264)  ...

  7. VideoCodec 入门篇 - 00 (编解码简介)

    目录 1.基本术语 (Basic Terminology) 1.1.图像 (Image) 1.2.像素 (Pixel) 1.3.颜色深度 (Color Depth) 1.4.分辨率 (Resoluti ...

  8. H.264 入门篇 - 00 (简介)

    目录 1.Profiles 2.应用领域 3.Level 4.层次结构 4.0.整个过程 4.1.数据切分 4.1.1.Macroblock (宏块) 4.2.帧内预测 (Intra-Frame Pr ...

  9. H264学习(二)编码方法和编码工具简介

    H264 FRExt H264最初版本只支持8bit量化,4:2:0色度采样,后来有一些应用 要求数据精度超过8bit/sample;色度要求使用4:2:2或者4:4:4:高分辨率或超高分辨率编码:超 ...

  10. 十三、熵编码CAVLC:1、编码原理

    一.引言 在前述的几章节的博文/视频中,我们已经了解到: 编码后可无失真还原信源信息 熵编码是利用信息的统计冗余进行数据压缩的无损编码方法 利用信源符号的概率特性,使编码后的信息尽可能接近信源的熵 H ...

最新文章

  1. element怎么设置复选框属性_【JavaScript 教程】DOM——属性的操作
  2. 轻量级姿态估计simplepose
  3. matlab 数据保存为txt excel mat
  4. 查看网关物理地址命令
  5. Object.assign()解释整理
  6. 沉淀,再出发:docker的原理浅析
  7. 图像处理-自适应的二值化图像
  8. Macromedia Studio 8 简体中文正式版激活码
  9. uni-app开发和常规Vue开发
  10. zebra扫码枪复位_条码扫描枪设置使用说明详解
  11. java根据出生年月计算年龄
  12. 哈希算法(哈希函数)基本
  13. 『团队协作的五大障碍』读书所得
  14. 关于面试的方法和技巧都有哪些呢?
  15. 你还别不信:过度关注技术就是浪费时间
  16. 【mmdetection系列】mmdetection之backbone讲解
  17. 基于C语言设计的像素小鸟小游戏
  18. 会声会影导出视频跳帧一卡一卡解决办法
  19. 2019电赛----模拟电磁曲射炮
  20. 构建整车七自由度模型

热门文章

  1. 简单的三层框架以及使用dbutils进行数据库操作(入门)
  2. python的条件(三元)运算符——实现b? x: y
  3. IEEE754标准浮点格式
  4. [译]应用内搜索功能实现 Android TV应用程序手册教程十三
  5. pyCharm-激活码(2018)
  6. 腾讯正式开源高性能Hybrid框架VasSonic!
  7. 2015-2016-2 《Java程序设计》项目小组博客
  8. 如何选择和部署长尾关键词
  9. 【SICP练习】142 练习3.77
  10. R语言学习笔记:简单的回归分析