锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

vvc代码阅读 encodeCtus()

时间:2023-05-02 21:07:01 dqp9051多参变送器

CodingStructure&  cs            = *pcPic->cs;   Slice* pcSlice                  = cs.slice;   const PreCalcValues& pcv        = *cs.pcv;///提前计算数据,所有ctu通用   const uint32_t        widthInCtus   = pcv.widthInCtus;///可以一帧中有一行ctu个数 #if ENABLE_QPA   const int iQPIndex              = pcSlice->getSliceQpBase(); #endif    CABACWriter*    pCABACWriter    = pEncLib->getCABACEncoder()->getCABACEstimator( pcSlice->getSPS() );   TrQuant*        pTrQuant        = pEncLib->getTrQuant();//transform 和 quantization   RdCost*         pRdCost         = pEncLib->getRdCost()//率失真优化   EncCfg*         pCfg            = pEncLib;   RateCtrl*       pRateCtrl       = pEncLib->getRateCtrl();   pRdCost->setLosslessRDCost(pcSlice->isLossless()); #if RDOQ_CHROMA_LAMBDA   ///色度率失真优化量化lambda   pTrQuant    ->setLambdas( pcSlice->getLambdas() ); #else   pTrQuant    ->setLambda ( pcSlice->getLambdas()[0] ); #endif   pRdCost     ->setLambda ( pcSlice->getLambdas()[0], pcSlice->getSPS()->getBitDepths() ); #if WCG_EXT && ER_CHROMA_QP_WCG_PPS && ENABLE_QPA   if (!pCfg->getWCGChromaQPControl().isEnabled() && pCfg->getUsePerceptQPA() && !pCfg->getUseRateCtrl())   {     pRdCost->saveUnadjustedLambda();   } #endif

CodingStructure& cs = *pcPic->cs ///在一帧中存储所有编码数据cs。 *pcPic是传输的图片指针,指向coding strcture,然后以引用的方式新建立赋值cs对象可以在后面直接修改

H.266/VVC-VTM代码学习25-VTM中RDcost的计算与λ设定(1)_liaojq2020的博客-CSDN博客

以下是一些关于变换和量化的初始化,之后看

 int prevQP[2];   int currQP[2];   prevQP[0] = prevQP[1] = pcSlice->getSliceQp();   currQP[0] = currQP[1] = pcSlice->getSliceQp();    prevQP[0] = prevQP[1] = pcSlice->getSliceQp();   if ( pcSlice->getSPS()->getFpelMmvdEnabledFlag() ||       (pcSlice->getSPS()->getIBCFlag() && m_pcCuEncoder->getEncCfg()->getIBCHashSearch()))   {     m_pcCuEncoder->getIbcHashMap().rebuildPicHashMap(cs.picture->getTrueOrigBuf());     if (m_pcCfg->getIntraPeriod() != -1)     {       int hashBlkHitPerc = m_pcCuEncoder->getIbcHashMap().calHashBlkMatchPerc(cs.area.Y());       cs.slice->setDisableSATDForRD(hashBlkHitPerc > 59);     }     if ((pcSlice->getSPS()->getSpsRangeExtension().getTSRCRicePresentFlag()) && (m_pcGOPEncoder->getPreQP() != pcSlice->getSliceQp()) && (pcPic->cs->pps->getNumSlicesInPic() == 1) && (pcSlice->get_tsrc_index() > 0) && (pcSlice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) <= 12))     {       uint32_t totalCtu  = 0;       uint32_t hashRatio = 0;       for (uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx  )       {         const uint32_t ctuRsAddr     = pcSlice->getCtuAddrInSlice(ctuIdx);         const uint32_t ctuXPosInCtus = ctuRsAddr % widthInCtus;         const uint32_t ctuYPosInCtus = ctuRsAddr / widthInCtus;         const Position pos(ctuXPosInCtus * pcv.maxCUWidth, ctuYPosInCtus * pcv.maxCUHeight);         const UnitArea ctuArea(cs.area.chromaFormat, Area(pos.x, pos.y, pcv.maxCUWidth, pcv.maxCUHeight));          hashRatio  = m_pcCuEncoder->getIbcHashMap().calHashBlkMatchPerc(cs.area.Y());         totalCtu  ;       } if (totalCtu > 0)       {         if ((hashRatio < 4200) || (hashRatio < (41 * totalCtu)))         {           pcSlice->set_tsrc_index(0);         }       }     }   }

prevQP[],currQP[]在compressSlice()还设置了图片之前和现在的设置。QP值。0和1分别代表亮度和色度,2代表亮度和色度MAX_NUM_CHANNEL_TYPE

