北京工业大学 朱维佳
邮箱: sparkjj1985@gmail.com(欢迎探讨任何关于编码的问题)
如转发本文章,请注明出处
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过程,这个函数会被调用两次: