第31篇博文大体介绍了HEVC参考代码HM10的编码器结构,但仅仅停留在compressCU()以上的层次,并未对具体编码的结构做深入解析。在此篇博文中我们依据对视频YUV序列的帧内编码的流程,重新梳理HM编码器的代码结构。
主要包括:
以上各个函数分别在前一个函数中调用,形成类似一个反向的call stack的结构。
TEncCu::compressCU()函数的实现如下:
Void TEncCu::compressCU( TComDataCU*& rpcCU ) { // initialize CU data m_ppcBestCU[0]->initCU( rpcCU->getPic(), rpcCU->getAddr() ); m_ppcTempCU[0]->initCU( rpcCU->getPic(), rpcCU->getAddr() ); #if RATE_CONTROL_LAMBDA_DOMAIN m_addSADDepth = 0; m_LCUPredictionSAD = 0; m_temporalSAD = 0; #endif // analysis of CU xCompressCU( m_ppcBestCU[0], m_ppcTempCU[0], 0 ); #if ADAPTIVE_QP_SELECTION if( m_pcEncCfg->getUseAdaptQpSelect() ) { if(rpcCU->getSlice()->getSliceType()!=I_SLICE) //IIII { xLcuCollectARLStats( rpcCU); } } #endif }
if ( !bEarlySkip ) { // speedup for inter frames if( rpcBestCU->getSlice()->getSliceType() == I_SLICE || rpcBestCU->getCbf( 0, TEXT_LUMA ) != 0 || rpcBestCU->getCbf( 0, TEXT_CHROMA_U ) != 0 || rpcBestCU->getCbf( 0, TEXT_CHROMA_V ) != 0 ) // avoid very complex intra if it is unlikely { xCheckRDCostIntra( rpcBestCU, rpcTempCU, SIZE_2Nx2N ); rpcTempCU->initEstData( uiDepth, iQP ); if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth ) { if( rpcTempCU->getWidth(0) > ( 1 << rpcTempCU->getSlice()->getSPS()->getQuadtreeTULog2MinSize() ) ) { xCheckRDCostIntra( rpcBestCU, rpcTempCU, SIZE_NxN ); rpcTempCU->initEstData( uiDepth, iQP ); } } } }
Void TEncCu::xCheckRDCostIntra( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize eSize ) { UInt uiDepth = rpcTempCU->getDepth( 0 ); rpcTempCU->setSkipFlagSubParts( false, 0, uiDepth ); rpcTempCU->setPartSizeSubParts( eSize, 0, uiDepth ); rpcTempCU->setPredModeSubParts( MODE_INTRA, 0, uiDepth ); rpcTempCU->setCUTransquantBypassSubParts( m_pcEncCfg->getCUTransquantBypassFlagValue(), 0, uiDepth ); Bool bSeparateLumaChroma = true; // choose estimation mode UInt uiPreCalcDistC = 0; if( !bSeparateLumaChroma ) { m_pcPredSearch->preestChromaPredMode( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth] ); } m_pcPredSearch ->estIntraPredQT ( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth], uiPreCalcDistC, bSeparateLumaChroma ); m_ppcRecoYuvTemp[uiDepth]->copyToPicLuma(rpcTempCU->getPic()->getPicYuvRec(), rpcTempCU->getAddr(), rpcTempCU->getZorderIdxInCU() ); m_pcPredSearch ->estIntraPredChromaQT( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth], uiPreCalcDistC ); m_pcEntropyCoder->resetBits(); if ( rpcTempCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) { m_pcEntropyCoder->encodeCUTransquantBypassFlag( rpcTempCU, 0, true ); } m_pcEntropyCoder->encodeSkipFlag ( rpcTempCU, 0, true ); m_pcEntropyCoder->encodePredMode( rpcTempCU, 0, true ); m_pcEntropyCoder->encodePartSize( rpcTempCU, 0, uiDepth, true ); m_pcEntropyCoder->encodePredInfo( rpcTempCU, 0, true ); m_pcEntropyCoder->encodeIPCMInfo(rpcTempCU, 0, true ); // Encode Coefficients Bool bCodeDQP = getdQPFlag(); m_pcEntropyCoder->encodeCoeff( rpcTempCU, 0, uiDepth, rpcTempCU->getWidth (0), rpcTempCU->getHeight(0), bCodeDQP ); setdQPFlag( bCodeDQP ); if( m_bUseSBACRD ) m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]); rpcTempCU->getTotalBits() = m_pcEntropyCoder->getNumberOfWrittenBits(); if(m_pcEncCfg->getUseSBACRD()) { rpcTempCU->getTotalBins() = ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); } rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); xCheckDQP( rpcTempCU ); xCheckBestMode(rpcBestCU, rpcTempCU, uiDepth); }该函数调用了estIntraPredQT和estIntraPredChromaQT分别实现亮度分量和色度分量的帧内估计,二者大同小异。这里重点观察亮度分量。estIntraPredQT执行了遍历各种intra模式的操作,调用了pcCU->getPattern()->initAdiPattern、predIntraLumaAng等函数。详情可见编号第 33和 36的博文。