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

VVC代码阅读 xCompressCU(2) do while结构 最后面有两小段函数没看

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

H.266/VVC代码学习:xCompressCU函数_涵小呆的博客-CSDN博客

尝试各种可用的编码器模式:例如skip,帧间,帧内,PCM等待,预测和划分。

do { } while( m_modeCtrl->nextMode( *tempCS, partitioner ) );

for (int i = compBegin; i < (compBegin   numComp); i  )     {       ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);       tempCS->prevPLT.curPLTSize[comID] = curLastPLTSize[comID];       memcpy(tempCS->prevPLT.curPLT[i], curLastPLT[i], curLastPLTSize[comID] * sizeof(Pel));     }     EncTestMode currTestMode = m_modeCtrl->currTestMode();     currTestMode.maxCostAllowed = maxCostAllowed;

for循环:遍历分量,将 PLT 填充相关变量。未使用当前帧PLT,先跳过

currTestMode:当前的测试模式

maxCostAllowed:当前测试模式允许模式cost

     if (pps.getUseDQP() && partitioner.isSepTree(*tempCS) && isChroma( partitioner.chType ))     {       const Position chromaCentral(tempCS->area.Cb().chromaPos().offset(tempCS->area.Cb().chromaSize().width >> 1, tempCS->area.Cb().chromaSize().height >> 1));       const Position lumaRefPos(chromaCentral.x << getComponentScaleX(COMPONENT_Cb, tempCS->area.chromaFormat), chromaCentral.y << getComponentScaleY(COMPONENT_Cb, tempCS->area.chromaFormat));       const CodingStructure* baseCS = bestCS->picture->cs;       const CodingUnit* colLumaCu = baseCS->getCU(lumaRefPos, CHANNEL_TYPE_LUMA);        if (colLumaCu)       {         currTestMode.qp = colLumaCu->qp;       }     } 

dqp:delta QP

【笔记】HEVC 编码标准(6)-量化_lock。的博客-CSDN博客_hevc 量化

把这个函数放在后面看

    if( currTestMode.type == ETM_INTER_ME )     {       if( ( currTestMode.opts & ETO_IMV ) != 0 )       {         const bool skipAltHpelIF = ( int( ( currTestMode.opts & ETO_IMV ) >> ETO_IMV_SHIFT ) == 4 ) && ( bestIntPelCost > 1.25 * bestCS->cost );         if (!skipAltHpelIF)         {           tempCS->bestCS = bestCS;           xCheckRDCostInterIMV(tempCS, bestCS, partitioner, currTestMode, bestIntPelCost);           tempCS->bestCS = nullptr;         }       }       else       {         tempCS->bestCS = bestCS;         xCheckRDCostInter( tempCS, bestCS, partitioner, currTestMode );         tempCS->bestCS = nullptr;       }      }

目前的测试模式是inter时启用

    // 若当前的测试模式是 HASH INTER     // 则检查 HashInter 的 RD cost  else if (currTestMode.type == ETM_HASH_INTER)     {       xCheckRDCostHashInter( tempCS, bestCS, partitioner, currTestMode );     }     // 若当前的测试模式是 AFFINE     // 则检查 Affine 的 RD cost     else if( currTestMode.type == ETM_AFFINE )     {       xCheckRDCostAffineMerge2Nx2N( tempCS, bestCS, partitioner, currTestMode );     } #if REUSE_CU_RESULTS     // 若当前的测试模式是 RECO_CACHED     // 则检查 Reuse Cached 的 RD cost     else if( currTestMode.type == ETM_RECO_CACHED )     {       xReuseCachedResult( tempCS, bestCS, partitioner );     }     // 若当前的测试模式是 MERGE_SKIP     // 则检查 Merge 的 RD cost     else if( currTestMode.type == ETM_MERGE_SKIP )     {       xCheckRDCostMerge2Nx2N( tempCS, bestCS, partitioner, currTestMode );       CodingUnit* cu = bestCS->getCU(partitioner.chType);       if (cu)       {         cu->mmvdSkip = cu->skip == false ? false : cu->mmvdSkip;       }     }     // 若当前的测试模式是 MERGE_GEO     // 则检查 Merge Geo 的 RD cost     else if( currTestMode.type == ETM_MERGE_GEO )     {       xCheckRDCostMergeGeo2Nx2N( tempCS, bestCS, partitioner, currTestMode );     }

