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; }
相关文章推荐
- HM编码器代码阅读(29)——码率控制
- x265代码阅读:码率控制(二)
- HEVC码率控制浅析——HM代码阅读之二
- HEVC码率控制浅析——HM代码阅读之一
- HEVC码率控制浅析——HM代码阅读之一
- HEVC码率控制浅析——HM代码阅读之四
- x265代码阅读:码率控制(一)
- HEVC码率控制浅析——HM代码阅读之一
- HEVC码率控制浅析——HM代码阅读之四
- HEVC码率控制浅析——HM代码阅读之三
- HEVC码率控制浅析——HM代码阅读之三
- HEVC码率控制浅析——HM代码阅读之四
- HEVC码率控制浅析——HM代码阅读之二
- HEVC码率控制浅析——HM代码阅读之二
- HM编码器代码阅读(7)——整个编码流程以及相关的函数
- homerHEVC代码阅读(24)——编码器控制函数HOMER_enc_control
- HM编码器代码阅读(10)——片的编码
- HM编码器代码阅读(21)——熵编码的概念以及在HEVC中应用
- HEVC码率控制算法研究与HM相应代码分析(三)——算法及代码分析