相信会有不少人对如何确定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的最佳划分。