根据看过的HEVC/X265的代码,这里提案有很大的区别,这里先不讨论其他的,只介绍一下我看的基本的内容;水平有限,还请各位大神指点;
先回忆一下 由在CompressGOP函数中,完成了以下的功能:
一,InitGOP将文件的码流分成若干GOP以便后续程序能够顺利执行。
二,InitEncSlice创建编码的Slice。
三,调用preCompressSlice和CompressSlice两个函数,前者的作用是选择不同的lamuda进行编码(编码是调用了CompressCU函数),后者是在最好的lamuda下进行编码。
四,循环滤波。
五,熵编码等。
一,InitGOP将文件的码流分成若干GOP以便后续程序能够顺利执行。
二,InitEncSlice创建编码的Slice。
三,调用preCompressSlice和CompressSlice两个函数,前者的作用是选择不同的lamuda进行编码(编码是调用了CompressCU函数),后者是在最好的lamuda下进行编码。
四,循环滤波。
五,熵编码等。
我这里先讲一下TEncSlice::compressSlice函数的详细步骤:
(1)计算当前slice的开始CU和结束CU
(2)初始化Sbac编码器
(3)再把slice的熵编码器设置为Sbac编码器
(4)重置熵编码器(主要是上下文的重置)
(5)取得二值化编码器
(6)取得比特计数器
(7)遍历slice中的每一个LCU
①初始化LCU
②调用compressCTU,用于求最优模式
③调用encodeCTU,进行熵编码(对CU进行熵编码,目的是选择最优参数)
Void TEncSlice::precompressSlice( TComPic* pcPic )
{
// if deltaQP RD is not used, simply return
if ( m_pcCfg->getDeltaQpRD() == 0 )
{
return;
}
if ( m_pcCfg->getUseRateCtrl() )
{
printf( "\nMultiple QP optimization is not allowed when rate control is enabled." );
assert(0);
return;
}
TComSlice* pcSlice = pcPic->getSlice(getSliceIdx());
if (pcSlice->getDependentSliceSegmentFlag())
{
// if this is a dependent slice segment, then it was optimised
// when analysing the entire slice.
return;
}
if (pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES)
{
// TODO: investigate use of average cost per CTU so that this Slice Mode can be used.
printf( "\nUnable to optimise Slice-level QP if Slice Mode is set to FIXED_NUMBER_OF_BYTES\n" );
assert(0);
return;
}
Double dPicRdCostBest = MAX_DOUBLE;
UInt uiQpIdxBest = 0;
Double dFrameLambda;
#if FULL_NBIT
Int SHIFT_QP = 12 + 6 * (pcSlice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 8);
#else
Int SHIFT_QP = 12;
#endif
// set frame lambda
if (m_pcCfg->getGOPSize() > 1)
{
dFrameLambda = 0.68 * pow (2, (m_piRdPicQp[0] - SHIFT_QP) / 3.0) * (pcSlice->isInterB()? 2 : 1);
}
else
{
dFrameLambda = 0.68 * pow (2, (m_piRdPicQp[0] - SHIFT_QP) / 3.0);
}
m_pcRdCost ->setFrameLambda(dFrameLambda);
// for each QP candidate
for ( UInt uiQpIdx = 0; uiQpIdx < 2 * m_pcCfg->getDeltaQpRD() + 1; uiQpIdx++ )
{
pcSlice ->setSliceQp ( m_piRdPicQp [uiQpIdx] );
#if ADAPTIVE_QP_SELECTION
pcSlice ->setSliceQpBase ( m_piRdPicQp [uiQpIdx] );
#endif
setUpLambda(pcSlice, m_pdRdPicLambda[uiQpIdx], m_piRdPicQp [uiQpIdx]);
// try compress
compressSlice ( pcPic, true, m_pcCfg->getFastDeltaQp());
UInt64 uiPicDist = m_uiPicDist; // Distortion, as calculated by compressSlice.
// NOTE: This distortion is the chroma-weighted SSE distortion for the slice.
// Previously a standard SSE distortion was calculated (for the entire frame).
// Which is correct?
// TODO: Update loop filter, SAO and distortion calculation to work on one slice only.
// m_pcGOPEncoder->preLoopFilterPicAll( pcPic, uiPicDist );
// compute RD cost and choose the best
Double dPicRdCost = m_pcRdCost->calcRdCost64( m_uiPicTotalBits, uiPicDist, true, DF_SSE_FRAME); // NOTE: Is the 'true' parameter really necessary?
if ( dPicRdCost < dPicRdCostBest )
{
uiQpIdxBest = uiQpIdx;
dPicRdCostBest = dPicRdCost;
}
}
// set best values
pcSlice ->setSliceQp ( m_piRdPicQp [uiQpIdxBest] );
#if ADAPTIVE_QP_SELECTION
pcSlice ->setSliceQpBase ( m_piRdPicQp [uiQpIdxBest] );
#endif
setUpLambda(pcSlice, m_pdRdPicLambda[uiQpIdxBest], m_piRdPicQp [uiQpIdxBest]);
}
Void TEncSlice::calCostSliceI(TComPic* pcPic) // TODO: this only analyses the first slice segment. What about the others?
{
Double iSumHadSlice = 0;
TComSlice * const pcSlice = pcPic->getSlice(getSliceIdx());
const TComSPS &sps = *(pcSlice->getSPS());
const Int shift = sps.getBitDepth(CHANNEL_TYPE_LUMA)-8;
const Int offset = (shift>0)?(1<<(shift-1)):0;
pcSlice->setSliceSegmentBits(0);
UInt startCtuTsAddr, boundingCtuTsAddr;
xDetermineStartAndBoundingCtuTsAddr ( startCtuTsAddr, boundingCtuTsAddr, pcPic );
for( UInt ctuTsAddr = startCtuTsAddr, ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap( startCtuTsAddr);
ctuTsAddr < boundingCtuTsAddr;
ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap(++ctuTsAddr) )
{
// initialize CU encoder
TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr );
pCtu->initCtu( pcPic, ctuRsAddr );
#if JVET_C0024_QTBT
Int height = min( sps.getCTUSize(),sps.getPicHeightInLumaSamples() - ctuRsAddr / pcPic->getFrameWidthInCtus() * sps.getCTUSize() );
Int width = min( sps.getCTUSize(), sps.getPicWidthInLumaSamples() - ctuRsAddr % pcPic->getFrameWidthInCtus() * sps.getCTUSize() );
#else
Int height = min( sps.getMaxCUHeight(),sps.getPicHeightInLumaSamples() - ctuRsAddr / pcPic->getFrameWidthInCtus() * sps.getMaxCUHeight() );
Int width = min( sps.getMaxCUWidth(), sps.getPicWidthInLumaSamples() - ctuRsAddr % pcPic->getFrameWidthInCtus() * sps.getMaxCUWidth() );
#endif
Int iSumHad = m_pcCuEncoder->updateCtuDataISlice(pCtu, width, height);
(m_pcRateCtrl->getRCPic()->getLCU(ctuRsAddr)).m_costIntra=(iSumHad+offset)>>shift;
iSumHadSlice += (m_pcRateCtrl->getRCPic()->getLCU(ctuRsAddr)).m_costIntra;
}
m_pcRateCtrl->getRCPic()->setTotalIntraCost(iSumHadSlice);
}
/** \param pcPic picture class
*/
Void TEncSlice::compressSlice( TComPic* pcPic, const Bool bCompressEntireSlice, const Bool bFastDeltaQP )
{
// if bCompressEntireSlice is true, then the entire slice (not slice segment) is compressed,
// effectively disabling the slice-segment-mode.
UInt startCtuTsAddr; // CU的开始地址
UInt boundingCtuTsAddr; // CU的边界地址
TComSlice* const pcSlice = pcPic->getSlice(getSliceIdx()); // 当前的条带
pcSlice->setSliceSegmentBits(0);
xDetermineStartAndBoundingCtuTsAddr ( startCtuTsAddr, boundingCtuTsAddr, pcPic ); // 得到CU(LCU)的开始和结束地址
#if VCEG_AZ08_KLT_COMMON
pcPic->getPicYuvRec()->fillPicRecBoundary(pcSlice->getSPS()->getBitDepths());
#endif
if (bCompressEntireSlice)
{
boundingCtuTsAddr = pcSlice->getSliceCurEndCtuTsAddr();
pcSlice->setSliceSegmentCurEndCtuTsAddr(boundingCtuTsAddr);
}
// initialize cost values - these are used by precompressSlice (they should be parameters).
m_uiPicTotalBits = 0; // 图像总的比特数
m_dPicRdCost = 0; // NOTE: This is a write-only variable! // 率失真代价
m_uiPicDist = 0; // 帧的distortion(失真)
#if VCEG_AZ07_BAC_ADAPT_WDOW || VCEG_AZ07_INIT_PREVFRAME
m_pcEntropyCoder->setStatsHandle ( pcSlice->getStatsHandle() );
#endif
#if JVET_C0024_QTBT
UInt uiMaxWIdx = g_aucConvertToBit[pcSlice->getSPS()->getCTUSize()];
UInt uiMaxHIdx = g_aucConvertToBit[pcSlice->getSPS()->getCTUSize()];
m_pcEntropyCoder->setEntropyCoder ( m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST] ); // 设置熵编码器
#else
m_pcEntropyCoder->setEntropyCoder ( m_pppcRDSbacCoder[0][CI_CURR_BEST] );
#endif
m_pcEntropyCoder->resetEntropy ( pcSlice ); // 重置熵编码 // //!< 主要进行上下文模型的初始化,codILow和codIRange的初始化等
#if JVET_C0024_QTBT // 加载熵编码器SBAC
TEncBinCABAC* pRDSbacCoder = (TEncBinCABAC *) m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST]->getEncBinIf();
#else
TEncBinCABAC* pRDSbacCoder = (TEncBinCABAC *) m_pppcRDSbacCoder[0][CI_CURR_BEST]->getEncBinIf();
#endif
pRDSbacCoder->setBinCountingEnableFlag( false );
pRDSbacCoder->setBinsCoded( 0 );
TComBitCounter tempBitCounter;
const UInt frameWidthInCtus = pcPic->getPicSym()->getFrameWidthInCtus();
m_pcCuEncoder->setFastDeltaQp(bFastDeltaQP);
#if ALF_HM3_REFACTOR
// initialize ALF parameters
m_pcEntropyCoder->setAlfCtrl(false);
m_pcEntropyCoder->setMaxAlfCtrlDepth(0); //unnecessary
#endif
//------------------------------------------------------------------------------
// Weighted Prediction parameters estimation.
//------------------------------------------------------------------------------
// calculate AC/DC values for current picture
if( pcSlice->getPPS()->getUseWP() || pcSlice->getPPS()->getWPBiPred() )
{
xCalcACDCParamSlice(pcSlice);
}
const Bool bWp_explicit = (pcSlice->getSliceType()==P_SLICE && pcSlice->getPPS()->getUseWP()) || (pcSlice->getSliceType()==B_SLICE && pcSlice->getPPS()->getWPBiPred());
if ( bWp_explicit )
{
//------------------------------------------------------------------------------
// Weighted Prediction implemented at Slice level. SliceMode=2 is not supported yet.
//------------------------------------------------------------------------------
if ( pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES || pcSlice->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES )
{
printf("Weighted Prediction is not supported with slice mode determined by max number of bins.\n"); exit(0);
}
xEstimateWPParamSlice( pcSlice );
pcSlice->initWpScaling(pcSlice->getSPS());
// check WP on/off
xCheckWPEnable( pcSlice );
}
#if ADAPTIVE_QP_SELECTION // 自适应量化步长
if( m_pcCfg->getUseAdaptQpSelect() && !(pcSlice->getDependentSliceSegmentFlag())) // 不进入
{
// TODO: this won't work with dependent slices: they do not have their own QP. Check fix to mask clause execution with && !(pcSlice->getDependentSliceSegmentFlag())
m_pcTrQuant->clearSliceARLCnt(); // TODO: this looks wrong for multiple slices - the results of all but the last slice will be cleared before they are used (all slices compressed, and then all slices encoded)
if(pcSlice->getSliceType()!=I_SLICE)
{
Int qpBase = pcSlice->getSliceQpBase();
pcSlice->setSliceQp(qpBase + m_pcTrQuant->getQpDelta(qpBase));
}
}
#endif
#if VCEG_AZ06_IC
if ( m_pcCfg->getUseIC() )
{
#if VCEG_AZ06_IC_SPEEDUP || JVET_C0024_QTBT
pcSlice->xSetApplyIC();
#else
pcSlice->setApplyIC( pcSlice->isIntra() ? false : true );
#endif
}
#endif
// Adjust initial state if this is the start of a dependent slice.
{
const UInt ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap( startCtuTsAddr);
const UInt currentTileIdx = pcPic->getPicSym()->getTileIdxMap(ctuRsAddr);
const TComTile *pCurrentTile = pcPic->getPicSym()->getTComTile(currentTileIdx);
const UInt firstCtuRsAddrOfTile = pCurrentTile->getFirstCtuRsAddr();
if( pcSlice->getDependentSliceSegmentFlag() && ctuRsAddr != firstCtuRsAddrOfTile )
{
// This will only occur if dependent slice-segments (m_entropyCodingSyncContextState=true) are being used.
if( pCurrentTile->getTileWidthInCtus() >= 2 || !m_pcCfg->getWaveFrontsynchro() )
{
#if JVET_C0024_QTBT
m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST]->loadContexts( &m_lastSliceSegmentEndContextState );
#else
m_pppcRDSbacCoder[0][CI_CURR_BEST]->loadContexts( &m_lastSliceSegmentEndContextState );
#endif
}
}
}
// for every CTU in the slice segment (may terminate sooner if there is a byte limit on the slice-segment)
for( UInt ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ++ctuTsAddr )
{
const UInt ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap(ctuTsAddr);
// initialize CTU encoder
TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr );
pCtu->initCtu( pcPic, ctuRsAddr );
// update CABAC state
const UInt firstCtuRsAddrOfTile = pcPic->getPicSym()->getTComTile(pcPic->getPicSym()->getTileIdxMap(ctuRsAddr))->getFirstCtuRsAddr();
const UInt tileXPosInCtus = firstCtuRsAddrOfTile % frameWidthInCtus;
const UInt ctuXPosInCtus = ctuRsAddr % frameWidthInCtus;
if (ctuRsAddr == firstCtuRsAddrOfTile)
{
#if JVET_C0024_QTBT
m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST]->resetEntropy(pcSlice);
#else
m_pppcRDSbacCoder[0][CI_CURR_BEST]->resetEntropy(pcSlice);
#endif
}
else if ( ctuXPosInCtus == tileXPosInCtus && m_pcCfg->getWaveFrontsynchro())
{
// reset and then update contexts to the state at the end of the top-right CTU (if within current slice and tile).
#if JVET_C0024_QTBT
m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST]->resetEntropy(pcSlice);
#else
m_pppcRDSbacCoder[0][CI_CURR_BEST]->resetEntropy(pcSlice);
#endif
// Sync if the Top-Right is available.
TComDataCU *pCtuUp = pCtu->getCtuAbove();
if ( pCtuUp && ((ctuRsAddr%frameWidthInCtus+1) < frameWidthInCtus) )
{
TComDataCU *pCtuTR = pcPic->getCtu( ctuRsAddr - frameWidthInCtus + 1 );
if ( pCtu->CUIsFromSameSliceAndTile(pCtuTR) )
{
// Top-Right is available, we use it.
#if JVET_C0024_QTBT
m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST]->loadContexts( &m_entropyCodingSyncContextState );
#else
m_pppcRDSbacCoder[0][CI_CURR_BEST]->loadContexts( &m_entropyCodingSyncContextState );
#endif
}
}
}
// set go-on entropy coder (used for all trial encodings - the cu encoder and encoder search also have a copy of the same pointer)
m_pcEntropyCoder->setEntropyCoder ( m_pcRDGoOnSbacCoder );
m_pcEntropyCoder->setBitstream( &tempBitCounter );
tempBitCounter.resetBits();
#if VCEG_AZ07_INIT_PREVFRAME
if( pcSlice->getSliceType() != I_SLICE && ctuTsAddr == 0 )
{
#if JVET_C0024_QTBT
m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST]->loadContextsFromPrev( pcSlice->getStatsHandle(), pcSlice->getSliceType(), pcSlice->getCtxMapQPIdx(), true, pcSlice->getCtxMapQPIdxforStore(), (pcSlice->getPOC() > pcSlice->getStatsHandle()->m_uiLastIPOC) );
#else
m_pppcRDSbacCoder[0][CI_CURR_BEST]->loadContextsFromPrev( pcSlice->getStatsHandle(), pcSlice->getSliceType(), pcSlice->getCtxMapQPIdx(), true, pcSlice->getCtxMapQPIdxforStore(), (pcSlice->getPOC() > pcSlice->getStatsHandle()->m_uiLastIPOC) );
#endif
}
#endif
#if JVET_C0024_QTBT
m_pcRDGoOnSbacCoder->load( m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST] ); // this copy is not strictly necessary here, but indicates that the GoOnSbacCoder
#else
m_pcRDGoOnSbacCoder->load( m_pppcRDSbacCoder[0][CI_CURR_BEST] ); // this copy is not strictly necessary here, but indicates that the GoOnSbacCoder
#endif
// is reset to a known state before every decision process.
((TEncBinCABAC*)m_pcRDGoOnSbacCoder->getEncBinIf())->setBinCountingEnableFlag(true);
Double oldLambda = m_pcRdCost->getLambda();
if ( m_pcCfg->getUseRateCtrl() )
{
Int estQP = pcSlice->getSliceQp();
Double estLambda = -1.0;
Double bpp = -1.0;
if ( ( pcPic->getSlice( 0 )->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() )
{
estQP = pcSlice->getSliceQp();
}
else
{
bpp = m_pcRateCtrl->getRCPic()->getLCUTargetBpp(pcSlice->getSliceType());
if ( pcPic->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()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, estQP );
m_pcRdCost->setLambda(estLambda, pcSlice->getSPS()->getBitDepths());
#if RDOQ_CHROMA_LAMBDA
// set lambda for RDOQ
const Double chromaLambda = estLambda / m_pcRdCost->getChromaWeight();
const Double lambdaArray[MAX_NUM_COMPONENT] = { estLambda, chromaLambda, chromaLambda };
m_pcTrQuant->setLambdas( lambdaArray );
#else
m_pcTrQuant->setLambda( estLambda );
#endif
}
m_pcRateCtrl->setRCQP( estQP );
#if ADAPTIVE_QP_SELECTION
pCtu->getSlice()->setSliceQpBase( estQP );
#endif
}
// run CTU trial encoder
// 对CU进行编码(压缩)
// 帧内预测,帧间预测编码还有变换编码
// 这里很重要
// 编码单元编码
// 最重要的部分!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// 注意这个只是尝试进行,然后选出最优熵编码方案,下面的encodeCU才是真正进行熵编码的地方
// 最重要的部分!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
m_pcCuEncoder->compressCtu( pCtu ); // 注意这个只是尝试进行,然后选出最优熵编码方案,下面的encodeCU才是真正进行熵编码的地方
// All CTU decisions have now been made. Restore entropy coder to an initial stage, ready to make a true encode,
// which will result in the state of the contexts being correct. It will also count up the number of bits coded,
// which is used if there is a limit of the number of bytes per slice-segment.
#if JVET_C0024_QTBT
m_pcEntropyCoder->setEntropyCoder ( m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST] ); // 熵编码器设置为Sbac
#else
m_pcEntropyCoder->setEntropyCoder ( m_pppcRDSbacCoder[0][CI_CURR_BEST] );
#endif
m_pcEntropyCoder->setBitstream( &tempBitCounter ); // 设置需要写入的比特流
pRDSbacCoder->setBinCountingEnableFlag( true );
#if JVET_C0024_QTBT
m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST]->resetBits();
#else
m_pppcRDSbacCoder[0][CI_CURR_BEST]->resetBits();
#endif
pRDSbacCoder->setBinsCoded( 0 );
// encode CTU and calculate the true bit counters.
/* // 对CU进编码
// 这里是真正的进行熵编码!!!!
// 重要!!!!!!!!!!!!!*/
m_pcCuEncoder->encodeCtu( pCtu );
// 重要!!!!!!!!!!!!!
pRDSbacCoder->setBinCountingEnableFlag( false );
const Int numberOfWrittenBits = m_pcEntropyCoder->getNumberOfWrittenBits();
// Calculate if this CTU puts us over slice bit size.
// cannot terminate if current slice/slice-segment would be 0 Ctu in size,
const UInt validEndOfSliceCtuTsAddr = ctuTsAddr + (ctuTsAddr == startCtuTsAddr ? 1 : 0);
// Set slice end parameter // 这两个判断,是为了判断该CU是否为条带中的最后一个CU,如果是则跳出循环
if(pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES && pcSlice->getSliceBits()+numberOfWrittenBits > (pcSlice->getSliceArgument()<<3))
{
pcSlice->setSliceSegmentCurEndCtuTsAddr(validEndOfSliceCtuTsAddr);
pcSlice->setSliceCurEndCtuTsAddr(validEndOfSliceCtuTsAddr);
boundingCtuTsAddr=validEndOfSliceCtuTsAddr;
}
else if((!bCompressEntireSlice) && pcSlice->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES && pcSlice->getSliceSegmentBits()+numberOfWrittenBits > (pcSlice->getSliceSegmentArgument()<<3))
{
pcSlice->setSliceSegmentCurEndCtuTsAddr(validEndOfSliceCtuTsAddr);
boundingCtuTsAddr=validEndOfSliceCtuTsAddr;
}
if (boundingCtuTsAddr <= ctuTsAddr)
{
break;
}
pcSlice->setSliceBits( (UInt)(pcSlice->getSliceBits() + numberOfWrittenBits) );
pcSlice->setSliceSegmentBits(pcSlice->getSliceSegmentBits()+numberOfWrittenBits);
// Store probabilities of second CTU in line into buffer - used only if wavefront-parallel-processing is enabled.
if ( ctuXPosInCtus == tileXPosInCtus+1 && m_pcCfg->getWaveFrontsynchro())
{
#if JVET_C0024_QTBT
m_entropyCodingSyncContextState.loadContexts(m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST]);
#else
m_entropyCodingSyncContextState.loadContexts(m_pppcRDSbacCoder[0][CI_CURR_BEST]);
#endif
}
if ( m_pcCfg->getUseRateCtrl() ) // 没有使用码率控制
{
Int actualQP = g_RCInvalidQPValue;
Double actualLambda = m_pcRdCost->getLambda();
Int actualBits = pCtu->getTotalBits();
Int numberOfEffectivePixels = 0;
for ( Int idx = 0; idx < pcPic->getNumPartitionsInCtu(); idx++ )
{
if ( pCtu->getPredictionMode( idx ) != NUMBER_OF_PREDICTION_MODES && ( !pCtu->isSkipped( idx ) ) )
{
numberOfEffectivePixels = numberOfEffectivePixels + 16;
break;
}
}
if ( numberOfEffectivePixels == 0 )
{
actualQP = g_RCInvalidQPValue;
}
else
{
actualQP = pCtu->getQP( 0 );
}
m_pcRdCost->setLambda(oldLambda, pcSlice->getSPS()->getBitDepths());
m_pcRateCtrl->getRCPic()->updateAfterCTU( m_pcRateCtrl->getRCPic()->getLCUCoded(), actualBits, actualQP, actualLambda,
pCtu->getSlice()->getSliceType() == I_SLICE ? 0 : m_pcCfg->getLCULevelRC() );
}
m_uiPicTotalBits += pCtu->getTotalBits(); // 计算总的比特数
m_dPicRdCost += pCtu->getTotalCost(); // 计算运行代价
m_uiPicDist += pCtu->getTotalDistortion();// 计算失真率
}
// store context state at the end of this slice-segment, in case the next slice is a dependent slice and continues using the CABAC contexts.
if( pcSlice->getPPS()->getDependentSliceSegmentsEnabledFlag() )
{
#if JVET_C0024_QTBT
m_lastSliceSegmentEndContextState.loadContexts( m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST] );//ctx end of dep.slice
#else
m_lastSliceSegmentEndContextState.loadContexts( m_pppcRDSbacCoder[0][CI_CURR_BEST] );//ctx end of dep.slice
#endif
}
// stop use of temporary bit counter object.
#if JVET_C0024_QTBT
m_ppppcRDSbacCoder[uiMaxWIdx][uiMaxHIdx][CI_CURR_BEST]->setBitstream(NULL);
#else
m_pppcRDSbacCoder[0][CI_CURR_BEST]->setBitstream(NULL);
#endif
m_pcRDGoOnSbacCoder->setBitstream(NULL); // stop use of tempBitCounter.
// TODO: optimise cabac_init during compress slice to improve multi-slice operation
//if (pcSlice->getPPS()->getCabacInitPresentFlag() && !pcSlice->getPPS()->getDependentSliceSegmentsEnabledFlag())
//{
// m_encCABACTableIdx = m_pcEntropyCoder->determineCabacInitIdx();
//}
//else
//{
// m_encCABACTableIdx = pcSlice->getSliceType();
//}
}