HM代码介绍

我对HM代码结构理解的启蒙文章,转自实验室前辈朱师兄的博客:http://blog.csdn.net/spark19851210/article/details/8964559

1.      环境配置

这个文档描述的版本是HM6.0

运行的方法如下可参考之前的文章:

2.      编码端主函数的调用

主函数中会调用create函数,但是这里面是空函数,所以不做任何操作

encode是非常重要的函数,负责了实际的编码工作,在里面调用m_cTEncTop的encode

函数对每个GOP进行编码,并对每个GOP调用compressGOP。GOP的概念在HEVC中规定的并没有H.264/AVC那么严格,在H.264/AVC中,GOP是以I slice开始,而HEVC中并没有这样的规定,相当于弱化了HEVC中GOP的概念。

3.      GOP划分为Slice

GOP进而会划分为slice,有raster顺序的划分和tile的划分方式,对每个slice会调用

compressSlice来的对其选出最优的参数。然后调用encodeSlice来对其进行实际的熵编码工作。

4.      Slice的划分(Slice到LCU)

到Slice层面后,会划分等大的LCU,对每个CU进行compress和encode的工作,调用的函数分别为compressCU和encodeCU。而在CompressSlice和EncoderSlice中都会调用encodeCU,是为了保证后续计算码率的准确性,重点在于保证了cabac的状态是准确的。下面将介绍compressCU和encodeCU,由于RDO的时候会编码CU的信息,所以着重介绍compressCU

5.      compressCU

把一个slice内部的图像划分为K个LCU,同时这K个LCU是以raster的顺序来进行扫描的。LCU的尺寸默认为64x64,可以通过配置文件中的MaxCUWidth,MaxCUHeight来进行设置。而每个LCU会调用如下的compressCU函数去决定编码的参数。 而LCU是采用四叉树的表示结构,每个LCU会被递归的划分为4个子CU,并根据RD代价来确定是否进行划分,而每个LCU相当于树的第1层,所以他会调用xCompressCU。且在xCompressCU中会对每个子CU递归的调用xCompressCU,如下图所示,当然子CU的尺寸是当前CU的四分之一。

然而在每次xCompressCU时,会对当前CU进行intra模式的测试,如果是B或Pslice,还对其进行merge和inter模式的测试。下面分别介绍intra,inter和merge相关的代码

5.1   帧内

intra的调用流程如下:

estIntraPredQT主要做模式选择的工作,负责选出对于当前PU的最优模式,如DC,或方向性,或planar。estIntraPredChromaQT做了类似的工作,不过是针对于色度。xRecurIntraCodingQT和xRecurIntraChromaCodingQT函数是依据给定的候选模式进行PU的分割,进而依据TU进行重建estIntraPredQT。

5.1.1         estIntraPredQT

在这里面首先对N个候选模式进行粗粒度筛选

代价函数为,从M个模式选出N个最可能的候选模式。所涉及的函数:

l predIntraLumaAng: 算出当前PU的预测值

l calcHAD: 计算SATD代价

l xModeBitsIntra: 计算当前模式所耗费的比特数目

l xUpdateCandList: 更新模式的代价,保持前N个模式的代价最小

在选出N个模式后,这N个模式会进入xRecurIntraCodingQT函数从而进行TU的分割

5.1.2         xRecurIntraCodingQT

为了加速RQT过程,这个函数会被调用两次:

第一次的调用不进行PU分割为TU的过程,PU直接转换为TU,只为算出N个模式的RD代价,从而选出一个最优的,在这个最优的模式被选出后,会第二次调用这个函数,再对这个最优的模式进行PU的分割。区分第一次和第二次调用的变量是bCheckFirst。这个过程所涉及的函数有:

l xIntraCodingLumaBlk: 进行对当前TU进行求残差,对残差变换,量化,反量化,反变换,重建当前TU等一系列编码工作,并求得失真

l xGetIntraBitsQT: 求出当前模式的所有信息进行熵编码会产生的比特数

