CABAC之手把手教你编码

首先要说明的是CABAC的生命期是SLICE,因此本篇所讲的也是一个SLICE里CABAC的流程,其次对于我们来说场模式几乎用不到,所以本文的编码流程只使用帧模式,因此实际上用到的表只有277个, 当然如果我写成399, 不是说里面所有表都用到的. 这里只是声明一下这个问题, 如果大家实际操作的时候发现模型表序号始终不过276那是很正常的. 本文参考了T264的代码, 应此一帧里只有一个SLICE. 而本文用的变量则采用标准里的变量.本文不会讲CABAC的原理, 想要了解原理请参考FTP上的<<Context-based adaptive binary arithmetic coding in the H.264AVC video compression standard>>

       注意:我用的标准是BS的正式标准,可能里面的序号和大家的不一样,但是内容应该是一样.大家对照着就可以了

片级: 即以下步骤在片期间只做1次

       1, 在一帧的开始的时候, 先看是否字节对齐, 没有对齐则补1, 直到字节对齐

       2, 先根据SliceQP算出399个模型表里的pStateIdx和valMPS, 构成一张初始表,根据标准9.3.1.1里的公式, 同时可以参考T264_cabac_context_init函数. 这张表不要和模型表弄混,虽然都是399维的, 但我们宏块级编码过程中实际用的只是这张表, 而不是标准里的那张模型表Table 9-23, 9-23这张表是用来算由pStateIdx和valMPS构成的初始表的.

       3, 然后就是初始化CABAC的初值, 下界指针,区间范围 (0x1FE)等等,可参考T264_cabac_encode_init函数.

宏块级: 以下则是每个宏块都要做一次的, 这一级中会处理很多的语法元素, 这里我只用前2个语法元素做为例子: mb_skip_flag, mb_type

        4, 重整区间, 确保在区间在28-29内.这里的区间概念来自BAC,如果不明白先google算术编码,然后再看上面那个参考文献.

        5, 首先mb_skip_flag标志进行CABAC编码, 由于这个元素本身就是2值的,所以直接就可以进行上下文模型选择了:

                1. 由标准Table 9-24知道, P帧(这里要注意是slice_type==P, 不是mb_type)的这个元素用11号表, B帧用24号表. 可以参考T264中的T264_cabac_mb_skip函数.

                2. 由于这个元素只有1个bit, 因此只要算第一个bit的ctxIdxInc就可以了, 参考标准Table 9-29, 可以看到表中11 和 24号表确实只有第一个bit是可用的, 根据9.3.3.1.1子条款可以知道这一位的ctxIdxInc可能是0, 1, 2中的一个, 在T264中简单的说就是看左边和上边宏块是否是Skip模式, 有一个是skip模式ctxIdxInc就加1. 也就是全不是skip为0, 有一个skip则ctxIdxInc就是1,全是skip则ctxIdxInc就是2.

                3. 下来就是算术编码部分了, 简单提一下基本原理: 在CABAC中为了减少RLPS = R*pLPS 这个区间变换公式的开销, 用128个有限状态(实际可用的为126)代替pLPS , 用rangeTab这张表代替了RLPS, 见标准Table 9-33. 可以参考T264中的T264_cabac_encode_decision函数, 看一下具体流程:

Ø         获得当前bin的pStateIdx和valMPS(来自片级计算的那张初始表)

Ø         根据标准9.3.3.2.1子条款, 求得qCodIRangeIdx用来索引表rangeTab, 即可以求得变换后的区间了.

Ø         修正区间codIRange = codIRange – codIRangeLPS

Ø         判断当前的bin是否为最有可能的值, 如果不是(binVal!= valMPS),则更新区间下边界codILow = codILow + codIRange, 同时修正区间codIRange = codIRangeLPS;然后判断当前状态, 如果已经达到状态0, 是则把valMPS的值取反(即0,1互换), 如果还有没达到0, 则进行LPS的状态迁移,具体参看标准Table 9-34的状态迁移表中的transIdxLPS

Ø         如果当前的binVal值等于valMPS, 就比较简单了, 直接进行状态迁移, MPS的状态迁移也很简单, 直接数据+1就可以了(最大63),具体参考标准Table 9-34的状态迁移表中的transIdxMPS, 状态的转移其实就是修改了399个模型的初始表.

Ø         区间重整, 如果区间过小则输出一些bit, 这样可以不用把数据全部编码完再输出, 可以编一部分输出一些.

