VVC代码阅读(2)compressGOP函数(2)

注意:本次代码运用的是encoder_intra_vtm的设置,所以GOP_size  只有一帧

   // store sub-picture numbers, sizes, and locations with a picture
    pcSlice->getPic()->subPictures.clear();

    for( int subPicIdx = 0; subPicIdx < pcPic->cs->pps->getNumSubPics(); subPicIdx++ )
    {
      pcSlice->getPic()->subPictures.push_back( pcPic->cs->pps->getSubPic( subPicIdx ) );//好像是根据序号,把子图片移动到队列末尾?
    }

    const VPS* vps = pcPic->cs->vps;//视频参数集
    int layerIdx = vps == nullptr ? 0 : vps->getGeneralLayerIdx(pcPic->layerId);
    if (vps && !vps->getIndependentLayerFlag(layerIdx) && pcPic->cs->pps->getNumSubPics() > 1)
    {
      CU::checkConformanceILRP(pcSlice);
    }

    xPicInitHashME( pcPic, pcSlice->getPPS(), rcListPic );

    if( m_pcCfg->getUseAMaxBT() )
    {
      if (!pcSlice->isIRAP())
      {
        int refLayer = pcSlice->getDepth();
        if (refLayer > 9)
        {
          refLayer = 9;   // Max layer is 10
        }

        if( m_bInitAMaxBT && pcSlice->getPOC() > m_uiPrevISlicePOC )
        {
          ::memset( m_uiBlkSize, 0, sizeof( m_uiBlkSize ) );
          ::memset( m_uiNumBlk,  0, sizeof( m_uiNumBlk ) );
          m_bInitAMaxBT = false;
        }

        if( refLayer >= 0 && m_uiNumBlk[refLayer] != 0 )
        {
          picHeader->setSplitConsOverrideFlag(true);
          double dBlkSize = sqrt( ( double ) m_uiBlkSize[refLayer] / m_uiNumBlk[refLayer] );
          unsigned int newMaxBtSize = picHeader->getMaxBTSize(pcSlice->getSliceType(), CHANNEL_TYPE_LUMA);
          if( dBlkSize < AMAXBT_TH32 )
          {
            newMaxBtSize = 32;
          }
          else if( dBlkSize < AMAXBT_TH64 )
          {
            newMaxBtSize = 64;
          }
          else
          {
            newMaxBtSize = 128;
          }
          newMaxBtSize = Clip3(picHeader->getMinQTSize(pcSlice->getSliceType()), pcPic->cs->sps->getCTUSize(), newMaxBtSize);
          picHeader->setMaxBTSize(1, newMaxBtSize);

          m_uiBlkSize[refLayer] = 0;
          m_uiNumBlk [refLayer] = 0;
        }
      }
      else
      {
        if( m_bInitAMaxBT )
        {
          ::memset( m_uiBlkSize, 0, sizeof( m_uiBlkSize ) );
          ::memset( m_uiNumBlk,  0, sizeof( m_uiNumBlk ) );
        }

        m_uiPrevISlicePOC = pcSlice->getPOC();
        m_bInitAMaxBT = true;
      }
      bool identicalToSPS=true;
      const SPS* sps =pcSlice->getSPS();

      if (picHeader->getPicInterSliceAllowedFlag())
      {
        if (picHeader->getMinQTSize(pcSlice->getSliceType()) != pcSlice->getSPS()->getMinQTSize(pcSlice->getSliceType()) ||
            picHeader->getMaxMTTHierarchyDepth(pcSlice->getSliceType()) != pcSlice->getSPS()->getMaxMTTHierarchyDepth() ||
            picHeader->getMaxBTSize(pcSlice->getSliceType()) != pcSlice->getSPS()->getMaxBTSize() ||
            picHeader->getMaxTTSize(pcSlice->getSliceType()) != pcSlice->getSPS()->getMaxTTSize()
          )
        {
          identicalToSPS=false;
        }
      }

      if (identicalToSPS && picHeader->getPicIntraSliceAllowedFlag())
      {
        if (picHeader->getMinQTSize(I_SLICE) != sps->getMinQTSize(I_SLICE) ||
            picHeader->getMaxMTTHierarchyDepth(I_SLICE) != sps->getMaxMTTHierarchyDepthI() ||
            picHeader->getMaxBTSize(I_SLICE) != sps->getMaxBTSizeI() ||
            picHeader->getMaxTTSize(I_SLICE) != sps->getMaxTTSizeI()
        )
        {
          identicalToSPS=false;
        }

        if (identicalToSPS && sps->getUseDualITree())
        {
          if (picHeader->getMinQTSize(I_SLICE, CHANNEL_TYPE_CHROMA) != sps->getMinQTSize(I_SLICE, CHANNEL_TYPE_CHROMA) ||
              picHeader->getMaxMTTHierarchyDepth(I_SLICE, CHANNEL_TYPE_CHROMA) != sps->getMaxMTTHierarchyDepthIChroma() ||
              picHeader->getMaxBTSize(I_SLICE, CHANNEL_TYPE_CHROMA) != sps->getMaxBTSizeIChroma() ||
              picHeader->getMaxTTSize(I_SLICE, CHANNEL_TYPE_CHROMA) != sps->getMaxTTSizeIChroma()
           )
          {
            identicalToSPS=false;
          }
        }
      }

      if (identicalToSPS)
      {
        picHeader->setSplitConsOverrideFlag(false);
      }
    }

