H.266/VVC-VTM code learning calculation and implementation of RDcost in 26-VTM λ Setting of

H.266/VVC column transmission

Previous: H.266/VVC-VTM code learning calculation and implementation of RDcost in 25-VTM λ Setting of (I)
Next: in continuous creation

preface

VTM is the reference software of H.266/VVC video coding standard. The study of VTM code explains the detailed standard specifications and details of VVC coding standard to researchers.

This paper is the author's learning record of VTM code. It was written during the period when the author first came into contact with VVC. During this period, many concepts and theoretical frameworks are still immature. If there are errors in the text, criticism and correction are welcome, and the majority of video coding learners are also welcome to communicate and make common progress.

For the download and compilation of VTM code, please refer to the blog:
[video coding learning] H.266/VVC reference software VTM configuration operation (VTM-6.0 version)

1, Introduction

Rate distortion optimization (RDO) is one of the core theories of video coding. The goal of conventional video coding is to make the encoded video stream have a good trade-off between bandwidth occupation (represented by rate) and image quality (represented by distortion). rate distortion (RD) cost is an index used to measure the balance between bit rate and distortion of video stream.

The previous blog introduced calculating RD cost and λ \lambda λ The main functions can be seen λ \lambda λ It is of great significance in the calculation of RD cost. λ \lambda λ It is not only a common parameter in the calculation of RD cost, but also a key factor to equalize distortion and bit rate in the coding process. Read VTM λ \lambda λ Can have a clearer understanding and grasp of the VVC coding process as a whole. Based on this, the author decided to use more space to introduce the relevant content in the code.

This blog will continue to focus on VTM code about λ \lambda λ Set the part of the RDO process λ \lambda λ Explain the relevant codes.

2, Code explanation

1. In initencslice() function λ \lambda λ Settings for

  // Get QP of current frame with double precision
  dQP = m_pcCfg->getQPForPicture(iGOPid, rpcSlice);
  int iQP;
  double dOrigQP = dQP;
  // pre-compute lambda and QP values for all possible QP candidates
  // Pre calculated for all possible candidate QPS λ And QP values
  // getDeltaQpRD() gets DeltaQpRD (set in cfg file, default = 0)
  for ( int iDQpIdx = 0; iDQpIdx < 2 * m_pcCfg->getDeltaQpRD() + 1; iDQpIdx++ )
  {
    // compute QP value
    // Calculate the current QP value according to the QP of picture level and DeltaQpRD
    dQP = dOrigQP + ((iDQpIdx+1)>>1)*(iDQpIdx%2 ? -1 : 1);
    // compute lambda value
    // calculation λ Value of
#if SHARP_LUMA_DELTA_QP / / enabled by default
	// Call calculateLambda calculation λ
    dLambda = calculateLambda (rpcSlice, iGOPid, dQP, dQP, iQP);
#else
    dLambda = initializeLambda (rpcSlice, iGOPid, int (dQP + 0.5), dQP);
    iQP = Clip3 (-rpcSlice->getSPS()->getQpBDOffset (CHANNEL_TYPE_LUMA), MAX_QP, int (dQP + 0.5));
#endif
	// The calculated λ And QP are stored in the array
    m_vdRdPicLambda[iDQpIdx] = dLambda;
    m_vdRdPicQp    [iDQpIdx] = dQP;
    m_viRdPicQp    [iDQpIdx] = iQP;
  }

The above part of the code is located in the initEncSlice function, that is, this part of the code is executed during initialization before entering the slice level encoding phase.

The getDeltaQpRD() function in the for loop condition judgment returns DeltaQpRD, that is, the maximum absolute value of slice level delta QP. Here are the basic steps of the code:

  1. During loop execution, the value range of iDQpIdx is the minimum value of 0 and the maximum value of 2*DeltaQpRD
  2. Calculate the QP value of the current cycle
  3. Call the calculateLambda function to calculate the corresponding QP value obtained in the previous step λ
  4. Sum QP value and λ Save to array

