VVC/JEM代码学习12:transformNxN

26 篇文章 2 订阅

对残差次数进行量化编码的函数,相比于HEVC,JEM中加入了二次变换,即在第一次主变换又进行第二次变换;此外,还加入了EMT,和DCT2是并列关系,根据相关索引进行选择;

Void TComTrQuant::transformNxN(       TComTU        & rTu,

                                const ComponentID     compID,
                                      Pel          *  pcResidual,//残差;
                                const UInt            uiStride,
                                      TCoeff       *  rpcCoeff,//残差经变换量化后的系数;
#if ADAPTIVE_QP_SELECTION
                                      TCoeff       *  pcArlCoeff,
#endif
                                      TCoeff        & uiAbsSum,
                                const QpParam       & cQP 
#if VCEG_AZ08_KLT_COMMON
                                , Bool useKLT
#endif
                                )
{
  const TComRectangle &rect = rTu.getRect(compID);
  const UInt uiWidth        = rect.width;
  const UInt uiHeight       = rect.height;
  TComDataCU* pcCU          = rTu.getCU();
  const UInt uiAbsPartIdx   = rTu.GetAbsPartIdxTU();
  const UInt uiOrgTrDepth   = rTu.GetTransformDepthRel();

  uiAbsSum=0;//存放残差绝对值的和;

  RDPCMMode rdpcmMode = RDPCM_OFF;
  rdpcmNxN( rTu, compID, pcResidual, uiStride, cQP, rpcCoeff, uiAbsSum, rdpcmMode );

  if (rdpcmMode == RDPCM_OFF)
  {
    uiAbsSum = 0;
    //transform and quantise
    if(pcCU->getCUTransquantBypass(uiAbsPartIdx))//旁路掉变换和量化
    {
      const Bool rotateResidual = rTu.isNonTransformedResidualRotated(compID);
      const UInt uiSizeMinus1   = (uiWidth * uiHeight) - 1;

      for (UInt y = 0, coefficientIndex = 0; y<uiHeight; y++)
      {
        for (UInt x = 0; x<uiWidth; x++, coefficientIndex++)
        {
          const Pel currentSample = pcResidual[(y * uiStride) + x];

          rpcCoeff[rotateResidual ? (uiSizeMinus1 - coefficientIndex) : coefficientIndex] = currentSample;
          uiAbsSum += TCoeff(abs(currentSample));
        }
      }
    }
    else//不旁路变换量化
    {
#if DEBUG_TRANSFORM_AND_QUANTISE
      std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at input to transform\n";
      printBlock(pcResidual, uiWidth, uiHeight, uiStride);
#endif
#if JVET_C0024_QTBT
      assert( (pcCU->getSlice()->getSPS()->getCTUSize() >= uiWidth) );
#else
      assert( (pcCU->getSlice()->getSPS()->getMaxTrSize() >= uiWidth) );
#endif

      if(pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0)//如果跳过变换;
      {
        xTransformSkip( pcResidual, uiStride, m_plTempCoeff, rTu, compID );
      }
      else//不跳过变换
      {
        const Int channelBitDepth=pcCU->getSlice()->getSPS()->getBitDepth(toChannelType(compID));//10;
        xT( channelBitDepth, rTu.useDST(compID), pcResidual, uiStride, m_plTempCoeff, uiWidth, uiHeight, pcCU->getSlice()->getSPS()->getMaxLog2TrDynamicRange(toChannelType(compID)) 
#if COM16_C806_EMT
          , getEmtMode ( rTu, compID )
          , getEmtTrIdx( rTu, compID )
#endif
#if VCEG_AZ08_KLT_COMMON
          , useKLT && (compID == 0)
#endif
          );//执行变换的主函数,也是第一次变换
      }

#if JVET_C0024_QTBT
    Char ucNsstIdx = pcCU->getROTIdx(toChannelType(compID), uiAbsPartIdx) ;//二次变换的索引
    if (ucNsstIdx && uiWidth>=4 && uiHeight>=4
#if  JVET_C0045_C0053_NO_NSST_FOR_TS
      && !pcCU->getTransformSkip(uiAbsPartIdx, compID)
#endif
      )//ucNsstIdx在不等于0的前提下才做二次变换;
#else
      if (pcCU->getROTIdx(uiAbsPartIdx) 
#if  JVET_C0045_C0053_NO_NSST_FOR_TS
        && !pcCU->getTransformSkip(uiAbsPartIdx, compID)
#endif
        )
#endif
      {           
#if JVET_D0120_NSST_IMPROV
        static Int NSST_MATRIX[64];
        const  Int iLog2SbSize   = (uiWidth > 4 && uiHeight > 4) ? 3 : 2;
        const  Int iSbSize       = (uiWidth > 4 && uiHeight > 4) ? 8 : 4;
        const  Int iSubGroupXMax = Clip3(1, 8, (Int)uiWidth ) >> iLog2SbSize;
        const  Int iSubGroupYMax = Clip3(1, 8, (Int)uiHeight) >> iLog2SbSize;
#else
        static Int NSST_MATRIX[16];
        Int iSubGroupXMax = Clip3 (1,16,(Int)( (uiWidth>>2)));
        Int iSubGroupYMax = Clip3 (1,16,(Int)( (uiHeight>>2)));
#endif

        Int iOffSetX = 0;
        Int iOffSetY = 0;
        Int y = 0;
        Int* piCoeffTemp = m_plTempCoeff;
        Int* piNsstTemp = NSST_MATRIX;
#if JVET_D0120_NSST_IMPROV
        Int iString2CopySize = iSbSize*sizeof(Int);
#else
        Int iString2CopySize = 4*sizeof(Int);
#endif
#if VCEG_AZ07_CTX_RESIDUALCODING
#if !JVET_C0024_QTBT
        const UInt uiLog2BlockSize = g_aucConvertToBit[ uiWidth ] + 2;
#endif
#endif
        const UInt uiScanIdx = pcCU->getCoefScanIdx(uiAbsPartIdx, uiWidth, uiHeight, compID);
#if JVET_C0024_QTBT
        const UInt log2BlockWidth  = g_aucConvertToBit[uiWidth]  + MIN_CU_LOG2;
        const UInt log2BlockHeight = g_aucConvertToBit[uiHeight] + MIN_CU_LOG2;
#else
        const UInt log2BlockWidth  = g_aucConvertToBit[uiWidth]  + 2;
        const UInt log2BlockHeight = g_aucConvertToBit[uiHeight] + 2;
#endif
#if VCEG_AZ07_CTX_RESIDUALCODING
#if JVET_D0120_NSST_IMPROV
#if JVET_C0024_QTBT
        const UInt *scan = (log2BlockWidth>=3 && log2BlockHeight>=3) ? g_auiCoefTopLeftDiagScan8x8[log2BlockWidth-3] : g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth    ][ log2BlockHeight    ];
#else
        const UInt *scan = uiLog2BlockSize>3 ? g_auiCoefTopLeftDiagScan8x8[log2BlockWidth-4] : g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth    ][ log2BlockHeight    ];

#endif

  UInt uiIntraMode = pcCU->getIntraDir( toChannelType(compID), uiAbsPartIdx);//得到帧内预测模式;
        if( compID != COMPONENT_Y )
        {
#if JVET_E0062_MULTI_DMS && COM16_C806_LMCHROMA
          if( uiIntraMode == LM_CHROMA_IDX )
          {
            uiIntraMode = PLANAR_IDX;
          }
#if JVET_E0077_ENHANCED_LM
          if (IsLMMode(uiIntraMode))
          {
              uiIntraMode = PLANAR_IDX;
          }

#endif

     }

        assert( uiIntraMode<NUM_INTRA_MODE-1 );
        const Int iNsstCandNum = ( uiIntraMode<=DC_IDX ) ? 3 : 4;//二次变换候选数量,DC和planar和CCLM模式的候选数量为3,其他为4;

#if JVET_C0024_QTBT
        if( iNsstCandNum > ucNsstIdx )
#else
        if( iNsstCandNum > pcCU->getROTIdx(uiAbsPartIdx) )
#endif
        {
#if JVET_D0120_NSST_IMPROV 
#if JVET_C0024_QTBT
          const Int * permut = iSbSize>4 ? g_nsstHyGTPermut8x8[g_NsstLut[uiIntraMode]][ucNsstIdx - 1] : g_nsstHyGTPermut4x4[g_NsstLut[uiIntraMode]][ucNsstIdx - 1];
#else
          const Int * permut = iSbSize>4 ? g_nsstHyGTPermut8x8[g_NsstLut[uiIntraMode]][pcCU->getROTIdx(uiAbsPartIdx) - 1] : g_nsstHyGTPermut4x4[g_NsstLut[uiIntraMode]][pcCU->getROTIdx(uiAbsPartIdx) - 1];
#endif
#endif
          for (Int iSubGroupX = 0; iSubGroupX<iSubGroupXMax; iSubGroupX++)
          {
            for (Int iSubGroupY = 0; iSubGroupY<iSubGroupYMax; iSubGroupY++)
            {
#if JVET_D0120_NSST_IMPROV
              iOffSetX = iSbSize*iSubGroupX;
              iOffSetY = iSbSize*iSubGroupY*uiWidth;
#else
              iOffSetX = 4*iSubGroupX;
              iOffSetY = 4*iSubGroupY*uiWidth;
#endif
              piNsstTemp = NSST_MATRIX;
              piCoeffTemp = m_plTempCoeff+iOffSetX+iOffSetY;

#if JVET_D0120_NSST_IMPROV
              for(  y = 0; y < iSbSize; y++ )
#else
              for(  y = 0; y < 4; y++ )
#endif
              {  
                if( uiIntraMode>DIA_IDX )//垂直方向,即将CoeffTemp转置后复制给NsstTemp;
                {
#if JVET_D0120_NSST_IMPROV
                  if( iSbSize==4 )
                  {
                    piNsstTemp[ 0] = piCoeffTemp[0]; piNsstTemp[ 4] = piCoeffTemp[1];
                    piNsstTemp[ 8] = piCoeffTemp[2]; piNsstTemp[12] = piCoeffTemp[3];
                  }
                  else if( iSbSize==8 )
                  {
                    piNsstTemp[ 0] = piCoeffTemp[0]; piNsstTemp[ 8] = piCoeffTemp[1];
                    piNsstTemp[16] = piCoeffTemp[2]; piNsstTemp[24] = piCoeffTemp[3];
                    piNsstTemp[32] = piCoeffTemp[4]; piNsstTemp[40] = piCoeffTemp[5];
                    piNsstTemp[48] = piCoeffTemp[6]; piNsstTemp[56] = piCoeffTemp[7];
                  }
#else
                  piNsstTemp[ 0] = piCoeffTemp[0]; piNsstTemp[ 4] = piCoeffTemp[1];
                  piNsstTemp[ 8] = piCoeffTemp[2]; piNsstTemp[12] = piCoeffTemp[3];
#endif
                  piNsstTemp ++;
                }
                else//uiIntraMode<=DIA_IDX
                {
                  ::memcpy(piNsstTemp, piCoeffTemp, iString2CopySize); //水平方向直接复制;
#if JVET_D0120_NSST_IMPROV
                  piNsstTemp += iSbSize;
#else
                  piNsstTemp +=4;
#endif
                }
                piCoeffTemp +=uiWidth;
              }

#if JVET_C0024_QTBT
#if JVET_D0120_NSST_IMPROV//NSST是JEM中新加的技术,有两种
              if ( iSbSize>4 )
              {
                FwdNsst8x8( NSST_MATRIX, g_NsstLut[uiIntraMode], ucNsstIdx-1 );//大于等于8x8的TU,使用8x8的NSST
              }
              else
              {
                FwdNsst4x4( NSST_MATRIX, g_NsstLut[uiIntraMode], ucNsstIdx-1 );//4x4的TU,使用4x4的NSST

              }

  piNsstTemp = NSST_MATRIX;
              piCoeffTemp = m_plTempCoeff+iOffSetX+iOffSetY;


#if JVET_D0120_NSST_IMPROV
              for(  y = 0; y < iSbSize*iSbSize; y++ )
#else
              for(  y = 0; y < 16; y++ )
#endif
              {
#if JVET_D0120_NSST_IMPROV 
                piCoeffTemp[scan[y]] = piNsstTemp[permut[y]];
#else
                piCoeffTemp[scan[y]] = piNsstTemp[y];
#endif
              }
            }
          }
        }
      }
#endif
#if VCEG_AZ08_KLT_COMMON
      if (useKLT && (compID == 0))//如果是亮度分量且使用KLT
      {
          TUEntropyCodingParameters codingParameters;
          getTUEntropyCodingParameters(codingParameters, rTu, compID);
          const UInt *scan = codingParameters.scan; 
          reOrderCoeff(m_plTempCoeff, scan, uiWidth, uiHeight);//对系数进行重排
      }
#endif 
      xQuant( rTu, m_plTempCoeff, rpcCoeff,

#if ADAPTIVE_QP_SELECTION
              pcArlCoeff,
#endif
              uiAbsSum, compID, cQP 
            );//进行量化的主函数

#if DEBUG_TRANSFORM_AND_QUANTISE
      std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU at output of quantiser\n";
      printBlock(rpcCoeff, uiWidth, uiHeight, uiWidth);
#endif
    }
  }

    //set the CBF
#if JVET_C0024_QTBT
  assert(uiOrgTrDepth==0);
  pcCU->setCbfPartRange((uiAbsSum > 0) ? 1 : 0, compID, uiAbsPartIdx, 0);
#else
  pcCU->setCbfPartRange((((uiAbsSum > 0) ? 1 : 0) << uiOrgTrDepth), compID, uiAbsPartIdx, rTu.GetAbsPartIdxNumParts(compID));
#endif
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值