l calcRdCos:根据xIntraCodingLumaBlk得到的失真和xGetIntraBitsQT产生的比特数目进行RD代价的计算,从而比较各模式的优劣

l xSetIntraResultQT:保存最优模式的数据

5.1.3         estIntraPredChromaQT

estIntraPredChromaQT会决定当前PU采用哪个色度模型对色度分量进行编码,其中涉及的函数如下:

l getAllowedChromaDir:获得可用的色度

l xRecurIntraChromaCodingQT:进行当前PU的色度分量的一系列编码工作,并求得失真

l xGetIntraBitsQT:进行当前PU的色度分量的熵编码工作,并得到产生的比特数

l calcRdCost:根据失真和码率进行率失真代价的计算

l xSetIntraResultChromaQT:保存当前色度最优模式的信息

5.1.4         xRecurIntraChromaCodingQT

这个函数是求PU的色度分量的残差,首先会对PU进行分割,分割的层数与亮度完全一致。涉及的函数如下:

l xIntraCodingChromaBlk:对当前TU进行色度信息的编码工作,如求残差,变换,量化,反量化,反变换,重建等一系列工作

5.2   帧间

帧间按默认的配置文件设置有两种:inter模式和merge模式

5.2.1         inter模式和merge模式的流程

主要调用流程:

Inter流程

Merge流程

流程中涉及的函数:

l predInterSearch进行的是ME和MC的过程,当然会测试各种情况

l Motioncompensation进行的是MC的工作,由于merge模式没有ME的过程,是将已有的MV信息直接代替当前PU的MV,所以直接进行MC

l encodeResAndCalcRdInterCU是对得到预测值后求出的残差进行TU的划分及RD代价的计算

5.2.2         encodeResAndCalcRdInterCU

涉及的主要函数:

l encodeSkipFlag:编码SKIP模式的flag

l encodeMergeIndex:编码选用哪套运动参数的索引

xEstimateResidualQT:在非SKIP模式的时候要进行RQT的决定,即PU分割为什么样的TU在这个函数里面确定

l xAddSymbolBitsInter:计算当前CU的信息在进行熵编码时所产生的比特数

l xSetResidualQTData:保存当前CU的最优的残差信息

6.      一些其他常用的函数说明:

6.1   预测

6.1.1         帧内

l initPattern:判断周围块的存在性

l initAdiPattern:获取周围像素的值当做生成预测值的像素,并开辟出一片缓存 区存储经过多种滤波类型的预测值

l getPredictorPtr:根据不同模式选择经过不同类型滤波的预测集

l predIntraLumaAng: 对亮度信号进行预测,里面会调用xPredIntraPlanar,xPredIntraAng以及xDCPredFiltering

l predIntraChromaAng: 对色度信号进行预测,里面会调用xPredIntraPlanar和xPredIntraAng

l xPredIntraPlanar: planar模式的预测

l xPredIntraAng: 角度的方向性预测

l xDCPredFiltering: 对DC的预测值进行滤波

l getLumaRecPixels: 获取亮度的重建值,为进行LM模式的预测做准备

l predLMIntraChroma:对LM模式进行预测,即利用亮度的相关性,对色度进行预测

6.1.2         帧间

l getInterMergeCandidates: 获取merge的候选运动参数集

l motionCompensation:进行运动补偿

l xMotionEstimation:进行运动估计

l xEstimateMvPredAMVP:选出代价最小的MVP

l xCheckBestMVP:在知道MV的情况下比较各个MVP的优劣,并保存最优的

l xMergeEstimation:在inter模式时也可以使用merge模式的运动估计方法,这个函数用于计算这种情况时的代价

6.2   变换

l transformNxN:会调用xT和xQuant函数

l invtransformNxN:会调用xDeQuant和xIT函数

l xT: 对残差信号进行变换

l xQuant:对变换系数进行量化

l xDeQuant:反量化

l xIT:反变换

6.3   熵编码

在这节中主要介绍编码端为算RD代价而设计的熵编码函数,实际的熵编码函数在后面的章节中进行介绍

主要函数:

6.3.1         帧内熵编码

l xEncIntraHeader:编码intra的一些头部信息,主要包括:模式号,PU的分割类型,PCM标志,如果是B或P slice,还包括skip的标志位和编码模式的类型

l xEncSubdivCbfQT:会编码Cbf和TU分割的标志位

l xEncCoeffQT:编码每个TU的系数

l encodeCoeffNxN:调用codeCoeffNxN来编码每个TU的残差系数

l encodeTransformSubdivFlag:调用codeTransformSubdivFlag来编码TU分割的标志,是否继续分割

l encodeQtCbf:编码cbf标志位,检查是否有非零的系数

l encodePredMode:编码所采用的编码模式

l encodePartSize:编码PU的分割类型

l encodeIntraDirModeLuma:编码PU的亮度模式号,这里引入了3MPM的机制,具体可参考提案H0238

l encodeIntraDirModeChroma:编码PU的色度模式号

6.3.2         帧间熵编码

l encodePredMode:编码CU所采用的模式,主要决定是inter还是intra

l encodePartSize:编码PU的分割类型

l encodePredInfo:编码运动参数

(1)       merge的标志位来区别是否采用merge模式,具体函数:encodeMergeFlag

然后分(2)和(3)两种情况。

(2)       merge模式:只需传输运动候选集的索引,具体函数:encodeMergeIndex

(3)       正常的inter模式

A.    encodeInterDirPU:编码帧间的预测方向,前向,后向,或多方向

B.     encodeRefFrmIdxPU: 编码参考帧索引

C.     encodeMvdPU:编码MV的残差MVD

D.    encodeMVPIdxPU: 编码MVP的索引

7.      EncoderCU

HEVC以LCU为基本单位,所以在进行熵编码时也是以LCU为单位进行的EncodeCU会调用从而对每个CU进行编码,如下图所示,在xEncodeCU中会调用如下几个函数:

encodeSkipFlag编码是否是skip模式

encodeMergeIndex如果是skip模式会编码选用哪套MVP的参数

encodePredMode编码CU的模式,是intra还是inter

encodePartSize编码CU中的PU的类型

encodeIPCMInfo 如果选用了PCM模式会编码PCM模式的信息

encodePredInfo编码预测的信息,如果是帧内,编码模式号,如果是帧间,则编码运动信息

encodeCoeff编码残差系数

encodeCoeff中会编码TU的分割标志位,cbf和残差系数的信息

而具体的信息可以参照3.3节

8.      一些主要变量和数据结构的说明:

8.1  TComDataCU:LCU及其子CU的数据结构,存储了一个LCU所有的相关信息,里面重要的数据结构包括:

l m_uiCUAddr:一个LCU在slice中的位置

l m_uiAbsIdxInLCU:当前CU在LCU中的位置,位置用Z扫描顺序

l m_puhWidth: CU的宽度

l m_puhHeight:CU的高度

l m_puhDepth: CU所处的深度

l m_pePartSize: PU的类型

l m_pePredMode:编码模式

l m_pcTrCoeffY,m_pcTrCoeffCb,m_pcTrCoeffCr:量化后的系数

l m_puhLumaIntraDir:亮度的模式信息

l m_puhChromaIntraDir:色度的模式信息

l m_puhInterDir:帧间的预测方向

l m_apiMVPIdx:MVP索引

l m_apiMVPNum:MVP的候选数

以上的数据结构都是以动态存储来分配空间,一般只有一维,这一维具体取值的含义就是CU里面的每个对应的4x4的小块的信息,而开辟的数目就是CU所包含的4x4的数目,而在实际编码时也是编码了这些信息。

需要着重说明2点

(1)    m_uiCUAddr是一个LCU在slice中的位置,是raster的扫描顺序

(2)    m_uiAbsIdxInLCU是表明CU在LCU中的位置,Z扫描顺序,最小单位为1,代表

其中的一个4x4子块,Z扫描顺序如下图所示