现在设置这两个参数,然后读取以前设置的参数QP值,然后赋值

10分钟拿下 HashMap_一页博客-CSDN博客

getIBCFlag():IntraBlockCopy(帧内块复制)模式标志,IBC默认false

IntraPeriod:I帧间隔

第一个if语句:求hashBlkHitPerc值,perc推测是perceptually的缩写,若大于59,则不适用SATD

SAD和SATD的区别_yanbdsky的博客-CSDN博客_satd

第二个if句子:同时满足五个条件(1)TSRCRicePresent 打开(2)亮度encodeGOP的preQP值 不等于现在slice的QP值 (3)一张图只有一张Slice (4)TSRC(Transform Skip Residual Coding),跳跃残差编码变换目录大于0 亮度通道的比特深度小于12

TSRC默认为false,所以这个if语句跳过。

// for every CTU in the slice   for( uint32_t ctuIdx = 0; ctuIdx < pcSlice->getNumCtuInSlice(); ctuIdx   )   {     const int32_t ctuRsAddr = pcSlice->getCtuAddrInSlice( ctuIdx );      // update CABAC state     const uint32_t ctuXPosInCtus        = ctuRsAddr % widthInCtus;     const uint32_t ctuYPosInCtus        = ctuRsAddr / widthInCtus;      constPosition pos (ctuXPosInCtus * pcv.maxCUWidth, ctuYPosInCtus * pcv.maxCUHeight);
    const UnitArea ctuArea( cs.area.chromaFormat, Area( pos.x, pos.y, pcv.maxCUWidth, pcv.maxCUHeight ) );
    DTRACE_UPDATE( g_trace_ctx, std::make_pair( "ctu", ctuRsAddr ) );

    if( pCfg->getSwitchPOC() != pcPic->poc || -1 == pCfg->getDebugCTU() )
    if ((cs.slice->getSliceType() != I_SLICE || cs.sps->getIBCFlag()) && cs.pps->ctuIsTileColBd( ctuXPosInCtus ))
    {
      cs.motionLut.lut.resize(0);
      cs.motionLut.lutIbc.resize(0);
    }

对Slice中所有Ctu进行处理

注意这里

ctuRsAddr:这里的RS是raster-scan的缩写,表示光栅扫描模式下slice中的每一个ctu的地址。

值跟ctuIdx一样

ctuXPosInCtus,ctuYPosInCtus:算出当前Ctu的x,y位置坐标。比如ctuRsAddr = 0时,x,y分别等于0,0,表明这个CTU的位置为(0,0).ctuRsAddr = 13时,x,y分别等于6,1,表明这个CTU的位置为(6,1)。这里面每一个块都是一个CTU,这个地址是CTU的相对地址

注意:这个图为832X480,CTU大小默认设置为128 X 128,而如果除下来,CTU应该只有24.3个,这与代码中28个的结果不同。原因是在边界不足以划分一个完整的CTU时,图像做了填充,加大了一部分面积,使一个CTU被完整划分出来。填充前图像宽度叫width,填充后的图像宽度叫stride。之后再具体了解

Image Stride(内存图像行跨度)_jsn_ze的博客-CSDN博客

pcv.maxCUWidth:PreCalcValue下的maxCUWidth,好像定为128,我改cfg文件中的maxCUWidth也没有变化。之后再看。推测可认定这个就为CTU的宽度,之后再看是否正确

pos():因为cu的大小可以像CTU一样大,这里又设置为128.所以ctuXPosInCtus * pcv.maxCUWidth即可表示当前CTU的位置,像素为基本单位。

ctuArea():表示要处理的CTU的位置和大小还有这个位置的色度采样格式

ctuIsTileColBd():设置m_tileColBd,为ture时代表CTU在Tile的左边界线

第一个if语句:当前帧是B或P帧,或者允许开启IBC且CTU在Tile的左边界线,需要清空motionLut,里面存储着HMVP候选列表

const SubPic &curSubPic = pcSlice->getPPS()->getSubPicFromPos(pos);
    // padding/restore at slice level
    if (pcSlice->getPPS()->getNumSubPics() >= 2 && curSubPic.getTreatedAsPicFlag() && ctuIdx == 0)
    {
      int subPicX = (int)curSubPic.getSubPicLeft();
      int subPicY = (int)curSubPic.getSubPicTop();
      int subPicWidth = (int)curSubPic.getSubPicWidthInLumaSample();
      int subPicHeight = (int)curSubPic.getSubPicHeightInLumaSample();

      for (int rlist = REF_PIC_LIST_0; rlist < NUM_REF_PIC_LIST_01; rlist++)
      {
        int n = pcSlice->getNumRefIdx((RefPicList)rlist);//n应该是参考帧的总数量
        for (int idx = 0; idx < n; idx++)
        {
          Picture *refPic = pcSlice->getRefPic((RefPicList)rlist, idx);//从参考帧列表中得到参考帧及其序号

          if( !refPic->getSubPicSaved() && refPic->subPictures.size() > 1 )//如果参考帧的subpicture的边界没有被保存,且参考帧的有subpicure划分
          {
            refPic->saveSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight);
            refPic->extendSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight);
            refPic->setSubPicSaved(true);
          }
        }
      }
    }

