转载自 http://blog.sina.com.cn/s/blog_7b7ddaf90101edj2.html
首先,对于四叉树的分割形式,大家想必都已经了解了,这里就不进行过多的赘述,下面是常见的四叉树结构示意图:
接下来是代码部分:
该过程主要由TEncCu::xCompressCU函数的递归实现。
-
// further split进一步进行CU的分割 -
if( bSubBranch && bTrySplitDQP && uiDepth < g_uiMaxCUDepth - g_uiAddCUDepth ) -
{ -
UChar uhNextDepth = uiDepth+1; -
TComDataCU* pcSubBestPartCU = m_ppcBestCU[uhNextDepth]; -
TComDataCU* pcSubTempPartCU = m_ppcTempCU[uhNextDepth]; -
-
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++ )//每次分成四个更小的CU -
{ -
pcSubBestPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init. -
pcSubTempPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init. -
-
Bool bInSlice = pcSubBestPartCU->getSCUAddr()+pcSubBestPartCU->getTotalNumPart()>pcSlice->getDependentSliceCurStar tCUAddr()&&pcSubBestPartCU->getSCUAddr()getDependentSliceCurEndC UAddr(); -
if(bInSlice && ( pcSubBestPartCU->getCUPelX() < pcSlice->getSPS()->getPicWidthInLumaSamples () ) && ( pcSubBestPartCU->getCUPelY() < pcSlice->getSPS()->getPicHeightInLumaSample s() ) ) -
{ -
if( m_bUseSBACRD ) -
{ -
if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer -
{ -
m_pppcRDSbacCoder[uhNextDepth][CI_CURR_BEST]->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]); -
} -
else -
{ -
m_pppcRDSbacCoder[uhNextDepth][CI_CURR_BEST]->load(m_pppcRDSbacCoder[uhNextDepth][CI_NEXT_BEST]); -
} -
} -
- #if
AMP_ENC_SPEEDUP -
if ( rpcBestCU->isIntra(0) ) -
{ -
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth, SIZE_NONE );//递归函数 -
} -
else -
{ -
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth, rpcBestCU->getPartitionSize(0) );//递归函数 -
} - #else
-
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth ); - #endif
-
-
rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth ); // Keep best part data to current temporary data. -
xCopyYuv2Tmp( pcSubBestPartCU->getTotalNumPart()*uiPartUnitIdx, uhNextDepth ); -
} -
else if (bInSlice) -
{ -
pcSubBestPartCU->copyToPic( uhNextDepth ); -
rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth ); -
} -
}
上述递归函数结束后,然后再通过xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth);判断决定是否选择本层CU还是下层CU.
以下是编程实现输出一个LCU的分割模式:
- //
We need to split, so don't try these modes. - if(!bSliceEnd
&& !bSliceStart && bInsidePicture ) - {
-
for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++) -
{ -
if (isAddLowestQP && (iQP == iMinQP)) -
{ -
iQP = lowestQP; -
} -
// variables for fast encoder decision -
bEarlySkip = false; -
bTrySplit = true; -
fRD_Skip = MAX_DOUBLE; -
-
rpcTempCU->initEstData( uiDepth, iQP ); -
//==输出分区深度信息depth==// -
cout<<"Depth:"; -
for(Int i=0;i<=uiDepth;i++) -
cout<<"->"; -
cout<<uiDepth<<endl; -
-
// do inter modes, SKIP and 2Nx2N
Depth:->0
Depth:->->1
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->1
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->1
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->1
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->2
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
Depth:->->->->3
上一篇文章对每个LCU进行遍历所有的CU分支,只是显示LCU的分割过程,但是并不能确定一个LCU分割结果,经过zhuix7788指出,意识到自己的误区了,后来通过一天的折腾,终于找到了真正的分割输出的结果。因为一个LCU的最终分割是要经过预测和熵编码后才能通过率失真代价确定。
所以,可以在m_pcCuEncoder->compressCU( pcCU );后查看pcCU->m_puhDepth对应的数组。这是一个大小为256的数组, 表示LCU的256个4X4到底如何分割的!
(详情可以参考
实现代码如下:
- //
run CU encoder - m_pcCuEncoder->compressCU(
pcCU ); - //==LCU分割单元深度信息输出==//
- fprintf(
g_hTrace,"=======LCU=========\n"); - for(Int
i=0;i<256;i++) - fprintf(
g_hTrace, "%d\t",pcCU->getDepth(i));
输出结果前先要进行TraceEnc开启设定,在TComRom.h文件下设置#define
输出结果在HM-9.0-dev\cfg文件夹下的TraceEnc文件中。
打印输出结果如下:
=======LCU=========
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
3 3
3 3
3 3
3 3
3 3
3 3
3 3
3 3
LCU的基本存储单元为4x4的块,这个可以在HM平台的HM-9.0-dev\doc文件夹下找到一个README_data-structure文件,上面有介绍。以下就是一个LCU的存储结构示意图:
下面是根据输出结果重构的一个LCU(64x64)的分割示意图:
其中红色数字代表当前块的分割深度。
或者采用下面的方法也可以查看:
- //
analysis of CU -
xCompressCU( m_ppcBestCU[0], m_ppcTempCU[0], 0 ); - UInt
LCUDepth[256] ; - for
(Int i=0;i<256;i++) - {
-
LCUDepth[i]= m_ppcBestCU[0]->getDepth(i); -
cout<<"CurTempCUDepth: "<<LCUDepth[i]<<endl; - }