JVET-代码分析之 片的编码 TEncSlice::compressSlice

    xiaoxiao2021-04-13  34

    根据看过的HEVC/X265的代码,这里提案有很大的区别,这里先不讨论其他的,只介绍一下我看的基本的内容;水平有限,还请各位大神指点;

    先回忆一下 由在CompressGOP函数中,完成了以下的功能:

     一,InitGOP将文件的码流分成若干GOP以便后续程序能够顺利执行。

       二,InitEncSlice创建编码的Slice

     三,调用preCompressSliceCompressSlice两个函数,前者的作用是选择不同的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(); //} }
    转载请注明原文地址: https://ju.6miu.com/read-669396.html

    最新回复(0)