继续分析第一篇提到的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
compressSlice子函数getLCUTargetBpp()
- #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;
- }
compressSlice子函数getLCUEstLambda( Double 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;
- }
compressSlice子函数getLCUEstQP()
- 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的框架搞清楚了,基本上就是照着提案找对应代码的事情了。但是,应该指出的是,这里仅仅只是浅显分析代码的含义,有关算法的深层内涵,比如为什么要这么做,这个值为什么要设置成这样等问题,需要在了解代码的基础上,进一步地仔细研究才行。