本文的学习离不开各路大神的帮助,这里主要谢谢hevc_cjl和yangxiao_xiang喽~~~
// ====================================================================================================================
// Protected member functions
// ====================================================================================================================
/** Compress a CU block recursively with enabling sub-LCU-level delta QP*\param rpcBestCU*\param rpcTempCU*\param uiDepth*\returns Void**- for loop of QP value to compress the current CU with all possible QP
*/
#if AMP_ENC_SPEEDUP
Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth, PartSize eParentPartSize )
#else
Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth )
#endif
{TComPic* pcPic = rpcBestCU->getPic();// get Original YUV data from picture//getZorderIdxInCU():CU中的Z扫描绝对地址;getAddr():CU在slice中的地址;getPicYuvOrg():输入YUV的纹理信息m_ppcOrigYuv[uiDepth]->copyFromPicYuv( pcPic->getPicYuvOrg(), rpcBestCU->getAddr(), rpcBestCU->getZorderIdxInCU() );// variables for fast encoder decisionBool bEarlySkip = false;Bool bTrySplit = true;Double fRD_Skip = MAX_DOUBLE;// variable for Early CU determinationBool bSubBranch = true;// variable for Cbf fast mode PU decision---Cbf: coded block flagsBool doNotBlockPu = true;Bool earlyDetectionSkipMode = false;Bool bTrySplitDQP = true;static Double afCost[ MAX_CU_DEPTH ];//MAX_CU_DEPTH为7 即128以2为底的对数,其中128为最大的LCU,即TCUstatic Int aiNum[ MAX_CU_DEPTH ];if ( rpcBestCU->getAddr() == 0 ){::memset( afCost, 0, sizeof( afCost ) );::memset( aiNum, 0, sizeof( aiNum ) );}//memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法Bool bBoundary = false;UInt uiLPelX = rpcBestCU->getCUPelX();//CU内部左边界UInt uiRPelX = uiLPelX + rpcBestCU->getWidth(0) - 1;//CU内部右边界UInt uiTPelY = rpcBestCU->getCUPelY();//CU内部上边界UInt uiBPelY = uiTPelY + rpcBestCU->getHeight(0) - 1;//CU内部下边界Int iBaseQP = xComputeQP( rpcBestCU, uiDepth );//配置文件(.cfg)中设置的QP值32.可以设置范围为0-51Int iMinQP;Int iMaxQP;Bool isAddLowestQP = false;Int lowestQP = -rpcTempCU->getSlice()->getSPS()->getQpBDOffsetY();//返回类型 m_qpBDOffsetY (0)if( (g_uiMaxCUWidth>>uiDepth) >= rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() )//64>=64{Int idQP = m_pcEncCfg->getMaxDeltaQP();//配置文件中MaxDeltaQP设置为0.iMinQP = Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffsetY(), MAX_QP, iBaseQP-idQP );iMaxQP = Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffsetY(), MAX_QP, iBaseQP+idQP );//MAX_QP宏定义为51,同时MIN_QP宏定义为0if ( (rpcTempCU->getSlice()->getSPS()->getUseLossless()) && (lowestQP
#elseif(m_pcEncCfg->getUseRateCtrl()){Int qp = m_pcRateCtrl->getUnitQP();iMinQP = Clip3( MIN_QP, MAX_QP, qp);iMaxQP = Clip3( MIN_QP, MAX_QP, qp);}
#endif// If slice start or slice end is within this cu...如果bSliceStart和bSliceStart都为false,则当前块需要长宽各缩小一倍TComSlice * pcSlice = rpcTempCU->getPic()->getSlice(rpcTempCU->getPic()->getCurrSliceIdx());Bool bSliceStart = pcSlice->getSliceSegmentCurStartCUAddr()>rpcTempCU->getSCUAddr()&&pcSlice->getSliceSegmentCurStartCUAddr()
#endifif(!earlyDetectionSkipMode){for (Int iQP&#61;iMinQP; iQP<&#61;iMaxQP; iQP&#43;&#43;){if (isAddLowestQP && (iQP &#61;&#61; iMinQP)){iQP &#61; lowestQP;}rpcTempCU->initEstData( uiDepth, iQP );//--------------------------------------------------帧间模式选择开始201348----------------------------------------------\\// do inter modes, NxN, 2NxN, and Nx2Nif( rpcBestCU->getSlice()->getSliceType() !&#61; I_SLICE ){// 2Nx2N, NxNif ( !bEarlySkip ){if(!( (rpcBestCU->getWidth(0)&#61;&#61;8) && (rpcBestCU->getHeight(0)&#61;&#61;8) )){if( uiDepth &#61;&#61; g_uiMaxCUDepth - g_uiAddCUDepth && doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_NxN );rpcTempCU->initEstData( uiDepth, iQP );}}}// 2NxN, Nx2Nif(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_Nx2N );rpcTempCU->initEstData( uiDepth, iQP );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) &#61;&#61; SIZE_Nx2N ){doNotBlockPu &#61; rpcBestCU->getQtRootCbf( 0 ) !&#61; 0;}}if(doNotBlockPu){xCheckRDCostInter ( rpcBestCU, rpcTempCU, SIZE_2NxN );rpcTempCU->initEstData( uiDepth, iQP );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) &#61;&#61; SIZE_2NxN){doNotBlockPu &#61; rpcBestCU->getQtRootCbf( 0 ) !&#61; 0;}}#if 1//! Try AMP (SIZE_2NxnU, SIZE_2NxnD, SIZE_nLx2N, SIZE_nRx2N)AMP: Asymmetric motion partitions 非对称运动分割if( pcPic->getSlice(0)->getSPS()->getAMPAcc(uiDepth) ){
#if AMP_ENC_SPEEDUP Bool bTestAMP_Hor &#61; false, bTestAMP_Ver &#61; false;#if AMP_MRGBool bTestMergeAMP_Hor &#61; false, bTestMergeAMP_Ver &#61; false;deriveTestModeAMP (rpcBestCU, eParentPartSize, bTestAMP_Hor, bTestAMP_Ver, bTestMergeAMP_Hor, bTestMergeAMP_Ver);
#elsederiveTestModeAMP (rpcBestCU, eParentPartSize, bTestAMP_Hor, bTestAMP_Ver);
#endif//! Do horizontal AMP 水平非对称运动分割if ( bTestAMP_Hor ){if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU );rpcTempCU->initEstData( uiDepth, iQP );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) &#61;&#61; SIZE_2NxnU ){doNotBlockPu &#61; rpcBestCU->getQtRootCbf( 0 ) !&#61; 0;}}if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD );rpcTempCU->initEstData( uiDepth, iQP );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) &#61;&#61; SIZE_2NxnD ){doNotBlockPu &#61; rpcBestCU->getQtRootCbf( 0 ) !&#61; 0;}}}
#if AMP_MRGelse if ( bTestMergeAMP_Hor ) {if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU, true );rpcTempCU->initEstData( uiDepth, iQP );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) &#61;&#61; SIZE_2NxnU ){doNotBlockPu &#61; rpcBestCU->getQtRootCbf( 0 ) !&#61; 0;}}if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD, true );rpcTempCU->initEstData( uiDepth, iQP );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) &#61;&#61; SIZE_2NxnD ){doNotBlockPu &#61; rpcBestCU->getQtRootCbf( 0 ) !&#61; 0;}}}
#endif//! Do vertical AMP 垂直非对称运动分割if ( bTestAMP_Ver ){if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N );rpcTempCU->initEstData( uiDepth, iQP );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) &#61;&#61; SIZE_nLx2N ){doNotBlockPu &#61; rpcBestCU->getQtRootCbf( 0 ) !&#61; 0;}}if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N );rpcTempCU->initEstData( uiDepth, iQP );}}
#if AMP_MRGelse if ( bTestMergeAMP_Ver ){if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N, true );rpcTempCU->initEstData( uiDepth, iQP );if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) &#61;&#61; SIZE_nLx2N ){doNotBlockPu &#61; rpcBestCU->getQtRootCbf( 0 ) !&#61; 0;}}if(doNotBlockPu){xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N, true );rpcTempCU->initEstData( uiDepth, iQP );}}
#endif#elsexCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU );rpcTempCU->initEstData( uiDepth, iQP );xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD );rpcTempCU->initEstData( uiDepth, iQP );xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N );rpcTempCU->initEstData( uiDepth, iQP );xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N );rpcTempCU->initEstData( uiDepth, iQP );#endif}
#endif}
//------------------------------------------------------帧间模式选择结束----------------------------------------------\\//------------------------------------------------------帧内模式选择开始201348----------------------------------------------\\// do normal intra modesif ( !bEarlySkip )//bEarlySkip&#61;false{/ texture component type//enum TextType//{// TEXT_LUMA, ///
//------------------------------------------------------帧内模式选择结束----------------------------------------------// test PCM测试PCM模式&#xff0c;一般不使用这种模式if(pcPic->getSlice(0)->getSPS()->getUsePCM()&& rpcTempCU->getWidth(0) <&#61; (1<
#if RATE_CONTROL_LAMBDA_DOMAINm_addSADDepth&#43;&#43;;
#endif}// copy orginal YUV samples to PCM bufferif( rpcBestCU->isLosslessCoded(0) && (rpcBestCU->getIPCMFlag(0) &#61;&#61; false)){xFillPCMBuffer(rpcBestCU, m_ppcOrigYuv[uiDepth]);}if( (g_uiMaxCUWidth>>uiDepth) &#61;&#61; rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() ){Int idQP &#61; m_pcEncCfg->getMaxDeltaQP();iMinQP &#61; Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffsetY(), MAX_QP, iBaseQP-idQP );iMaxQP &#61; Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffsetY(), MAX_QP, iBaseQP&#43;idQP );if ( (rpcTempCU->getSlice()->getSPS()->getUseLossless()) && (lowestQP
#if RATE_CONTROL_LAMBDA_DOMAINif ( m_pcEncCfg->getUseRateCtrl() ){iMinQP &#61; m_pcRateCtrl->getRCQP();iMaxQP &#61; m_pcRateCtrl->getRCQP();}
#elseif(m_pcEncCfg->getUseRateCtrl()){Int qp &#61; m_pcRateCtrl->getUnitQP();iMinQP &#61; Clip3( MIN_QP, MAX_QP, qp);iMaxQP &#61; Clip3( MIN_QP, MAX_QP, qp);}
#endiffor (Int iQP&#61;iMinQP; iQP<&#61;iMaxQP; iQP&#43;&#43;){if (isAddLowestQP && (iQP &#61;&#61; iMinQP)){iQP &#61; lowestQP;}rpcTempCU->initEstData( uiDepth, iQP );// further split 进一步进行CU分割if( bSubBranch && bTrySplitDQP && uiDepth
#elsexCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth );
#endifrpcTempCU->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 );}}if( !bBoundary ){m_pcEntropyCoder->resetBits();m_pcEntropyCoder->encodeSplitFlag( rpcTempCU, 0, uiDepth, true );rpcTempCU->getTotalBits() &#43;&#61; m_pcEntropyCoder->getNumberOfWrittenBits(); // split bitsif(m_pcEncCfg->getUseSBACRD()){rpcTempCU->getTotalBins() &#43;&#61; ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();}}rpcTempCU->getTotalCost() &#61; m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );if( (g_uiMaxCUWidth>>uiDepth) &#61;&#61; rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() && rpcTempCU->getSlice()->getPPS()->getUseDQP()){Bool hasResidual &#61; false;for( UInt uiBlkIdx &#61; 0; uiBlkIdx
#if !RDO_WITHOUT_DQP_BITSm_pcEntropyCoder->resetBits();m_pcEntropyCoder->encodeQP( rpcTempCU, uiTargetPartIdx, false );rpcTempCU->getTotalBits() &#43;&#61; m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bitsif(m_pcEncCfg->getUseSBACRD()){rpcTempCU->getTotalBins() &#43;&#61; ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();}rpcTempCU->getTotalCost() &#61; m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
#endifBool foundNonZeroCbf &#61; false;rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( uiTargetPartIdx ), rpcTempCU, 0, uiDepth, foundNonZeroCbf );assert( foundNonZeroCbf );}else{rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( uiTargetPartIdx ), 0, uiDepth ); // set QP to default QP}}if( m_bUseSBACRD ){m_pppcRDSbacCoder[uhNextDepth][CI_NEXT_BEST]->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]);}Bool isEndOfSlice &#61; rpcBestCU->getSlice()->getSliceMode()&#61;&#61;FIXED_NUMBER_OF_BYTES&& (rpcBestCU->getTotalBits()>rpcBestCU->getSlice()->getSliceArgument()<<3);Bool isEndOfSliceSegment &#61; rpcBestCU->getSlice()->getSliceSegmentMode()&#61;&#61;FIXED_NUMBER_OF_BYTES&& (rpcBestCU->getTotalBits()>rpcBestCU->getSlice()->getSliceSegmentArgument()<<3);if(isEndOfSlice||isEndOfSliceSegment){rpcBestCU->getTotalCost()&#61;rpcTempCU->getTotalCost()&#43;1;}xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth); // RD compare current larger prediction} // with sub partitioned prediction.判断决定是否选择本层CU还是下层CUif (isAddLowestQP && (iQP &#61;&#61; lowestQP)){iQP &#61; iMinQP;}}rpcBestCU->copyToPic(uiDepth); // Copy Best data to Picture for next partition prediction.xCopyYuv2Pic( rpcBestCU->getPic(), rpcBestCU->getAddr(), rpcBestCU->getZorderIdxInCU(), uiDepth, uiDepth, rpcBestCU, uiLPelX, uiTPelY ); // Copy Yuv data to picture Yuvif( bBoundary ||(bSliceEnd && bInsidePicture)){return;}// Assert if Best prediction mode is NONE// Selected mode&#39;s RD-cost must be not MAX_DOUBLE.assert( rpcBestCU->getPartitionSize ( 0 ) !&#61; SIZE_NONE );assert( rpcBestCU->getPredictionMode( 0 ) !&#61; MODE_NONE );assert( rpcBestCU->getTotalCost ( ) !&#61; MAX_DOUBLE );
}