相信會有不少人對如何確定CU最終的劃分有所困惑(包括我在內,剛開始接觸時也不知道該怎麼做),我覺得很大的一個原因就是CU是遞歸劃分的,這就導致在尋找確定最佳分割位置時比較困難。
其實,解決問題的辦法說難也不難,關鍵在於思路的轉換,既然對於xCompressCU中是如何保存劃分模式的覺得難以理解,何不跳出這個小圈子尋找新的方法呢?
我們可以從解碼器的角度來考慮,因爲最終編碼後的碼流是要經過解碼器解碼的,解碼器事先也是不知道CU到底最終是如何劃分的。因此,可以推斷,編碼器必然會保存下這個信息,至少是提示信息。不妨參考encodeCU這個函數的實現,因爲它是最終將信息編碼成碼流的函數。該函數調用的是xEncodeCU來完成實際工作,截取它當中其中一段對我們有用的代碼:
- // We need to split, so don't try these modes.
- if(!bSliceStart&&( uiRPelX < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( uiBPelY < pcSlice->getSPS()->getPicHeightInLumaSamples() ) )
- {
- m_pcEntropyCoder->encodeSplitFlag( pcCU, uiAbsPartIdx, uiDepth );
- }
不錯,encodeSplitFlag就是用於編碼CU分割信息的函數,它的實現如下:
- // Split mode
- Void TEncEntropy::encodeSplitFlag( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, Bool bRD )
- {
- if( bRD )
- {
- uiAbsPartIdx = 0;
- }
- if( !bRD )
- {
- if( pcCU->getLastCUSucIPCMFlag() && pcCU->getIPCMFlag(uiAbsPartIdx) )
- {
- return;
- }
- }
- m_pcEntropyCoderIf->codeSplitFlag( pcCU, uiAbsPartIdx, uiDepth );
- }
對我們有用的函數是最後的codeSplitFlag函數,它的實現如下:
- Void TEncSbac::codeSplitFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth )
- {
- if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth )
- return;
- UInt uiCtx = pcCU->getCtxSplitFlag( uiAbsPartIdx, uiDepth );
- UInt uiCurrSplitFlag = ( pcCU->getDepth( uiAbsPartIdx ) > uiDepth ) ? 1 : 0;
- assert( uiCtx < 3 );
- m_pcBinIf->encodeBin( uiCurrSplitFlag, m_cCUSplitFlagSCModel.get( 0, 0, uiCtx ) );
- DTRACE_CABAC_VL( g_nSymbolCounter++ )
- DTRACE_CABAC_T( "\tSplitFlag\n" )
- return;
- }
可以看到最爲有用的一句:
- UInt uiCurrSplitFlag = ( pcCU->getDepth( uiAbsPartIdx ) > uiDepth ) ? 1 : 0;
也就是說,通過判斷pcCU->getDepth( uiAbsPartIdx )是否大於uiDepth來確定當前CU是否還要繼續分割,後者我們知道,是當前CU的深度,那麼前者呢?自然就是在xCompressCU中確定下來的當前CU的最佳分割模式。至此,我們最想獲得的信息就在這裏。
經過上述分析後,一句話總結獲取CU最佳劃分的方法:在HM中調用完xCompressCU之後(至少也應該是compressCU調用完它之後,此時最佳PU爲m_ppcBestCU[0]),在調用encodeCU之前(也可以之後,這個只要保證pcCU沒被修改過即可),對compressCU的參數pcCU進行類似語句: pcCU->getDepth( uiAbsPartIdx ),即可獲得Z order爲uiAbsPartIdx的4x4塊的深度,如果把整個CU每個4x4塊的深度確定下來,那麼它的劃分自然也就確定下來了。
下圖是我打印出的某一塊CU在最大尺寸64 x 64,最大深度爲4(即depth = 0 ~ 3)的某一種劃分情況,每個數字代表對應位置的4x4塊的實際深度,紅線給出CU的最佳劃分。