(3)   Z扫描转换,如下图所示,展示了一个CU内部的Z扫描的顺序,在hevc中,Z扫描顺序是以4x4为基本单位的,一个具有默认尺寸的LCU,具有256个基本单元

8.2   RDO时所用到的主要临时变量

l m_ppcQTTempCoeffY,m_ppcQTTempCoeffCb,m_ppcQTTempCoeffCr:RQT时每层的量化系数,都保存在此,是为了确定最终分割后可以很容易的获取最优值

l m_pcQTTempCoeffY,m_pcQTTempCoeffCb,m_pcQTTempCoeffCr:CU层的量化系数暂存地,只有帧间编码时才会用到,是中间变量

l m_pcQTTempTComYuv: 重建视频的暂存缓冲区

l m_puhQTTempCbf: cbf的暂存

l m_puhQTTempTrIdx:变换层数的暂存

l m_ppcBestCU:存储每层最优(RD代价最小)的CU的信息

l m_ppcTempCU:  存储每层CU的信息的临时变量

l m_ppcPredYuvBest: 存储每层最优的预测值

l m_ppcResiYuvBest:存储每层最优的残差值

l m_ppcRecoYuvBest:存储每层最优的重建值

l m_ppcPredYuvTemp:存储每层预测值的临时变量

l m_ppcResiYuvTemp:存储每层残差值的临时变量

l m_ppcRecoYuvTemp:存储每层重建值的临时变量

l m_ppcOrigYuv::存储每层对应的原始值

8.3   yuv的存储的关系

8.3.1         TComYuv数据结构

由m_apiBufY,m_apiBufU以及m_apiBufV三个buffer组成,通用的yuv数据结构,存储是yuv的亮度和色度信息

8.3.2         TComPicYuv数据结构

图像层级的yuv数据结构,存储的是一帧的yuv信息,主要用于ALF和去方块滤波等处理的过程中

TComYuv的类型的变量存储的是RDO时的值,最优的信息要存在TComPicYuv中,便于输出和进行全局处理

9.      解码端的简单说明

9.1    xDecodeCU: 与xEncodeCU类似,进行LCU的读取码流并存至变量的工作,可以理解为与xEncodeCU的逆过程。涉及的函数如下:

l decodeSkipFlag:解码skip的flag,看是不是skip模式

l decodePredMode:解码编码模式

l decodePartSize: 解码PU分割的类型

l decodePredInfo:解码预测信息,帧内就是解码模式信息,帧间是解码运动信息

l decodeCoeff:解码量化系数

9.2   xDecompressCU: 具体的任务为重建这个LCU,涉及的函数如下:

9.2.1         xReconInter

负责inter部分的重建,主要函数如下:

l xDecodeInterTexture:分别对YUV分量调用invRecurTransformNxN

l invRecurTransformNxN:对特定分量进行TU的反量化和反变换

l addClip:得到残差后会加上预测值形成重建指

l copyPartToPartYuv:如果系数全是零,则直接将重构值赋值为预测值

9.2.2         xReconIntraQT

负责intra部分的重建

xIntraLumaRecQT:亮度信息的重建,会对每个TU调用xIntraRecLumaBlk

xIntraRecLumaBlk:TU的亮度信息反量化及重建工作

xIntraChromaRecQT:色度信息的重建,会对每个TU调用xIntraRecChromaBlk:TU的色度信息反量化及重建工作

时间: 2024-08-27 10:36:21

HM代码介绍的相关文章

Android ViewPager实例代码介绍2。

以前写过一篇ViewPager:内容content+指示点的Demo: 这篇文章继续介绍ViewPager:内容content+标题title的Demo. 实现效果图: 源代码: 布局文件:activity_main: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"

Entity Framework 实体框架的形成之旅--几种数据库操作的代码介绍(9)

