您的位置:首页 > 编程语言

HEVC码率控制浅析——HM代码阅读之三

2013-10-20 10:19 337 查看
续上文继续分析

m_pcRateCtrl->initRCPic( )

[cpp] view
plaincopy

Void TEncRateCtrl::initRCPic( Int frameLevel )

{

m_encRCPic = new TEncRCPic;

m_encRCPic->create( m_encRCSeq, m_encRCGOP, frameLevel, m_listRCPictures );

}

m_encRCPic->create

[cpp] view
plaincopy

Void TEncRCPic::create( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP, Int frameLevel, list<TEncRCPic*>& listPreviousPictures )

{

destroy();

m_encRCSeq = encRCSeq;

m_encRCGOP = encRCGOP;

Int targetBits = xEstPicTargetBits( encRCSeq, encRCGOP ); //!< K0103式子(9)

Int estHeaderBits = xEstPicHeaderBits( listPreviousPictures, frameLevel ); //!< header bits estimation

if ( targetBits < estHeaderBits + 100 )

{

targetBits = estHeaderBits + 100; // at least allocate 100 bits for picture data

}

//!< 以下为RC相关参数的初始化,根据变量名很容易就能判断其用途,故不罗嗦~

m_frameLevel = frameLevel;

m_numberOfPixel = encRCSeq->getNumPixel();

m_numberOfLCU = encRCSeq->getNumberOfLCU();

m_estPicLambda = 100.0;

m_targetBits = targetBits;

m_estHeaderBits = estHeaderBits;

m_bitsLeft = m_targetBits;

Int picWidth = encRCSeq->getPicWidth();

Int picHeight = encRCSeq->getPicHeight();

Int LCUWidth = encRCSeq->getLCUWidth();

Int LCUHeight = encRCSeq->getLCUHeight();

Int picWidthInLCU = ( picWidth % LCUWidth ) == 0 ? picWidth / LCUWidth : picWidth / LCUWidth + 1;

Int picHeightInLCU = ( picHeight % LCUHeight ) == 0 ? picHeight / LCUHeight : picHeight / LCUHeight + 1;

m_LCULeft = m_numberOfLCU;

m_bitsLeft -= m_estHeaderBits; //!< 考虑header bits后的剩余比特数

m_pixelsLeft = m_numberOfPixel;

m_LCUs = new TRCLCU[m_numberOfLCU];

Int i, j;

Int LCUIdx;

for ( i=0; i<picWidthInLCU; i++ )

{

for ( j=0; j<picHeightInLCU; j++ )

{

LCUIdx = j*picWidthInLCU + i;

m_LCUs[LCUIdx].m_actualBits = 0;

m_LCUs[LCUIdx].m_QP = 0;

m_LCUs[LCUIdx].m_lambda = 0.0;

m_LCUs[LCUIdx].m_targetBits = 0;

#if M0036_RC_IMPROVEMENT

m_LCUs[LCUIdx].m_bitWeight = 1.0;

#else

m_LCUs[LCUIdx].m_MAD = 0.0;

#endif

Int currWidth = ( (i == picWidthInLCU -1) ? picWidth - LCUWidth *(picWidthInLCU -1) : LCUWidth );

Int currHeight = ( (j == picHeightInLCU-1) ? picHeight - LCUHeight*(picHeightInLCU-1) : LCUHeight );

m_LCUs[LCUIdx].m_numberOfPixel = currWidth * currHeight;

}

}

m_picActualHeaderBits = 0;

#if !M0036_RC_IMPROVEMENT

m_totalMAD = 0.0;

#endif

m_picActualBits = 0;

m_picQP = 0;

m_picLambda = 0.0;

#if !M0036_RC_IMPROVEMENT

m_lastPicture = NULL;

list<TEncRCPic*>::reverse_iterator it;

for ( it = listPreviousPictures.rbegin(); it != listPreviousPictures.rend(); it++ )

{

if ( (*it)->getFrameLevel() == m_frameLevel ) //!< 保存跟当前帧同一层的前一帧

{

m_lastPicture = (*it);

break;

}

}

#endif

}

