compressGOP()函数要点:
- 根据iGOPid逐次递增,对一个GOP内的picture依次编码
- 根据picture level对当前picture进行码率分配
- 实际中一个Pic就是一个Slice,因此关于slice的循环只执行一次(默认)
- 根据已经编过的picture,来得到当前picture的lambda
- 得到当前picture的lambda后,对该picture下每一个CTU进行码率分配
- 一个picture编完,码流写好了,根据实际编码所用的比特,更新对应level下的lambda参数
compressGOP(){ ... for(Int iGOPid=0;iGOPid<m_iGopSize;iGOPid++) //GOP内picture循环 { m_pcSliceEncoder->initEncSlice(); //当前Slice编码参数QP、lambda的默认设置,会在码率控制中进一步被修改 ... if(m_pcCfg->getUseRateCtrl()) { m_pcRateCtrl->initRCPic(frameLevel);//根据frame level进行比特分配 ... lambda=m_pcRateCtrl->getRCPic()->estimatePicLambda();//确定当前picture的lambda sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda,.. );//QP由lambda计算 ... } for(UInt nextCtuTsAddr = 0; nextCtuTsAddr < numberOfCtusInFrame; ) //这个循环只执行了一次 { ... m_pcSliceEncoder->compressSlice(); ... } ... //编完一帧,开始熵编码,写码流等等 ... if(m_pcCfg->getUseRateCtrl()) { ... updataAfterPicture(); //编完一帧,更新当前picture level对应的lambda参数值(alpha和beta) ... } }//iGOPid loop}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- estimatePicLambda()函数中,在得到lambda之后,对一个picture内所有LCU进行比特分配:
Double TEncRCPic::estimatePicLambda( ){ Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; //alpha和beta从数组中对应level处取,这两个值在编完前一个相同level的帧后,被设置 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; //对estLambda进行Clip操作 m_estPicLambda = estLambda; //TEncRCPic::m_estPicLambda Double totalWeight = 0.0; // initial BU bit allocation weight 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;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
m_bitWeight即使每一个CTU对应的比特分配权重
- 跟新picture level 的alpha和beta函数updateAfterPicture():
void TEncRCPic::updateAfterPicture(){ //计算inputLambda //计算calLambda alpha += m_encRCSeq->getAlphaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * alpha; Double lnbpp = log( picActualBpp ); lnbpp = Clip3( -5.0, -0.1, lnbpp ); //按照码率控制算法,跟新alpha和beta TRCParameter rcPara; rcPara.m_alpha = alpha; rcPara.m_beta = beta; m_encRCSeq->setPicPara( m_frameLevel, rcPara ); //将更新后的alpha和beta保存在数组中}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
compressSlice()函数
- 按照CTU的先后顺序循环遍历编码
- 编完一个CTU之后,要更新参数
void TEncSlice::compressSlice(){ ... xDetermineStartAndBoundingCtuTsAddr ( startCtuTsAddr, boundingCtuTsAddr, pcPic ); ... for( UInt ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ++ctuTsAddr ) //对一个Slice内所有CTU开始循环编码 { ... if ( m_pcCfg->getUseRateCtrl() ) { Int estQP = pcSlice->getSliceQp(); Double estLambda = -1.0; Double bpp = -1.0; //根据LCU的m_bitWeight这个成员计算当前LCU的比特,再除以LCU内Pixel总数,得到bpp。而m_bitWeight这个成员是得到Pic的lambda之后被赋值。 estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambdaAndQP(bpp, pcSlice->getSliceQp(), &estQP); ... m_pcRdCost->setLambda(estLambda, pcSlice->getSPS()->getBitDepths()); } m_pcCuEncoder->compressCtu(pCtu); ... if(m_pcCfg->getUseRateCtrl()) { ... updateAfterCTU(); ... } //将CTU的编码结果累加到Picture的统计量之中 m_uiPicTotalBits+=pCtu->getTotalBits(); m_dPicRdcost+=PCtu->getTotalCost(); m_uiPicDist+=PCtu->getTotalDistortion; }}