之后再细看

 else if( currTestMode.type == ETM_INTRA )     {       ///如果使用颜色变化,则不是dual tree       if (slice.getSPS()->getUseColorTrans() && !CS::isDualITree(*tempCS))       {         ///不跳过第二色空间         bool skipSecColorSpace = false;         skipSecColorSpace = xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, (m_pcEncCfg->getRGBFormatFlag() ? true : false));         if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()) && !m_pcEncCfg->getRGBFormatFlag())         {           skipSecColorSpace = true;         }         if (!m_pcEncCfg->getRGBFormatFlag())         {           skipSecColorSpace = true;         }         if (!skipSecColorSpace && !tempCS->firstColorSpaceTestOnly)         {           xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, (m_pcEncCfg->getRGBFormatFlag() ? false : true));         }          if (! false : true));         }          if (!tempCS->firstColorSpaceTestOnly)         {           if (tempCS->tmpColorSpaceIntraCost[0] != MAX_DOUBLE && tempCS->tmpColorSpaceIntraCost[1] != MAX_DOUBLE)           {             double skipCostRatio =m_pcEncCfg->getRGBFormatFlag() ? 1.1 : 1.0;
            if (tempCS->tmpColorSpaceIntraCost[1] > (skipCostRatio*tempCS->tmpColorSpaceIntraCost[0]))
            {
              tempCS->firstColorSpaceTestOnly = bestCS->firstColorSpaceTestOnly = true;
            }
          }
        }
        else
        {
          CHECK(tempCS->tmpColorSpaceIntraCost[1] != MAX_DOUBLE, "the RD test of the second color space should be skipped");
        }
      }
      else
      {
        xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, false);
      }
    }

当前测试模式是intra

    // 若当前测试模式是 PALETTE
    // 则检查 PLT 的 RD cost
else if (currTestMode.type == ETM_PALETTE)
    {
      xCheckPLT( tempCS, bestCS, partitioner, currTestMode );
    }
    // 若当前测试模式是 IBC(Intra block copy)
    // 则检查 IBC 的 RD cost
    else if (currTestMode.type == ETM_IBC)
    {
      xCheckRDCostIBCMode(tempCS, bestCS, partitioner, currTestMode);
    }
    // 若当前测试模式是 IBC_MERGE
    // 则检查 IBC_MERGE 的 RD cost
    else if (currTestMode.type == ETM_IBC_MERGE)
    {
      xCheckRDCostIBCModeMerge2Nx2N(tempCS, bestCS, partitioner, currTestMode);
    }

之后再看