m_encRCPic->create子函数xEstPicTargetBits()

[cpp] view
plaincopy

<span style="font-size:12px;">Int TEncRCPic::xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP )

{

Int targetBits = 0;

Int GOPbitsLeft = encRCGOP->getBitsLeft(); //!< TGOP - CodedGOP

Int i;

Int currPicPosition = encRCGOP->getNumPic()-encRCGOP->getPicLeft();

Int currPicRatio = encRCSeq->getBitRatio( currPicPosition ); //!< 当前picture的权值

Int totalPicRatio = 0;

for ( i=currPicPosition; i<encRCGOP->getNumPic(); i++ )

{

totalPicRatio += encRCSeq->getBitRatio( i ); //!< 总权值

}

#if M0036_RC_IMPROVEMENT

targetBits = Int( ((Double)GOPbitsLeft) * currPicRatio / totalPicRatio );

#else

targetBits = Int( GOPbitsLeft * currPicRatio / totalPicRatio );

#endif

if ( targetBits < 100 )

{

targetBits = 100; // at least allocate 100 bits for one picture

}

//!< 在此之前targetBits是基于K0103式子(9)计算的结果,而m_encRCGOP->getTargetBitInGOP( currPicPosition )得到的

//!< bits为NotCodedPictures=0通过式子(9)得到的

if ( m_encRCSeq->getFramesLeft() > 16 )

{

targetBits = Int( g_RCWeightPicRargetBitInBuffer * targetBits + g_RCWeightPicTargetBitInGOP * m_encRCGOP->getTargetBitInGOP( currPicPosition ) );

}

return targetBits;

}</span>

m_encRCPic->create子函数xEstPicHeaderBits()

[cpp] view
plaincopy

<span style="font-size:12px;">Int TEncRCPic::xEstPicHeaderBits( list<TEncRCPic*>& listPreviousPictures, Int frameLevel )

{

Int numPreviousPics = 0;

Int totalPreviousBits = 0;

list<TEncRCPic*>::iterator it;

for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ ) //!< 求出当前帧之前所有与其在同一层的帧的header bits之和

{

if ( (*it)->getFrameLevel() == frameLevel )

{

totalPreviousBits += (*it)->getPicActualHeaderBits();

numPreviousPics++;

}

}

Int estHeaderBits = 0;

if ( numPreviousPics > 0 ) //!< 取平均值

{

estHeaderBits = totalPreviousBits / numPreviousPics;

}

return estHeaderBits;

}</span>

分析第一篇提到的compressGOP中的RC初始化代码片段:

[cpp] view
plaincopy

<span style="font-size:12px;">#if RATE_CONTROL_LAMBDA_DOMAIN

Double lambda = 0.0;

Int actualHeadBits = 0;

Int actualTotalBits = 0;

Int estimatedBits = 0;

Int tmpBitsBeforeWriting = 0;

if ( m_pcCfg->getUseRateCtrl() )

{

Int frameLevel = m_pcRateCtrl->getRCSeq()->getGOPID2Level( iGOPid );

if ( pcPic->getSlice(0)->getSliceType() == I_SLICE )

{

frameLevel = 0;

}

m_pcRateCtrl->initRCPic( frameLevel ); //!< picture level 初始化

estimatedBits = m_pcRateCtrl->getRCPic()->getTargetBits(); //!< 在initRCPic中已经计算出了targetBits

Int sliceQP = m_pcCfg->getInitialQP(); //!< 对应于配置文件中的InitalQP

if ( ( pcSlice->getPOC() == 0 && m_pcCfg->getInitialQP() > 0 ) || ( frameLevel == 0 && m_pcCfg->getForceIntraQP() ) ) // QP is specified

{//!< 如果配置文件对序列第一帧指定了初始QP,则基于这个QP计算出lamda

Int NumberBFrames = ( m_pcCfg->getGOPSize() - 1 );

Double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05*(Double)NumberBFrames );

Double dQPFactor = 0.57*dLambda_scale;

Int SHIFT_QP = 12;

Int bitdepth_luma_qp_scale = 0;

Double qp_temp = (Double) sliceQP + bitdepth_luma_qp_scale - SHIFT_QP;

lambda = dQPFactor*pow( 2.0, qp_temp/3.0 );

}

