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

HM编码器代码阅读(41)——码率控制(二)

2017-02-20 20:56 465 查看

码率控制

原理和公式


HM编码器代码阅读(29)——码率控制 中,主要讲了码率控制的一些基本原理以及在HM中实现,但是关于很多的细节没有细讲。

下面有几篇文章是讲码率控制方面的:

H264三种码率控制方法(CBR, VBR, CVBR)

简述x264几种码率控制方式的实现

码率控制技术原理

x264编码指南——码率控制

接下来我们就详细介绍码率控制的其他方面的知识。

与码率控制相关的参数:α、β、λ、QP、比特率(bitRate)、bpp,update_α(α更新因子),update_β(β更新因子),它们的关系如下:

bpp(bits per pixel)需要通过比特率计算

λ = α * pow( bpp, β );

QP = 4.2005 * log( λ ) + 13.7122 ;

每次编码完成一个LCU或者帧之后,码率控制对象都会根据当前剩余的比特数来更新α和β,由此来更新QP参数,以适应比特率的变化,更新方式如下:

α_new += update_α * ( log( old_λ ) - log( temp_λ ) ) * α_old;其中temp_λ = α * pow( bpp, β );

β_new += update_β * ( log( old_λ ) - log( temp_λ ) ) * log( bpp );

update_α和update_β的初始值如下:

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 )
{
// ....
m_targetBits      = (Int64)m_totalFrames * (Int64)m_targetRate / (Int64)m_frameRate;
m_seqTargetBpp = (Double)m_targetRate / (Double)m_frameRate / (Double)m_numberOfPixel;

// 根据bpp设置α和β更新因子的值,这两个因子用于编码完成一个LCU/帧之后更新α和β的值
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;
}

// ....
}


序列级别的码率控制

初始化

初始化的流程如下:

1、根据用户输入的总得帧的数量、帧率、比特率,计算总的比特数、平均比特数等

2、根据gop的结构确定每个frame的时域层,不同的时域层的frame占用的比特数的百分比不同bitsRatio

3、确定每个帧的α和β

4、确定每个LCU的α和β

Void TEncRateCtrl::init( Int totalFrames,  // 编码序列中帧的总数
Int targetBitrate,  // 目标比特率(即每秒发送多少比特)
Int frameRate, // 帧率(一秒钟播放多少帧)
Int GOPSize, // gop中包含帧的数量
Int picWidth, // 图像的宽度
Int picHeight, // 图像的高度
Int LCUWidth, // CTU的宽度
Int LCUHeight, // CTU的高度
Int keepHierBits,
Bool useLCUSeparateModel,
GOPEntry  GOPList[MAX_GOP] // 图像组的结构(表示了图像组中各个图像的参考依赖关系)
)
{
destroy();

// 是否为低延迟的(默认是true)
Bool isLowdelay = true;

// 是否为低延迟的判断方法:
// 如果前面一帧的poc大于后面一帧的poc(即播放顺序在后面的帧的poc反而小一点)
// 那么就不是低延迟的,表示有延迟(有B帧的情况下一般都是有延迟的)
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

// 设置一个GOP中,每个图像的比特率的占用比
Int* bitsRatio;
bitsRatio = new Int[ GOPSize ];
for ( Int i=0; i<GOPSize; i++ )
{
bitsRatio[i] = 10;
if ( !GOPList[i].m_refPic )
{
bitsRatio[i] = 2;
}
}

// 下面这些设置可以通过查询HEVC标准的表来得到
if ( keepHierBits > 0 )
{
// bpp表示bit per pixel
Double bpp = (Double)( targetBitrate / (Double)( frameRate*picWidth*picHeight ) );
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;
}
}
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" );
}
}

// GOP中图像的序号到level的映射
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();// 主要是LCU级别的alpha和beta参数的设置
}

delete[] bitsRatio;
delete[] GOPID2Level;
}


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是指一秒之内的平均比特数量
m_targetBits      = (Int64)m_totalFrames * (Int64)m_targetRate / (Int64)m_frameRate;
m_seqTargetBpp = (Double)m_targetRate / (Double)m_frameRate / (Double)m_numberOfPixel;

// 根据bpp设置α和β更新因子的值,这两个因子用于编码完成一个LCU/帧之后更新α和β的值
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;

// 计算一个帧中LCU的数量
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];
for ( Int i=0; i<m_numberOfLevel; i++ )
{
m_picPara[i].m_alpha = 0.0;
m_picPara[i].m_beta  = 0.0;
}

