HEVC码率控制浅析——HM代码阅读之三
来源:互联网 发布:淘宝买家号信誉查询 编辑:程序博客网 时间:2024/05/12 10:07
续上文继续分析
m_pcRateCtrl->initRCPic( )
Void TEncRateCtrl::initRCPic( Int frameLevel ){ m_encRCPic = new TEncRCPic; m_encRCPic->create( m_encRCSeq, m_encRCGOP, frameLevel, m_listRCPictures );}
m_encRCPic->create
Void TEncRCPic::create( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP, Int frameLevel, list<TEncRCPic*>& listPreviousPictures ){ destroy(); m_encRCSeq = encRCSeq; m_encRCGOP = encRCGOP; Int targetBits = xEstPicTargetBits( encRCSeq, encRCGOP );//!< K0103式子(9) Int estHeaderBits = xEstPicHeaderBits( listPreviousPictures, frameLevel ); //!< header bits estimation if ( targetBits < estHeaderBits + 100 ) { targetBits = estHeaderBits + 100; // at least allocate 100 bits for picture data } //!< 以下为RC相关参数的初始化,根据变量名很容易就能判断其用途,故不罗嗦~ 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; //!< 考虑header bits后的剩余比特数 m_pixelsLeft = m_numberOfPixel; m_LCUs = new TRCLCU[m_numberOfLCU]; Int i, j; Int LCUIdx; for ( i=0; i<picWidthInLCU; i++ ) { for ( j=0; j<picHeightInLCU; j++ ) { LCUIdx = j*picWidthInLCU + i; m_LCUs[LCUIdx].m_actualBits = 0; m_LCUs[LCUIdx].m_QP = 0; m_LCUs[LCUIdx].m_lambda = 0.0; m_LCUs[LCUIdx].m_targetBits = 0;#if M0036_RC_IMPROVEMENT m_LCUs[LCUIdx].m_bitWeight = 1.0;#else m_LCUs[LCUIdx].m_MAD = 0.0;#endif Int currWidth = ( (i == picWidthInLCU -1) ? picWidth - LCUWidth *(picWidthInLCU -1) : LCUWidth ); Int currHeight = ( (j == picHeightInLCU-1) ? picHeight - LCUHeight*(picHeightInLCU-1) : LCUHeight ); m_LCUs[LCUIdx].m_numberOfPixel = currWidth * currHeight; } } m_picActualHeaderBits = 0;#if !M0036_RC_IMPROVEMENT m_totalMAD = 0.0;#endif m_picActualBits = 0; m_picQP = 0; m_picLambda = 0.0;#if !M0036_RC_IMPROVEMENT m_lastPicture = NULL; list<TEncRCPic*>::reverse_iterator it; for ( it = listPreviousPictures.rbegin(); it != listPreviousPictures.rend(); it++ ) { if ( (*it)->getFrameLevel() == m_frameLevel ) //!< 保存跟当前帧同一层的前一帧 { m_lastPicture = (*it); break; } }#endif}
xEstPicTargetBits()
Int TEncRCPic::xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP ){ Int targetBits = 0; Int GOPbitsLeft = encRCGOP->getBitsLeft(); //!< TGOP - CodedGOP Int i; Int currPicPosition = encRCGOP->getNumPic()-encRCGOP->getPicLeft(); Int currPicRatio = encRCSeq->getBitRatio( currPicPosition );//!< 当前picture的权值 Int totalPicRatio = 0; for ( i=currPicPosition; i<encRCGOP->getNumPic(); i++ ) { totalPicRatio += encRCSeq->getBitRatio( i );//!< 总权值 }#if M0036_RC_IMPROVEMENT targetBits = Int( ((Double)GOPbitsLeft) * currPicRatio / totalPicRatio );#else targetBits = Int( GOPbitsLeft * currPicRatio / totalPicRatio );#endif if ( targetBits < 100 ) { targetBits = 100; // at least allocate 100 bits for one picture } //!< 在此之前targetBits是基于K0103式子(9)计算的结果,而m_encRCGOP->getTargetBitInGOP( currPicPosition )得到的 //!< bits为NotCodedPictures=0通过式子(9)得到的 if ( m_encRCSeq->getFramesLeft() > 16 ) { targetBits = Int( g_RCWeightPicRargetBitInBuffer * targetBits + g_RCWeightPicTargetBitInGOP * m_encRCGOP->getTargetBitInGOP( currPicPosition ) ); } return targetBits;}
xEstPicHeaderBits()
Int TEncRCPic::xEstPicHeaderBits( list<TEncRCPic*>& listPreviousPictures, Int frameLevel ){ Int numPreviousPics = 0; Int totalPreviousBits = 0; list<TEncRCPic*>::iterator it; for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ ) //!< 求出当前帧之前所有与其在同一层的帧的header bits之和 { if ( (*it)->getFrameLevel() == frameLevel ) { totalPreviousBits += (*it)->getPicActualHeaderBits(); numPreviousPics++; } } Int estHeaderBits = 0; if ( numPreviousPics > 0 ) //!< 取平均值 { estHeaderBits = totalPreviousBits / numPreviousPics; } return estHeaderBits;}
分析第一篇提到的compressGOP中的RC初始化代码片段:
#if RATE_CONTROL_LAMBDA_DOMAIN Double lambda = 0.0; Int actualHeadBits = 0; Int actualTotalBits = 0; Int estimatedBits = 0; Int tmpBitsBeforeWriting = 0; if ( m_pcCfg->getUseRateCtrl() ) { Int frameLevel = m_pcRateCtrl->getRCSeq()->getGOPID2Level( iGOPid ); if ( pcPic->getSlice(0)->getSliceType() == I_SLICE ) { frameLevel = 0; } m_pcRateCtrl->initRCPic( frameLevel ); //!< picture level 初始化 estimatedBits = m_pcRateCtrl->getRCPic()->getTargetBits(); //!< 在initRCPic中已经计算出了targetBits Int sliceQP = m_pcCfg->getInitialQP(); //!< 对应于配置文件中的InitalQP if ( ( pcSlice->getPOC() == 0 && m_pcCfg->getInitialQP() > 0 ) || ( frameLevel == 0 && m_pcCfg->getForceIntraQP() ) ) // QP is specified {//!< 如果配置文件对序列第一帧指定了初始QP,则基于这个QP计算出lamda Int NumberBFrames = ( m_pcCfg->getGOPSize() - 1 ); Double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05*(Double)NumberBFrames ); Double dQPFactor = 0.57*dLambda_scale; Int SHIFT_QP = 12; Int bitdepth_luma_qp_scale = 0; Double qp_temp = (Double) sliceQP + bitdepth_luma_qp_scale - SHIFT_QP; lambda = dQPFactor*pow( 2.0, qp_temp/3.0 ); } else if ( frameLevel == 0 ) // intra case, but use the model { //!< 对I slice的情况,需要做些特殊处理,如targetBits的修正等#if RATE_CONTROL_INTRA m_pcSliceEncoder->calCostSliceI(pcPic);#endif if ( m_pcCfg->getIntraPeriod() != 1 ) // do not refine allocated bits for all intra case { Int bits = m_pcRateCtrl->getRCSeq()->getLeftAverageBits();#if RATE_CONTROL_INTRA bits = m_pcRateCtrl->getRCPic()->getRefineBitsForIntra( bits );#else bits = m_pcRateCtrl->getRCSeq()->getRefineBitsForIntra( bits ); //!< K0103 Table 3#endif if ( bits < 200 ) { bits = 200; } m_pcRateCtrl->getRCPic()->setTargetBits( bits ); } list<TEncRCPic*> listPreviousPicture = m_pcRateCtrl->getPicList();#if RATE_CONTROL_INTRA m_pcRateCtrl->getRCPic()->getLCUInitTargetBits(); lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture, pcSlice->getSliceType());#else lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture );#endif sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda, listPreviousPicture ); } else // normal case { list<TEncRCPic*> listPreviousPicture = m_pcRateCtrl->getPicList();#if RATE_CONTROL_INTRA lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture, pcSlice->getSliceType());#else lambda = m_pcRateCtrl->getRCPic()->estimatePicLambda( listPreviousPicture );#endif sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda, listPreviousPicture ); } sliceQP = Clip3( -pcSlice->getSPS()->getQpBDOffsetY(), MAX_QP, sliceQP ); m_pcRateCtrl->getRCPic()->setPicEstQP( sliceQP ); m_pcSliceEncoder->resetQP( pcPic, sliceQP, lambda ); //!< 设置当前slice使用的QP, lambda,编码时用到 }#endif
#if !RATE_CONTROL_INTRAInt TEncRCSeq::getRefineBitsForIntra( Int orgBits ) //!< K0103 Table 3{ Double bpp = ( (Double)orgBits ) / m_picHeight / m_picHeight; if ( bpp > 0.2 ) { return orgBits * 5; } if ( bpp > 0.1 ) { return orgBits * 7; } return orgBits * 10;}#endif
#if RATE_CONTROL_INTRADouble TEncRCPic::estimatePicLambda( list<TEncRCPic*>& listPreviousPictures, SliceType eSliceType)#elseDouble TEncRCPic::estimatePicLambda( list<TEncRCPic*>& listPreviousPictures )#endif{ 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;#if RATE_CONTROL_INTRA Double estLambda; if (eSliceType == I_SLICE) { estLambda = calculateLambdaIntra(alpha, beta, pow(m_totalCostIntra/(Double)m_numberOfPixel, BETA1), bpp); } else { estLambda = alpha * pow( bpp, beta ); }#else Double estLambda = alpha * pow( bpp, beta ); //!< K0103 式子(10)#endif Double lastLevelLambda = -1.0; Double lastPicLambda = -1.0; Double lastValidLambda = -1.0; list<TEncRCPic*>::iterator it; for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ ) { if ( (*it)->getFrameLevel() == m_frameLevel ) { lastLevelLambda = (*it)->getPicActualLambda(); } lastPicLambda = (*it)->getPicActualLambda(); if ( lastPicLambda > 0.0 ) { lastValidLambda = lastPicLambda; } } //!< 以下对lastLevelLambda和estLambda进行clip,范围在K0103的section 3.2中进行了定义 if ( lastLevelLambda > 0.0 ) { lastLevelLambda = Clip3( 0.1, 10000.0, lastLevelLambda ); estLambda = Clip3( lastLevelLambda * pow( 2.0, -3.0/3.0 ), lastLevelLambda * pow( 2.0, 3.0/3.0 ), estLambda ); } if ( lastPicLambda > 0.0 ) { lastPicLambda = Clip3( 0.1, 2000.0, lastPicLambda ); estLambda = Clip3( lastPicLambda * pow( 2.0, -10.0/3.0 ), lastPicLambda * pow( 2.0, 10.0/3.0 ), estLambda ); } else if ( lastValidLambda > 0.0 ) { lastValidLambda = Clip3( 0.1, 2000.0, lastValidLambda ); estLambda = Clip3( lastValidLambda * pow(2.0, -10.0/3.0), lastValidLambda * pow(2.0, 10.0/3.0), estLambda ); } else { estLambda = Clip3( 0.1, 10000.0, estLambda ); } if ( estLambda < 0.1 ) { estLambda = 0.1; } m_estPicLambda = estLambda;#if M0036_RC_IMPROVEMENT Double totalWeight = 0.0; // initial BU bit allocation weight for ( Int i=0; i<m_numberOfLCU; i++ ) {#if RC_FIX 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; }#else Double alphaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_alpha; Double betaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_beta;#endif 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; }#endif return estLambda;}
Int TEncRCPic::estimatePicQP( Double lambda, list<TEncRCPic*>& listPreviousPictures ){ Int QP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 ); //!< 通过lambda求QP Int lastLevelQP = g_RCInvalidQPValue; Int lastPicQP = g_RCInvalidQPValue; Int lastValidQP = g_RCInvalidQPValue; list<TEncRCPic*>::iterator it; for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ ) { if ( (*it)->getFrameLevel() == m_frameLevel ) { lastLevelQP = (*it)->getPicActualQP(); } lastPicQP = (*it)->getPicActualQP(); if ( lastPicQP > g_RCInvalidQPValue ) { lastValidQP = lastPicQP; } } //!< 以下对QP进行clip,范围在K0103的section 3.2进行了定义 if ( lastLevelQP > g_RCInvalidQPValue ) { QP = Clip3( lastLevelQP - 3, lastLevelQP + 3, QP ); } if( lastPicQP > g_RCInvalidQPValue ) { QP = Clip3( lastPicQP - 10, lastPicQP + 10, QP ); } else if( lastValidQP > g_RCInvalidQPValue ) { QP = Clip3( lastValidQP - 10, lastValidQP + 10, QP ); } return QP;}
- HEVC码率控制浅析——HM代码阅读之三
- HEVC码率控制浅析——HM代码阅读之三
- HEVC码率控制浅析——HM代码阅读之二
- HEVC码率控制浅析——HM代码阅读之四
- HEVC码率控制浅析——HM代码阅读之二
- HEVC码率控制浅析——HM代码阅读之四
- HEVC码率控制浅析——HM代码阅读之一
- HEVC码率控制浅析——HM代码阅读之一
- HEVC码率控制算法研究与HM相应代码分析(三)——算法及代码分析
- HM编码器代码阅读(29)——码率控制
- HEVC码率控制算法研究与HM相应代码分析(一)——HEVC标准及编码流程介绍
- HM编码器代码阅读(41)——码率控制(二)
- HEVC码率控制算法研究与HM相应代码分析(二)——新的码率控制模型
- HM编码器代码阅读(21)——熵编码的概念以及在HEVC中应用
- HEVC参考软件(HM)代码阅读之帧内预测:Void TComPrediction::xPredIntraAng
- HM编码器代码阅读(42)——率失真优化
- HM编码器代码阅读(15)——帧间预测之AMVP模式(三)xGetBlkBits函数
- HEVC解码器HM源码阅读(三)读取一个NALU
- jquery1.9不支持browser对象的解决方案
- java 批量修改文件名称
- 锁 死锁 阻塞 Latch 等待 详解 --转发
- java中实际运用之-Flyweight享元模式(实现单纯享元模式结构)
- 2013 ICCV 文章列表
- HEVC码率控制浅析——HM代码阅读之三
- WPF中StringFormat的用法 (转)
- linux下vim命令详解
- UESTC 1808 Eating Fish is Fun
- Portal开源框架介绍
- Orcale中的decode函数用法
- 堆和栈
- Android 扫雷总结
- hsql错误: user lacks privilege or object not found: LAST_INSERT_ID