subPictures.clear():清空缓存并存放一个图片的子图片编号、大小和位置

getNumSubPics():设置m_numSubPics,已使用的子图片数量,必须与SPS相匹配。默认设置为0.       software_manual里有相关名词解释。

第一个if语句:看vps参数,得到m_generalLayerIdx,代表设置的分层层数。由layerId的值决定,最大64.

xPicInitHashME():初始化m_uiBlkSize,m_uiNumBlk并设置为0.

第二个if语句(2545~2640):查看是否使用AMaxBT(Adaptive maximal BT-size)这个技术,默认都使用。再看是什么帧.B,P帧有一个if语句,i帧是另一个if语句

memset用法详解(转)_luxuejuncarl的博客-CSDN博客

两个memset:初始化m_uiBlkSize,m_uiNumBlk并设置为0.Blk(BLOCK),

identicalToSPS:因为此时设置的全为I帧,所以帧内预测。这个参数也设置为true。

getPicIntraSliceAllowedFlag():slice帧内的一个标志。

maxBTSize[3]:允许的二叉树根节点最大尺寸.// 0: I slice luma; 1: P/B slice; 2: I slice chroma

if语句(picHeader->getMaxBTSize(I_SLICE) != sps->getMaxBTSizeI()):如果从图片头信息中得到的maxBTSize和从sps中得到的maxBTSize不同,则将identicalToSPS设置为false。注意这里是getMaxBTSizeI(),得到的是I slice 的亮度分量的maxBTSize

getUseDualITree():dualtree(Enables or disables the use of separate QTBT trees for intra slice luma and chroma channel types.),即亮色度具有不同的编码树结构

if语句(picHeader->getMaxBTSize(I_SLICE, CHANNEL_TYPE_CHROMA) != sps->getMaxBTSizeIChroma()):如果从图片头信息中得到的maxBTSize和从sps中得到的maxBTSize不同,则将identicalToSPS设置为false.这里得到的是I slice 的色度分量的maxBTSize。

setSplitConsOverrideFlag():设置m_splitConsOverrideFlag为false。划分受限操控标志,表示现在划分不受限

 //  Slice info. refinement
    if ( (pcSlice->getSliceType() == B_SLICE) && (pcSlice->getNumRefIdx(REF_PIC_LIST_1) == 0) )
    {
      pcSlice->setSliceType ( P_SLICE );
    }

    xUpdateRasInit( pcSlice );

    if (pcSlice->getPendingRasInit() || pcSlice->isIRAP())
    {
      // this ensures that independently encoded bitstream chunks can be combined to bit-equal
      pcSlice->setEncCABACTableIdx( pcSlice->getSliceType() );
    }
    else
    {
      pcSlice->setEncCABACTableIdx( m_pcSliceEncoder->getEncCABACTableIdx() );
    }

    if (pcSlice->getSliceType() == B_SLICE)
    {
      bool bLowDelay = true;
      int  iCurrPOC  = pcSlice->getPOC();
      int iRefIdx = 0;

      for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_0) && bLowDelay; iRefIdx++)
      {
        if ( pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx)->getPOC() > iCurrPOC )
        {
          bLowDelay = false;
        }
      }
      for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1) && bLowDelay; iRefIdx++)
      {
        if ( pcSlice->getRefPic(REF_PIC_LIST_1, iRefIdx)->getPOC() > iCurrPOC )
        {
          bLowDelay = false;
        }
      }

      pcSlice->setCheckLDC(bLowDelay);
    }
    else
    {
      pcSlice->setCheckLDC(true);
    }

第一个if语句:修正slice的类型,如果检验为B slice且无参考帧列表1,则修正为P slice

