熵编码:CABAC

article/2025/9/30 10:28:15

基于上下文的二进制算术编码(Context-Based Adaptive Binary Arithmetic Coding,CABAC)将自适应二进制算术编码和上下文模型相结合。是H.265/HEVC的主要熵编码方案。

主要包括三个步骤:

  1. 二进制化;

  2. 上下文建模;

  3. 二进制算术编码;

其流程如下:

 

二进制化

二进制化就是将输入的语法元素转化为二进制形式,如果语法元素以及是二进制形式则跳过该步骤。

H.265/HEVC中的二进制化方法有截断莱斯二元化(Truncated Rice binarization,TR),K阶指数哥伦布二元化(k-th order Exp-Golomb binarization,EGK)和定长二元化(Fixed-length binarization,FL)。K阶指数哥伦布编码前面已经介绍过。下面介绍TR和FL。

(1)截断莱斯二元化TR

设阈值为cMax,莱斯参数R,待二元化的语法元素为V。

截断莱斯码由前缀串和后缀串拼接成,前缀值P由下式计算得到:P = V >> R

则前缀串获取过程为:若P值小于(cMax >> R),则前缀串由P个1和一个0组成,长度为P+1;若P值大于等于(cMax >> R),则前缀串由(cMax >> R)个1组成,长度为(cMax >> R)。

当语法元素V小于cMax时,后缀值S为:S = V - (P << R)

后缀串为S的二元化串,长度为R。当语法元素V大于等于cMax时,无后缀串。

(2)定长二元化FL

当语法元素均匀分布时,可采用定长二元化。假设语法元素值为x,且x在[0,Max]间,则直接将x从十进制转为二进制得到二元化串。

上下文建模

一般情况下,不同语法元素间有一定相关性,且相同语法元素自身也具有一定记忆性。因此根据已编码元素进行条件编码可以提高编码性能。这些已编码元素就是当前待编码元素的上下文。

语法元素使用的上下文模型包括两个概率模型变量:最大概率符号MPS和概率状态索引pStateIdx。

MPS表示待编码的Bin最可能出现的符号,取值为1或0;与之对应,LPS为最小概率符号。在CABAC中,依据先验知识为LPS预设了64个概率值,如下表。

 

在对第一个二元位编码前需要对概率模型参数进行初始化。在H.265/HEVC中,为每个概率模型分配一个初始值V,通过V计算上下文模型初始变量MPS和pStateIdx。

 

HM中相关代码如下:

/**- initialize context model with respect to QP and initialization value.\param  qp         input QP value\param  initValue  8 bit initialization value*/
Void ContextModel::init( Int qp, Int initValue )
{qp = Clip3(0, 51, qp);
​Int  slope      = (initValue>>4)*5 - 45;Int  offset     = ((initValue&15)<<3)-16;Int  initState  =  min( max( 1, ( ( ( slope * qp ) >> 4 ) + offset ) ), 126 );UInt mpState    = (initState >= 64 );//!<m_ucState最后1位存放MPS值m_ucState       = ( (mpState? (initState - 64):(63 - initState)) <<1) + mpState;
}

获得上下文模型初始参数后即可对输入二元符号进行二元算术编码和模型参数更新,实现上下文自适应的编码。概率模型在每个二元位编码后都要更新。

概率状态pStateIdx更新方法为:

若编码的二元符号值等于MPS,则通过查上面的表更新pStateIdx_new=transIdxMps(pStateIdx)

若编码的二元符号值等于LPS,如果pStateIdx为0则互换MPS和LPS,更新pStateIdx;否则不互换MPS和LPS,只更新pStateIdx;pStateIdx更新也是通过查表pStateIdx_new=transIdxLps(pStateIdx)

HM16中相关代码如下:

  Void updateLPS (){m_ucState = m_aucNextStateLPS[ m_ucState ];}
​Void updateMPS (){m_ucState = m_aucNextStateMPS[ m_ucState ];}

从概率模型更新过程可以看出:若当前编码Bin等于MPS,更新后的概率索引值变大,表示下一个符号是MPS的概率变大;若当前编码Bin等于LPS,更新后的概率索引值变小,表示下一个符号是LPS的概率变大;当概率索引值pStateIdx为0时,表示MPS和LPS的概率相同,若再出现LPS符号则MPS和LPS需要交换。