else if ( frameLevel == 0 ) // intra case, but use the model

{ //!< 对I slice的情况,需要做些特殊处理,如targetBits的修正等

#if RATE_CONTROL_INTRA

m_pcSliceEncoder->calCostSliceI(pcPic);

#endif

if ( m_pcCfg->getIntraPeriod() != 1 ) // do not refine allocated bits for all intra case

{

Int bits = m_pcRateCtrl->getRCSeq()->getLeftAverageBits();

#if RATE_CONTROL_INTRA

bits = m_pcRateCtrl->getRCPic()->getRefineBitsForIntra( bits );

#else

bits = m_pcRateCtrl->getRCSeq()->getRefineBitsForIntra( bits ); //!< K0103 Table 3

#endif

if ( bits < 200 )

{

bits = 200;

}

m_pcRateCtrl->getRCPic()->setTargetBits( bits );

}

list<TEncRCPic*> listPreviousPicture = m_pcRateCtrl->getPicList();

#if RATE_CONTROL_INTRA

m_pcRateCtrl->getRCPic()->getLCUInitTargetBits();

lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture, pcSlice->getSliceType());

#else

lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture );

#endif

sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda, listPreviousPicture );

}

else // normal case

{

list<TEncRCPic*> listPreviousPicture = m_pcRateCtrl->getPicList();

#if RATE_CONTROL_INTRA

lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture, pcSlice->getSliceType());

#else

lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture );

#endif

sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda, listPreviousPicture );

}

sliceQP = Clip3( -pcSlice->getSPS()->getQpBDOffsetY(), MAX_QP, sliceQP );

m_pcRateCtrl->getRCPic()->setPicEstQP( sliceQP );

m_pcSliceEncoder->resetQP( pcPic, sliceQP, lambda ); //!< 设置当前slice使用的QP, lambda,编码时用到

}

#endif</span>

compressGOP子函数getRefineBitsForIntra()

[cpp] view
plaincopy

<span style="font-size:12px;">#if !RATE_CONTROL_INTRA

Int TEncRCSeq::getRefineBitsForIntra( Int orgBits ) //!< K0103 Table 3

{

Double bpp = ( (Double)orgBits ) / m_picHeight / m_picHeight;

if ( bpp > 0.2 )

{

return orgBits * 5;

}

if ( bpp > 0.1 )

{

return orgBits * 7;

}

return orgBits * 10;

}

#endif</span>

compressGOP子函数estimatePicLambda()

[cpp] view
plaincopy

<span style="font-size:12px;">#if RATE_CONTROL_INTRA

Double TEncRCPic::estimatePicLambda( list<TEncRCPic*>& listPreviousPictures, SliceType eSliceType)

#else

Double TEncRCPic::estimatePicLambda( list<TEncRCPic*>& listPreviousPictures )

#endif

{

Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;

Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;

Double bpp = (Double)m_targetBits/(Double)m_numberOfPixel;

#if RATE_CONTROL_INTRA

Double estLambda;

if (eSliceType == I_SLICE)

{

estLambda = calculateLambdaIntra(alpha, beta, pow(m_totalCostIntra/(Double)m_numberOfPixel, BETA1), bpp);

}

else

{

estLambda = alpha * pow( bpp, beta );

}

#else

Double estLambda = alpha * pow( bpp, beta ); //!< K0103 式子(10)

#endif

Double lastLevelLambda = -1.0;

Double lastPicLambda = -1.0;

Double lastValidLambda = -1.0;

list<TEncRCPic*>::iterator it;

for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ )

{

if ( (*it)->getFrameLevel() == m_frameLevel )

{

lastLevelLambda = (*it)->getPicActualLambda();

}

lastPicLambda = (*it)->getPicActualLambda();

if ( lastPicLambda > 0.0 )

{

lastValidLambda = lastPicLambda;

}

}

//!< 以下对lastLevelLambda和estLambda进行clip,范围在K0103的section 3.2中进行了定义

if ( lastLevelLambda > 0.0 )

{

lastLevelLambda = Clip3( 0.1, 10000.0, lastLevelLambda );

estLambda = Clip3( lastLevelLambda * pow( 2.0, -3.0/3.0 ), lastLevelLambda * pow( 2.0, 3.0/3.0 ), estLambda );

}

if ( lastPicLambda > 0.0 )

{

lastPicLambda = Clip3( 0.1, 2000.0, lastPicLambda );

estLambda = Clip3( lastPicLambda * pow( 2.0, -10.0/3.0 ), lastPicLambda * pow( 2.0, 10.0/3.0 ), estLambda );

}

else if ( lastValidLambda > 0.0 )

{

lastValidLambda = Clip3( 0.1, 2000.0, lastValidLambda );

estLambda = Clip3( lastValidLambda * pow(2.0, -10.0/3.0), lastValidLambda * pow(2.0, 10.0/3.0), estLambda );

}

else

{

estLambda = Clip3( 0.1, 10000.0, estLambda );

}

if ( estLambda < 0.1 )

{

estLambda = 0.1;

}

m_estPicLambda = estLambda;

#if M0036_RC_IMPROVEMENT

Double totalWeight = 0.0;

// initial BU bit allocation weight

for ( Int i=0; i<m_numberOfLCU; i++ )

{

#if RC_FIX

Double alphaLCU, betaLCU;

if ( m_encRCSeq->getUseLCUSeparateModel() )

{

alphaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_alpha;

betaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_beta;

}

else

{

alphaLCU = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;

betaLCU = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;

}

#else

Double alphaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_alpha;

Double betaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_beta;

#endif

m_LCUs[i].m_bitWeight = m_LCUs[i].m_numberOfPixel * pow( estLambda/alphaLCU, 1.0/betaLCU );

if ( m_LCUs[i].m_bitWeight < 0.01 )

{

m_LCUs[i].m_bitWeight = 0.01;

}

totalWeight += m_LCUs[i].m_bitWeight;

}

for ( Int i=0; i<m_numberOfLCU; i++ )

{

Double BUTargetBits = m_targetBits * m_LCUs[i].m_bitWeight / totalWeight;

m_LCUs[i].m_bitWeight = BUTargetBits;

}

#endif

return estLambda;

}</span>

compressGOP子函数estimatePicQP()

[cpp] view
plaincopy

<span style="font-size:12px;">Int TEncRCPic::estimatePicQP( Double lambda, list<TEncRCPic*>& listPreviousPictures )

{

Int QP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 ); //!< 通过lambda求QP

Int lastLevelQP = g_RCInvalidQPValue;

Int lastPicQP = g_RCInvalidQPValue;

Int lastValidQP = g_RCInvalidQPValue;

list<TEncRCPic*>::iterator it;

for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ )

{

if ( (*it)->getFrameLevel() == m_frameLevel )

{

lastLevelQP = (*it)->getPicActualQP();

}

lastPicQP = (*it)->getPicActualQP();

if ( lastPicQP > g_RCInvalidQPValue )

{

lastValidQP = lastPicQP;

}

}

//!< 以下对QP进行clip,范围在K0103的section 3.2进行了定义

if ( lastLevelQP > g_RCInvalidQPValue )

{

QP = Clip3( lastLevelQP - 3, lastLevelQP + 3, QP );

}

if( lastPicQP > g_RCInvalidQPValue )

{

QP = Clip3( lastPicQP - 10, lastPicQP + 10, QP );

}

else if( lastValidQP > g_RCInvalidQPValue )

{

QP = Clip3( lastValidQP - 10, lastValidQP + 10, QP );

}

return QP;

}</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HEVC 代码分析