• 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个最可能的候选模式。所涉及的函数:

    predIntraLumaAng: 算出当前PU的预测值

    calcHAD: 计算SATD代价

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

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

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

    5.1.2         xRecurIntraCodingQT

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

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

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

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

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

    xSetIntraResultQT:保存最优模式的数据

    5.1.3         estIntraPredChromaQT

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

    getAllowedChromaDir:获得可用的色度

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

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

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

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

    5.1.4         xRecurIntraChromaCodingQT

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

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

    5.2   帧间

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

    5.2.1         inter模式和merge模式的流程

    主要调用流程:

                 Inter流程                     

     

     

                                   Merge流程

     

    流程中涉及的函数:

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

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

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

     

    5.2.2         encodeResAndCalcRdInterCU

     

     涉及的主要函数:

    encodeSkipFlag:编码SKIP模式的flag

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

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

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

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

          

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

    6.1   预测

    6.1.1         帧内

    initPattern:判断周围块的存在性

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

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

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

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

    xPredIntraPlanar: planar模式的预测

    xPredIntraAng: 角度的方向性预测

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

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

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

    6.1.2         帧间

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

    motionCompensation:进行运动补偿

    xMotionEstimation:进行运动估计

    xEstimateMvPredAMVP:选出代价最小的MVP

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

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

    6.2   变换

    transformNxN:会调用xT和xQuant函数

    invtransformNxN:会调用xDeQuant和xIT函数

    xT: 对残差信号进行变换

    xQuant:对变换系数进行量化

    xDeQuant:反量化

    xIT:反变换

     

    6.3   熵编码

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

    主要函数:

    6.3.1         帧内熵编码

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

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

    xEncCoeffQT:编码每个TU的系数

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

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

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

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

    encodePartSize:编码PU的分割类型

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

    encodeIntraDirModeChroma:编码PU的色度模式号

    6.3.2         帧间熵编码

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

    encodePartSize:编码PU的分割类型

    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所有的相关信息,里面重要的数据结构包括:

    m_uiCUAddr:一个LCU在slice中的位置

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

    m_puhWidth: CU的宽度

    m_puhHeight:CU的高度

    m_puhDepth: CU所处的深度

    m_pePartSize: PU的类型

    m_pePredMode:编码模式

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

    m_puhLumaIntraDir:亮度的模式信息

    m_puhChromaIntraDir:色度的模式信息

    m_puhInterDir:帧间的预测方向

    m_apiMVPIdx:MVP索引

    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时所用到的主要临时变量

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

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

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

    m_puhQTTempCbf: cbf的暂存

    m_puhQTTempTrIdx:变换层数的暂存

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

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

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

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

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

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

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

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

    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的逆过程。涉及的函数如下:

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

    decodePredMode:解码编码模式

    decodePartSize: 解码PU分割的类型

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

    decodeCoeff:解码量化系数

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

    9.2.1         xReconInter

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

    xDecodeInterTexture:分别对YUV分量调用invRecurTransformNxN

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

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

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

    9.2.2         xReconIntraQT

    负责intra部分的重建

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

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

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

  • 相关阅读:
    python bottle学习(二)加载配置文件
    python bottle学习(一)快速入门
    python 文件读写模式r,r+,w,w+,a,a+的区别(附代码示例)
    Centos 虚拟机网络问题,网卡起不来,重启network服务失败
    机器学习框架MXnet安装步骤
    linux机器之间配置ssh无密访问
    好多年没写点技术相关的东西了,今天回来看看,找找当年做程序员的感觉
    vue路由传参的三种基本方式
    JavaScript判断对象是否包含某个属性的几种方法
    CSS实现三栏布局(左边固定、右边固定、中间自适应)的五种方式
  • 原文地址:https://www.cnblogs.com/Bill-LHR/p/6825763.html
Copyright © 2020-2023  润新知