xUpdateRasInit():设置m_lastRasPoc和slice的m_pendingRasInit。m_lastRasPoc表示按编码顺序之前最近的IRAP帧的POC,包括自身。m_pendingRasInit和下面的if分支有关。

如果当前slice的poc序号大于m_lastRasPoc,代表当前不是I帧,则把m_pendingRasInit设为true。否则m_lastRasPoc设为当前帧的poc序号。

第二个if语句:如果m_pendingRasInit为true或当前帧为i帧,则执行setEncCABACTableIdx()。

setEncCABACTableIdx():好像是关于自适应算术编码的一个确保机制,之后再修改

第三个if语句:与low _delay模式有关,之后再看

    pcSlice->setRefPOCList();

    pcSlice->setList1IdxToList0Idx();

    if (m_pcEncLib->getTMVPModeId() == 2)
    {
      if (iGOPid == 0) // first picture in SOP (i.e. forward B)
      {
        picHeader->setEnableTMVPFlag(0);
      }
      else
      {
        // Note: pcSlice->getColFromL0Flag() is assumed to be always 0 and getcolRefIdx() is always 0.
        picHeader->setEnableTMVPFlag(1);
      }
    }
    else if (m_pcEncLib->getTMVPModeId() == 1)
    {
      picHeader->setEnableTMVPFlag(1);
    }
    else
    {
      picHeader->setEnableTMVPFlag(0);
    }

    // disable TMVP when current picture is the only ref picture
    if (pcSlice->isIRAP() && pcSlice->getSPS()->getIBCFlag())
    {
      picHeader->setEnableTMVPFlag(0);//当前图片是唯一的参考图片时禁用TMVP
    }

    if( pcSlice->getSliceType() != I_SLICE && picHeader->getEnableTMVPFlag() )
    {
      int colRefIdxL0 = -1, colRefIdxL1 = -1;

      for( int refIdx = 0; refIdx < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); refIdx++ )
      {
        CHECK( pcSlice->getRefPic( REF_PIC_LIST_0, refIdx )->unscaledPic == nullptr, "unscaledPic is not set for L0 reference picture" );

        if( pcSlice->getRefPic( REF_PIC_LIST_0, refIdx )->isRefScaled( pcSlice->getPPS() ) == false )
        {
          colRefIdxL0 = refIdx;
          break;
        }
      }

      if( pcSlice->getSliceType() == B_SLICE )
      {
        for( int refIdx = 0; refIdx < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); refIdx++ )
        {
          CHECK( pcSlice->getRefPic( REF_PIC_LIST_1, refIdx )->unscaledPic == nullptr, "unscaledPic is not set for L1 reference picture" );

          if( pcSlice->getRefPic( REF_PIC_LIST_1, refIdx )->isRefScaled( pcSlice->getPPS() ) == false )
          {
            colRefIdxL1 = refIdx;
            break;
          }
        }
      }

      if( colRefIdxL0 >= 0 && colRefIdxL1 >= 0 )
      {
        const Picture *refPicL0 = pcSlice->getRefPic( REF_PIC_LIST_0, colRefIdxL0 );
        if( !refPicL0->slices.size() )
        {
          refPicL0 = refPicL0->unscaledPic;
        }

        const Picture *refPicL1 = pcSlice->getRefPic( REF_PIC_LIST_1, colRefIdxL1 );
        if( !refPicL1->slices.size() )
        {
          refPicL1 = refPicL1->unscaledPic;
        }

        CHECK( !refPicL0->slices.size(), "Wrong L0 reference picture" );
        CHECK( !refPicL1->slices.size(), "Wrong L1 reference picture" );

        const uint32_t uiColFromL0 = refPicL0->slices[0]->getSliceQp() > refPicL1->slices[0]->getSliceQp();
        picHeader->setPicColFromL0Flag( uiColFromL0 );
        pcSlice->setColFromL0Flag( uiColFromL0 );
        pcSlice->setColRefIdx( uiColFromL0 ? colRefIdxL0 : colRefIdxL1 );
        picHeader->setColRefIdx( uiColFromL0 ? colRefIdxL0 : colRefIdxL1 );
      }
      else if( colRefIdxL0 < 0 && colRefIdxL1 >= 0 )
      {
        picHeader->setPicColFromL0Flag( false );
        pcSlice->setColFromL0Flag( false );
        pcSlice->setColRefIdx( colRefIdxL1 );
        picHeader->setColRefIdx( colRefIdxL1 );
      }
      else if( colRefIdxL0 >= 0 && colRefIdxL1 < 0 )
      {
        picHeader->setPicColFromL0Flag( true );
        pcSlice->setColFromL0Flag( true );
        pcSlice->setColRefIdx( colRefIdxL0 );
        picHeader->setColRefIdx( colRefIdxL0 );
      }
      else
      {
        picHeader->setEnableTMVPFlag( 0 );
      }
    }