else if( isModeSplit( currTestMode ) )
    {
      if (bestCS->cus.size() != 0) //size()返回当前序列长度,不为0表示已划分过
      {
        splitmode = bestCS->cus[0]->splitSeries;
      }
      assert( partitioner.modeType == tempCS->modeType );
      int signalModeConsVal = tempCS->signalModeCons( getPartSplit( currTestMode ), partitioner, modeTypeParent );
      int numRoundRdo = signalModeConsVal == LDT_MODE_TYPE_SIGNAL ? 2 : 1;
      bool skipInterPass = false;
    // 遍历 RDO 轮次
      for( int i = 0; i < numRoundRdo; i++ )
      {
        //change cons modes
        // 若当前信号模式值为 LDT_MODE_TYPE_SIGNAL
        // 则当前测试模式类型在第一轮设置为 INTER,在第二轮设置为 INTRA
        if( signalModeConsVal == LDT_MODE_TYPE_SIGNAL )
        {
          CHECK( numRoundRdo != 2, "numRoundRdo shall be 2 - [LDT_MODE_TYPE_SIGNAL]" );
          tempCS->modeType = partitioner.modeType = (i == 0) ? MODE_TYPE_INTER : MODE_TYPE_INTRA;
        }
        // 若当前信号模式值为 LDT_MODE_TYPE_INFER
        // 则当前测试模式类型为 INTRA
        else if( signalModeConsVal == LDT_MODE_TYPE_INFER )
        {
          CHECK( numRoundRdo != 1, "numRoundRdo shall be 1 - [LDT_MODE_TYPE_INFER]" );
          tempCS->modeType = partitioner.modeType = MODE_TYPE_INTRA;
        }
        // 若当前信号模式值为 LDT_MODE_TYPE_INHERIT
        // 则当前测试模式类型为父结点模式类型
        else if( signalModeConsVal == LDT_MODE_TYPE_INHERIT )
        {
          CHECK( numRoundRdo != 1, "numRoundRdo shall be 1 - [LDT_MODE_TYPE_INHERIT]" );
          tempCS->modeType = partitioner.modeType = modeTypeParent;
        }

        //for lite intra encoding fast algorithm, set the status to save inter coding info
        //帧间模式
        // 若父结点模式类型为 MODE_TYPE_ALL(可以尝试所有类型),且当前测试模式类型为 Inter
        // 则 SaveCuCostInSCIPU,且设置 NumCuInSCIPU 为0
        if( modeTypeParent == MODE_TYPE_ALL && tempCS->modeType == MODE_TYPE_INTER )
        {
          m_pcIntraSearch->setSaveCuCostInSCIPU( true );
          m_pcIntraSearch->setNumCuInSCIPU( 0 );
        }
        // 若父结点模式类型为 MODE_TYPE_ALL(可以尝试所有类型),且当前测试模式类型不为 Inter
        // 则 SaveCuCostInSCIPU 为 false,且当前测试模式 MODE_TYPE_ALL 时设置 NumCuInSCIPU 为0
        else if( modeTypeParent == MODE_TYPE_ALL && tempCS->modeType != MODE_TYPE_INTER )
        {
          m_pcIntraSearch->setSaveCuCostInSCIPU( false );
          if( tempCS->modeType == MODE_TYPE_ALL )
          {
            m_pcIntraSearch->setNumCuInSCIPU( 0 );
          }
        }

        xCheckModeSplit( tempCS, bestCS, partitioner, currTestMode, modeTypeParent, skipInterPass );
        //recover cons modes
        tempCS->modeType = partitioner.modeType = modeTypeParent;
        tempCS->treeType = partitioner.treeType = treeTypeParent;
        partitioner.chType = chTypeParent;
        if( modeTypeParent == MODE_TYPE_ALL )
        {
          m_pcIntraSearch->setSaveCuCostInSCIPU( false );
          if( numRoundRdo == 2 && tempCS->modeType == MODE_TYPE_INTRA )
          {
            m_pcIntraSearch->initCuAreaCostInSCIPU();
          }
        }
        if( skipInterPass )
        {
          break;
        }
      }
#if GDR_ENABLED
      if (bestCS->cus.size() > 0 && splitmode != bestCS->cus[0]->splitSeries)
#else
      if (splitmode != bestCS->cus[0]->splitSeries)
#endif
      {
        splitmode = bestCS->cus[0]->splitSeries;
        const CodingUnit&     cu = *bestCS->cus.front();
        cu.cs->prevPLT = bestCS->prevPLT;
        for (int i = compBegin; i < (compBegin + numComp); i++)
        {
          ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
          bestLastPLTSize[comID] = bestCS->cus[0]->cs->prevPLT.curPLTSize[comID];
          memcpy(bestLastPLT[i], bestCS->cus[0]->cs->prevPLT.curPLT[i], bestCS->cus[0]->cs->prevPLT.curPLTSize[comID] * sizeof(Pel));
        }
      }
    }
else
    {
      THROW( "Don't know how to handle mode: type = " << currTestMode.type << ", options = " << currTestMode.opts );
    }
  } while( m_modeCtrl->nextMode( *tempCS, partitioner ) );

当前测试模式为划分

SplitSeries 类:对于每个cu尺寸的具体的划分顺序的一个参数

VVC学习之四:VTM中的数据结构——CodingUnit、PredictionUnit、TransformUnit_Aidoneus_y的博客-CSDN博客

bestCS->cus.size():若当前CU已划分,则当前BestCs的cu数目就不为零。此时设置splitmode,这个好像与在帧内预测中的一个叫getSplitSeries()函数有关,之后看到帧内时再写。推测表示划分时的顺序

assert:检验当前CS结构modeType是否和划分类中设定的modeType相同,如果不同,则终止程序

getPartSplit():从当前测试模式中得到当前CU的划分方式

https://blog.csdn.net/dfhg54/article/details/124284888

signalModeConsVal():获得当前信号模式值,规定了子节点是否继承父节点的模式测试方法。0,1,2分别代表三个模式。如0代表LDT_MODE_TYPE_INHERIT

numRoundRdo:当前信号模式值为 LDT_MODE_TYPE_SIGNAL,则Rdo轮次为2

for循环:注释在代码里

xCheckModeSplit():划分模式,这里会递归调用xcompressCu

 //
  // Finishing CU
  if( tempCS->cost == MAX_DOUBLE && bestCS->cost == MAX_DOUBLE )
  {
    //although some coding modes were planned to be tried in RDO, no coding mode actually finished encoding due to early termination
    //thus tempCS->cost and bestCS->cost are both MAX_DOUBLE; in this case, skip the following process for normal case
    m_modeCtrl->finishCULevel( partitioner );
    return;
  }

  // set context states
  m_CABACEstimator->getCtx() = m_CurrCtx->best;

如果tempCS和bestCS中的cost都等于double最大值,则finishCULevel()中实现