VTM10.0代码学习3:DecSlice_decompressSlice()_柴门风雪夜的博客-CSDN博客

curSubPic:包含当前CTU的subpicture

curSubPic.getTreatedAsPicFlag():将子图片看做图片,为true时则子图片的边界也被当成图片的边界,环路滤波时不执行这个。在当前设置下,默认为true。

第一个if语句:在子图片数量大于2,getTreatedAsPicFlag为TRUE且CTU序号为0时。将子图片的左和上边界设为子图片的X,Y,将子图片在亮度分量中的宽度和高度设为子图片的宽度和高度。

for循环:猜测NUM_REF_PIC_LIST_01为参考帧列表0和1都放在一起,全包括。此处遍历所有参考帧列表的每一个参考帧,如果参考帧也有subpicture划分,且没有保存的边界,那么就要进行以下操作(这个没有验证,之后再看):

  • saveSubPicBorder():保存未被扩展的边界
  • extendSubPicBorder():扩展边界
  • setSubPicSaved():设置有边界被保存
if (cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && cs.pps->ctuIsTileRowBd( ctuYPosInCtus ))
    {
      pCABACWriter->initCtxModels( *pcSlice );
      cs.resetPrevPLT(cs.prevPLT);
      prevQP[0] = prevQP[1] = pcSlice->getSliceQp();
    }
    else if (cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && pEncLib->getEntropyCodingSyncEnabledFlag())
    {
      // reset and then update contexts to the state at the end of the top CTU (if within current slice and tile).
      pCABACWriter->initCtxModels( *pcSlice );
      cs.resetPrevPLT(cs.prevPLT);
      if( cs.getCURestricted( pos.offset(0, -1), pos, pcSlice->getIndependentSliceIdx(), cs.pps->getTileIdx( pos ), CH_L ) )
      {
        // Top is available, we use it.
        pCABACWriter->getCtx() = pEncLib->m_entropyCodingSyncContextState;
        cs.setPrevPLT(pEncLib->m_palettePredictorSyncState);
      }
      prevQP[0] = prevQP[1] = pcSlice->getSliceQp();
    }

第一个if语句:如果CTU同时在Tile的上和左边界,则

  • initCtxModels():初始化上下文模型。看CABAC时注意这里,H.264将一个片内可能出现的数据划分为 399 个上下文模型,每个模型以 ctxIdx 标识
  • 重置prePLT,palette mode coding
  • 重置色度和亮度的preQP

else if语句:如果CTU在Tile的左边界且开启了EntropyCodingSync

  • initCtxModels():初始化上下文模型。看CABAC时注意这里
  • 重置prePLT,palette mode coding
  • 重置色度和亮度的preQP
  • 其中如果getCURestricted()为true,重新设置CABAC上下文模型的ctx和prePLT模式
  const double oldLambda = pRdCost->getLambda();
    if ( pCfg->getUseRateCtrl() )
    {
      int estQP        = pcSlice->getSliceQp();
      double estLambda = -1.0;
      double bpp       = -1.0;

      if( ( pcPic->slices[0]->isIRAP() && pCfg->getForceIntraQP() ) || !pCfg->getLCULevelRC() )
      {
        estQP = pcSlice->getSliceQp();
      }
      else
      {
        bpp = pRateCtrl->getRCPic()->getLCUTargetBpp(pcSlice->isIRAP());
        if ( pcPic->slices[0]->isIntra())
        {
          estLambda = pRateCtrl->getRCPic()->getLCUEstLambdaAndQP(bpp, pcSlice->getSliceQp(), &estQP);
        }
        else
        {
          estLambda = pRateCtrl->getRCPic()->getLCUEstLambda( bpp );
          estQP     = pRateCtrl->getRCPic()->getLCUEstQP    ( estLambda, pcSlice->getSliceQp() );
        }

        estQP     = Clip3( -pcSlice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, estQP );

        pRdCost->setLambda(estLambda, pcSlice->getSPS()->getBitDepths());
#if WCG_EXT
        pRdCost->saveUnadjustedLambda();
#endif
        for (uint32_t compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++)
        {
          const ComponentID compID = ComponentID(compIdx);
          int chromaQPOffset = pcSlice->getPPS()->getQpOffset(compID) + pcSlice->getSliceChromaQpDelta(compID);
          int qpc = pcSlice->getSPS()->getMappedChromaQpValue(compID, estQP) + chromaQPOffset;
          double tmpWeight = pow(2.0, (estQP - qpc) / 3.0);  // takes into account of the chroma qp mapping and chroma qp Offset
          if (m_pcCfg->getDepQuantEnabledFlag())
          {
            tmpWeight *= (m_pcCfg->getGOPSize() >= 8 ? pow(2.0, 0.1 / 3.0) : pow(2.0, 0.2 / 3.0));  // increase chroma weight for dependent quantization (in order to reduce bit rate shift from chroma to luma)
          }
          m_pcRdCost->setDistortionWeight(compID, tmpWeight);
        }
#if RDOQ_CHROMA_LAMBDA
        const double lambdaArray[MAX_NUM_COMPONENT] = {estLambda / m_pcRdCost->getDistortionWeight (COMPONENT_Y),
                                                       estLambda / m_pcRdCost->getDistortionWeight (COMPONENT_Cb),
                                                       estLambda / m_pcRdCost->getDistortionWeight (COMPONENT_Cr)};
        pTrQuant->setLambdas( lambdaArray );
#else
        pTrQuant->setLambda( estLambda );
#endif
      }

      pRateCtrl->setRCQP( estQP );
    }
