一、Void TEncRCPic中的更新函数
(1)updateAfterLCU()
Void TEncRCPic::updateAfterLCU( Int LCUIdx, Int bits, Int QP, Double lambda, Bool updateLCUParameter )
{
m_LCUs[LCUIdx].m_actualBits = bits;//对当前的LCU的实际编码比特、QP和lambda进行初始化
m_LCUs[LCUIdx].m_QP = QP;
m_LCUs[LCUIdx].m_lambda = lambda;
m_LCULeft--;//当前LCU已经编码完成,未编码LCU数目=原数目-1
m_bitsLeft -= bits;//剩余比特=原剩余比特-当前LCU的实际编码比特
m_pixelsLeft -= m_LCUs[LCUIdx].m_numberOfPixel;//剩余像素=原剩余像素-当前LCU的像素
if ( !updateLCUParameter )//如果LCU的参数不需要更新,直接返回
{
return;
}
if ( !m_encRCSeq->getUseLCUSeparateModel() )//如果LCU的参数不是独立的,直接返回
{
return;
}
Double alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha;//新建alpha、beta变量并初始化
Double beta = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta;
Int LCUActualBits = m_LCUs[LCUIdx].m_actualBits;//获得当前LCU的实际编码比特
Int LCUTotalPixels = m_LCUs[LCUIdx].m_numberOfPixel;//获得当前LCU的实际像素数
Double bpp = ( Double )LCUActualBits/( Double )LCUTotalPixels;//获得当前LCU的实际Bpp
Double calLambda = alpha * pow( bpp, beta );//实际lambda
Double inputLambda = m_LCUs[LCUIdx].m_lambda;//获得当前LCU的lambda,即原来(old)的lambda
if( inputLambda < 0.01 || calLambda < 0.01 || bpp < 0.0001 )//三种情况有一种出现
{
alpha *= ( 1.0 - m_encRCSeq->getAlphaUpdate() / 2.0 );//对alpha和beta更新
beta *= ( 1.0 - m_encRCSeq->getBetaUpdate() / 2.0 );
alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha );//对alpha进行修正
//const Double g_RCAlphaMinValue = 0.05;const Double g_RCAlphaMaxValue = 500.0;
beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta );//对beta进行修正
//const Double g_RCBetaMinValue = -3.0;const Double g_RCBetaMaxValue = -0.1;
TRCParameter rcPara;
rcPara.m_alpha = alpha;
rcPara.m_beta = beta;
m_encRCSeq->setLCUPara( m_frameLevel, LCUIdx, rcPara );//传参返回
return;
}
calLambda = Clip3( inputLambda / 10.0, inputLambda * 10.0, calLambda );//对lambda进行修正
alpha += m_encRCSeq->getAlphaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * alpha;
//P360页更新公式
Double lnbpp = log( bpp );
lnbpp = Clip3( -5.0, -0.1, lnbpp );
beta += m_encRCSeq->getBetaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * lnbpp;
//P360页更新公式
alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha ); //对alpha进行修正
//const Double g_RCAlphaMinValue = 0.05;const Double g_RCAlphaMaxValue = 500.0;
beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta );//对beta进行修正
//const Double g_RCBetaMinValue = -3.0;const Double g_RCBetaMaxValue = -0.1;
TRCParameter rcPara;
rcPara.m_alpha = alpha;
rcPara.m_beta = beta;
m_encRCSeq->setLCUPara( m_frameLevel, LCUIdx, rcPara );//传参返回
}
①其中调用了m_encRCSeq->getAlphaUpdate()来获得alpha的更新值
Double getAlphaUpdate() { return m_alphaUpdate; }
②其中调用了m_encRCSeq->getBetaUpdate()来获得beta的更新值
Double getBetaUpdate() { return m_betaUpdate; }
(2)updateAfterPicture()
Void TEncRCPic::updateAfterPicture( Int actualHeaderBits, Int actualTotalBits, Double averageQP, Double averageLambda, SliceType eSliceType)
{
m_picActualHeaderBits = actualHeaderBits;//新建并初始化该图像的头信息比特和实际编码比特
m_picActualBits = actualTotalBits;
if ( averageQP > 0.0 )//若传入的QP>0,
{
m_picQP = Int( averageQP + 0.5 );//QP=QP+0.5
}
else//否则
{
m_picQP = g_RCInvalidQPValue;//QP=-99
}
m_picLambda = averageLambda;//新建该帧的lambda并初始化
Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;//获得原来的alpha个beta的值
Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;
if (eSliceType == I_SLICE)//如果是I帧,利用update函数进行更新
{
updateAlphaBetaIntra(&alpha, &beta);
}
else//如果不是I帧
{
// update parameters
Double picActualBits = ( Double )m_picActualBits;//获得图像实际编码比特、Bpp
Double picActualBpp = picActualBits/(Double)m_numberOfPixel;
Double calLambda = alpha * pow( picActualBpp, beta );//实际的lambda
Double inputLambda = m_picLambda;//old 的lambda
if ( inputLambda < 0.01 || calLambda < 0.01 || picActualBpp < 0.0001 )//三种情况有一种出现
{
alpha *= ( 1.0 - m_encRCSeq->getAlphaUpdate() / 2.0 );//对alpha和beta更新
beta *= ( 1.0 - m_encRCSeq->getBetaUpdate() / 2.0 );
alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha );//对alpha进行修正
beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta );//对beta进行修正
TRCParameter rcPara;
rcPara.m_alpha = alpha;
rcPara.m_beta = beta;
m_encRCSeq->setPicPara( m_frameLevel, rcPara );//传参返回
return;
}
calLambda = Clip3( inputLambda / 10.0, inputLambda * 10.0, calLambda );//对实际的lambda进行修正
alpha += m_encRCSeq->getAlphaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * alpha;
//P360页更新公式
Double lnbpp = log( picActualBpp );
lnbpp = Clip3( -5.0, -0.1, lnbpp );//获得实际的Bpp并修正
beta += m_encRCSeq->getBetaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * lnbpp;
//P360页更新公式
alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha );//对alpha进行修正
beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta );//对beta进行修正
}
TRCParameter rcPara;
rcPara.m_alpha = alpha;
rcPara.m_beta = beta;
m_encRCSeq->setPicPara( m_frameLevel, rcPara );//传参返回
if ( m_frameLevel == 1 )//如果framelevel==1
{
Double currLambda = Clip3( 0.1, 10000.0, m_picLambda );//获得当前lambda并修正
Double updateLastLambda = g_RCWeightHistoryLambda * m_encRCSeq->getLastLambda() + g_RCWeightCurrentLambda * currLambda;
//利用该公式获得lastlambda,并传递更新
m_encRCSeq->setLastLambda( updateLastLambda );
}
}
①其中调用了updateAlphaBetaIntra(&alpha, &beta);对帧内的alpha和beta进行更新
Void TEncRCPic::updateAlphaBetaIntra(Double *alpha, Double *beta)
{
Double lnbpp = log(pow(m_totalCostIntra / (Double)m_numberOfPixel, BETA1));//计算lnBpp
Double diffLambda = (*beta)*(log((Double)m_picActualBits)-log((Double)m_targetBits));//计算diffLambda
diffLambda = Clip3(-0.125, 0.125, 0.25*diffLambda);//对diffLambda进行修正
*alpha = (*alpha) * exp(diffLambda);//计算更新后的alpha和beta值
*beta = (*beta) + diffLambda / lnbpp;
}
二、TEncRCGOP更新函数
Void TEncRCGOP::updateAfterPicture( Int bitsCost )
{
m_bitsLeft -= bitsCost;
m_picLeft--;//更新剩余比特和剩余图片数
}
三、TEncRCSeq更新函数
Void TEncRCSeq::updateAfterPic ( Int bits )
{
m_bitsLeft -= bits;//更新剩余比特和帧数
m_framesLeft--;
}
四、何处调用?
1、在TEncSlice.cpp中的CompressSlice()中
if ( m_pcCfg->getUseRateCtrl() )
{
Int actualQP = g_RCInvalidQPValue;//=-999
Double actualLambda = m_pcRdCost->getLambda();//新建变量并初始化
Int actualBits = pcCU->getTotalBits();//获得实际编码比特
Int numberOfEffectivePixels = 0;//新建有影响的像素点个数
for ( Int idx = 0; idx < rpcPic->getNumPartInCU(); idx++ )//遍历整个帧的所有CU以4x4为单位
{
if ( pcCU->getPredictionMode( idx ) != NUMBER_OF_PREDICTION_MODES && ( !pcCU->isSkipped( idx ) ) )
//CU的预测模式是帧内或者帧间并且不是skip模式
{
numberOfEffectivePixels = numberOfEffectivePixels + 16;//有用像素点个数16++
break;
}
}
if ( numberOfEffectivePixels == 0 )//如果所有像素点均为无用
{
actualQP = g_RCInvalidQPValue;//=-999
}
else//否则
{
actualQP = pcCU->getQP( 0 );//实际像素选取第一个QP值
}
m_pcRdCost->setLambda(oldLambda);
// Void setLambda(Double dLambda) { m_dLambda = dLambda;}对m_dLambda进行设置
m_pcRateCtrl->getRCPic()->updateAfterLCU( m_pcRateCtrl->getRCPic()->getLCUCoded(), actualBits, actualQP, actualLambda,
pcCU->getSlice()->getSliceType() == I_SLICE ? 0 : m_pcCfg->getLCULevelRC() );//LCU编码完成后进行参数更新
}
m_uiPicTotalBits += pcCU->getTotalBits();//对帧的编码总比特更新
m_dPicRdCost += pcCU->getTotalCost();//对帧的率失真更新
m_uiPicDist += pcCU->getTotalDistortion();//对帧的失真更新
}
2、在TEncGOP.cpp中的CompressGOP()中
if ( m_pcCfg->getUseRateCtrl() )
{
Double avgQP = m_pcRateCtrl->getRCPic()->calAverageQP();//获取当前图片的平均QP
Double avgLambda = m_pcRateCtrl->getRCPic()->calAverageLambda();//获取当前图片的平均lambda
if ( avgLambda < 0.0 )
{
avgLambda = lambda;//对平均lambda进行修正
}
m_pcRateCtrl->getRCPic()->updateAfterPicture( actualHeadBits, actualTotalBits, avgQP, avgLambda, pcSlice->getSliceType());
//对当前帧编码完成后,帧层的参数更新
m_pcRateCtrl->getRCPic()->addToPictureLsit( m_pcRateCtrl->getPicList() );
//把当前帧加入到已经编码完成的帧链表
m_pcRateCtrl->getRCSeq()->updateAfterPic( actualTotalBits );
//对序列层进行参数更新
if ( pcSlice->getSliceType() != I_SLICE )//判断当前帧是否为I帧
{
m_pcRateCtrl->getRCGOP()->updateAfterPicture( actualTotalBits );//若不是I帧,传入实际编码比特数进行GOP层的参数更新
}
else // for intra picture, the estimated bits are used to update the current status in the GOP
{
m_pcRateCtrl->getRCGOP()->updateAfterPicture( estimatedBits );//若为I帧,传入估计比特数进行GOP层的参数更新
}
}