Ø         已编码的2进制值bin总数+1, 即SymCnt+1, 这个值用于字节填充, 可以参考标准9.3.4.6, 其中的BinCountsInNALunits就是指这个值,至此算术编码部分就结束了.

        6, 下面就是开始编码第二个语法元素了: mb_type

                  1)     不同于上一个语法元素mb_skip_flag, mb_type这个语法元素本身并不是二值化的, 因此编码的第一步是进行二值化, 查阅标准Table 9-24可知mb_type的二值化方法需要参考9.3.2.5子条款, 由该条款可知mb_type的二值化相对简单, 可以直接参考表得到, 例如I片中某宏块mb_type为I_16x16时则二值化后bin0=1, 且非I_PCM则bin1=0, 亮度AC无非0系数则bin2=0, 色度有非0系数则bin3=1, 色度DC,AC都无非0系数时,bin4=0, 帧内预测模式为0时则bin5=0, bin6=0, 因此我们就得到了标准中I_16x16_0_1_0的二值化串为1001000

                 2)     下来是上下文模型选择, 由Table 9-24可知 I的mb_type元素起始表是3号表, 然后参考标准表Table 9-29, 计算bin串中每个bin的ctxIdxInc值,由表可知bin0要参考9.3.3.1.1.3才能确定ctxIdxInc值, 简单的说就是如果上边和左边的块模式有一个不是I_4x4则ctxIdxInc++, 这样就有0,1,2这3种可能的结果了; bin1的ctxIdx固定是276, 直接就调用了encoder_terminal模块, 即标准Figure 9-11的右分支;bin2的ctxIdxInc是3;bin3的ctxIdxInc是4,; bin4和bin5要参考9.3.3.1.2子条款, 由该条款可知如果bin3是1则bin4的ctxIdxInc=5,bin5的ctxIdxInc=6,如果bin3=0则bin4的ctxIdxInc =6,bin5的ctxIdxInc =7,由于I_16x16_0_1_0的二值化串为1001000, 其中bin3=1, 由此可知此时bin4的ctxIdxInc =5, bin5的ctxIdxInc =6; 最后由表9-29 中bin6的ctxIdxInc为7.至此二进制串所有位的表号可以用3+的ctxIdxInc来得到了.

                3)     下来就是算术编码部分,这个部分于mb_skip_flag的算术编码部分步骤一样.这里要提的是, 第一步获得当前bin的pStateIdx和valMPS的模型表已经被更新了(是表被更新,但不一定是当前表), 还记得么? 是在上一个语法元素的状态转移的时候更新的.

        7, 下面的语法元素就是按照标准7.3.5的语法一一编码的, 其过程和上面2个语法元素的编码过程大同小异,就不一一细述了.

 

……如此做完所有的宏块里的语法元素

又回到片级:

       8, 写入end_of_slice_flag的标志,即完成标准Figure 9-11的左分支, 然后调用T264_cabac_encode_flush函数, 输出bit

       9, 进行byte stuffing, 参考标准9.3.4.6 Byte stuffing process里的公式可以求得k, 在码流中填充k次的0x000003

       10, 最后是模型更新,更换模型表(更改PB帧所用的模型表,而I帧所用的不变)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/455736.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python网络攻击代码_Python-python网络编程写arp攻击代码

from scapy.all import ARP,send,arping import sys,re,random,time stdoutsys.stdout ip IPADDR"192.168.1.102" 网关 gateway_ip"192.168.1.1" tmp[] 伪造网关mac地址 for i in range(0,6): tmp.append(str("%02x"%random.randint(0x01,0xfe))…

Kubernetes初步学习

今天分享如题&#xff1a; Kubernetes 本篇内容源于工作项目需要自学 但K8s确实现在十分的主流so推荐给大家 最近更新缓慢由于工作太忙惹&#xff0c;忙里偷闲整理愿分享能与君共勉&#x1f4aa; 大家新年快乐&#x1f389; &#x1f508;言归正题&#xff0c;相信很多朋友…

手机界面常见的的九宫格

手机界面常见的的九宫格 手机界面常见的的九宫格 首先布局的话需要用到一个mainactivity和一个item的布局目前用得最多也最熟悉的还是LinearLayout布局所以&#xff0c;一下也是&#xff0c;按套路就不过多赘述了。 <GridView android:layout_width"wrap_content"…

JavaScript中的运算符

js运算符 算 字 赋 比 逻 位 它算术运算符 - * / --字符串连接 赋值运算 - %比较运算符 < > > < ! !逻辑运算符 && || !位运算 ^ & | << >>其它运算符 ? : 三元运算符 delete&#xff1…

CABAC编码

H&#xff0e;264&#xff0f;AVC标准采用了很多新技术和新方法&#xff0c;大大提高了视频编码效率&#xff0c;其中CABAC便是H&#xff0e;264&#xff0f;AVC采用的新型熵编码方法之一。CABAC采用了高效的算术编码思想&#xff0c;同时充分考虑了视频流相关统计特性&#xf…

【教程分享】Jmeter入门教程

好&#xff01;回归学长每周的教程分享&#xff01; PART2 >今天又来分享Jmter 因为最近好像有相关工作内容 提前准备资修一下 分享仅供参考- JMeter的作用对软件做压力测试 1.能够对HTTP和FTP服务器进行压力和性能测试&#xff0c; 也可以对任何数据库进行同样的测试&…

linux 特殊shell变量

特殊变量 环境变量&#xff1a; 系统本身运行需要由linux系统提前创建好的一类变量 主要用于用户的工作环境&#xff0c;包括&#xff08;用户的宿主目录&#xff0c;命令的查找路径&#xff0c;用户的当前目录&#xff0c;登录的终端等&#xff09;环境变量的值由操作系统本身…

JavaScript中的循环

js循环 程序中进行有规律的重复性操作&#xff0c;需要用到循环语句。 break 和 continue 语句对循环中的代码执行提供了更严格的控制。 for循环 for(var i0;i<len;i){...... }while循环 var i0;while(i<8){......i;}for-in 语句 for-in 语句是严格的迭代语句&…

快速傅里叶变换python_FFT快速傅里叶变换的python实现过程解析

FFT是DFT的高效算法&#xff0c;能够将时域信号转化到频域上&#xff0c;下面记录下一段用python实现的FFT代码。 # encodingutf-8 import numpy as np import pylab as pl # 导入和matplotlib同时安装的作图库pylab sampling_rate 8000 # 采样频率8000Hz fft_size 512 # 采样…

rabbitmq的安装全过程

2019独角兽企业重金招聘Python工程师标准>>> 1 首先下载安装依赖elang 添加yum支持 cd /usr/local/src/ mkdir rabbitmq cd rabbitmq wget http://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm rpm -Uvh erlang-solutions-1.0-1.noarch.rpm rp…

【框架学习分享】HttpRunner

今天文章分为两部分 :) PART1 HttpRunner内容分享/ PART2 关于后厂村儿 10 Minutes HttpRunner: PART 1 首先感谢作者开源&#x1f44d; 因为最近工作需要用到HttpRunner&#xff0c; 于是便趁着周末学了下这个测试框架&#xff0c;感觉还可以~ 所以分享一下今天的学习记…