二进制算术编码

二进制算术编码也是算术编码的一种,只不过算术编码过程中的区间和编码输出等都用二进制表示。当前语法元素完成二进制化后,对每个Bin根据其概率模型进行二进制算术编码。二进制算术编码是基于递归区间划分方式,在递归过程中保存编码区间的长度和区间下限。包括两种编码方式:常规编码和旁路编码。常规编码利用自适应的概率模型进行编码。旁路编码以等概率方式进行,概率状态无需更新。

常规编码

编码器输入是上下文模型变量和待编码Bin,编码器的状态是当前编码区间长度ivlCurrRange和区间下限ivlLow。

编码流程如下:

 

算术编码首先需要估计每个符号概率然后进行区间划分。在CABAC中总是估计LPS的概率(P_lps<0.5),且LPS的概率通过64个离散值表示可以通过查表得到概率索引pStateIdx(见上一节)。

区间划分通常需要多位乘法运算(区间长度x概率),CABAC为了降低其复杂度通过查表获得区间长度。

首先计算索引:qRangeIdx=(ivlCurrRange >> 6) & 3

通过查下表LPS对应的子区间长度为:ivlLpsRange = rangeTabLps[pStateIdx] [qRangeIdx]

则MPS的子区间长度为:ivlCurrRange = ivlCurrRange - ivlLpsRange

因为二进制编码只有两个符号0和1,所有区间总是被分为两个子区间,且MPS总是在左侧,LPS总是在右侧。

 

如果当前Bin等于MPS,则MPS的区间长度R_mps作为下一个符号编码的区间长度R,区间下限L不变;如果当前Bin等于LPS,则LPS的区间长度R_lps作为下一个符号编码的区间长度R,区间下限L变为L+R_mps;编码完一个Bin后根据该Bin值更新上下文模型。

区间重归一化

上面区间划分后得到的新区间长度可能不在[256,512]间(HM中区间长度初始化为510),这就需要进行重归一化。

 

 

当区间长度小于256时就需要进行重归一化。

设归一化时用区间[0,102)表示[0,1);

1、当R<256&L<256时,区间落在[0,512)间,即[0,0.5)间(0.5二进制表示为0.1)。此时输出0(PutBit(0)),因为此区间内的数都是0.0x(二进制)。

2、当R<256&L>=512时,区间落在[512,1024)间,即[0.5,1)间。此时输出1(PutBit(1)),因为此区间内的数都是0.1x(二进制)。

3、当R<256&L<512时,区间落在[0,512)间或同时跨越[0,512)和[512,1024)。此时既可能是0.01x也可能是0.10x。暂缓输出,保存这个比特进入下一个重归一化循环。

4、当R>=256时,无法判断编码区间,需要通过输入下一个符号对R和L进行更新后继续判断,因此当前符号编码流程结束。由于这个原因,因此在一个符号编码结束后,另一个符号编码开始前,总是256<=R<512。

PutBit(B)用来输出编码符号0或1,从重归一化可以看出:

1、当满足条件1时执行PutBit(0),输出0;

2、当满足条件2时执行PutBit(1),输出1;

3、当满足条件3时,输出可能为“10”或者“01”,因此不能直接输出,走bitsOutstanding++的步骤。在下一次编码符号时,符合情况2,走PutBit(1),此时bitsOutstanding = 1,因此输出“10”。符合情况1,走PutBit(0),此时bitsOutstanding = 1,因此输出“01”;

另外,PutBit(B)不会编码第一个bit。原因是CABAC在初始化的时候,会以[0,1024)表示区间[0,1),而在初始化区间时R=510,L=0,这意味着已经进行了第一次区间选择,区间为[0,0.5),需要输出“0”。PutBit(B)在此阻止这个“0”的输出,这样就能得到正确的算术编码结果了。

WriteBits( B, N ) 表示将值B以N比特写入码流,然后将码流指针往前移动N个位置。

旁路编码

旁路编码不需要对概率模型进行更新,而是采用0和1概率各1/2的方式进行编码。当bypassFlag标志位为1时采用旁路编码。为了使区间划分更加简单,不采用直接对区间长度二等分的方法,而是采用保持编码区间长度不变使区间下限L加倍的方法实现区间划分。随后进行重归一化操作。旁路编码流程如下:

 

