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 );  }  
原创粉丝点击