继续分析第一篇提到的compressSlice中对LCU的RC参数初始化:
#if RATE_CONTROL_LAMBDA_DOMAIN Double oldLambda = m_pcRdCost->getLambda(); if ( m_pcCfg->getUseRateCtrl() ) { Int estQP = pcSlice->getSliceQp(); Double estLambda = -1.0; Double bpp = -1.0; #if M0036_RC_IMPROVEMENT if ( ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() ) #else if ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE || !m_pcCfg->getLCULevelRC() ) #endif { //!< 如果当前slice为I slice或者不进行LCU level RC,则LCU直接使用当前slice的QP estQP = pcSlice->getSliceQp(); } else { #if RATE_CONTROL_INTRA bpp = m_pcRateCtrl->getRCPic()->getLCUTargetBpp(pcSlice->getSliceType()); if ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE) { estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambdaAndQP(bpp, pcSlice->getSliceQp(), &estQP); } else { estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambda( bpp ); estQP = m_pcRateCtrl->getRCPic()->getLCUEstQP ( estLambda, pcSlice->getSliceQp() ); } #else bpp = m_pcRateCtrl->getRCPic()->getLCUTargetBpp(); estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambda( bpp ); estQP = m_pcRateCtrl->getRCPic()->getLCUEstQP ( estLambda, pcSlice->getSliceQp() ); #endif estQP = Clip3( -pcSlice->getSPS()->getQpBDOffsetY(), MAX_QP, estQP ); m_pcRdCost->setLambda(estLambda); #if M0036_RC_IMPROVEMENT #if RDOQ_CHROMA_LAMBDA // set lambda for RDOQ Double weight=m_pcRdCost->getChromaWeight(); m_pcTrQuant->setLambda( estLambda, estLambda / weight ); #else m_pcTrQuant->setLambda( estLambda ); #endif #endif } m_pcRateCtrl->setRCQP( estQP ); pcCU->getSlice()->setSliceQpBase( estQP ); //!< 设置编码时使用的QP值 } #endif
#if RATE_CONTROL_INTRA Double TEncRCPic::getLCUTargetBpp(SliceType eSliceType) #else Double TEncRCPic::getLCUTargetBpp() //!< LCU level bit allocation #endif { Int LCUIdx = getLCUCoded(); //!< 未编码LCU数 Double bpp = -1.0; Int avgBits = 0; #if !M0036_RC_IMPROVEMENT Double totalMAD = -1.0; Double MAD = -1.0; #endif #if RATE_CONTROL_INTRA if (eSliceType == I_SLICE){ Int noOfLCUsLeft = m_numberOfLCU - LCUIdx + 1; Int bitrateWindow = min(4,noOfLCUsLeft); Double MAD = getLCU(LCUIdx).m_costIntra; if (m_remainingCostIntra > 0.1 ) { Double weightedBitsLeft = (m_bitsLeft*bitrateWindow+(m_bitsLeft-getLCU(LCUIdx).m_targetBitsLeft)*noOfLCUsLeft)/(Double)bitrateWindow; avgBits = Int( MAD*weightedBitsLeft/m_remainingCostIntra ); } else { avgBits = Int( m_bitsLeft / m_LCULeft ); } m_remainingCostIntra -= MAD; } else { #endif #if M0036_RC_IMPROVEMENT Double totalWeight = 0; for ( Int i=LCUIdx; i<m_numberOfLCU; i++ ) { totalWeight += m_LCUs[i].m_bitWeight; } Int realInfluenceLCU = min( g_RCLCUSmoothWindowSize, getLCULeft() ); avgBits = (Int)( m_LCUs[LCUIdx].m_bitWeight - ( totalWeight - m_bitsLeft ) / realInfluenceLCU + 0.5 ); #else if ( m_lastPicture == NULL ) //!< 如果前一帧图像为空,则直接求平均比特数 { avgBits = Int( m_bitsLeft / m_LCULeft ); } else //!< 利用前一帧保存下来的MAD求出当前LCU对应的权重,注意:此处的MAD已经进行过K0103中公式的两个处理了。 { MAD = m_lastPicture->getLCU(LCUIdx).m_MAD; totalMAD = m_lastPicture->getTotalMAD(); for ( Int i=0; i<LCUIdx; i++ ) { totalMAD -= m_lastPicture->getLCU(i).m_MAD; } if ( totalMAD > 0.1 ) { avgBits = Int( m_bitsLeft * MAD / totalMAD ); } else { avgBits = Int( m_bitsLeft / m_LCULeft ); } } #endif #if RATE_CONTROL_INTRA } #endif if ( avgBits < 1 ) { avgBits = 1; } bpp = ( Double )avgBits/( Double )m_LCUs[ LCUIdx ].m_numberOfPixel; m_LCUs[ LCUIdx ].m_targetBits = avgBits; return bpp; } Double TEncRCPic::getLCUEstLambda( Double bpp ) { Int LCUIdx = getLCUCoded(); Double alpha; Double beta; if ( m_encRCSeq->getUseLCUSeparateModel() ) //!< enable LCU level RC { alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha; beta = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta; } else //!< 只进行picture level 的 RC,故alpha,beta使用的是picture level的值 { alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; } Double estLambda = alpha * pow( bpp, beta ); //for Lambda clip, picture level clip Double clipPicLambda = m_estPicLambda; //for Lambda clip, LCU level clip Double clipNeighbourLambda = -1.0; for ( int i=LCUIdx - 1; i>=0; i-- ) { if ( m_LCUs[i].m_lambda > 0 ) { clipNeighbourLambda = m_LCUs[i].m_lambda; break; } } //!< 在K0103的section 3.2中进行了定义 if ( clipNeighbourLambda > 0.0 ) { estLambda = Clip3( clipNeighbourLambda * pow( 2.0, -1.0/3.0 ), clipNeighbourLambda * pow( 2.0, 1.0/3.0 ), estLambda ); } if ( clipPicLambda > 0.0 ) { estLambda = Clip3( clipPicLambda * pow( 2.0, -2.0/3.0 ), clipPicLambda * pow( 2.0, 2.0/3.0 ), estLambda ); } else { estLambda = Clip3( 10.0, 1000.0, estLambda ); } if ( estLambda < 0.1 ) { estLambda = 0.1; } return estLambda; } Int TEncRCPic::getLCUEstQP( Double lambda, Int clipPicQP ) { Int LCUIdx = getLCUCoded(); Int estQP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 ); //for Lambda clip, LCU level clip Int clipNeighbourQP = g_RCInvalidQPValue; for ( int i=LCUIdx - 1; i>=0; i-- ) { if ( (getLCU(i)).m_QP > g_RCInvalidQPValue ) { clipNeighbourQP = getLCU(i).m_QP; break; } } //!< 在K0103的section 3.2中进行了定义 if ( clipNeighbourQP > g_RCInvalidQPValue ) { estQP = Clip3( clipNeighbourQP - 1, clipNeighbourQP + 1, estQP ); } estQP = Clip3( clipPicQP - 2, clipPicQP + 2, estQP ); return estQP; }
至此,RC的初始化过程分析完毕,从之前几篇也能发现,其实看懂代码并不难,只要把提案看明白了,对整个流程熟悉,再把HM的框架搞清楚了,基本上就是照着提案找对应代码的事情了。但是,应该指出的是,这里仅仅只是浅显分析代码的含义,有关算法的深层内涵,比如为什么要这么做,这个值为什么要设置成这样等问题,需要在了解代码的基础上,进一步地仔细研究才行。