参考

新一代高效视频编码H.265/HEVC:原理、标准与实现

ITU-T H.265 (V5)

https://www.cnblogs.com/TaigaCon/p/5304563.html

感兴趣的请关注微信公众号Video Coding

 


http://chatgpt.dhexx.cn/article/MRwEGlxL.shtml

相关文章

熵编码:算术编码

算术编码不是简单的将每个信源符号映射成一个码字&#xff0c;而是对整个输入序列分配一个码字&#xff0c;所以平均意义上可以为每个信源符号分配长度小于1的码字。 算术编码操作简单&#xff0c;下面以一个实例讲解算术编码的原理&#xff1a; 设信源有a,b,c,d四种符号&…

GitLab-CI基础使用总结

思路梳理 下图是GitLab-ci的实现结构图&#xff1a; (实际结构会有出入&#xff0c;画成这样只是便于理解) GitLab:是一个基于 Git 的代码托管平台&#xff0c;提供了代码仓库管理、问题跟踪、CI/CD 等功能。它可以用于团队协作开发、版本控制、代码审查等场景。GitLab-runne…

Git --- Git Gui

目录 1. 创建和删除分支(了解即可) 2. Git Gui 3. 什么是ssh key 4. git/gitee生成密钥并通过 第一步&#xff1a;本地电脑配置 第二步&#xff1a;远程gitee仓库配置 第三步&#xff1a;修改你本地的ssh remote url. 不用https协议&#xff0c;改用git 协议 第四步&#x…

git与gerrit基础概念

序 本文记录了 git 与 gerrit 学习所得 重点关注于当前所用到的实际操作部分&#xff0c;其余理论部分以及更复杂用法留待将来用到时继续补充 1 Git 与 Gerrit Git 是当前全世界流行的分布式版本控制工具&#xff0c;但是只适用于纯文本文件&#xff0c;包括markdown、网页、…

Git入门|Git的基本用法(一)

1. Git的安装 首先在安装之前确认一下系统有没有安装Git。在Terminal中输入&#xff1a; git --version若确认系统没有安装git&#xff0c;可通过以下指南安装&#xff1a; Getting Started - Installing Git 2. 创建本地Git库 每次进行新项目时&#xff0c;都需要创建一个…

Gitlab-CI入门配置

Gitlab-CI使用及.gitlab-ci.yml配置 Gitlab-CI/CD 持续集成测试篇 Gitlab-CI/CD使用场景在这里插入代码片 首先&#xff0c;公司使用Gitlab作为工作仓库进行代码发布及版本控制&#xff0c;Gitlab内置了CI/CD的工具&#xff0c;这些工具可以用于代码提交的同时完成镜像构建、…

Gitlab CI/CD:入门指南

功能概览 CI/CD工作流 上图是基本的CI/CD工作流&#xff0c;与之对应的&#xff0c;gitlab几乎提供了上述流程节点所需的所有相关功能&#xff1a; 阶段功能 1. Verify 通过持续集成自动构建和测试你的应用程序 使用GitLab代码质量&#xff08;GitLab Code Quality&#xff09…

GitLab-CI 基础介绍

转载自 kubeclub GitLab-CI 工作原理 将代码托管到 git 仓库在项目的根目录下创建 .gitlab-ci.yml 文件&#xff0c;在文件中包含了构建、测试以及部署等脚本&#xff0c;这些脚本被分组为 stage&#xff0c;共同组成了 pipelineGitLab 检测到 ci.yml 文件&#xff0c;使用 G…

GitLab CI Pipeline

GitLab 不单单只是作为一个代码版本控制的仓库&#xff0c;很多场景下使用 GitLab 作为整合 CI 持续集成就 CD 持续发布的工作平台&#xff0c;那么就是 GitLab 的 CI Pipeline 功能了。 CI Pipeline 试想一下&#xff0c;如果开发人员只需要编写代码&#xff0c;而编译、打包…

CICD之 gitlab和gtilab runner

