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的色度信息反量化及重建工作


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM