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

码率控制


介绍

码率控制
    码率控制也叫速率控制,主要是控制编码后的比特率。
    存在码率控制模块的原因是,有时候解码器处理的速度不够快、网络带宽不行,这些情况的存在要求我们必须减少数据的发送量(即比特率要变小),减少数据的发送量
意味着我们要对数据进行更近一步的压缩,在编码器中就表现为量化参数QP的变化。
    当满足一定码率要求的情况下,我们还需要让编码的失真尽量小。
    码率控制的核心就是要确定量化参数QP。

    如果不使用码率控制,那么量化参数QP就是自定义的或者根据需要选择


    码率控制是一级一级进行控制的,先分配图像组级(GOP)的比特数,然后分配图像级的比特数,再分配CTU级别的比特数。利用已经分配的比特数来确定量化参数。
    更多的细节请参考http://blog.csdn.net/nb_vol_1/article/details/53288902

码率控制在HEVC中的实现


码率控制流程

在TEncCfg中有个布尔类型的m_RCEnableRateControl成员,它表示是否使用码率控制
在HM中码率控制的流程是:

    1、在TEncTop::create中,定义了编码序列级别的码率控制

	if ( m_RCEnableRateControl )
	{
		// 码率控制器初始化
		m_cRateCtrl.init( m_framesToBeEncoded, m_RCTargetBitrate, m_iFrameRate, m_iGOPSize, m_iSourceWidth, m_iSourceHeight,
			g_uiMaxCUWidth, g_uiMaxCUHeight, m_RCKeepHierarchicalBit, m_RCUseLCUSeparateModel, m_GOPList );
	}
    2、在TEncTop::encode中,定义了图像组级别的码率控制

	if ( m_RCEnableRateControl )
	{
		m_cRateCtrl.initRCGOP( m_iNumPicRcvd );
	}
	if ( m_RCEnableRateControl )
	{
		m_cRateCtrl.destroyRCGOP();
	}

    3、在TEncGOP::compressGOP,定义了图像级别的码率控制

    m_pcRateCtrl->initRCPic( frameLevel );
    4、在TEncSlice::compressSlice()中,设置CTU(LCU)级别的码率控制参数

		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
		}
    5、在TEncSlice::compressSlice中,编码完成一个CTU之后,需要更新剩余比特数等相关的参数

		if ( m_pcCfg->getUseRateCtrl() )
		{

			Int actualQP        = g_RCInvalidQPValue;
			Double actualLambda = m_pcRdCost->getLambda();
			Int actualBits      = pcCU->getTotalBits();
			Int numberOfEffectivePixels    = 0;
			for ( Int idx = 0; idx < rpcPic->getNumPartInCU(); idx++ )
			{
				if ( pcCU->getPredictionMode( idx ) != MODE_NONE && ( !pcCU->isSkipped( idx ) ) )
				{
					numberOfEffectivePixels = numberOfEffectivePixels + 16;
					break;
				}
			}

			if ( numberOfEffectivePixels == 0 )
			{
				actualQP = g_RCInvalidQPValue;
			}
			else
			{
				actualQP = pcCU->getQP( 0 );
			}
			m_pcRdCost->setLambda(oldLambda);

			m_pcRateCtrl->getRCPic()->updateAfterLCU( m_pcRateCtrl->getRCPic()->getLCUCoded(), actualBits, actualQP, actualLambda,
				pcCU->getSlice()->getSliceType() == I_SLICE ? 0 : m_pcCfg->getLCULevelRC() );
		}
    6、在TEncGOP::compressGOP中,每编码完成一个图像,就更新剩余比特数等码率控制相关的参数

        if ( m_pcCfg->getUseRateCtrl() )
        {
            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 );
            }
        }

码率控制的相关结构

CTU(LCU)级别的码率控制结构

/*
** LCU(CTU)级别的码率控制信息
*/
struct TRCLCU
{
	// 实际比特数
	Int m_actualBits;
	// 相应的QP
	Int m_QP;     // QP of skip mode is set to g_RCInvalidQPValue
	// 目标比特数
	Int m_targetBits;
	// lambda参数
	Double m_lambda;
	// 比特权重
	Double m_bitWeight;
	// 像素的数量
	Int m_numberOfPixel;
	// 帧内的代价
	Double m_costIntra;
	// 剩余的比特数(目标的剩余比特数)
	Int m_targetBitsLeft;
};
码率参数结构

/*
** 码率控制参数!
*/
struct TRCParameter
{
	Double m_alpha; // alpha参数
	Double m_beta; // beta参数
};
编码序列级别的码率控制结构
/*
** seq序列级别(级别比gop高)的码率控制
*/
class TEncRCSeq
{
public:
	TEncRCSeq();
	~TEncRCSeq();

public:
	Void create( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int numberOfLevel, Bool useLCUSeparateModel, Int adaptiveBit );
	Void destroy();

	// 初始化比特率
	Void initBitsRatio( Int bitsRatio[] );
	// 初始化gop到level的映射
	Void initGOPID2Level( Int GOPID2Level[] );
	// 初始化pic的码率控制参数
	Void initPicPara( TRCParameter* picPara  = NULL );    // NULL to initial with default value
	// 初始化LCU的码率控制参数
	Void initLCUPara( TRCParameter** LCUPara = NULL );    // NULL to initial with default value
	// 在处理完一帧之后更新
	Void updateAfterPic ( Int bits );
	// 设置总得比特率
	Void setAllBitRatio( Double basicLambda, Double* equaCoeffA, Double* equaCoeffB );

public:
	Int  getTotalFrames()                 { return m_totalFrames; }
	Int  getTargetRate()                  { return m_targetRate; }
	Int  getFrameRate()                   { return m_frameRate; }
	Int  getGOPSize()                     { return m_GOPSize; }
	Int  getPicWidth()                    { return m_picWidth; }
	Int  getPicHeight()                   { return m_picHeight; } 
	Int  getLCUWidth()                    { return m_LCUWidth; }
	Int  getLCUHeight()                   { return m_LCUHeight; }
	Int  getNumberOfLevel()               { return m_numberOfLevel; }
	Int  getAverageBits()                 { return m_averageBits; }
	Int  getLeftAverageBits()             { assert( m_framesLeft > 0 ); return (Int)(m_bitsLeft / m_framesLeft); }
	Bool getUseLCUSeparateModel()         { return m_useLCUSeparateModel; }

	Int  getNumPixel()                    { return m_numberOfPixel; }
	Int64  getTargetBits()                { return m_targetBits; }
	Int  getNumberOfLCU()                 { return m_numberOfLCU; }
	Int* getBitRatio()                    { return m_bitsRatio; }
	Int  getBitRatio( Int idx )           { assert( idx<m_GOPSize); return m_bitsRatio[idx]; }
	Int* getGOPID2Level()                 { return m_GOPID2Level; }
	Int  getGOPID2Level( Int ID )         { assert( ID < m_GOPSize ); return m_GOPID2Level[ID]; }
	TRCParameter*  getPicPara()                                   { return m_picPara; }
	TRCParameter   getPicPara( Int level )                        { assert( level < m_numberOfLevel ); return m_picPara[level]; }
	Void           setPicPara( Int level, TRCParameter para )     { assert( level < m_numberOfLevel ); m_picPara[level] = para; }
	TRCParameter** getLCUPara()                                   { return m_LCUPara; }
	TRCParameter*  getLCUPara( Int level )                        { assert( level < m_numberOfLevel ); return m_LCUPara[level]; }
	TRCParameter   getLCUPara( Int level, Int LCUIdx )            { assert( LCUIdx  < m_numberOfLCU ); return getLCUPara(level)[LCUIdx]; }
	Void           setLCUPara( Int level, Int LCUIdx, TRCParameter para ) { assert( level < m_numberOfLevel ); assert( LCUIdx  < m_numberOfLCU ); m_LCUPara[level][LCUIdx] = para; }

	Int  getFramesLeft()                  { return m_framesLeft; }
	Int64  getBitsLeft()                  { return m_bitsLeft; }

	Double getSeqBpp()                    { return m_seqTargetBpp; }
	Double getAlphaUpdate()               { return m_alphaUpdate; }
	Double getBetaUpdate()                { return m_betaUpdate; }

	Int    getAdaptiveBits()              { return m_adaptiveBit;  }
	Double getLastLambda()                { return m_lastLambda;   }
	Void   setLastLambda( Double lamdba ) { m_lastLambda = lamdba; }

private:
	// 总的帧数
	Int m_totalFrames;
	// 目标码率
	Int m_targetRate;
	// 帧率
	Int m_frameRate; 
	// gop的大小
	Int m_GOPSize;
	// 帧宽和高
	Int m_picWidth;
	Int m_picHeight;
	// LCU的宽和高
	Int m_LCUWidth;
	Int m_LCUHeight;
	// level的数量
	Int m_numberOfLevel;
	// 平均的比特数
	Int m_averageBits;

	// 像素的数量
	Int m_numberOfPixel;
	// 目标比特数
	Int64 m_targetBits;
	// LCU的数量
	Int m_numberOfLCU;
	// 比特率
	Int* m_bitsRatio;
	// gop的id到level的映射
	Int* m_GOPID2Level;
	// pic的码率控制参数
	TRCParameter*  m_picPara;
	// LCU的码率控制参数
	TRCParameter** m_LCUPara;

	// 剩余的帧数
	Int m_framesLeft;
	// 剩余的比特数
	Int64 m_bitsLeft;
	Double m_seqTargetBpp;
	// alpha参数的更新
	Double m_alphaUpdate;
	// beta参数的更新
	Double m_betaUpdate;
	// 是否使用LCU分开的模型
	Bool m_useLCUSeparateModel;

	// 自适应的比特
	Int m_adaptiveBit;
	// 最后的lambda参数
	Double m_lastLambda;
};
图像组(gop)级别的码率控制

/*
** GOP级别的码率控制
*/
class TEncRCGOP
{
public:
	TEncRCGOP();
	~TEncRCGOP();

public:
	Void create( TEncRCSeq* encRCSeq, Int numPic );
	Void destroy();

	// 在处理完一帧之后更新
	Void updateAfterPicture( Int bitsCost );

private:
	// 预估一个gop占用的比特数
	Int  xEstGOPTargetBits( TEncRCSeq* encRCSeq, Int GOPSize );
	Void   xCalEquaCoeff( TEncRCSeq* encRCSeq, Double* lambdaRatio, Double* equaCoeffA, Double* equaCoeffB, Int GOPSize );
	Double xSolveEqua( Double targetBpp, Double* equaCoeffA, Double* equaCoeffB, Int GOPSize );

public:
	TEncRCSeq* getEncRCSeq()        { return m_encRCSeq; }
	Int  getNumPic()                { return m_numPic;}
	Int  getTargetBits()            { return m_targetBits; }
	Int  getPicLeft()               { return m_picLeft; }
	Int  getBitsLeft()              { return m_bitsLeft; }
	Int  getTargetBitInGOP( Int i ) { return m_picTargetBitInGOP[i]; }

private:
    // 所属的码率控制序列
	TEncRCSeq* m_encRCSeq;
	// 该gop中,每一帧的目标比特数
	Int* m_picTargetBitInGOP;
	// 帧数量
	Int m_numPic;
	// gop总的目标比特数
	Int m_targetBits;
	// 还剩多少帧处理完成
	Int m_picLeft;
	// 还剩多少比特
	Int m_bitsLeft;
};
图像级别的码率控制对象
/*
** 图像级别的码率控制
*/
class TEncRCPic
{
public:
	TEncRCPic();
	~TEncRCPic();

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

	Int    estimatePicQP    ( Double lambda, list<TEncRCPic*>& listPreviousPictures );
	Int    getRefineBitsForIntra(Int orgBits);
	Double calculateLambdaIntra(double alpha, double beta, double MADPerPixel, double bitsPerPixel);
	Double estimatePicLambda( list<TEncRCPic*>& listPreviousPictures, SliceType eSliceType);

	Void   updateAlphaBetaIntra(double *alpha, double *beta);

	Double getLCUTargetBpp(SliceType eSliceType);
	Double getLCUEstLambdaAndQP(Double bpp, Int clipPicQP, Int *estQP);
	Double getLCUEstLambda( Double bpp );
	Int    getLCUEstQP( Double lambda, Int clipPicQP );

	Void updateAfterLCU( Int LCUIdx, Int bits, Int QP, Double lambda, Bool updateLCUParameter = true );
	Void updateAfterPicture( Int actualHeaderBits, Int actualTotalBits, Double averageQP, Double averageLambda, SliceType eSliceType);

	Void addToPictureLsit( list<TEncRCPic*>& listPreviousPictures );
	Double calAverageQP();
	Double calAverageLambda();

private:
	Int xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP );
	Int xEstPicHeaderBits( list<TEncRCPic*>& listPreviousPictures, Int frameLevel );

public:
	TEncRCSeq*      getRCSequence()                         { return m_encRCSeq; }
	TEncRCGOP*      getRCGOP()                              { return m_encRCGOP; }

	Int  getFrameLevel()                                    { return m_frameLevel; }
	Int  getNumberOfPixel()                                 { return m_numberOfPixel; }
	Int  getNumberOfLCU()                                   { return m_numberOfLCU; }
	Int  getTargetBits()                                    { return m_targetBits; }
	Int  getEstHeaderBits()                                 { return m_estHeaderBits; }
	Int  getLCULeft()                                       { return m_LCULeft; }
	Int  getBitsLeft()                                      { return m_bitsLeft; }
	Int  getPixelsLeft()                                    { return m_pixelsLeft; }
	Int  getBitsCoded()                                     { return m_targetBits - m_estHeaderBits - m_bitsLeft; }
	Int  getLCUCoded()                                      { return m_numberOfLCU - m_LCULeft; }
	TRCLCU* getLCU()                                        { return m_LCUs; }
	TRCLCU& getLCU( Int LCUIdx )                            { return m_LCUs[LCUIdx]; }
	Int  getPicActualHeaderBits()                           { return m_picActualHeaderBits; }
	Void setTargetBits( Int bits )                          { m_targetBits = bits; m_bitsLeft = bits;}
	Void setTotalIntraCost(Double cost)                     { m_totalCostIntra = cost; }
	Void getLCUInitTargetBits();

	Int  getPicActualBits()                                 { return m_picActualBits; }
	Int  getPicActualQP()                                   { return m_picQP; }
	Double getPicActualLambda()                             { return m_picLambda; }
	Int  getPicEstQP()                                      { return m_estPicQP; }
	Void setPicEstQP( Int QP )                              { m_estPicQP = QP; }
	Double getPicEstLambda()                                { return m_estPicLambda; }
	Void setPicEstLambda( Double lambda )                   { m_picLambda = lambda; }

private:
	// 所属的码率控制序列
	TEncRCSeq* m_encRCSeq;
	// 所属的码率控制gop
	TEncRCGOP* m_encRCGOP;

	// 帧的level
	Int m_frameLevel;
	// 像素的数量
	Int m_numberOfPixel;
	// LCU的数量
	Int m_numberOfLCU;
	// 目标比特数
	Int m_targetBits;
	// 帧头部/slice头部等占用的比特数
	Int m_estHeaderBits;
	// 预估的帧的qp
	Int m_estPicQP;
	// 预估的lambda
	Double m_estPicLambda;

	// 剩下的LCU的数量
	Int m_LCULeft;
	// 剩下的比特数量
	Int m_bitsLeft;
	// 剩下的像素数量
	Int m_pixelsLeft;

	// 该帧对应的LCU码率控制对象
	TRCLCU* m_LCUs;
	// 真实的头部占用的比特数
	Int m_picActualHeaderBits;    // only SH and potential APS
	// 帧内模式消耗的比特数
	Double m_totalCostIntra;
	// 帧内模式还剩余的比特数
	Double m_remainingCostIntra;
	// 帧真实占用的比特数
	Int m_picActualBits;          // the whole picture, including header
	// 帧的qp
	Int m_picQP;                  // in integer form
	// 帧的lambda参数
	Double m_picLambda;
};
码率控制对象

/*
** 码率控制管理器
** 管理了TEncRCSeq TEncRCGOP TEncRCPic等对象
*/
class TEncRateCtrl
{
public:
	TEncRateCtrl();
	~TEncRateCtrl();

public:
	Void 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] );
	Void destroy();
	Void initRCPic( Int frameLevel );
	Void initRCGOP( Int numberOfPictures );
	Void destroyRCGOP();