x264 移植到 ARM的方法

1。Linux下编译X264&#xff1a; 其实在windows下使用vc已经编译过了&#xff0c;不过听到有人说在linux下编好了&#xff0c;我也就尝试做一下&#xff0c;况且x264源代码的makefile已经做好了&#xff0c;我只需要做的就是把文件copy一下&#xff0c;然后make 一下就可以了。…

JavaScript中的元素获取与操作

js元素获取与操作 可以使用内置对象document上的getElementById方法来获取页面上设置了id属性的元素&#xff0c;获取到的是一个html对象&#xff0c;然后将它赋值给一个变量&#xff0c;比如&#xff1a; <script type"text/javascript">var oDiv document…

VUE2第五天学习---自定义指令

阅读目录 1.理解VUE中的自定义指令回到顶部1.理解VUE中的自定义指令 默认核心指令有 (v-model 和 v-show), 但是有时候我们需要用到自定义指令&#xff0c;在vue中&#xff0c;代码复用主要形式和抽象是组件&#xff0c;但是在有的情况下&#xff0c;我们仍然需要对DOM元素进行…

python报名_2019年少儿Python创意编程比赛报名时间

2019年Python创意编程比赛时间及相关规定&#xff1a;参赛对象 Python创意编程比赛设初中组和高中组。 全国各地初中、高中(含中等职业学校)在校学生均以个人名义报名参加。 参赛步骤 Python创意编程比赛分初评、复评和终评三个阶段&#xff0c;初评和复评以线上形式开展&#…

【分享】后厂村鲜为人知的另一面

好&#xff01;回归学长每周的杂谈分享&#xff01; 有人说“后厂村”像一座孤岛&#xff0c; 这里远离喧嚣&#xff0c;没有生活气息。 而刚刚到厂的学长&#xff0c; 却想和你分享他鲜为人知的另一面。 内容整理源于网络看客原创侵删 说起后厂村&#xff0c;也许是老北京人…

windows 下安装rabbitmq

2019独角兽企业重金招聘Python工程师标准>>> 1、下载 下载地址&#xff1a;http://www.rabbitmq.com/download.html 2、Windows上安装 2.1 安装安装Erlang 下载erlang&#xff1a;http://www.erlang.org/download/otp_win64_17.3.exe 安装&#xff1a; erlang安装完…

【Kubernetes】k8s 的基本使用指令

今天分享如题&#xff1a; Kubernetes 最近更新缓慢由于工作太忙惹&#xff0c;忙里偷闲整理愿能与君共勉&#x1f4aa; K8S对我来说是个新的技术栈&#xff0c;程序员就是需要一直充电&#x1f50b; 加油&#xff0c;一起进步&#x1f4aa; 结构模型 k8s 是经典的一对多模…

php是如何工作的

a:前提条件: apache服务器启动正常工作 b:客户端浏览器在地址栏输入一个程序地栏 按回车发送请求 {请求}http://127.0.0.1/day03/1.php c:apache接收请求&#xff0c;并且负责查找相应资源1.php d:如果apache没有找到相应的资源,返回错误消息给客户端浏览器404 NOT FOUND e:如果…

c语言 malloc_C语言快速入门——动态内存分配

在前面一系列的字符串操作中&#xff0c;我们都是先定义一个固定大小的字符数组&#xff0c;然后根据所需&#xff0c;或拷贝、或连接、或格式化来为这个数组提供内容。固定大小的数组意味着在程序运行期间&#xff0c;数组所占用的内存是确定的(即划分了固定数量的内存)&#…