本篇主要对常规数据操作的处理和实体框架的处理代码进行对比,以便更容易学习理解实体框架里面,对各种数据库处理技巧,本篇介绍几种数据库操作的代码,包括写入中间表操作.联合中间表获取对象集合.递归操作.设置单一字段的修改等几种方式. 1.写入中间表操作 一般情况下,我们可以通过执行数据库脚本方式写入. /// <summary> /// 增加用户IP信息 /// </summary> /// <param name="userID"></param&

(四)整合spring cloud云服务架构 - particle-common-framework代码介绍

上一篇我们介绍了spring cloud云服务架构 - particle云架构代码结构,简单的按照几个大的部分去构建代码模块,让我们来回顾一下: 第一部分: 针对于普通服务的基础框架封装(entity.dao.service.controller.api)等 第二部分: spring cloud通用微服务项目,可以监控左右微服务,当然,本身自己也是微服务. 第三部分: 针对于框架内所有组件的封装,可以植入任何的模块项目中. 第四部分: 自身项目的微服务业务,比如:会员模块.消息模块.资金模块.订

Apache Rewrite module 配置开启代码介绍

首先,你必须要确认Apache安装目录下面conf/httpd.conf文件中已经开启: #代码1# LoadModule rewrite_module modules/mod_rewrite.so 然后你要在httpd.conf文件中指定你所想要实现rewrite功能的目录和配置,如下所示: #代码2# <Directory "D:\www\bc"> #指定你需要执行下面rewrite规则的目录     #     # Possible values for the Op

spawn-fcgi 代码介绍

原文转自:http://chenzhenianqing.cn/articles/936.html spawn-fcgi是一个小程序,作用是管理fast-cgi进程,功能和php-fpm类似,简单小巧,原先是属于lighttpd的一部分,后来由于使用比较广泛,所以就迁移出来作为独立项目了,本文介绍的是这个版本“spawn-fcgi-1.6.3”.不过从发布新版本到目前已经4年了,代码一直没有变动,需求少,基本满足了.另外php有php-fpm后,码农们再也不担心跑不起FCGI了. 很久之前看的sp

Particle-Common-Framework代码介绍

第一部分: 针对于普通服务的基础框架封装(entity.dao.service.controller.api)等 第二部分: spring cloud通用微服务项目,可以监控左右微服务,当然,本身自己也是微服务. 第三部分: 针对于框架内所有组件的封装,可以植入任何的模块项目中. 第四部分: 自身项目的微服务业务,比如:会员模块.消息模块.资金模块.订单模块等. 我们针对于以上四个模块分别做详细讲解: 第一部分: 针对于particle-framework模块: 1.  包括阿里巴巴Druid的

linux usb驱动——Gadget代码介绍

一般网上关于介绍USB Gadget的资料都是基于Linux2.6.32或在这之前的版本,作者在关注了Linux2.6.37和Linux3.0.4版本的内核,USB Gadget的一些API已经与Linux2.6.32的不同了.但是那些关键的数据结构还是一样滴. Linux USB Gadget分三层架构: 层次关系从上到下 一层:USB Gadget功能层.BSP/Driver开发者通常是要实现这一层,从而实现一个具体的设备驱动,如Anddroid在此层实现了adb,mtp,mass_stor

PHP设计模式之单例模式简单代码介绍

PHP设计模式之单例模式 单例模式是一种创建型模式,它会限制应用程序,使其只能创建某一特定类类型的一个单一的实例.举例来说,一个web站点将会需要一个数据库连接对象,但是应该有且只能有一个,因此我们通过使用单例模式来实现这种限制. 我们可以使用一个静态属性来保证对于一个特定的类来说只存在一个单一的实例. Class someclass{ Static private $_instance = NULL; } [示例]config类实现了单例模式,以便整个web应用程序可以使用同一个配置对象. <

HEVC逆扫描之一:在HM代码中的位置

逆扫描在整个解码器标准代码中的位置如下图所示: 图3  逆扫描在整个解码器标准代码中的位置 在上图中,在TDecEntropy::xDecodeTransform()函数中通过递归调用将CU划分成TU,在TDecSbac::parseCoeffNxN()函数中完成对TU以4x4为单位的逆扫描.