// m_useLCUSeparateModel表示是否使用LCU级别的码率控制
if ( m_useLCUSeparateModel )
{
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;
}


更新

/*
** 编码完一帧之后更新
*/
Void TEncRCSeq::updateAfterPic ( Int bits )
{
m_bitsLeft -= bits;
m_framesLeft--;
}


图像组级别的码率控制

初始化

初始化的流程如下:

1、计算根据一个公式去估计一个gop占用的比特数

2、根据bitsRatio估计每个frame的比特数,这里是很粗略的计算,下一步在frame级别的码率控制时还要细化

Void TEncRCGOP::create( TEncRCSeq* encRCSeq, Int numPic )
{
// 先销毁原先的数据
destroy();

// 估计比特数
Int targetBits = xEstGOPTargetBits( encRCSeq, numPic );

// 如果使用了自适应比特率的模式,且Lambda大于0.1
// 就计算gop中每个frame的比特权重(即该frame的比特数占gop的比特数的百分比)
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 );
}

// 粗略的计算GOP中每一帧分配的比特数
for ( i=0; i<numPic; i++ )
{
currPicRatio = encRCSeq->getBitRatio( i );
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;
}


/*
** 估计一个GOP所需的比特数
*/
Int TEncRCGOP::xEstGOPTargetBits( TEncRCSeq* encRCSeq, Int GOPSize )
{
// 选择滑动窗口的大小
Int realInfluencePicture = min( g_RCSmoothWindowSize, encRCSeq->getFramesLeft() );
// 计算理论的每图像比特数,直接用总比特数除以总得帧数
Int averageTargetBitsPerPic = (Int)( encRCSeq->getTargetBits() / encRCSeq->getTotalFrames() );
// 计算每一帧平均分配的比特数
Int currentTargetBitsPerPic = (Int)( ( encRCSeq->getBitsLeft() - averageTargetBitsPerPic * (encRCSeq->getFramesLeft() - realInfluencePicture) ) / realInfluencePicture );

// 当前GOP应该分配的比特数
Int targetBits = currentTargetBitsPerPic * GOPSize;

if ( targetBits < 200 )
{
targetBits = 200;   // at least allocate 200 bits for one GOP
}

return targetBits;
}

更新

/*
** 编码完一帧之后进行更新
*/
Void TEncRCGOP::updateAfterPicture( Int bitsCost )
{
// 更新剩余比特数
m_bitsLeft -= bitsCost;
// 更新剩余帧数
m_picLeft--;
}


图像级别的码率控制

初始化

初始化的流程

1、估计每个frame占用的比特数

2、估计slice头部/frame头部占用的比特数

3、把步骤1和步骤2计算的结果相加,就是分配给帧的比特数

4、设置LCU的相关参数

Void TEncRCPic::create( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP, Int frameLevel, list<TEncRCPic*>& listPreviousPictures )
{
destroy();
m_encRCSeq = encRCSeq;
m_encRCGOP = encRCGOP;

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_LCULeft         = m_numberOfLCU;
m_bitsLeft       -= m_estHeaderBits;
m_pixelsLeft      = m_numberOfPixel;

// 分配LCU级别的码率控制对象
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;	// QP参数
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; // 一个LCU拥有的像素数
}
}
m_picActualHeaderBits = 0;
m_picActualBits       = 0;
m_picQP               = 0;
m_picLambda           = 0.0;
}
/*
** 估计一个帧所需的比特数
*/
Int TEncRCPic::xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP )
{
Int targetBits        = 0;

// 当前GOP剩余的比特数
Int GOPbitsLeft       = encRCGOP->getBitsLeft();

Int i;
// 当前帧在gop中的位置,根据位置可以得到它的时域层,同时得到该帧的重要性
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;
}
/*
** 估计帧头部/slice头部等占用的比特数
*/
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;
}


更新

/*
** 编码完成一帧之后进行处理
** 主要是更新各种参数
*/
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;