setRefPOCList():设置slice的m_aiRefPOCList,表示参考帧列表中对应帧的POC。

几个函数解释(在 B 帧时记得验证一下)_青椒鸡汤的博客-CSDN博客

setList1IdxToList0Idx():设置slice的m_list1IdxToList0Idx,含义是RPL1的帧如果同时存在RPL0中,则为帧在RPL0中的Index,否则为-1。等后面再验证

第一个和第二个if分支:设置PictureHeader的m_enableTMVPFlag,表示是否开启TMVP。默认设置sbTMVP = 1.

 setEnableTMVPFlag():设置m_enableTMVPFlag,是否启用时间运动矢量预测

 if( pcSlice->getSliceType() != I_SLICE:进行有关TMVP的非I帧的设置,没仔细看

#if GDR_ENABLED
    PicHeader *picHeader = new PicHeader;
    *picHeader = *pcPic->cs->picHeader;
    pcSlice->scaleRefPicList(scaledRefPic, picHeader, m_pcEncLib->getApss(), picHeader->getLmcsAPS(), picHeader->getScalingListAPS(), false);
    picHeader = pcPic->cs->picHeader;
#else
    pcSlice->scaleRefPicList( scaledRefPic, pcPic->cs->picHeader, m_pcEncLib->getApss(), picHeader->getLmcsAPS(), picHeader->getScalingListAPS(), false );
#endif

    // set adaptive search range for non-intra-slices
    if (m_pcCfg->getUseASR() && !pcSlice->isIntra())
    {
      m_pcSliceEncoder->setSearchRange(pcSlice);//如果开启ASR,设置运动搜索范围
    }

    bool bGPBcheck=false;//为true表示RPL0和RPL1相同
    if ( pcSlice->getSliceType() == B_SLICE)
    {
      if ( pcSlice->getNumRefIdx(RefPicList( 0 ) ) == pcSlice->getNumRefIdx(RefPicList( 1 ) ) )
      {
        bGPBcheck=true;
        int i;
        for ( i=0; i < pcSlice->getNumRefIdx(RefPicList( 1 ) ); i++ )
        {
          if ( pcSlice->getRefPOC(RefPicList(1), i) != pcSlice->getRefPOC(RefPicList(0), i) )
          {
            bGPBcheck=false;
            break;
          }
        }
      }
    }
    if(bGPBcheck)
    {
      picHeader->setMvdL1ZeroFlag(true);
    }
    else
    {
      picHeader->setMvdL1ZeroFlag(false);
    }

    if ( pcSlice->getSPS()->getUseSMVD() && pcSlice->getCheckLDC() == false
      && picHeader->getMvdL1ZeroFlag() == false
      )
    {
      int currPOC = pcSlice->getPOC();

      int forwardPOC = currPOC;
      int backwardPOC = currPOC;
      int ref = 0, refIdx0 = -1, refIdx1 = -1;

      // search nearest forward POC in List 0
      for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); ref++ )
      {
        int poc = pcSlice->getRefPic( REF_PIC_LIST_0, ref )->getPOC();
        const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_0, ref)->longTerm;
        if ( poc < currPOC && (poc > forwardPOC || refIdx0 == -1) && !isRefLongTerm )
        {
          forwardPOC = poc;
          refIdx0 = ref;
        }
      }

      // search nearest backward POC in List 1
      for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); ref++ )
      {
        int poc = pcSlice->getRefPic( REF_PIC_LIST_1, ref )->getPOC();
        const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_1, ref)->longTerm;
        if ( poc > currPOC && (poc < backwardPOC || refIdx1 == -1) && !isRefLongTerm )
        {
          backwardPOC = poc;
          refIdx1 = ref;
        }
      }

      if ( !(forwardPOC < currPOC && backwardPOC > currPOC) )
      {
        forwardPOC = currPOC;
        backwardPOC = currPOC;
        refIdx0 = -1;
        refIdx1 = -1;

        // search nearest backward POC in List 0
        for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); ref++ )
        {
          int poc = pcSlice->getRefPic( REF_PIC_LIST_0, ref )->getPOC();
          const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_0, ref)->longTerm;
          if ( poc > currPOC && (poc < backwardPOC || refIdx0 == -1) && !isRefLongTerm )
          {
            backwardPOC = poc;
            refIdx0 = ref;
          }
        }

        // search nearest forward POC in List 1
        for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); ref++ )
        {
          int poc = pcSlice->getRefPic( REF_PIC_LIST_1, ref )->getPOC();
          const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_1, ref)->longTerm;
          if ( poc < currPOC && (poc > forwardPOC || refIdx1 == -1) && !isRefLongTerm )
          {
            forwardPOC = poc;
            refIdx1 = ref;
          }
        }
      }

      if ( forwardPOC < currPOC && backwardPOC > currPOC )
      {
        pcSlice->setBiDirPred( true, refIdx0, refIdx1 );
      }
      else
      {
        pcSlice->setBiDirPred( false, -1, -1 );
      }
    }
    else
    {
      pcSlice->setBiDirPred( false, -1, -1 );
    }


if( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL && m_pcCfg->getRprRASLtoolSwitch() )
    {
      pcSlice->setDisableLmChromaCheck( true );
      picHeader->setDmvrDisabledFlag( true );
      xUpdateRPRtmvp( picHeader, pcSlice );
    }

scaleRefPicList():如果参考帧的分辨率和编码帧的不一致,则要进行缩放

getUseASR():adaptive search range,自适应搜索范围,默认关闭

 第一个if语句:当ASR开启且不是I帧时,设置运动搜索范围

第二个if语句:查验当为B 帧时,参考帧列表0和1是否相同,相同则bGPBcheck=true

if(bGPBcheck):如果参考帧列表0和1相同,设置PictureHeader的m_mvdL1ZeroFlag,为true表示不用传输RPL1的MVD

第三个if分支:设置是否开启SMVD,以及前后向参考帧在RPL中的Index。SMVD默认关闭

最后一个if语句:设置一些标志

【八】 H.266/vvc中对称MVD模式(SMVD)_Cohen_ina的博客-CSDN博客

H.266/VVC帧间预测总结_涵小呆的博客-CSDN博客_vvc帧间

double lambda            = 0.0;//定义lambda,并且赋初值
    int actualHeadBits       = 0;//写入码流中的slice header的比特数(可能包括picture header)
    int actualTotalBits      = 0;//写入码流中的总比特数
    int estimatedBits        = 0;//预测比特数
    int tmpBitsBeforeWriting = 0;

    xPicInitRateControl(estimatedBits, iGOPid, lambda, pcPic, pcSlice);//初始化码率控制

    uint32_t uiNumSliceSegments = 1;

    pcSlice->setDefaultClpRng(*pcSlice->getSPS());//设置slice的m_clpRngs,有关于clip

    // Allocate some coders, now the number of tiles are known.
    const uint32_t numberOfCtusInFrame = pcPic->cs->pcv->sizeInCtus;//一帧内CTU的数量
    const int numSubstreamsColumns = pcSlice->getPPS()->getNumTileColumns();//一般为1
    const int numSubstreamRows     = pcSlice->getSPS()->getEntropyCodingSyncEnabledFlag() ? pcPic->cs->pcv->heightInCtus : (pcSlice->getPPS()->getNumTileRows());//一般为1
    const int numSubstreams        = std::max<int> (numSubstreamRows * numSubstreamsColumns, (int) pcPic->cs->pps->getNumSlicesInPic());//一帧内substreams的数量,一般为1
    std::vector<OutputBitstream> substreamsOut(numSubstreams);//substreams的输出buffer

可参考  HEVC码率控制代码追踪(一)(HEVC code tracing-Rate control)_yang-彧的博客-CSDN博客

actualTotalBits:写入码流中的总比特数

actualHeadBits:写入码流中的slice header的比特数(可能包括picture header)

xPicInitRateControl:初始化码率控制,虽然cfg中默认不开,但还是提一下方便以后找

uiNumSliceSegments:slices的数量

setDefaultClpRng:设置slice的m_clpRngs,有关于clip

一个slice会形成一个stream,然后封装在VCL-NALU中。在形成stream之前会先形成substreams然后再合成stream。如何划分substreams和slice划分、tile划分、是否开启WaveFrontSynchro都有关系

getNumTileColumns():得到tile单元的列数

getEntropyCodingSyncEnabledFlag():WPP的标志。默认关闭


#if ENABLE_QPA
    pcPic->m_uEnerHpCtu.resize (numberOfCtusInFrame);
    pcPic->m_iOffsetCtu.resize (numberOfCtusInFrame);
