HEVC函数入门(16)——Slice编码
来源:互联网 发布:做菜单用什么软件 编辑:程序博客网 时间:2024/06/03 23:43
本文转载整理自: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 ); }
阅读全文
0 0
- HEVC函数入门(16)——Slice编码
- HEVC函数入门(17)——编码一个CU
- HEVC函数入门(23)——熵编码&CABAC
- HEVC函数入门(2)——帧内编码一个CU
- HEVC函数入门(19)——帧间编码AMVP
- HEVC函数入门(14)——建议先看:整个编码流程以及相关的函数
- HEVC—参数GOP,SLICE,TILE解疑
- HEVC函数入门(13)——HEVC中容易混淆的类和结构
- HEVC函数入门(8)——变换的实现
- HEVC函数入门(9)——tile相关
- HEVC函数入门(22)——变换&量化
- HEVC函数入门(24)——比特流
- HEVC编码结构:Slice和Tile
- HEVC—编码树结构
- HEVC函数入门——重要变量以及CU索引
- HEVC函数入门(10)——HM软件手册software-manual(GOP,RPS,POC)
- HEVC函数入门(1)——HM编码器的基本结构
- HEVC函数入门(3)——参数命名及帧内预测
- 1102. Invert a Binary Tree (25)<反转二叉树>
- BeautifulSoup简记
- 【MySql】mysql中的聚集索引和非聚集索引
- linux基本权限 --修改文件所有者和所有组命令
- Ubuntu系统Tab键不能自动补全问题解决
- HEVC函数入门(16)——Slice编码
- Boostrap--组件
- MVC
- Java的反射,动态代理,模版设计模式,
- socket(套接字)在服务器端和客户端之间的基本工作原理流程图
- caffe:create_txt.sh(数据预处理成txt文本文件)
- apply、call、bind
- vs2013+opencv1.0,cvvidsurv.hpp报错C4996
- 大明A+B