// 如果是I slice
if (eSliceType == I_SLICE)
{
updateAlphaBetaIntra(&alpha, &beta);
}
else
{
// update parameters

/*
** 下面按照公式计算:
** α_new += update_α * ( log( old_λ ) - log( temp_λ ) ) * α_old;其中temp_λ   = α * pow( bpp, β );
** β_new  += update_β * ( log( old_λ ) - log( temp_λ ) ) * log( bpp );
*/
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 );
}
}
/*
** I帧的码率控制参数的更新
*/
Void TEncRCPic::updateAlphaBetaIntra(double *alpha, double *beta)
{
Double lnbpp = log(pow(m_totalCostIntra / (Double)m_numberOfPixel, BETA1));
Double diffLambda = (*beta)*(log((Double)m_picActualBits)-log((Double)m_targetBits));

diffLambda = Clip3(-0.125, 0.125, 0.25*diffLambda);
*alpha    =  (*alpha) * exp(diffLambda);
*beta     =  (*beta) + diffLambda / lnbpp;
}


LCU级别的码率控制

初始化

/*
** 估计帧的lambda
** 同时这个函数也对一个图像中所有的LCU的码率控制参数进行初始化
*/
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 );
}

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;
}
}

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
// 初始化LCU级别的码率控制参数
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;
}


更新

/*
** 编码完成一个LCU之后进行处理
** 参数的更新
*/
Void TEncRCPic::updateAfterLCU( 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;
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;

/*
** 按照公式计算参数:
** α_new += update_α * ( log( old_λ ) - log( temp_λ ) ) * α_old;其中temp_λ   = α * pow( bpp, β );
** β_new  += update_β * ( log( old_λ ) - log( temp_λ ) ) * log( bpp );
*/
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 );

}


QP的计算

在compressSlice中,通过码率控制计算QP参数,大概的计算流程如下:

1、调用getLCUTargetBpp,取得bpp

2、计算QP:

(1)如果是I slice 调用getLCUEstLambdaAndQP,取得lambda(λ),QP值直接取自slice中的QP值

(2)如果是P、B slice,调用getLCUEstLambda,取得lambda(λ),QP值根据λ和slice的QP值调用getLCUEstQP计算

3、往码率控制对象中保存λ和初始的QP值,这个QP的值就是编码的时候使用的QP值

if ( m_pcCfg->getUseRateCtrl() )
{
Int estQP        = pcSlice->getSliceQp();
Double estLambda = -1.0;
Double bpp       = -1.0;

if ( ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() )
{
estQP = pcSlice->getSliceQp();
}
else
{
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() );
}

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

m_pcRdCost->setLambda(estLambda);
#if RDOQ_CHROMA_LAMBDA
// set lambda for RDOQ
Double weight=m_pcRdCost->getChromaWeight();
const Double lambdaArray[3] = { estLambda, (estLambda / weight), (estLambda / weight) };
m_pcTrQuant->setLambdas( lambdaArray );
#else
m_pcTrQuant->setLambda( estLambda );
#endif
}

m_pcRateCtrl->setRCQP( estQP );
#if ADAPTIVE_QP_SELECTION
pcCU->getSlice()->setSliceQpBase( estQP );
#endif
}

计算bpp(bits per pixel)

/*
** 计算LCU的bpp
*/
Double TEncRCPic::getLCUTargetBpp(SliceType eSliceType)
{
Int   LCUIdx    = getLCUCoded();
Double bpp      = -1.0;
Int avgBits     = 0;

// 先计算LCU的平均的比特数
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
{
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;
}

// 根据LCU的平均比特数计算bpp
bpp = ( Double )avgBits/( Double )m_LCUs[ LCUIdx ].m_numberOfPixel;
m_LCUs[ LCUIdx ].m_targetBits = avgBits;

return bpp;
}


计算λ

/*
** 估计LCU的λ
*/
Double TEncRCPic::getLCUEstLambda( Double bpp )
{
Int   LCUIdx = getLCUCoded();
Double alpha;
Double beta;
if ( m_encRCSeq->getUseLCUSeparateModel() )
{
alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha;
beta  = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta;
}
else
{
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;
}
}

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;
}


计算QP参数

/*
** 计算LCU的QP参数
*/
Int TEncRCPic::getLCUEstQP( Double lambda, Int clipPicQP )
{
Int LCUIdx = getLCUCoded();
// 计算QP的公式:QP = 4.2005 * log( λ ) + 13.7122 ;
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;
}
}

if ( clipNeighbourQP > g_RCInvalidQPValue )
{
estQP = Clip3( clipNeighbourQP - 1, clipNeighbourQP + 1, estQP );
}

estQP = Clip3( clipPicQP - 2, clipPicQP + 2, estQP );

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