#if ENABLE_QPA_SUB_CTU
    if (pcSlice->getPPS()->getUseDQP() && pcSlice->getCuQpDeltaSubdiv() > 0)
    {
      const PreCalcValues &pcv = *pcPic->cs->pcv;
      const unsigned   mtsLog2 = (unsigned)floorLog2(std::min (pcPic->cs->sps->getMaxTbSize(), pcv.maxCUWidth));
      pcPic->m_subCtuQP.resize ((pcv.maxCUWidth >> mtsLog2) * (pcv.maxCUHeight >> mtsLog2));
    }
#endif
#endif
    if (pcSlice->getSPS()->getSAOEnabledFlag())
    {
      pcPic->resizeSAO( numberOfCtusInFrame, 0 );
      pcPic->resizeSAO( numberOfCtusInFrame, 1 );
    }

    // it is used for signalling during CTU mode decision, i.e. before ALF processing
    if( pcSlice->getSPS()->getALFEnabledFlag() )
    {
      pcPic->resizeAlfCtuEnableFlag( numberOfCtusInFrame );
      pcPic->resizeAlfCtuAlternative( numberOfCtusInFrame );
      pcPic->resizeAlfCtbFilterIndex(numberOfCtusInFrame);
    }

    bool decPic = false;
    bool encPic = false;
    // test if we can skip the picture entirely or decode instead of encoding
    trySkipOrDecodePicture( decPic, encPic, *m_pcCfg, pcPic, m_pcEncLib->getApsMap() );

这几个函数是关于一些新技术还有SAO(采样点自适应偏移),ALF(环路滤波)的标志等设定

pcPic->cs->slice = pcSlice; // please keep this
#if ENABLE_QPA
    if (pcSlice->getPPS()->getSliceChromaQpFlag() && CS::isDualITree (*pcSlice->getPic()->cs) && !m_pcCfg->getUsePerceptQPA() && (m_pcCfg->getSliceChromaOffsetQpPeriodicity() == 0))
#else
    if (pcSlice->getPPS()->getSliceChromaQpFlag() && CS::isDualITree (*pcSlice->getPic()->cs))
