参考阅读https://blog.csdn.net/HEVC_CJL/article/details/10982699和https://blog.csdn.net/NB_vol_1/article/details/56022073
最近重新回顾了HM里面的R-lambda码率控制,对应提案为JCTVC-K0103,已放在https://download.csdn.net/download/cztl520/85255894
是否使用码率控制(RC)由类TEncCfg中的成员变量m_RCEnableRateControl决定,需要手动在配置文件中开启。码率控制函数调用关系为:
1. 初始化
1.1 整个序列的码控参数初始化
这部分包含TEncRateCtrl和TEncRCSeq的初始化
在TEncTop::create()中,会对整个序列的码率控制进行初始化
if ( m_RCEnableRateControl )
{
m_cRateCtrl.init( m_framesToBeEncoded, m_RCTargetBitrate, (Int)( (Double)m_iFrameRate/m_temporalSubsampleRatio + 0.5), m_iGOPSize, m_iSourceWidth, m_iSourceHeight,
m_maxCUWidth, m_maxCUHeight,m_RCKeepHierarchicalBit, m_RCUseLCUSeparateModel, m_GOPList );
}
1.1.1 TEncRateCtrl::init()
主要进行码率控制各种参数的初始化
Void TEncRateCtrl::init( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int keepHierBits, Bool useLCUSeparateModel, GOPEntry GOPList[MAX_GOP] )
{
destroy();
// 默认低延时配置
Bool isLowdelay = true;
for ( Int i=0; i<GOPSize-1; i++ )
{
if ( GOPList[i].m_POC > GOPList[i+1].m_POC )
{
isLowdelay = false; // 此为随机接入配置
break;
}
}
Int numberOfLevel = 1;
Int adaptiveBit = 0;
if ( keepHierBits > 0 )
{
numberOfLevel = Int( log((Double)GOPSize)/log(2.0) + 0.5 ) + 1;
}
if ( !isLowdelay && GOPSize == 8 )
{
numberOfLevel = Int( log((Double)GOPSize)/log(2.0) + 0.5 ) + 1;
}
numberOfLevel++; // intra picture
numberOfLevel++; // non-reference picture
Int* bitsRatio; // 比特权重(w)
bitsRatio = new Int[ GOPSize ];
for ( Int i=0; i<GOPSize; i++ )
{
bitsRatio[i] = 10;
if ( !GOPList[i].m_refPic )
{
bitsRatio[i] = 2;
}
}
//如果采用分层编码,则每一帧的权重不同,这里的权重为每一帧获得比特数的比例
if ( keepHierBits > 0 )
{
// K0103 式子(3)每像素的比特数,码率 / 帧率 = 一帧的比特数
Double bpp = (Double)( targetBitrate / (Double)( frameRate*picWidth*picHeight ) );
// K0103 table 1
if ( GOPSize == 4 && isLowdelay )
{
if ( bpp > 0.2 )
{
bitsRatio[0] = 2;
bitsRatio[1] = 3;
bitsRatio[2] = 2;
bitsRatio[3] = 6;
}
else if( bpp > 0.1 )
{
bitsRatio[0] = 2;
bitsRatio[1] = 3;
bitsRatio[2] = 2;
bitsRatio[3] = 10;
}
else if ( bpp > 0.05 )
{
bitsRatio[0] = 2;
bitsRatio[1] = 3;
bitsRatio[2] = 2;
bitsRatio[3] = 12;
}
else
{
bitsRatio[0] = 2;
bitsRatio[1] = 3;
bitsRatio[2] = 2;
bitsRatio[3] = 14;
}
if ( keepHierBits == 2 )
{
adaptiveBit = 1;
}
}
// K0103 table 2
else if ( GOPSize == 8 && !isLowdelay )
{
if ( bpp > 0.2 )
{
bitsRatio[0] = 15;
bitsRatio[1] = 5;
bitsRatio[2] = 4;
bitsRatio[3] = 1;
bitsRatio[4] = 1;
bitsRatio[5] = 4;
bitsRatio[6] = 1;
bitsRatio[7] = 1;
}
else if ( bpp > 0.1 )
{
bitsRatio[0] = 20;
bitsRatio[1] = 6;
bitsRatio[2] = 4;
bitsRatio[3] = 1;
bitsRatio[4] = 1;
bitsRatio[5] = 4;
bitsRatio[6] = 1;
bitsRatio[7] = 1;
}
else if ( bpp > 0.05 )
{
bitsRatio[0] = 25;
bitsRatio[1] = 7;
bitsRatio[2] = 4;
bitsRatio[3] = 1;
bitsRatio[4] = 1;
bitsRatio[5] = 4;
bitsRatio[6] = 1;
bitsRatio[7] = 1;
}
else
{
bitsRatio[0] = 30;
bitsRatio[1] = 8;
bitsRatio[2] = 4;
bitsRatio[3] = 1;
bitsRatio[4] = 1;
bitsRatio[5] = 4;
bitsRatio[6] = 1;
bitsRatio[7] = 1;
}
if ( keepHierBits == 2 )
{
adaptiveBit = 2;
}
}
else
{
printf( "\n hierarchical bit allocation is not support for the specified coding structure currently.\n" );
}
}
// GOPID到时域层的映射
Int* GOPID2Level = new Int[ GOPSize ];
for ( Int i=0; i<GOPSize; i++ )
{
GOPID2Level[i] = 1;
if ( !GOPList[i].m_refPic )
{
GOPID2Level[i] = 2;
}
}
if ( keepHierBits > 0 )
{
if ( GOPSize == 4 && isLowdelay )
{
GOPID2Level[0] = 3;
GOPID2Level[1] = 2;
GOPID2Level[2] = 3;
GOPID2Level[3] = 1;
}
else if ( GOPSize == 8 && !isLowdelay )
{
GOPID2Level[0] = 1;
GOPID2Level[1] = 2;
GOPID2Level[2] = 3;
GOPID2Level[3] = 4;
GOPID2Level[4] = 4;
GOPID2Level[5] = 3;
GOPID2Level[6] = 4;
GOPID2Level[7] = 4;
}
}
if ( !isLowdelay && GOPSize == 8 )
{
GOPID2Level[0] = 1;
GOPID2Level[1] = 2;
GOPID2Level[2] = 3;
GOPID2Level[3] = 4;
GOPID2Level[4] = 4;
GOPID2Level[5] = 3;
GOPID2Level[6] = 4;
GOPID2Level[7] = 4;
}
m_encRCSeq = new TEncRCSeq; // 创建序列级码率控制对象,并将初始化好的参数传给此对象
m_encRCSeq->create( totalFrames, targetBitrate, frameRate, GOPSize, picWidth, picHeight, LCUWidth, LCUHeight, numberOfLevel, useLCUSeparateModel, adaptiveBit );
m_encRCSeq->initBitsRatio( bitsRatio );
m_encRCSeq->initGOPID2Level( GOPID2Level );
m_encRCSeq->initPicPara(); // 初始化alpha和beta参数
if ( useLCUSeparateModel )
{
m_encRCSeq->initLCUPara();
}
m_CpbSaturationEnabled = false;
m_cpbSize = targetBitrate;
m_cpbState = (UInt)(m_cpbSize*0.5f);
m_bufferingRate = (Int)(targetBitrate / frameRate);
delete[] bitsRatio;
delete[] GOPID2Level;
}
1.1.2 TEncRCSeq::create()
Void TEncRCSeq::create( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int numberOfLevel, Bool useLCUSeparateModel, Int adaptiveBit )
{
destroy();
m_totalFrames = totalFrames;
m_targetRate = targetBitrate;
m_frameRate = frameRate;
m_GOPSize = GOPSize;
m_picWidth = picWidth;
m_picHeight = picHeight;
m_LCUWidth = LCUWidth;
m_LCUHeight = LCUHeight;
m_numberOfLevel = numberOfLevel;
m_useLCUSeparateModel = useLCUSeparateModel;
m_numberOfPixel = m_picWidth * m_picHeight;
// 码率 / 帧率 = 一帧的比特数,分配的目标总比特数,即输出码流大小
m_targetBits = (Int64)m_totalFrames * (Int64)m_targetRate / (Int64)m_frameRate;
// 每像素被分到的目标比特
m_seqTargetBpp = (Double)m_targetRate / (Double)m_frameRate / (Double)m_numberOfPixel;
//m_alphaUpdate、m_betaUpdate这两个变量用于在接下来更新lamda的参数值
if ( m_seqTargetBpp < 0.03 )
{
m_alphaUpdate = 0.01;
m_betaUpdate = 0.005;
}
else if ( m_seqTargetBpp < 0.08 )
{
m_alphaUpdate = 0.05;
m_betaUpdate = 0.025;
}
else if ( m_seqTargetBpp < 0.2 )
{
m_alphaUpdate = 0.1;
m_betaUpdate = 0.05;
}
else if ( m_seqTargetBpp < 0.5 )
{
m_alphaUpdate = 0.2;
m_betaUpdate = 0.1;
}
else
{
m_alphaUpdate = 0.4;
m_betaUpdate = 0.2;
}
// 平均每帧占用的目标比特数
m_averageBits = (Int)(m_targetBits / totalFrames);
Int picWidthInBU = ( m_picWidth % m_LCUWidth ) == 0 ? m_picWidth / m_LCUWidth : m_picWidth / m_LCUWidth + 1;
Int picHeightInBU = ( m_picHeight % m_LCUHeight ) == 0 ? m_picHeight / m_LCUHeight : m_picHeight / m_LCUHeight + 1;
m_numberOfLCU = picWidthInBU * picHeightInBU;
m_bitsRatio = new Int[m_GOPSize];
for ( Int i=0; i<m_GOPSize; i++ )
{
m_bitsRatio[i] = 1;
}
m_GOPID2Level = new Int[m_GOPSize];
for ( Int i=0; i<m_GOPSize; i++ )
{
m_GOPID2Level[i] = 1;
}
m_picPara = new TRCParameter[m_numberOfLevel];
// 每个图像层的alpha和beta参数值
for ( Int i=0; i<m_numberOfLevel; i++ )
{
m_picPara[i].m_alpha = 0.0;
m_picPara[i].m_beta = 0.0;
}
if ( m_useLCUSeparateModel ) // 每个LCU的alpha和beta都有各自的值
{
m_LCUPara = new TRCParameter*[m_numberOfLevel];
for ( Int i=0; i<m_numberOfLevel; i++ )
{
m_LCUPara[i] = new TRCParameter[m_numberOfLCU];
for ( Int j=0; j<m_numberOfLCU; j++)
{
m_LCUPara[i][j].m_alpha = 0.0;
m_LCUPara[i][j].m_beta = 0.0;
}
}
}
m_framesLeft = m_totalFrames; // 剩余帧数
m_bitsLeft = m_targetBits; // 剩余可分配的比特数
m_adaptiveBit = adaptiveBit;
m_lastLambda = 0.0;
}
1.2 GOP级码控参数初始化
TEncTop::encode()中
if ( m_RCEnableRateControl )
{
m_cRateCtrl.initRCGOP( m_iNumPicRcvd );
}
1.2.1 TEncRCGOP::create()
Void TEncRCGOP::create( TEncRCSeq* encRCSeq, Int numPic )
{
destroy();
Int targetBits = xEstGOPTargetBits( encRCSeq, numPic );
// 一般不进入此if判断,除非开启adaptiveBits
if ( encRCSeq->getAdaptiveBits() > 0 && encRCSeq->getLastLambda() > 0.1 )
{
Double targetBpp = (Double)targetBits / encRCSeq->getNumPixel();
Double basicLambda = 0.0;
Double* lambdaRatio = new Double[encRCSeq->getGOPSize()];
Double* equaCoeffA = new Double[encRCSeq->getGOPSize()];
Double* equaCoeffB = new Double[encRCSeq->getGOPSize()];
if ( encRCSeq->getAdaptiveBits() == 1 ) // for GOP size =4, low delay case
{
if ( encRCSeq->getLastLambda() < 120.0 )
{
lambdaRatio[1] = 0.725 * log( encRCSeq->getLastLambda() ) + 0.5793;
lambdaRatio[0] = 1.3 * lambdaRatio[1];
lambdaRatio[2] = 1.3 * lambdaRatio[1];
lambdaRatio[3] = 1.0;
}
else
{
lambdaRatio[0] = 5.0;
lambdaRatio[1] = 4.0;
lambdaRatio[2] = 5.0;
lambdaRatio[3] = 1.0;
}
}
else if ( encRCSeq->getAdaptiveBits() == 2 ) // for GOP size = 8, random access case
{
if ( encRCSeq->getLastLambda() < 90.0 )
{
lambdaRatio[0] = 1.0;
lambdaRatio[1] = 0.725 * log( encRCSeq->getLastLambda() ) + 0.7963;
lambdaRatio[2] = 1.3 * lambdaRatio[1];
lambdaRatio[3] = 3.25 * lambdaRatio[1];
lambdaRatio[4] = 3.25 * lambdaRatio[1];
lambdaRatio[5] = 1.3 * lambdaRatio[1];
lambdaRatio[6] = 3.25 * lambdaRatio[1];
lambdaRatio[7] = 3.25 * lambdaRatio[1];
}
else
{
lambdaRatio[0] = 1.0;
lambdaRatio[1] = 4.0;
lambdaRatio[2] = 5.0;
lambdaRatio[3] = 12.3;
lambdaRatio[4] = 12.3;
lambdaRatio[5] = 5.0;
lambdaRatio[6] = 12.3;
lambdaRatio[7] = 12.3;
}
}
xCalEquaCoeff( encRCSeq, lambdaRatio, equaCoeffA, equaCoeffB, encRCSeq->getGOPSize() );
basicLambda = xSolveEqua( targetBpp, equaCoeffA, equaCoeffB, encRCSeq->getGOPSize() );
encRCSeq->setAllBitRatio( basicLambda, equaCoeffA, equaCoeffB );
delete []lambdaRatio;
delete []equaCoeffA;
delete []equaCoeffB;
}
m_picTargetBitInGOP = new Int[numPic];
Int i;
Int totalPicRatio = 0;
Int currPicRatio = 0;
for ( i=0; i<numPic; i++ )
{
totalPicRatio += encRCSeq->getBitRatio( i );
}
for ( i=0; i<numPic; i++ )
{
currPicRatio = encRCSeq->getBitRatio( i );
// K0103 式子(9),注意:由于是初始化,式子中的CodedGOP等于0
m_picTargetBitInGOP[i] = (Int)( ((Double)targetBits) * currPicRatio / totalPicRatio );
}
m_encRCSeq = encRCSeq;
m_numPic = numPic;
m_targetBits = targetBits;
m_picLeft = m_numPic;
m_bitsLeft = m_targetBits;
}
1.2.2 TEncRCGOP::xEstGOPTargetBits()
Int TEncRCGOP::xEstGOPTargetBits( TEncRCSeq* encRCSeq, Int GOPSize )
{
// 滑动窗口大小
Int realInfluencePicture = min( g_RCSmoothWindowSize, encRCSeq->getFramesLeft() );
// 平均每帧的比特数
Int averageTargetBitsPerPic = (Int)( encRCSeq->getTargetBits() / encRCSeq->getTotalFrames() );
// K0103 式(7)
// TAvgPic,计算方法跟K0103不同,这里利用left的思路计算,而K0103利用coded的思路计算,但结果是一样的
Int currentTargetBitsPerPic = (Int)( ( encRCSeq->getBitsLeft() - averageTargetBitsPerPic * (encRCSeq->getFramesLeft() - realInfluencePicture) ) / realInfluencePicture );
// K0103 式(8)TGOP
Int targetBits = currentTargetBitsPerPic * GOPSize;
if ( targetBits < 200 )
{
targetBits = 200; // at least allocate 200 bits for one GOP
}
return targetBits;
}
1.3 Picture级码控参数初始化
在TEncGOP::compressGOP()中,对Picture级的相关参数进行初始化
if ( m_pcCfg->getUseRateCtrl() ) // TODO: does this work with multiple slices and slice-segments?
{
Int frameLevel = m_pcRateCtrl->getRCSeq()->getGOPID2Level( iGOPid );
if ( pcPic->getSlice(0)->getSliceType() == I_SLICE )
{
frameLevel = 0;
}
// 初始化Picture参数
m_pcRateCtrl->initRCPic( frameLevel );
estimatedBits = m_pcRateCtrl->getRCPic()->getTargetBits();
if (m_pcRateCtrl->getCpbSaturationEnabled() && frameLevel != 0)
{
Int estimatedCpbFullness = m_pcRateCtrl->getCpbState() + m_pcRateCtrl->getBufferingRate();
// prevent overflow
if (estimatedCpbFullness - estimatedBits > (Int)(m_pcRateCtrl->getCpbSize()*0.9f))
{
estimatedBits = estimatedCpbFullness - (Int)(m_pcRateCtrl->getCpbSize()*0.9f);
}
estimatedCpbFullness -= m_pcRateCtrl->getBufferingRate();
// prevent underflow
if (estimatedCpbFullness - estimatedBits < m_pcRateCtrl->getRCPic()->getLowerBound())
{
estimatedBits = max(200, estimatedCpbFullness - m_pcRateCtrl->getRCPic()->getLowerBound());
}
m_pcRateCtrl->getRCPic()->setTargetBits(estimatedBits);
}
Int sliceQP = m_pcCfg->getInitialQP(); // 为配置文件中的InitialQP参数
// 如果配置文件对序列第一帧指定了初始QP,则基于这个QP计算出lamda
if ( ( pcSlice->getPOC() == 0 && m_pcCfg->getInitialQP() > 0 ) || ( frameLevel == 0 && m_pcCfg->getForceIntraQP() ) ) // QP is specified
{
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
{
m_pcSliceEncoder->calCostSliceI(pcPic); // TODO: This only analyses the first slice segment - what about the others?
if ( m_pcCfg->getIntraPeriod() != 1 ) // do not refine allocated bits for all intra case
{
Int bits = m_pcRateCtrl->getRCSeq()->getLeftAverageBits();
bits = m_pcRateCtrl->getRCPic()->getRefineBitsForIntra( bits );
if (m_pcRateCtrl->getCpbSaturationEnabled() )
{
Int estimatedCpbFullness = m_pcRateCtrl->getCpbState() + m_pcRateCtrl->getBufferingRate();
// prevent overflow
if (estimatedCpbFullness - bits > (Int)(m_pcRateCtrl->getCpbSize()*0.9f))
{
bits = estimatedCpbFullness - (Int)(m_pcRateCtrl->getCpbSize()*0.9f);
}
estimatedCpbFullness -= m_pcRateCtrl->getBufferingRate();
// prevent underflow
if (estimatedCpbFullness - bits < m_pcRateCtrl->getRCPic()->getLowerBound())
{
bits = estimatedCpbFullness - m_pcRateCtrl->getRCPic()->getLowerBound();
}
}
if ( bits < 200 )
{
bits = 200;
}
m_pcRateCtrl->getRCPic()->setTargetBits( bits );
}
list<TEncRCPic*> listPreviousPicture = m_pcRateCtrl->getPicList();
m_pcRateCtrl->getRCPic()->getLCUInitTargetBits();
lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture, pcSlice->getSliceType());
sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda, listPreviousPicture );
}
else // normal case
{
list<TEncRCPic*> listPreviousPicture = m_pcRateCtrl->getPicList();
lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture, pcSlice->getSliceType());
sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda, listPreviousPicture );
}
sliceQP = Clip3( -pcSlice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, sliceQP );
m_pcRateCtrl->getRCPic()->setPicEstQP( sliceQP );
//!< 设置当前slice使用的QP, lambda,编码时用到
m_pcSliceEncoder->resetQP( pcPic, sliceQP, lambda );
}
1.3.1 TEncRCPic::create()
Void TEncRCPic::create( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP, Int frameLevel, list<TEncRCPic*>& listPreviousPictures )
{
destroy();
m_encRCSeq = encRCSeq;
m_encRCGOP = encRCGOP;
//!< K0103式子(9)
Int targetBits = xEstPicTargetBits( encRCSeq, encRCGOP );
Int estHeaderBits = xEstPicHeaderBits( listPreviousPictures, frameLevel );
if ( targetBits < estHeaderBits + 100 )
{
targetBits = estHeaderBits + 100; // at least allocate 100 bits for picture data
}
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_lowerBound = xEstPicLowerBound( encRCSeq, encRCGOP );
m_LCULeft = m_numberOfLCU;
m_bitsLeft -= m_estHeaderBits;
m_pixelsLeft = m_numberOfPixel;
m_LCUs = new TRCLCU[m_numberOfLCU];
Int i, j;
Int LCUIdx;
// 初始化每个LCU的参数
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;
m_LCUs[LCUIdx].m_bitWeight = 1.0;
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;
m_picActualBits = 0;
m_picQP = 0;
m_picLambda = 0.0;
}
1.3.2 TEncRCPic::xEstPicTargetBits()
Int TEncRCPic::xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP )
{
Int targetBits = 0;
Int GOPbitsLeft = encRCGOP->getBitsLeft();
Int i;
Int currPicPosition = encRCGOP->getNumPic()-encRCGOP->getPicLeft();
Int currPicRatio = encRCSeq->getBitRatio( currPicPosition );
Int totalPicRatio = 0;
for ( i=currPicPosition; i<encRCGOP->getNumPic(); i++ )
{
totalPicRatio += encRCSeq->getBitRatio( i );
}
targetBits = Int( ((Double)GOPbitsLeft) * currPicRatio / totalPicRatio );
if ( targetBits < 100 )
{
targetBits = 100; // at least allocate 100 bits for one picture
}
if ( m_encRCSeq->getFramesLeft() > 16 )
{
targetBits = Int( g_RCWeightPicRargetBitInBuffer * targetBits + g_RCWeightPicTargetBitInGOP * m_encRCGOP->getTargetBitInGOP( currPicPosition ) );
}
return targetBits;
}
1.3.3 TEncRCPic::xEstPicHeaderBits()
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++ )
{
if ( (*it)->getFrameLevel() == frameLevel )
{
totalPreviousBits += (*it)->getPicActualHeaderBits();
numPreviousPics++;
}
}
Int estHeaderBits = 0;
if ( numPreviousPics > 0 )
{
estHeaderBits = totalPreviousBits / numPreviousPics;
}
return estHeaderBits;
}
1.3.4 TEncRCPic::estimatePicLambda()
此函数计算帧级lambda
Double TEncRCPic::estimatePicLambda( list<TEncRCPic*>& listPreviousPictures, SliceType eSliceType)
{
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;
Double estLambda;
if (eSliceType == I_SLICE)
{
estLambda = calculateLambdaIntra(alpha, beta, pow(m_totalCostIntra/(Double)m_numberOfPixel, BETA1), bpp);
}
else
{
estLambda = alpha * pow( bpp, beta ); //!< K0103 式子(10)
}
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;
Double totalWeight = 0.0;
// initial BU bit allocation weight
for ( Int i=0; i<m_numberOfLCU; i++ )
{
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;
}
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;
}
return estLambda;
}
1.3.5 TEncRCPic::estimatePicQP()
此函数计算帧级QP
Int TEncRCPic::estimatePicQP( Double lambda, list<TEncRCPic*>& listPreviousPictures )
{
Int QP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 ); // 经典R-λ模型
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;
}
1.4 LCU级码控参数初始化
在TEncSlice::compressSlice()中,对LCU级的相关参数进行初始化
if ( m_pcCfg->getUseRateCtrl() ) // LCU的RC参数初始化
{
Int estQP = pcSlice->getSliceQp();
Double estLambda = -1.0;
Double bpp = -1.0;
if ( ( pcPic->getSlice( 0 )->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() )
{
// 如果为I帧并且启用了RCForceIntraQP,或者没有启用LCULevelRateControl,则LCU直接使用当前slice的QP
estQP = pcSlice->getSliceQp();
}
else
{
bpp = m_pcRateCtrl->getRCPic()->getLCUTargetBpp(pcSlice->getSliceType());
if ( pcPic->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() );
}
estQP = Clip3( -pcSlice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, estQP );
m_pcRdCost->setLambda(estLambda, pcSlice->getSPS()->getBitDepths());
#if RDOQ_CHROMA_LAMBDA
// set lambda for RDOQ
const Double chromaLambda = estLambda / m_pcRdCost->getChromaWeight();
const Double lambdaArray[MAX_NUM_COMPONENT] = { estLambda, chromaLambda, chromaLambda };
m_pcTrQuant->setLambdas( lambdaArray );
#else
m_pcTrQuant->setLambda( estLambda );
#endif
}
m_pcRateCtrl->setRCQP( estQP );
#if ADAPTIVE_QP_SELECTION
pCtu->getSlice()->setSliceQpBase( estQP ); //!< 设置编码时使用的QP值
#endif
}
1.4.1 TEncRCPic::getLCUTargetBpp()
此函数计算LCU的bpp
Double TEncRCPic::getLCUTargetBpp(SliceType eSliceType)
{
Int LCUIdx = getLCUCoded();
Double bpp = -1.0;
Int avgBits = 0;
if (eSliceType == I_SLICE)
{
Int noOfLCUsLeft = m_numberOfLCU - LCUIdx + 1;
Int bitrateWindow = min(4,noOfLCUsLeft); // 类似于之前的滑动窗口
Double MAD = getLCU(LCUIdx).m_costIntra; //计算出每个LCU对应的MAD值
// m_remainingCostIntra为当前帧的总MAD
// m_remainingCostIntra = m_totalCostIntra;
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 );
}
//分配完一个LCU比特后,更新剩余的m_remainingCostIntra
m_remainingCostIntra -= MAD;
}
else // 非I帧
{
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 );
}
if ( avgBits < 1 )
{
avgBits = 1;
}
bpp = ( Double )avgBits/( Double )m_LCUs[ LCUIdx ].m_numberOfPixel;
m_LCUs[ LCUIdx ].m_targetBits = avgBits;
return bpp;
}
1.4.2 TEncRCPic::getLCUEstLambda()
此函数计算LCU的lambda
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;
}
1.4.3 TEncRCPic::getLCUEstQP()
此函数计算LCU的QP
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;
}
2. 参数更新
2.1 编码完一个LCU后,进行参数值更新
在TEncSlice::compressSlice()中
if ( m_pcCfg->getUseRateCtrl() ) // 每编码完一个LCU,进行一次更新
{
Int actualQP = g_RCInvalidQPValue;
Double actualLambda = m_pcRdCost->getLambda();
Int actualBits = pCtu->getTotalBits();
Int numberOfEffectivePixels = 0;
for ( Int idx = 0; idx < pcPic->getNumPartitionsInCtu(); idx++ )
{
//!< 不考虑skip模式
if ( pCtu->getPredictionMode( idx ) != NUMBER_OF_PREDICTION_MODES && ( !pCtu->isSkipped( idx ) ) )
{
numberOfEffectivePixels = numberOfEffectivePixels + 16;
break;
}
}
if ( numberOfEffectivePixels == 0 )
{
actualQP = g_RCInvalidQPValue;
}
else
{
actualQP = pCtu->getQP( 0 );
}
m_pcRdCost->setLambda(oldLambda, pcSlice->getSPS()->getBitDepths());
m_pcRateCtrl->getRCPic()->updateAfterCTU( m_pcRateCtrl->getRCPic()->getLCUCoded(), actualBits, actualQP, actualLambda,
pCtu->getSlice()->getSliceType() == I_SLICE ? 0 : m_pcCfg->getLCULevelRC() );
}
2.1.1 TEncRCPic::updateAfterLCU()
更新LCU级参数:剩余的比特数及α、β等
Void TEncRCPic::updateAfterCTU( Int LCUIdx, Int bits, Int QP, Double lambda, Bool updateLCUParameter )
{
m_LCUs[LCUIdx].m_actualBits = bits;
m_LCUs[LCUIdx].m_QP = QP;
m_LCUs[LCUIdx].m_lambda = lambda;
m_LCULeft--;
m_bitsLeft -= bits; // frame中剩余比特数的更新
m_pixelsLeft -= m_LCUs[LCUIdx].m_numberOfPixel;
if ( !updateLCUParameter )
{
return;
}
if ( !m_encRCSeq->getUseLCUSeparateModel() )
{
return;
}
Double alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha;
Double beta = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta;
// 按照公式(12)-(13)更新参数
Int LCUActualBits = m_LCUs[LCUIdx].m_actualBits;
Int LCUTotalPixels = m_LCUs[LCUIdx].m_numberOfPixel;
Double bpp = ( Double )LCUActualBits/( Double )LCUTotalPixels;
Double calLambda = alpha * pow( bpp, beta );
Double inputLambda = m_LCUs[LCUIdx].m_lambda;
if( inputLambda < 0.01 || calLambda < 0.01 || bpp < 0.0001 )
{
alpha *= ( 1.0 - m_encRCSeq->getAlphaUpdate() / 2.0 );
beta *= ( 1.0 - m_encRCSeq->getBetaUpdate() / 2.0 );
alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha );
beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta );
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 );
alpha += m_encRCSeq->getAlphaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * alpha;
Double lnbpp = log( bpp );
lnbpp = Clip3( -5.0, -0.1, lnbpp );
beta += m_encRCSeq->getBetaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * lnbpp;
alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha );
beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta );
TRCParameter rcPara;
rcPara.m_alpha = alpha;
rcPara.m_beta = beta;
m_encRCSeq->setLCUPara( m_frameLevel, LCUIdx, rcPara );
}
2.2 编码完一帧后,进行参数更新
TEncGOP::compressGOP()中
if ( m_pcCfg->getUseRateCtrl() )
{
// 每个LCU都有自己的λ和QP
// 整帧的λ为所有LCU的λ的几何平均值
// 整帧的QP为所有LCU的QP的算术平均值
Double avgQP = m_pcRateCtrl->getRCPic()->calAverageQP();
Double avgLambda = m_pcRateCtrl->getRCPic()->calAverageLambda();
if ( avgLambda < 0.0 )
{
avgLambda = 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 )
{
m_pcRateCtrl->getRCGOP()->updateAfterPicture( actualTotalBits );
}
else // for intra picture, the estimated bits are used to update the current status in the GOP
{
m_pcRateCtrl->getRCGOP()->updateAfterPicture( estimatedBits );
}
if (m_pcRateCtrl->getCpbSaturationEnabled())
{
m_pcRateCtrl->updateCpbState(actualTotalBits);
printf(" [CPB %6d bits]", m_pcRateCtrl->getCpbState());
}
}
2.2.1 TEncRCPic::updateAfterPictur()
更新Picture级参数:α、β等
Void TEncRCPic::updateAfterPicture( Int actualHeaderBits, Int actualTotalBits, Double averageQP, Double averageLambda, SliceType eSliceType)
{
m_picActualHeaderBits = actualHeaderBits;
m_picActualBits = actualTotalBits;
if ( averageQP > 0.0 )
{
m_picQP = Int( averageQP + 0.5 );
}
else
{
m_picQP = g_RCInvalidQPValue;
}
m_picLambda = averageLambda;
Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;
Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;
if (eSliceType == I_SLICE)
{
updateAlphaBetaIntra(&alpha, &beta);
}
else
{
// update parameters
// 按照公式(11)-(13)计算
Double picActualBits = ( Double )m_picActualBits;
Double picActualBpp = picActualBits/(Double)m_numberOfPixel;
Double calLambda = alpha * pow( picActualBpp, beta );
Double inputLambda = m_picLambda;
if ( inputLambda < 0.01 || calLambda < 0.01 || picActualBpp < 0.0001 )
{
alpha *= ( 1.0 - m_encRCSeq->getAlphaUpdate() / 2.0 );
beta *= ( 1.0 - m_encRCSeq->getBetaUpdate() / 2.0 );
alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha );
beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, 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 );
alpha += m_encRCSeq->getAlphaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * alpha;
Double lnbpp = log( picActualBpp );
lnbpp = Clip3( -5.0, -0.1, lnbpp );
beta += m_encRCSeq->getBetaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * lnbpp;
alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha );
beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta );
}
TRCParameter rcPara;
rcPara.m_alpha = alpha;
rcPara.m_beta = beta;
m_encRCSeq->setPicPara( m_frameLevel, rcPara );
if ( m_frameLevel == 1 )
{
Double currLambda = Clip3( 0.1, 10000.0, m_picLambda );
Double updateLastLambda = g_RCWeightHistoryLambda * m_encRCSeq->getLastLambda() + g_RCWeightCurrentLambda * currLambda;
m_encRCSeq->setLastLambda( updateLastLambda );
}
}
2.2.2 TEncRCSeq::updateAfterPic()
更新剩余比特数和帧数
Void TEncRCSeq::updateAfterPic ( Int bits )
{
m_bitsLeft -= bits;
m_framesLeft--;
}
2.2.3 TEncRCGOP::updateAfterPicture()
更新剩余比特数和帧数
Void TEncRCGOP::updateAfterPicture( Int bitsCost )
{
m_bitsLeft -= bitsCost;
m_picLeft--;
}