1、RC总体框架
参考http://blog.csdn.net/hevc_cjl/article/details/10982699
2、码率控制的一个大致流程图:来自于http://blog.csdn.net/cpp12341234/article/details/46043615
3、copressGOP函数:HM16.0中TEncGop类中compressGop函数RC部分在1447-1543行(初始化相关参数),1838-1864行(每编码完一张图片更新参数)。
参考http://blog.csdn.net/cpp12341234/article/details/45766687
和http://blog.csdn.net/hevc_cjl/article/details/11115721
- 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,编码时用到
- }
compressSlice函数:参考http://blog.csdn.net/hevc_cjl/article/details/11128745。在TEncSlice中的第698行,涉及到的RC部分为第834-876行(初始化相关参数),第931-957行(每编码完一个CTU后进行参数更新)。
- #if RATE_CONTROL_LAMBDA_DOMAIN
- Double oldLambda = m_pcRdCost->getLambda();
- if ( m_pcCfg->getUseRateCtrl() )
- {
- Int estQP = pcSlice->getSliceQp();
- Double estLambda = -1.0;
- Double bpp = -1.0;
- #if M0036_RC_IMPROVEMENT
- if ( ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() )
- #else
- if ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE || !m_pcCfg->getLCULevelRC() )
- #endif
- { //!< 如果当前slice为I slice或者不进行LCU level RC,则LCU直接使用当前slice的QP
- estQP = pcSlice->getSliceQp();
- }
- else
- {
- #if RATE_CONTROL_INTRA
- 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() );
- }
- #else
- bpp = m_pcRateCtrl->getRCPic()->getLCUTargetBpp();
- estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambda( bpp );
- estQP = m_pcRateCtrl->getRCPic()->getLCUEstQP ( estLambda, pcSlice->getSliceQp() );
- #endif
- estQP = Clip3( -pcSlice->getSPS()->getQpBDOffsetY(), MAX_QP, estQP );
- m_pcRdCost->setLambda(estLambda);
- #if M0036_RC_IMPROVEMENT
- #if RDOQ_CHROMA_LAMBDA
- // set lambda for RDOQ
- Double weight=m_pcRdCost->getChromaWeight();
- m_pcTrQuant->setLambda( estLambda, estLambda / weight );
- #else
- m_pcTrQuant->setLambda( estLambda );
- #endif
- #endif
- }
- m_pcRateCtrl->setRCQP( estQP );
- pcCU->getSlice()->setSliceQpBase( estQP ); //!< 设置编码时使用的QP值
- }
- #endif
4、CTU目标比特分配(CTU bpp的计算)
参考http://blog.csdn.net/cpp12341234/article/details/45851175
5、RC涉及到的关键函数
可以看看http://blog.csdn.net/hevc_cjl/article/category/1283611系列博客
6、对RC整体概括、写的不错的一篇博客,详细介绍了RC涉及到的一些类内成员变量的含义
http://blog.csdn.net/nb_vol_1/article/details/55096464
比如:
- // 帧内模式消耗的比特数
- Double m_totalCostIntra;
- // 帧内模式还剩余的比特数
- Double m_remainingCostIntra;
- // gop的id到level的映射
- Int* m_GOPID2Level;
- // 自适应的比特
- Int m_adaptiveBit;
- // 最后的lambda参数
- Double m_lastLambda;
- // 帧内的代价
- Double m_costIntra;
该博主的另外一篇介绍码率控制的博客:http://blog.csdn.net/nb_vol_1/article/details/56022073(结合原理分析代码)