gitlab官网地址 官网文档地址 https://docs.gitlab.com/runner/install/docker.html 一。gitlab 1。gitlab安装 方式一&#xff1a;rpm包安装&#xff08;centos&#xff09;1,下载rpm包清华源软件镜像站https://mirrors.tuna.tsinghua.edu.cn/linux命令wget https://mirror…

gitlab-CI入门

gitlab-CI 代码管理自动化部署及消息推送 (1) 通过在项目根目录下配置**.gitlab-ci.yml**文件&#xff0c;可以控制ci流程的不同阶段&#xff0c;gitlab平台会扫描.gitlab-ci.yml文件&#xff0c;并据此处理ci流程。 (2) ci流程在每次团队成员push/merge后之后触发。每当你pu…

Gerrit介绍

谷歌 Android 开源项目在 Git 的使用上有两个重要的创新&#xff0c;一个是为多版本库协同而引入的 repo&#xff0c;这在之前我们已经详细讨论过。另外一个重要的创新就是 Gerrit —— 代码审核服务器。Gerrit 为 Git 引入的代码审核是强制性的&#xff0c;就是说除非特别的授…

Git--GUI

前言 上一篇文章简单的分享了Git 的 Bash Here的使用&#xff0c;以及一些Git常用的命令等。本篇文章要分享的内容为Git GUI Here 的使用。 一、GUI GIT官方网站为了解决部分用户通过命令行对git工具使用时的怨声载道的现象&#xff0c;因此推出了一个GIT的可视化工具Git Gui …

GitLab CI介绍——入门篇

本文将会对Gitlab CI进行简要介绍,包括Gitlab Runner,Gitlab CI中的相关概念以及.gitlab-ci.yml的常用配置。 那么,GitLab CI 是什么? GitLab CI 是GitLab内置的进行持续集成的工具,只需要在仓库根目录下创建.gitlab-ci.yml 文件,并配置GitLab Runner;每次提交的时候,…

Gerrit

开发、提交、push、入库流程&#xff1a; repo init -u ssh://gerrit帐号[ip:port/platform/manifest -b 分支名 repo sync -c -f --no-tags -j1 git commit git push origin HEAD:refs/for/分支名 有的可能是这样push的&#xff1a; git push ssh://usernameip:port/path…

CICD详解(八)——gitlab安装与配置

今天继续给大家介绍Linux运维相关知识&#xff0c;本文主要内容是gitlab的安装与配置。 一、安装环境准备 首先&#xff0c;我们先来安装一下Gitlab的依赖包&#xff0c;执行命令&#xff1a; yum install curl policycoreutils openssh-server openssh-clients postfix -y然…

CICD详解(九)——gitlab简单使用

今天继续给大家介绍Linux运维相关知识&#xff0c;本文主要内容是Gitlab简单使用。 一、Gitlab关闭自动注册 在企业生产环境中&#xff0c;我们一般由项目负责人负责创建用户并分配权限&#xff0c;一般禁止员工私自注册用户&#xff0c;以防给项目开发工作带来安全性上的风险…

GitLab -- 简单使用CICD功能

前提&#xff1a; 新建GitLab 项目&#xff0c;可参考我另一篇博客 GitLab -- 创建项目_DGH2430284817的博客-CSDN博客 安装配置好Runner&#xff0c;可参考我另一篇博客&#xff1a; GitLab -- 安装和配置Runner_DGH2430284817的博客-CSDN博客 创建.gitlab-ci.yml 文件&…

Git Gui

目录 1.什么是Git Gui 2. 什么是ssh key 3. git/github生成密钥并通过 第一步&#xff1a;本地电脑配置 1.配置用户名和邮箱&#xff08;如果已经配置&#xff0c;就跳过&#xff09; 2.检查下自己之前有没有已经生成ssh 3.生成(或删除)秘钥 第二步&#xff1a;远程git…

GitLab CI/CD artifacts 属性的配置与使用

😀最新最全的 GitLab CI/CD 全部关键词解析 请查阅该专栏 GitLab CI/CD 关键词 artifacts用于指定在job 成功或失败 时应附加到作业的文件和目录的列表。 作业完成后,工件将被发送到GitLab,并可在GitLab UI中下载 如 artifacts:paths 路径是相对于项目目录($CI_PROJECT…