public:
	Void       setRCQP ( Int QP ) { m_RCQP = QP;   }
	Int        getRCQP ()         { return m_RCQP; }
	TEncRCSeq* getRCSeq()          { assert ( m_encRCSeq != NULL ); return m_encRCSeq; }
	TEncRCGOP* getRCGOP()          { assert ( m_encRCGOP != NULL ); return m_encRCGOP; }
	TEncRCPic* getRCPic()          { assert ( m_encRCPic != NULL ); return m_encRCPic; }
	list<TEncRCPic*>& getPicList() { return m_listRCPictures; }

private:
    // 当前的码率控制序列
	TEncRCSeq* m_encRCSeq;
	// 当前码率控制gop
	TEncRCGOP* m_encRCGOP;
	// 当前对应的码率控制pic
	TEncRCPic* m_encRCPic;
	// TEncRCPic列表(应该是一个gop中/或者一个序列中的所有帧)
	list<TEncRCPic*> m_listRCPictures;
	// qp参数
	Int        m_RCQP;
};

码率控制是怎么样控制比特率的

首先我们找到码率控制初始化函数TEncRateCtrl::init



TEncRateCtrl::initRCGOP用于图像组级别的码率控制的初始化,实际初始化在TEncRCGOP::create中,其中调用了一个比较重要的函数是xEstGOPTargetBits,用于估计GOP占用的比特数

TEncRateCtrl::initRCPic,图像级别的码率控制的初始化,实际调用TEncRCGOP::create

这几个初始化函数的大致功能都是比特率分配,即每一帧多少比特、每一个CTU多少个比特之类的


这些都没有什么看头,最重要的是看码率控制在HEVC中怎么样和编码器结合起来的

重点1——计算QP:
在TEncSlice::compressSlice中
(1)获取bpp(bits per pixel),通过getLCUTargetBpp得到
(2)获取Lambda参数,通过bpp等参数调用getLCUEstLambda得到
(3)获取码率控制对象计算出的QP,通过Lambda和slice的QP等参数调用getLCUEstQP得到
(4)把计算出来的QP保存起来,调用setRCQP

		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
		}


重点2——把计算出来的QP应用到编码上:
在TEncCu::xCompressCU中
(1)把iMinQP设置为通过码率控制计算出来的QP(调用getRCQP)
(2)把iMaxQP设置为通过码率控制计算出来的QP(调用getRCQP)
(3)然后利用iMinQP和iMaxQP进行编码

	// 使用码率控制
	// 注意这里的QP使用了,码率控制对象计算出来的QP
	// 通过QP,码率控制对象控制了编码器的比特率
	if ( m_pcEncCfg->getUseRateCtrl() )
	{
		iMinQP = m_pcRateCtrl->getRCQP(); 
		iMaxQP = m_pcRateCtrl->getRCQP();
	}


重点3——根据比特率动态调整:
(1)编码一个CTU或者图像之后,可以得到它占用的比特数
(2)调用updateAfterLCU/updateAfterPicture,更新剩余比特数、Lambda等相关参数下一次计算QP的时候就利用这些参数重新计算,就能够自适应的改变比特率

		if ( m_pcCfg->getUseRateCtrl() )
		{

			Int actualQP        = g_RCInvalidQPValue;
			Double actualLambda = m_pcRdCost->getLambda();
			Int actualBits      = pcCU->getTotalBits();
			Int numberOfEffectivePixels    = 0;
			for ( Int idx = 0; idx < rpcPic->getNumPartInCU(); idx++ )
			{
				if ( pcCU->getPredictionMode( idx ) != MODE_NONE && ( !pcCU->isSkipped( idx ) ) )
				{
					numberOfEffectivePixels = numberOfEffectivePixels + 16;
					break;
				}
			}

			if ( numberOfEffectivePixels == 0 )
			{
				actualQP = g_RCInvalidQPValue;
			}
			else
			{
				actualQP = pcCU->getQP( 0 );
			}
			m_pcRdCost->setLambda(oldLambda);

			m_pcRateCtrl->getRCPic()->updateAfterLCU( m_pcRateCtrl->getRCPic()->getLCUCoded(), actualBits, actualQP, actualLambda,
				pcCU->getSlice()->getSliceType() == I_SLICE ? 0 : m_pcCfg->getLCULevelRC() );
		}

        if ( m_pcCfg->getUseRateCtrl() )
        {
            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 );
            }
        }


  • 4
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值