#if JVET_C0024_QTBT
Void TEncCu::xEncodeCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt uiWidth, UInt uiHeight, UInt uiSplitConstrain )
#else
Void TEncCu::xEncodeCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth )
#endif
{
#if JVET_C0024_BT_RMV_REDUNDANT
pcCU->setSplitConstrain( uiSplitConstrain );
Bool bQTreeValid = false;//bQTreeValid不用于知道四叉树的划分,而只用于赋值给bBTVerRmvEnable用于帧间二叉树划分的限制;
#endif
TComPic *const pcPic = pcCU->getPic();
TComSlice *const pcSlice = pcCU->getSlice();
const TComSPS &sps =*(pcSlice->getSPS());
const TComPPS &pps =*(pcSlice->getPPS());
#if !JVET_C0024_QTBT
const UInt maxCUWidth = sps.getMaxCUWidth();
const UInt maxCUHeight = sps.getMaxCUHeight();
Bool bBoundary = false;
#endif//当前CU的左上角和右下角的坐标;
UInt uiLPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ];
#if JVET_C0024_QTBT
const UInt uiRPelX = uiLPelX + uiWidth - 1;
#else
const UInt uiRPelX = uiLPelX + (maxCUWidth>>uiDepth) - 1;
#endif
UInt uiTPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ];
#if JVET_C0024_QTBT
const UInt uiBPelY = uiTPelY + uiHeight - 1;
#else
const UInt uiBPelY = uiTPelY + (maxCUHeight>>uiDepth) - 1;
#endif
#if JVET_C0024_QTBT
Bool bForceQT = uiWidth > MAX_TU_SIZE;
if( bForceQT )
{
assert(uiWidth == uiHeight);
}
UInt uiCTUSize = pcCU->getSlice()->getSPS()->getCTUSize();
#if JVET_C0024_DELTA_QP_FIX
UInt uiQTWidth = uiCTUSize>>uiDepth;
UInt uiQTHeight = uiCTUSize>>uiDepth;
const UInt uiQTBTDepth = (uiDepth<<1) + (g_aucConvertToBit[uiQTWidth]-g_aucConvertToBit[uiWidth] + g_aucConvertToBit[uiQTHeight]-g_aucConvertToBit[uiHeight]);
const UInt uiMaxDQPDepthQTBT = pps.getMaxCuDQPDepth() << 1;
#endif
if (uiCTUSize>>uiDepth == uiWidth && uiWidth==uiHeight)//判断是否是正方形;
{
#endif
if( ( uiRPelX < sps.getPicWidthInLumaSamples() ) && ( uiBPelY < sps.getPicHeightInLumaSamples() ) )//没到达边缘
{
#if JVET_C0024_QTBT
if( bForceQT )//强迫四叉树划分
{
assert(uiDepth < pcCU->getDepth( uiAbsPartIdx ) );
}
else//不强迫四叉树划分
#endif
m_pcEntropyCoder->encodeSplitFlag( pcCU, uiAbsPartIdx, uiDepth );//编码四叉树的划分标记;
}
else//是边缘,则不编码四叉树划分标记
{
#if JVET_C0024_QTBT
assert(uiDepth < pcCU->getDepth( uiAbsPartIdx ) );
#else
bBoundary = true;
#endif
}
#if JVET_C0024_BT_RMV_REDUNDANT
bQTreeValid = true;
UInt uiMinQTSize = sps.getMinQTSize(pcCU->getSlice()->getSliceType(), pcCU->getTextType());
if ((uiCTUSize>>uiDepth) <= uiMinQTSize)//如果此时方块大小小于等于最小的四叉树大小,则不进行四叉树划分;
{
bQTreeValid = false;
}
#endif
#if JVET_C0024_QTBT
if( uiDepth < pcCU->getDepth( uiAbsPartIdx ) )//如果还没达到最大深度,用深度来判断是否进行了划分;
#else
if( ( ( uiDepth < pcCU->getDepth( uiAbsPartIdx ) ) && ( uiDepth < sps.getLog2DiffMaxMinCodingBlockSize() ) ) || bBoundary )
#endif
{//getNumPartitionsInCtu()函数返回一个CTU中包含4*4小块的个数;
UInt uiQNumParts = ( pcPic->getNumPartitionsInCtu() >> (uiDepth<<1) )>>2;//最小的分区是4x4大小的块,这里计算出以该4x4块为单位的分割数,这么做便于计算当前CU的Zorder坐标
#if JVET_C0024_DELTA_QP_FIX
if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
#else
if( uiDepth == pps.getMaxCuDQPDepth() && pps.getUseDQP())
#endif
{
setdQPFlag(true);
#if JVET_C0024_DELTA_QP_FIX
pcCU->setQuPartIdx( uiAbsPartIdx );
pcCU->setQuLastCodedQP( pcCU->getCodedQP() );
#endif
}
if( uiDepth == pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth() && pcSlice->getUseChromaQpAdj())
{
setCodeChromaQpAdjFlag(true);
}
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++, uiAbsPartIdx+=uiQNumParts )//如果进行了四叉树划分,则递归调用4次xEncodeCU;
{
uiLPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ];
uiTPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ];
if( ( uiLPelX < sps.getPicWidthInLumaSamples() ) && ( uiTPelY < sps.getPicHeightInLumaSamples() ) )//没达到图像边界
{
#if JVET_C0024_QTBT
xEncodeCU( pcCU, uiAbsPartIdx, uiDepth+1, uiWidth>>1, uiHeight>>1 );//深度加1,宽和高减半
#else
xEncodeCU( pcCU, uiAbsPartIdx, uiDepth+1 );
#endif
}
#if JVET_C0024_QTBT
else//到达边界,则累加编码面积;
{
pcCU->getPic()->addCodedAreaInCTU(uiWidth*uiHeight>>2);
}
#endif
}
return;
}
#if JVET_C0024_QTBT
}
#if JVET_C0024_BT_RMV_REDUNDANT
Bool bBTHorRmvEnable = false;
Bool bBTVerRmvEnable = false;
if (pcCU->getSlice()->getSliceType() != I_SLICE)//不是I SLICE才能进行remove redundant???
{
bBTHorRmvEnable = true;
bBTVerRmvEnable = bQTreeValid;
}
#endif
#if JVET_C0024_SPS_MAX_BT_DEPTH
UInt uiMaxBTD = pcSlice->isIntra() ? (isLuma(pcCU->getTextType())?sps.getMaxBTDepthISliceL():sps.getMaxBTDepthISliceC()): sps.getMaxBTDepth();
#else
UInt uiMaxBTD = pcCU->getSlice()->isIntra() ? (isLuma(pcCU->getTextType())?MAX_BT_DEPTH:MAX_BT_DEPTH_C): MAX_BT_DEPTH_INTER;
#endif
#if JVET_C0024_SPS_MAX_BT_SIZE
UInt uiMaxBTSize = pcSlice->isIntra() ? (isLuma(pcCU->getTextType())?sps.getMaxBTSizeISliceL():sps.getMaxBTSizeISliceC()): sps.getMaxBTSize();
#else
UInt uiMaxBTSize = isLuma(pcCU->getTextType()) ? pcCU->getSlice()->getMaxBTSize(): MAX_BT_SIZE_C;
#endif
UInt uiMinBTSize = pcCU->getSlice()->isIntra() ? (isLuma(pcCU->getTextType())?MIN_BT_SIZE:MIN_BT_SIZE_C): MIN_BT_SIZE_INTER;
UInt uiBTDepth = pcCU->getBTDepth(uiAbsPartIdx, uiWidth, uiHeight);//二叉树的深度是从四叉树叶节点开始算的
if ( (uiHeight>uiMinBTSize || uiWidth>uiMinBTSize)
&& uiWidth<=uiMaxBTSize && uiHeight<=uiMaxBTSize && uiBTDepth<uiMaxBTD) //判断是否进行了二叉树划分
{
#if JVET_C0024_BT_RMV_REDUNDANT
uiSplitConstrain = 0;
#endif
m_pcEntropyCoder->encodeBTSplitMode(pcCU, uiAbsPartIdx, uiWidth, uiHeight);//编码二叉树划分标记;
if (pcCU->getBTSplitModeForBTDepth(uiAbsPartIdx, uiBTDepth)==1)//水平二叉树划分;
{
#if JVET_C0024_DELTA_QP_FIX
if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
{
setdQPFlag(true);
#if JVET_C0024_DELTA_QP_FIX
pcCU->setQuPartIdx( uiAbsPartIdx );
pcCU->setQuLastCodedQP( pcCU->getCodedQP() );
#endif
}
#endif
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//递归调用两次xEncodeCU;
{
if (uiPartUnitIdx==1)
{
uiAbsPartIdx = g_auiRasterToZscan[g_auiZscanToRaster[uiAbsPartIdx]
+ (uiHeight>>1)/pcCU->getPic()->getMinCUHeight()*pcCU->getPic()->getNumPartInCtuWidth()];
}
#if JVET_C0024_BT_RMV_REDUNDANT
xEncodeCU( pcCU, uiAbsPartIdx, uiDepth, uiWidth, uiHeight>>1, uiSplitConstrain );//高度减半,uiDepth不变,应该这个指的是四叉树的深度
if (pcCU->getBTSplitModeForBTDepth(uiAbsPartIdx, uiBTDepth+1) == 2 && bBTHorRmvEnable && uiPartUnitIdx==0)//如果当前层是水平划分,下一层是上边垂直个划分
{
uiSplitConstrain = 2;//则限制下一层进行垂直划分(即防止通过二叉树划分出来一个四叉树)
}
#else
xEncodeCU( pcCU, uiAbsPartIdx, uiDepth, uiWidth, uiHeight>>1 );
#endif
}
return;
}
else if (pcCU->getBTSplitModeForBTDepth(uiAbsPartIdx, uiBTDepth)==2)//垂直二叉树划分;
{
#if JVET_C0024_DELTA_QP_FIX
if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
{
setdQPFlag(true);
#if JVET_C0024_DELTA_QP_FIX
pcCU->setQuPartIdx( uiAbsPartIdx );
pcCU->setQuLastCodedQP( pcCU->getCodedQP() );
#endif
}
#endif
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//递归调用两次xEncodeCU;
{
if (uiPartUnitIdx==1)
{
uiAbsPartIdx = g_auiRasterToZscan[g_auiZscanToRaster[uiAbsPartIdx]
+ (uiWidth>>1)/pcCU->getPic()->getMinCUWidth()];
}
#if JVET_C0024_BT_RMV_REDUNDANT
xEncodeCU( pcCU, uiAbsPartIdx, uiDepth, uiWidth>>1, uiHeight, uiSplitConstrain );//宽度减半,uiDepth也不变
if (pcCU->getBTSplitModeForBTDepth(uiAbsPartIdx, uiBTDepth+1) == 1 && bBTVerRmvEnable && uiPartUnitIdx==0)//如果当前层是垂直划分,且下一层的左边是水平划分,
{
uiSplitConstrain = 1;//则限制右边水平划分(即防止通过二叉树划分出来一个四叉树);
}
#else
xEncodeCU( pcCU, uiAbsPartIdx, uiDepth, uiWidth>>1, uiHeight );
#endif
}
return;
}
}
pcCU->getPic()->addCodedAreaInCTU(uiWidth*uiHeight);
UInt uiBlkX = g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ] >> MIN_CU_LOG2;
UInt uiBlkY = g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ] >> MIN_CU_LOG2;
pcCU->getPic()->setCodedBlkInCTU(true, uiBlkX, uiBlkY, uiWidth>> MIN_CU_LOG2, uiHeight>> MIN_CU_LOG2);
#endif
#if JVET_C0024_AMAX_BT
if (!pcCU->getSlice()->isIntra())//不是I帧
{
g_uiBlkSize[pcCU->getSlice()->getDepth()] += uiWidth*uiHeight;
g_uiNumBlk[pcCU->getSlice()->getDepth()]++;
}
#endif
#if JVET_C0024_DELTA_QP_FIX
if( uiQTBTDepth <= uiMaxDQPDepthQTBT && pps.getUseDQP())
#else
if( uiDepth <= pps.getMaxCuDQPDepth() && pps.getUseDQP())
#endif
{
setdQPFlag(true);
#if JVET_C0024_DELTA_QP_FIX
pcCU->setQuPartIdx( uiAbsPartIdx );
pcCU->setQuLastCodedQP( pcCU->getCodedQP() );
#endif
}
if( uiDepth <= pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth() && pcSlice->getUseChromaQpAdj())
{
setCodeChromaQpAdjFlag(true);
}
if (pps.getTransquantBypassEnableFlag())
{
m_pcEntropyCoder->encodeCUTransquantBypassFlag( pcCU, uiAbsPartIdx );//编码CU的变换量化旁路标记;
}
if( !pcSlice->isIntra() )//不是I帧;
{
m_pcEntropyCoder->encodeSkipFlag( pcCU, uiAbsPartIdx );//编码skip标记,只有帧间有skip;
}
if( pcCU->isSkipped( uiAbsPartIdx ) )//如果是skip模式;
{
#if VCEG_AZ07_FRUC_MERGE
m_pcEntropyCoder->encodeFRUCMgrMode( pcCU , uiAbsPartIdx , 0 );//编码FRUCmerge模式;
if( !pcCU->getFRUCMgrMode( uiAbsPartIdx ) )//如果不是FRUC merge模式,因为FRUC merge,Affine merge和merge是竞争关系;
#endif
#if COM16_C1016_AFFINE
{
if ( pcCU->isAffineMrgFlagCoded(uiAbsPartIdx, 0) )
{
m_pcEntropyCoder->encodeAffineFlag( pcCU, uiAbsPartIdx, 0 );//编码仿射标记;
}
if ( !pcCU->isAffine(uiAbsPartIdx) )//如果不是仿射;
{
m_pcEntropyCoder->encodeMergeIndex( pcCU, uiAbsPartIdx );//编码MERGE索引;
}
}
#else
m_pcEntropyCoder->encodeMergeIndex( pcCU, uiAbsPartIdx );
#endif
#if VCEG_AZ06_IC
m_pcEntropyCoder->encodeICFlag ( pcCU, uiAbsPartIdx );//编码局部亮度补偿标记;
#endif
#if !JVET_C0024_QTBT
finishCU(pcCU,uiAbsPartIdx);
#endif
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() )
{
pcCU->setCodedQP( pcCU->getQP(uiAbsPartIdx) );
}
#endif
return;
}
m_pcEntropyCoder->encodePredMode( pcCU, uiAbsPartIdx );//编码预测模式
#if JVET_C0024_QTBT
if (isLuma(pcCU->getTextType()))
{
#endif
#if VCEG_AZ05_INTRA_MPI
m_pcEntropyCoder->encodeMPIIdx(pcCU, uiAbsPartIdx);
#endif
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
m_pcEntropyCoder->encodePDPCIdx(pcCU, uiAbsPartIdx);
#endif
#if JVET_C0024_QTBT
}
#else
m_pcEntropyCoder->encodePartSize( pcCU, uiAbsPartIdx, uiDepth );
#endif
#if JVET_C0024_QTBT
if (pcCU->isIntra( uiAbsPartIdx ) )//如果是帧内预测
#else
if (pcCU->isIntra( uiAbsPartIdx ) && pcCU->getPartitionSize( uiAbsPartIdx ) == SIZE_2Nx2N )
#endif
{
m_pcEntropyCoder->encodeIPCMInfo( pcCU, uiAbsPartIdx );//编码PCM信息,所以PCM属于帧内;
if(pcCU->getIPCMFlag(uiAbsPartIdx))
{
#if !JVET_C0024_QTBT
// Encode slice finish
finishCU(pcCU,uiAbsPartIdx);
#endif
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() )
{
pcCU->setCodedQP( pcCU->getQP(uiAbsPartIdx) );
}
#endif
return;
}
}
// prediction Info ( Intra : direction mode, Inter : Mv, reference idx )
m_pcEntropyCoder->encodePredInfo( pcCU, uiAbsPartIdx );//编码预测信息(帧内:预测方向,帧间:MV和参考帧索引);
#if COM16_C806_OBMC
m_pcEntropyCoder->encodeOBMCFlag( pcCU, uiAbsPartIdx );//编码重叠块运动补偿标记;
#endif
#if VCEG_AZ06_IC
m_pcEntropyCoder->encodeICFlag ( pcCU, uiAbsPartIdx );//编码局部光照补偿标记;
#endif
// Encode Coefficients
Bool bCodeDQP = getdQPFlag();
Bool codeChromaQpAdj = getCodeChromaQpAdjFlag();
#if VCEG_AZ05_ROT_TR || VCEG_AZ05_INTRA_MPI || COM16_C1044_NSST || COM16_C1046_PDPC_INTRA
Int bNonZeroCoeff = false;
#endif
#if JVET_C0045_C0053_NO_NSST_FOR_TS
Int iNonZeroCoeffNonTs;
#endif
m_pcEntropyCoder->encodeCoeff( pcCU, uiAbsPartIdx, uiDepth, bCodeDQP, codeChromaQpAdj
#if VCEG_AZ05_ROT_TR || VCEG_AZ05_INTRA_MPI || COM16_C1044_NSST || COM16_C1046_PDPC_INTRA
, bNonZeroCoeff
#endif
#if JVET_C0045_C0053_NO_NSST_FOR_TS
, iNonZeroCoeffNonTs
#endif
);//编码残差系数;
setCodeChromaQpAdjFlag( codeChromaQpAdj );
setdQPFlag( bCodeDQP );
#if JVET_C0024_DELTA_QP_FIX
if( pps.getUseDQP() )
{
pcCU->setCodedQP( pcCU->getQP(uiAbsPartIdx) );
}
#endif
#if !JVET_C0024_QTBT
// --- write terminating bit ---
finishCU(pcCU,uiAbsPartIdx);
#endif
}