m_ComprCUCtxList.pop_back();

 在运行完以后,m_ComprCUCtxList的size减少了1.原本的那层出了intra没有其他模式,所以当前CU已经算测试完了,就把栈中这个CU的信息消去,返回上一层父CU

 

  // QP from last processed CU for further processing
  //copy the qp of the last non-chroma CU
  int numCUInThisNode = (int)bestCS->cus.size();
  if( numCUInThisNode > 1 && bestCS->cus.back()->chType == CHANNEL_TYPE_CHROMA && !CS::isDualITree( *bestCS ) )
  {
    CHECK( bestCS->cus[numCUInThisNode-2]->chType != CHANNEL_TYPE_LUMA, "wrong chType" );
    bestCS->prevQP[partitioner.chType] = bestCS->cus[numCUInThisNode-2]->qp;
  }
  else
  {
  bestCS->prevQP[partitioner.chType] = bestCS->cus.back()->qp;
  }
  if ((!slice.isIntra() || slice.getSPS()->getIBCFlag())
    && partitioner.chType == CHANNEL_TYPE_LUMA
    && bestCS->cus.size() == 1 && (bestCS->cus.back()->predMode == MODE_INTER || bestCS->cus.back()->predMode == MODE_IBC)
    && bestCS->area.Y() == (*bestCS->cus.back()).Y()
    )
  {
    const CodingUnit&     cu = *bestCS->cus.front();

    bool isIbcSmallBlk = CU::isIBC(cu) && (cu.lwidth() * cu.lheight() <= 16);
    CU::saveMotionInHMVP( cu, isIbcSmallBlk );
  }
  // 将预测像素和重建像素复制到bestCS->picture中
  bestCS->picture->getPredBuf(currCsArea).copyFrom(bestCS->getPredBuf(currCsArea));
  bestCS->picture->getRecoBuf( currCsArea ).copyFrom( bestCS->getRecoBuf( currCsArea ) );
  m_modeCtrl->finishCULevel( partitioner );
  if( m_pcIntraSearch->getSaveCuCostInSCIPU() && bestCS->cus.size() == 1 )
  {
    m_pcIntraSearch->saveCuAreaCostInSCIPU( Area( partitioner.currArea().lumaPos(), partitioner.currArea().lumaSize() ), bestCS->cost );
  }

这部分代码有预测和重建像素,要结合后面的预测函数来看

 if (bestCS->cus.size() == 1) // no partition
  {
    CHECK(bestCS->cus[0]->tileIdx != bestCS->pps->getTileIdx(bestCS->area.lumaPos()), "Wrong tile index!");
    if (bestCS->cus[0]->predMode == MODE_PLT)
    {
      for (int i = compBegin; i < (compBegin + numComp); i++)
      {
        ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
        bestCS->prevPLT.curPLTSize[comID] = curLastPLTSize[comID];
        memcpy(bestCS->prevPLT.curPLT[i], curLastPLT[i], curLastPLTSize[comID] * sizeof(Pel));
      }
      bestCS->reorderPrevPLT(bestCS->prevPLT, bestCS->cus[0]->curPLTSize, bestCS->cus[0]->curPLT, bestCS->cus[0]->reuseflag, compBegin, numComp, jointPLT);
    }
    else
    {
      for (int i = compBegin; i<(compBegin + numComp); i++)
      {
        ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
        bestCS->prevPLT.curPLTSize[comID] = curLastPLTSize[comID];
        memcpy(bestCS->prevPLT.curPLT[i], curLastPLT[i], bestCS->prevPLT.curPLTSize[comID] * sizeof(Pel));
      }
    }
  }
  else
  {
    for (int i = compBegin; i<(compBegin + numComp); i++)
    {
      ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
      bestCS->prevPLT.curPLTSize[comID] = bestLastPLTSize[comID];
      memcpy(bestCS->prevPLT.curPLT[i], bestLastPLT[i], bestCS->prevPLT.curPLTSize[comID] * sizeof(Pel));
    }
  }
  const CodingUnit&     cu = *bestCS->cus.front();
  cu.cs->prevPLT = bestCS->prevPLT;
  // Assert if Best prediction mode is NONE
  // Selected mode's RD-cost must be not MAX_DOUBLE.
  CHECK( bestCS->cus.empty()                                   , "No possible encoding found" );
  CHECK( bestCS->cus[0]->predMode == NUMBER_OF_PREDICTION_MODES, "No possible encoding found" );
  CHECK( bestCS->cost             == MAX_DOUBLE                , "No possible encoding found" );
}

与PLT模式有关,之后再看

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

相关文章