本文转载整理自:http://blog.csdn.net/NB_vol_1/article/details/51152578
这篇文章很多东西还没搞懂,所以先转载放在这。
入口函数TEncSlice::compressSlice
这个函数主要是设置一些参数和初始化一些东西,然后对片中的每一个LCU调用initCU(初始化CU)和compressCU(对CU编码)和encodeCU(对CU进行熵编码,目的是选择最优参数)。
TEncSlice::compressSlice函数的详解:
(1)计算当前slice的开始CU和结束CU
(2)初始化Sbac编码器
(3)再把slice的熵编码器设置为Sbac编码器
(4)重置熵编码器(主要是上下文的重置)
(5)取得二值化编码器
(6)取得比特计数器
(7)遍历slice中的每一个LCU
①初始化LCU
②调用compressCU,用于求最优模式
③调用encodeCU,进行熵编码
下面放代码:
// 对条带编码
Void TEncSlice::compressSlice( TComPic*& rpcPic )
{
// CU的地址
UInt uiCUAddr;
// CU的开始地址
UInt uiStartCUAddr;
// CU的边界地址
UInt uiBoundingCUAddr;
// 条带中当前的比特数量是0
rpcPic->getSlice(getSliceIdx())->setSliceSegmentBits(0);
TEncBinCABAC* pppcRDSbacCoder = NULL;
// 当前的条带
TComSlice* pcSlice = rpcPic->getSlice(getSliceIdx());
// 得到CU(LCU)的开始和结束地址
xDetermineStartAndBoundingCUAddr ( uiStartCUAddr, uiBoundingCUAddr, rpcPic, false );
//uiStartCUAddr = 0, uiBoundingCUAddr = 2304
// initialize cost values
// 图像总的比特数
m_uiPicTotalBits = 0;
// 率失真代价
m_dPicRdCost = 0;
// 帧的distortion(失真)
m_uiPicDist = 0;
// set entropy coder
// 初始化熵编码器
m_pcSbacCoder->init( m_pcBinCABAC );
// 设置熵编码器
m_pcEntropyCoder->setEntropyCoder ( m_pcSbacCoder, pcSlice );
// 重置熵编码
// //!< 主要进行上下文模型的初始化,codILow和codIRange的初始化等
m_pcEntropyCoder->resetEntropy ();
// 加载熵编码器SBAC
m_pppcRDSbacCoder[0][CI_CURR_BEST]->load(m_pcSbacCoder);
pppcRDSbacCoder = (TEncBinCABAC *) m_pppcRDSbacCoder[0][CI_CURR_BEST]->getEncBinIf();
pppcRDSbacCoder->setBinCountingEnableFlag( false );
pppcRDSbacCoder->setBinsCoded( 0 );
//------------------------------------------------------------------------------
// Weighted Prediction parameters estimation.
//------------------------------------------------------------------------------
// calculate AC/DC values for current picture
// 不进入,因为没有使用波前前向预测
if( pcSlice->getPPS()->getUseWP() || pcSlice->getPPS()->getWPBiPred() )
{
xCalcACDCParamSlice(pcSlice);
}
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()==2 || pcSlice->getSliceSegmentMode()==2 )
{
printf("Weighted Prediction is not supported with slice mode determined by max number of bins.\n"); exit(0);
}
xEstimateWPParamSlice( pcSlice );
pcSlice->initWpScaling();
// check WP on/off
xCheckWPEnable( pcSlice );
}
// 自适应量化步长
#if ADAPTIVE_QP_SELECTION
// 不进入
if( m_pcCfg->getUseAdaptQpSelect() )
{
m_pcTrQuant->clearSliceARLCnt();
if(pcSlice->getSliceType()!=I_SLICE)
{
Int qpBase = pcSlice->getSliceQpBase();
pcSlice->setSliceQp(qpBase + m_pcTrQuant->getQpDelta(qpBase));
}
}
#endif
// 获取编码器的配置
TEncTop* pcEncTop = (TEncTop*) m_pcCfg;
// 从配置中取得sbac编码器
TEncSbac**** ppppcRDSbacCoders = pcEncTop->getRDSbacCoders();
// 从配置中获取比特计数器
TComBitCounter* pcBitCounters = pcEncTop->getBitCounters();
// 子流的数量
Int iNumSubstreams = 1;
// 穿过区块的个数
UInt uiTilesAcross = 0;
iNumSubstreams = pcSlice->getPPS()->getNumSubstreams();//1
uiTilesAcross = rpcPic->getPicSym()->getNumColumnsMinus1()+1;//1
delete[] m_pcBufferSbacCoders;
delete[] m_pcBufferBinCoderCABACs;
m_pcBufferSbacCoders = new TEncSbac [uiTilesAcross];
m_pcBufferBinCoderCABACs = new TEncBinCABAC[uiTilesAcross];
for (Int ui = 0; ui < uiTilesAcross; ui++)
{
m_pcBufferSbacCoders[ui].init( &m_pcBufferBinCoderCABACs[ui] );
}
for (UInt ui = 0; ui < uiTilesAcross; ui++)
{
m_pcBufferSbacCoders[ui].load(m_pppcRDSbacCoder[0][CI_CURR_BEST]); //init. state
}
for ( UInt ui = 0 ; ui < iNumSubstreams ; ui++ ) //init all sbac coders for RD optimization
{
ppppcRDSbacCoders[ui][0][CI_CURR_BEST]->load(m_pppcRDSbacCoder[0][CI_CURR_BEST]);
}
delete[] m_pcBufferLowLatSbacCoders;
delete[] m_pcBufferLowLatBinCoderCABACs;
m_pcBufferLowLatSbacCoders = new TEncSbac [uiTilesAcross];
m_pcBufferLowLatBinCoderCABACs = new TEncBinCABAC[uiTilesAcross];
for (Int ui = 0; ui < uiTilesAcross; ui++)
{
m_pcBufferLowLatSbacCoders[ui].init( &m_pcBufferLowLatBinCoderCABACs[ui] );
}
for (UInt ui = 0; ui < uiTilesAcross; ui++)
m_pcBufferLowLatSbacCoders[ui].load(m_pppcRDSbacCoder[0][CI_CURR_BEST]); //init. state
// 获取一帧图像中纵向可以存放多少个CU(目前是3个)
// 同理垂直方向上也有可以存放3个,因此,一个slice中有3*3=9个LCU
UInt uiWidthInLCUs = rpcPic->getPicSym()->getFrameWidthInCU(); // 3
//UInt uiHeightInLCUs = rpcPic->getPicSym()->getFrameHeightInCU();
UInt uiCol=0, uiLin=0, uiSubStrm=0;
UInt uiTileCol = 0;
UInt uiTileStartLCU = 0;
UInt uiTileLCUX = 0;
// 禁用了依赖性条带片段
Bool depSliceSegmentsEnabled = pcSlice->getPPS()->getDependentSliceSegmentsEnabledFlag(); // false
uiCUAddr = rpcPic->getPicSym()->getCUOrderMap( uiStartCUAddr /rpcPic->getNumPartInCU());//0
uiTileStartLCU = rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(uiCUAddr))->getFirstCUAddr();//0
// 是否启用了条带片段功能
if( depSliceSegmentsEnabled )
{
if((pcSlice->getSliceSegmentCurStartCUAddr()!= pcSlice->getSliceCurStartCUAddr())&&(uiCUAddr != uiTileStartLCU))
{
if( m_pcCfg->getWaveFrontsynchro() )
{
uiTileCol = rpcPic->getPicSym()->getTileIdxMap(uiCUAddr) % (rpcPic->getPicSym()->getNumColumnsMinus1()+1);
m_pcBufferSbacCoders[uiTileCol].loadContexts( CTXMem[1] );
Int iNumSubstreamsPerTile = iNumSubstreams/rpcPic->getPicSym()->getNumTiles();
uiCUAddr = rpcPic->getPicSym()->getCUOrderMap( uiStartCUAddr /rpcPic->getNumPartInCU());
uiLin = uiCUAddr / uiWidthInLCUs;
uiSubStrm = rpcPic->getPicSym()->getTileIdxMap(rpcPic->getPicSym()->getCUOrderMap(uiCUAddr))*iNumSubstreamsPerTile
+ uiLin%iNumSubstreamsPerTile;
if ( (uiCUAddr%uiWidthInLCUs+1) >= uiWidthInLCUs )
{
uiTileLCUX = uiTileStartLCU % uiWidthInLCUs;
uiCol = uiCUAddr % uiWidthInLCUs;
if(uiCol==uiTileStartLCU)
{
CTXMem[0]->loadContexts(m_pcSbacCoder);
}
}
}
m_pppcRDSbacCoder[0][CI_CURR_BEST]->loadContexts( CTXMem[0] );
ppppcRDSbacCoders[uiSubStrm][0][CI_CURR_BEST]->loadContexts( CTXMem[0] );
}
else
{
if(m_pcCfg->getWaveFrontsynchro())
{
CTXMem[1]->loadContexts(m_pcSbacCoder);
}
CTXMem[0]->loadContexts(m_pcSbacCoder);
}
}
// for every CU in slice
// 处理条带中的每一个CU
int nLCUofSlice = 0;
// 编码CU的顺序
UInt uiEncCUOrder;
// rpcPic->getNumPartInCU()获取一个LCU分裂的个数,即它内部包含多少个CU
for( uiEncCUOrder = uiStartCUAddr/rpcPic->getNumPartInCU();
uiEncCUOrder < (uiBoundingCUAddr+(rpcPic->getNumPartInCU()-1))/rpcPic->getNumPartInCU();
uiCUAddr = rpcPic->getPicSym()->getCUOrderMap(++uiEncCUOrder) )
{
// initialize CU encoder
// 根据CU的地址取得CU(LCU)
TComDataCU*& pcCU = rpcPic->getCU( uiCUAddr );
// 初始化CU
pcCU->initCU( rpcPic, uiCUAddr );
// HM15.0中似乎没有用到区块
// inherit from TR if necessary, select substream to use.
uiTileCol = rpcPic->getPicSym()->getTileIdxMap(uiCUAddr) % (rpcPic->getPicSym()->getNumColumnsMinus1()+1); // what column of tiles are we in? // 0
uiTileStartLCU = rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(uiCUAddr))->getFirstCUAddr(); // 0
uiTileLCUX = uiTileStartLCU % uiWidthInLCUs; // 0
//UInt uiSliceStartLCU = pcSlice->getSliceCurStartCUAddr();
uiCol = uiCUAddr % uiWidthInLCUs; // 0
uiLin = uiCUAddr / uiWidthInLCUs; // 0
// 子比特流数量是1,所以没有进去
if (pcSlice->getPPS()->getNumSubstreams() > 1)
{
// independent tiles => substreams are "per tile". iNumSubstreams has already been multiplied.
Int iNumSubstreamsPerTile = iNumSubstreams/rpcPic->getPicSym()->getNumTiles();
uiSubStrm = rpcPic->getPicSym()->getTileIdxMap(uiCUAddr)*iNumSubstreamsPerTile
+ uiLin%iNumSubstreamsPerTile;
}
else
{
// dependent tiles => substreams are "per frame".
uiSubStrm = uiLin % iNumSubstreams; //0
}
//
if ( ((pcSlice->getPPS()->getNumSubstreams() > 1) || depSliceSegmentsEnabled ) && (uiCol == uiTileLCUX) && m_pcCfg->getWaveFrontsynchro())
{
// We'll sync if the TR is available.
TComDataCU *pcCUUp = pcCU->getCUAbove();
UInt uiWidthInCU = rpcPic->getFrameWidthInCU();
UInt uiMaxParts = 1<<(pcSlice->getSPS()->getMaxCUDepth()<<1);
TComDataCU *pcCUTR = NULL;
if ( pcCUUp && ((uiCUAddr%uiWidthInCU+1) < uiWidthInCU) )
{
pcCUTR = rpcPic->getCU( uiCUAddr - uiWidthInCU + 1 );
}
if ( ((pcCUTR==NULL) || (pcCUTR->getSlice()==NULL) ||
(pcCUTR->getSCUAddr()+uiMaxParts-1 < pcSlice->getSliceCurStartCUAddr()) ||
((rpcPic->getPicSym()->getTileIdxMap( pcCUTR->getAddr() ) != rpcPic->getPicSym()->getTileIdxMap(uiCUAddr)))
)
)
{
// TR not available.
}
else
{
// TR is available, we use it.
ppppcRDSbacCoders[uiSubStrm][0][CI_CURR_BEST]->loadContexts( &m_pcBufferSbacCoders[uiTileCol] );
}
}
m_pppcRDSbacCoder[0][CI_CURR_BEST]->load( ppppcRDSbacCoders[uiSubStrm][0][CI_CURR_BEST] ); //this load is used to simplify the code
// reset the entropy coder
// 重置熵编码器
if( uiCUAddr == rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(uiCUAddr))->getFirstCUAddr() && // must be first CU of tile
uiCUAddr!=0 && // cannot be first CU of picture
uiCUAddr!=rpcPic->getPicSym()->getPicSCUAddr(rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getSliceSegmentCurStartCUAddr())/rpcPic->getNumPartInCU() &&
uiCUAddr!=rpcPic->getPicSym()->getPicSCUAddr(rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getSliceCurStartCUAddr())/rpcPic->getNumPartInCU()) // cannot be first CU of slice
{
SliceType sliceType = pcSlice->getSliceType();
if (!pcSlice->isIntra() && pcSlice->getPPS()->getCabacInitPresentFlag() && pcSlice->getPPS()->getEncCABACTableIdx()!=I_SLICE)
{
sliceType = (SliceType) pcSlice->getPPS()->getEncCABACTableIdx();
}
m_pcEntropyCoder->updateContextTables ( sliceType, pcSlice->getSliceQp(), false );
m_pcEntropyCoder->setEntropyCoder ( m_pppcRDSbacCoder[0][CI_CURR_BEST], pcSlice );
m_pcEntropyCoder->updateContextTables ( sliceType, pcSlice->getSliceQp() );
m_pcEntropyCoder->setEntropyCoder ( m_pcSbacCoder, pcSlice );
}
// set go-on entropy coder
m_pcEntropyCoder->setEntropyCoder ( m_pcRDGoOnSbacCoder, pcSlice );
m_pcEntropyCoder->setBitstream( &pcBitCounters[uiSubStrm] );
((TEncBinCABAC*)m_pcRDGoOnSbacCoder->getEncBinIf())->setBinCountingEnableFlag(true);
Double oldLambda = m_pcRdCost->getLambda();//57.9。。。
// 没有使用码率控制
if ( m_pcCfg->getUseRateCtrl() )
{
Int estQP = pcSlice->getSliceQp();
Double estLambda = -1.0;
Double bpp = -1.0;
if ( ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() )
{
estQP = pcSlice->getSliceQp();
}
else
{
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() );
}
estQP = Clip3( -pcSlice->getSPS()->getQpBDOffsetY(), MAX_QP, estQP );
m_pcRdCost->setLambda(estLambda);
#if RDOQ_CHROMA_LAMBDA
// set lambda for RDOQ
Double weight=m_pcRdCost->getChromaWeight();
const Double lambdaArray[3] = { estLambda, (estLambda / weight), (estLambda / weight) };
m_pcTrQuant->setLambdas( lambdaArray );
#else
m_pcTrQuant->setLambda( estLambda );
#endif
}
m_pcRateCtrl->setRCQP( estQP );
#if ADAPTIVE_QP_SELECTION
pcCU->getSlice()->setSliceQpBase( estQP );
#endif
}
// run CU encoder
// 对CU进行编码(压缩)
// 帧内预测,帧间预测编码还有变换编码
// 这里很重要
// 编码单元编码
// 最重要的部分!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// 注意这个只是尝试进行,然后选出最优熵编码方案,下面的encodeCU才是真正进行熵编码的地方
m_pcCuEncoder->compressCU( pcCU );
// 最重要的部分!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// restore entropy coder to an initial stage
// 熵编码器设置为Sbac
m_pcEntropyCoder->setEntropyCoder ( m_pppcRDSbacCoder[0][CI_CURR_BEST], pcSlice );
// 设置需要写入的比特流
m_pcEntropyCoder->setBitstream( &pcBitCounters[uiSubStrm] );
m_pcCuEncoder->setBitCounter( &pcBitCounters[uiSubStrm] );
// 比特计数器(用于统计熵编码器写入到比特流中的比特数)
m_pcBitCounter = &pcBitCounters[uiSubStrm];
pppcRDSbacCoder->setBinCountingEnableFlag( true );
m_pcBitCounter->resetBits();
pppcRDSbacCoder->setBinsCoded( 0 );
// 对CU进编码
// 这里是真正的进行熵编码!!!!
// 重要!!!!!!!!!!!!!
m_pcCuEncoder->encodeCU( pcCU );
// 重要!!!!!!!!!!!!!
pppcRDSbacCoder->setBinCountingEnableFlag( false );
// 这两个判断,是为了判断该CU是否为条带中的最后一个CU,如果是则跳出循环
if (m_pcCfg->getSliceMode()==FIXED_NUMBER_OF_BYTES && ( ( pcSlice->getSliceBits() + m_pcEntropyCoder->getNumberOfWrittenBits() ) ) > m_pcCfg->getSliceArgument()<<3)
{
pcSlice->setNextSlice( true );
break;
}
if (m_pcCfg->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES && pcSlice->getSliceSegmentBits()+m_pcEntropyCoder->getNumberOfWrittenBits() > (m_pcCfg->getSliceSegmentArgument() << 3) &&pcSlice->getSliceCurEndCUAddr()!=pcSlice->getSliceSegmentCurEndCUAddr())
{
pcSlice->setNextSliceSegment( true );
break;
}
ppppcRDSbacCoders[uiSubStrm][0][CI_CURR_BEST]->load( m_pppcRDSbacCoder[0][CI_CURR_BEST] );
//Store probabilties of second LCU in line into buffer
if ( ( uiCol == uiTileLCUX+1) && (depSliceSegmentsEnabled || (pcSlice->getPPS()->getNumSubstreams() > 1)) && m_pcCfg->getWaveFrontsynchro())
{
m_pcBufferSbacCoders[uiTileCol].loadContexts(ppppcRDSbacCoders[uiSubStrm][0][CI_CURR_BEST]);
}
// 没有使用码率控制
if ( m_pcCfg->getUseRateCtrl() )
{
Int actualQP = g_RCInvalidQPValue;
Double actualLambda = m_pcRdCost->getLambda();
Int actualBits = pcCU->getTotalBits();
Int numberOfEffectivePixels = 0;
for ( Int idx = 0; idx < rpcPic->getNumPartInCU(); idx++ )
{
if ( pcCU->getPredictionMode( idx ) != MODE_NONE && ( !pcCU->isSkipped( idx ) ) )
{
numberOfEffectivePixels = numberOfEffectivePixels + 16;
break;
}
}
if ( numberOfEffectivePixels == 0 )
{
actualQP = g_RCInvalidQPValue;
}
else
{
actualQP = pcCU->getQP( 0 );
}
m_pcRdCost->setLambda(oldLambda);
m_pcRateCtrl->getRCPic()->updateAfterLCU( m_pcRateCtrl->getRCPic()->getLCUCoded(), actualBits, actualQP, actualLambda,
pcCU->getSlice()->getSliceType() == I_SLICE ? 0 : m_pcCfg->getLCULevelRC() );
}
// 计算总的比特数
m_uiPicTotalBits += pcCU->getTotalBits();
// 计算运行代价
m_dPicRdCost += pcCU->getTotalCost();
// 计算失真率
m_uiPicDist += pcCU->getTotalDistortion();
} // for end
if ((pcSlice->getPPS()->getNumSubstreams() > 1) && !depSliceSegmentsEnabled)
{
pcSlice->setNextSlice( true );
}
if(m_pcCfg->getSliceMode()==FIXED_NUMBER_OF_BYTES || m_pcCfg->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES)
{
if(pcSlice->getSliceCurEndCUAddr()<=pcSlice->getSliceSegmentCurEndCUAddr())
{
pcSlice->setNextSlice( true );
}
else
{
pcSlice->setNextSliceSegment( true );
}
}
if( depSliceSegmentsEnabled )
{
if (m_pcCfg->getWaveFrontsynchro())
{
CTXMem[1]->loadContexts( &m_pcBufferSbacCoders[uiTileCol] );//ctx 2.LCU
}
CTXMem[0]->loadContexts( m_pppcRDSbacCoder[0][CI_CURR_BEST] );//ctx end of dep.slice
}
// 存储WP参数
xRestoreWPparam( pcSlice );
}