#endif
    {
      // overwrite chroma qp offset for dual tree
      pcSlice->setSliceChromaQpDelta(COMPONENT_Cb, m_pcCfg->getChromaCbQpOffsetDualTree());
      pcSlice->setSliceChromaQpDelta(COMPONENT_Cr, m_pcCfg->getChromaCrQpOffsetDualTree());
      if (pcSlice->getSPS()->getJointCbCrEnabledFlag())
      {
        pcSlice->setSliceChromaQpDelta(JOINT_CbCr, m_pcCfg->getChromaCbCrQpOffsetDualTree());
      }
      m_pcSliceEncoder->setUpLambda(pcSlice, pcSlice->getLambdas()[0], pcSlice->getSliceQp());
    }

    xPicInitLMCS(pcPic, picHeader, pcSlice);//进行LMCS的初始化

    if( pcSlice->getSPS()->getScalingListFlag() && m_pcCfg->getUseScalingListId() == SCALING_LIST_FILE_READ )
    {
      picHeader->setExplicitScalingListEnabledFlag( true );
      pcSlice->setExplicitScalingListUsed( true );

      int apsId = std::min<int>( 7, m_pcEncLib->getVPS() == nullptr ? 0 : m_pcEncLib->getVPS()->getGeneralLayerIdx( m_pcEncLib->getLayerId() ) );
      picHeader->setScalingListAPSId( apsId );

      ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
      APS*  scalingListAPS = apsMap->getPS( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
      assert( scalingListAPS != NULL );
      picHeader->setScalingListAPS( scalingListAPS );
    }

    pcPic->cs->picHeader->setPic(pcPic);//设置变量m_valid,表明图片头信息是否正确
    pcPic->cs->picHeader->setValid();//设置指针变量 m_pcPic,接收指向图片的指针变量pcPic
    if(pcPic->cs->sps->getFpelMmvdEnabledFlag())
    {
      // cannot set ph_fpel_mmvd_enabled_flag at slice level - need new picture-level version of checkDisFracMmvd algorithm?
      // m_pcSliceEncoder->checkDisFracMmvd( pcPic, 0, numberOfCtusInFrame );
      bool useIntegerMVD = (pcPic->lwidth()*pcPic->lheight() > 1920 * 1080);
      pcPic->cs->picHeader->setDisFracMMVD( useIntegerMVD );
    }
    if (pcSlice->getSPS()->getJointCbCrEnabledFlag())
    {
      m_pcSliceEncoder->setJointCbCrModes(*pcPic->cs, Position(0, 0), pcPic->cs->area.lumaSize());
    }
LMCSEnable:Enables or disables the use of LMCS (luma mapping with chroma scaling).
 xPicInitLMCS():初始化LMCS
第一个if语句:是否使用缩放列表(ScalingList),默认设置为0
getFpelMmvdEnabledFlag():设置m_fpelMmvdEnabledFlag标志,表明是否开启MMVD( merge mode with motion vector difference
第二个if语句: 推测如果图片的级别(level)不够,会设置useIntegerMVD为false,不使用MMVD
getJointCbCrEnabledFlag():JointCbCr (the joint coding of chroma residuals)色度残差联合编码的标志
  if (!pcSlice->getSPS()->getSpsRangeExtension().getReverseLastSigCoeffEnabledFlag() || pcSlice->getSliceQp() > 12)
    {
      pcSlice->setReverseLastSigCoeffFlag(false);
    }
    else
    {
      /*for RA serial and parallel alignment start*/
      if (m_pcCfg->getIntraPeriod() > 1)
      {
        if (pcSlice->isIntra())
        {
          m_cnt_right_bottom = 0;
        }
        if ((pocCurr % m_pcCfg->getIntraPeriod()) <= m_pcCfg->getGOPSize() && iGOPid == 0 && !pcSlice->isIntra())
        {
          m_cnt_right_bottom = m_cnt_right_bottom_i;
        }
      }
      /*for RA serial and parallel alignment end*/
      pcSlice->setReverseLastSigCoeffFlag(m_cnt_right_bottom >= 0);
    }

setReverseLastSigCoeffFlag():设置m_reverseLastSigCoeffFlag,默认为false。

ReverseLastSigCoeff        When true, enable reverse last signifificant coeffificient postion in RRC.
if( encPic )
    // now compress (trial encode) the various slice segments (slices, and dependent slices)
    {
      DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "poc", pocCurr ) ) );
      const std::vector<uint16_t> sliceLosslessArray = *(m_pcCfg->getSliceLosslessArray());
      bool mixedLossyLossless = m_pcCfg->getMixedLossyLossless();
      if (m_pcCfg->getCostMode() == COST_LOSSLESS_CODING)
      {
        pcPic->fillSliceLossyLosslessArray(sliceLosslessArray, mixedLossyLossless);
      }

      for(uint32_t sliceIdx = 0; sliceIdx < pcPic->cs->pps->getNumSlicesInPic(); sliceIdx++ )
      {
        pcSlice->setSliceMap( pcPic->cs->pps->getSliceMap( sliceIdx ) );
        if (pcSlice->getSPS()->getSpsRangeExtension().getTSRCRicePresentFlag() && (pcPic->cs->pps->getNumSlicesInPic() == 1))
        {
          if (!pcSlice->isIntra())
          {
            int nextRice = 1;

            if (m_preIPOC < pocCurr)
            {
              for (int idx = 0; idx < MAX_TSRC_RICE; idx++)
              {
                m_riceBit[idx][0] = m_riceBit[idx][1];
              }
              m_preQP[0] = m_preQP[1];
              m_preIPOC = MAX_INT;
            }

            if (m_preQP[0] != pcSlice->getSliceQp())
            {
              m_riceBit[pcSlice->get_tsrc_index()][0] = (int) (m_riceBit[pcSlice->get_tsrc_index()][0] * 9 / 10);
            }

            for (int idx = 2; idx < 9; idx++)
            {
              if (m_riceBit[idx - 2][0] > m_riceBit[idx - 1][0])
              {
                nextRice = idx;
              }
              else
              {
                m_riceBit[idx - 1][0] = m_riceBit[idx - 2][0];
              }
              m_riceBit[idx - 2][0] = 0;
            }
            m_riceBit[7][0] = 0;
            pcSlice->set_tsrc_index(nextRice - 1);
          }
          else
          {
            m_preIPOC = pocCurr;
            m_preQP[0] = MAX_INT;          
            m_preQP[1] = pcSlice->getSliceQp();
            for (int idx = 0; idx < MAX_TSRC_RICE; idx++)
            {
              m_riceBit[idx][0] = 0;
            }
          }
          for (int idx = 0; idx < MAX_TSRC_RICE; idx++)
          {
             pcSlice->setRiceBit(idx, m_riceBit[idx][0]);
          }
        }
        if( pcPic->cs->pps->getRectSliceFlag() )
        {
          Position firstCtu;
          firstCtu.x = pcSlice->getFirstCtuRsAddrInSlice() % pcPic->cs->pps->getPicWidthInCtu();//SLICE中第一个CTU的位置
          firstCtu.y = pcSlice->getFirstCtuRsAddrInSlice() / pcPic->cs->pps->getPicWidthInCtu();
          int subPicIdx = NOT_VALID;//为后面check函数初始化赋值
          for( int sp = 0; sp < pcPic->cs->pps->getNumSubPics(); sp++ )
          {
            if( pcPic->cs->pps->getSubPic( sp ).containsCtu( firstCtu ) )
            {
              subPicIdx = sp;
              break;
            }
          }
          CHECK( subPicIdx == NOT_VALID, "Sub-picture was not found" );

          pcSlice->setSliceSubPicId( pcPic->cs->pps->getSubPic( subPicIdx ).getSubPicID() );
        }
       

 encPic:encode picture ,在前面的trySkipOrDecodePicture()变成了true.

现在压缩(试编码)各种片段(片和相关片)
getSliceLosslessArray():返回一个无损编码片的数组m_sliceLosslessArray
getMixedLossyLossless():启用混合有损/无损编码,默认为false
getCostMode():COSTMODE是一个枚举函数,表示编码方式。
默认为COST_STANDARD_LOSSY   
for循环:把图片中的每一个slice,以光栅扫描的顺序,扫描slice中的每一个CTU,得到每个ctu的地址。
getTSRCRicePresentFlag():设置m_tsrcRicePresentFlag,默认为false。 TSRCRicePresent 技术
getRectSliceFlag():矩形模式slice的标志。

 列表中包含矩形模式slice下左上角的CTU RS地址,右下角的CTU RS地址。RS代表Rectangular slice。

getPicWidthInCtu():得到m_picWidthInCtu,应该是一帧图像一行包含CTU个数。在encodectus()函数中可体现出

firstCtu.x:得到矩形模式SLICE中第一个CTU的X地址

推荐看VVC正式标准里第21页,有对subicture的更准确解释.一个subpicture可由一个或多个slice组成
getSubPic():m_subPics[idx]是按顺序存储子图片数据的一个表,idx为调用对应子图片的编号
containsCtu():m_subPicCtuTopLeftX,CTU结构中一个子图片的左上角CTU的水平位置。同理可得m_subPicCtuTopLeftY。如果这个CTU的x,y在这个子图宽度,长度范围内,则返回一个true
for循环:遍历每一个子图片,检测每个子图中的第一个CTU是否在子图的范围里,如果在,则把当前序号即为这个子图的索引号。
否则运行check,显示错误
 if (pcPic->cs->sps->getUseLmcs())
        {
          pcSlice->setLmcsEnabledFlag(picHeader->getLmcsEnabledFlag());
          if (pcSlice->getSliceType() == I_SLICE)
          {
            //reshape original signal
            if(m_pcCfg->getGopBasedTemporalFilterEnabled())
            {
              pcPic->getOrigBuf().copyFrom(pcPic->getFilteredOrigBuf());
            }
            else
            {
              pcPic->getOrigBuf().copyFrom(pcPic->getTrueOrigBuf());
            }

            if (pcSlice->getLmcsEnabledFlag())
            {
              pcPic->getOrigBuf(COMPONENT_Y).rspSignal(m_pcReshaper->getFwdLUT());
              m_pcReshaper->setSrcReshaped(true);
              m_pcReshaper->setRecReshaped(true);
            }
            else
            {
              m_pcReshaper->setSrcReshaped(false);
              m_pcReshaper->setRecReshaped(false);
            }
          }
        }

getUseLmcs():使用LMCS

LMCS设置一些参数,先跳过

bool isLossless = false; //关闭无损编码
        if (m_pcCfg->getCostMode() == COST_LOSSLESS_CODING)
        {
          isLossless = pcPic->losslessSlice(sliceIdx);
        }
        m_pcSliceEncoder->setLosslessSlice(pcPic, isLossless);

        if( pcSlice->getSliceType() != I_SLICE && pcSlice->getRefPic( REF_PIC_LIST_0, 0 )->subPictures.size() > 1 )
        {
          clipMv = clipMvInSubpic;
          m_pcEncLib->getInterSearch()->setClipMvInSubPic(true);
        }
        else
        {
          clipMv = clipMvInPic;
          m_pcEncLib->getInterSearch()->setClipMvInSubPic(false);
        }

        m_pcSliceEncoder->precompressSlice( pcPic );
        m_pcSliceEncoder->compressSlice   ( pcPic, false, false );

前两个if语句:与无损编码设置有关,跳过

precompressSlice():检查deltaQP,如果还没使用,直接return

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

compressSlice():进入compressSlice()

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值