The calculation of the second step is as follows:
∣ Δ Q P ∣ = ( i D Q p I d x + 1 ) > > 1 |\Delta QP| = (iDQpIdx+1)>>1 ∣ΔQP∣=(iDQpIdx+1)>>1
Δ Q P = { ∣ Δ Q P ∣ , i D Q p I d x % 2 = 0 − ∣ Δ Q P ∣ , i D Q p I d x % 2 = 1 \Delta QP=\begin{cases} |\Delta QP| &, iDQpIdx\% 2=0 \\ -|\Delta QP| &, iDQpIdx\% 2=1 \end{cases} ΔQP={∣ΔQP∣−∣ΔQP∣​,iDQpIdx%2=0,iDQpIdx%2=1​
Q P = Q P p i c + Δ Q P QP = QP_{pic}+\Delta QP QP=QPpic​+ΔQP

That is, during the execution of the loop Δ Q P \Delta QP Δ The absolute value of QP is from small to large, and the sign is positive and negative alternately.

2. When using rate control λ \lambda λ Adjusted code

This part of the code is located in the encodeCtus function of the EncSlice.cpp file and inside the loop that traverses each CTU in the processing slice. Adjust according to current QP λ \lambda λ Value of.

It should be noted that this part of the code is only executed when rate control (RC) is set. Readers who only focus on VTM main framework can skip this section.

    // Storage source λ Value of
    const double oldLambda = pRdCost->getLambda();
    // If rate control is used
    if ( pCfg->getUseRateCtrl() )
    {
      // Set sliceQP to estQP
      int estQP        = pcSlice->getSliceQp();
      // Initialize estLambda and bpp to - 1
      double estLambda = -1.0;
      double bpp       = -1.0;

      // Using sliceQP directly
      if( ( pcPic->slices[0]->isIRAP() && pCfg->getForceIntraQP() ) || !pCfg->getLCULevelRC() )
      {
        estQP = pcSlice->getSliceQp();
      }
      // In other cases
      else
      {
        // Calculate the target bpp of LCU first
        bpp = pRateCtrl->getRCPic()->getLCUTargetBpp(pcSlice->isIRAP());
        // If the current frame is I frame
        if ( pcPic->slices[0]->isIntra())
        {
          // Calculate the QP and QP of the current slice based on bpp λ
          estLambda = pRateCtrl->getRCPic()->getLCUEstLambdaAndQP(bpp, pcSlice->getSliceQp(), &estQP);
        }
        // If the current frame is not an I frame
        else
        {
          // Calculated according to the target bpp of LCU λ
          estLambda = pRateCtrl->getRCPic()->getLCUEstLambda( bpp );
          // according to λ Get QP
          estQP     = pRateCtrl->getRCPic()->getLCUEstQP    ( estLambda, pcSlice->getSliceQp() );
        }

        // Normalize QP to fixed interval
        estQP     = Clip3( -pcSlice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, estQP );

        // set up λ
        pRdCost->setLambda(estLambda, pcSlice->getSPS()->getBitDepths());
#if WCG_EXT
        // Will get λ Save as unadjusted λ
        pRdCost->saveUnadjustedLambda();
#endif
        // Each component is processed
        for (uint32_t compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++)
        {
          const ComponentID compID = ComponentID(compIdx);
          // The offset of chroma component QP is obtained
          int chromaQPOffset = pcSlice->getPPS()->getQpOffset(compID) + pcSlice->getSliceChromaQpDelta(compID);
          // The QP value of chroma component is obtained
          int qpc = pcSlice->getSPS()->getMappedChromaQpValue(compID, estQP) + chromaQPOffset;
          
          // Calculate weight
          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())
          {
            // If Dependent quantization is used, adjust the weight
            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)
          }
          // Set the weight of D
          m_pcRdCost->setDistortionWeight(compID, tmpWeight);
        }
#if RDOQ_CHROMA_LAMBDA
        // Storage record λ And QP
        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 );
    }

Previous: H.266/VVC-VTM code learning calculation and implementation of RDcost in 25-VTM λ Setting of (I)
Next: in continuous creation

Posted on Fri, 10 Sep 2021 13:12:36 -0400 by chingwaah