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

码率控制


原理和公式

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







  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值