#if ENABLE_QPA
    else if (pCfg->getUsePerceptQPA() && pcSlice->getPPS()->getUseDQP())
    {
#if ENABLE_QPA_SUB_CTU
      const int adaptedQP    = applyQPAdaptationSubCtu (cs, ctuArea, ctuRsAddr, m_pcCfg->getLumaLevelToDeltaQPMapping().mode == LUMALVL_TO_DQP_NUM_MODES);
#else
      const int adaptedQP    = pcPic->m_iOffsetCtu[ctuRsAddr];
#endif
      const double newLambda = pcSlice->getLambdas()[0] * pow (2.0, double (adaptedQP - iQPIndex) / 3.0);
      pcPic->m_uEnerHpCtu[ctuRsAddr] = newLambda; // for ALF and SAO
#if !ENABLE_QPA_SUB_CTU
#if RDOQ_CHROMA_LAMBDA
      pTrQuant->getLambdas (oldLambdaArray); // save the old lambdas
      const double lambdaArray[MAX_NUM_COMPONENT] = {newLambda / m_pcRdCost->getDistortionWeight (COMPONENT_Y),
                                                     newLambda / m_pcRdCost->getDistortionWeight (COMPONENT_Cb),
                                                     newLambda / m_pcRdCost->getDistortionWeight (COMPONENT_Cr)};
      pTrQuant->setLambdas (lambdaArray);
#else
      pTrQuant->setLambda (newLambda);
#endif
      pRdCost->setLambda (newLambda, pcSlice->getSPS()->getBitDepths());
#endif
      currQP[0] = currQP[1] = adaptedQP;
    }
#endif

第一个if语句:ratecontrol  默认是false,先跳过

else if语句:关于QPA,也是默认false,跳过

 bool updateBcwCodingOrder = cs.slice->getSliceType() == B_SLICE && ctuIdx == 0;
    if( updateBcwCodingOrder )
    {
      resetBcwCodingOrder(false, cs);
      m_pcInterSearch->initWeightIdxBits();
    }
    if (pcSlice->getSPS()->getUseLmcs())
    {
      m_pcCuEncoder->setDecCuReshaperInEncCU(m_pcLib->getReshaper(), pcSlice->getSPS()->getChromaFormatIdc());
    }
    if( !cs.slice->isIntra() && pCfg->getMCTSEncConstraint() )
    {
      pcPic->mctsInfo.init( &cs, ctuRsAddr );
    }

    if (pCfg->getSwitchPOC() != pcPic->poc || ctuRsAddr >= pCfg->getDebugCTU())
    {
      m_pcCuEncoder->compressCtu(cs, ctuArea, ctuRsAddr, prevQP, currQP);
    }

updateBcwCodingOrder:如果当前为B 帧且是slice里第一个CTU,则开启BCW

if语句(BCW为true):没仔细看,应该是重置BCW且根据序号初始化加权系数

setDecCuReshaperInEncCU():因为与lmcs有关,推测与对亮度色度分量的形状改变有关,之后再仔细看

最后一个if语句:如果poc和CTU未出现错误,则进入compressCtu()函数

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章