VVC/JEM代码学习26:m_pcTrQuant->transformN*N

26 篇文章 2 订阅
在H.266中,做完主变换后,还要进行二次变换,然后才进行量化;
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;//默认是关闭rdpcm的;
  rdpcmNxN( rTu, compID, pcResidual, uiStride, cQP, rpcCoeff, uiAbsSum, rdpcmMode );

  if (rdpcmMode == RDPCM_OFF)
  {
    uiAbsSum = 0;
    //transform and quantise
    if(pcCU->getCUTransquantBypass(uiAbsPartIdx))//旁路掉变换和量化,即直接把残差系数赋值给rpcCoeff;
    {
      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)//如果跳过变换,将残差系数经过伸缩和移位后赋值给m_plTempCoeff;
      {
        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 DEBUG_TRANSFORM_AND_QUANTISE
      std::cout << g_debugCounter << ": " << uiWidth << "x" << uiHeight << " channel " << compID << " TU between transform and quantiser\n";
      printBlock(m_plTempCoeff, uiWidth, uiHeight, uiWidth);
#endif
#if VCEG_AZ05_ROT_TR
#if JVET_C0024_QTBT
  Char ucROTIdx = pcCU->getROTIdx(toChannelType(compID), uiAbsPartIdx) ;
  if (ucROTIdx && uiWidth>=4 && uiHeight>=4)
#else
  if (pcCU->getROTIdx(uiAbsPartIdx) )
#endif
  {           
            static Int ROT_MATRIX[16];
      Int iSubGroupXMax = Clip3 (1,16,(Int)( (uiWidth>>2)));
      Int iSubGroupYMax = Clip3 (1,16,(Int)( (uiHeight>>2)));

      Int iOffSetX = 0;
      Int iOffSetY = 0;
      Int y = 0;
      Int* piCoeffTemp = m_plTempCoeff;
      Int* piROTTemp = ROT_MATRIX;
      Int iString2CopySize = 4*sizeof(Int);
    for (Int iSubGroupX = 0; iSubGroupX<iSubGroupXMax; iSubGroupX++)
      for (Int iSubGroupY = 0; iSubGroupY<iSubGroupYMax; iSubGroupY++)
      {
        iOffSetX = 4*iSubGroupX;
        iOffSetY = 4*iSubGroupY*uiWidth;
          piROTTemp = ROT_MATRIX;
          piCoeffTemp = m_plTempCoeff+iOffSetX+iOffSetY;
          for(  y = 0; y < 4; y++ )
           {  
             ::memcpy(piROTTemp, piCoeffTemp, iString2CopySize); 
                       piROTTemp +=4;
             piCoeffTemp +=uiWidth;
            }
#if JVET_C0024_QTBT
           RotTransform4I( ROT_MATRIX, ucROTIdx-1 );
#else
           RotTransform4I( ROT_MATRIX, pcCU->getROTIdx(uiAbsPartIdx)-1 );
#endif
          piROTTemp = ROT_MATRIX;
          piCoeffTemp = m_plTempCoeff+iOffSetX+iOffSetY;
          for(  y = 0; y < 4; y++ )
          {    
             ::memcpy(piCoeffTemp,piROTTemp, iString2CopySize);
                       piROTTemp +=4;
             piCoeffTemp +=uiWidth;
          }
             }
  }
#elif COM16_C1044_NSST
#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且宽和高都大于等于4且不是TS的前提下才做二次变换;
#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;//宽和高都大于4,则等于3,否则等于2
        const  Int iSbSize       = (uiWidth > 4 && uiHeight > 4) ? 8 : 4;//宽和高都大于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
#else
#if JVET_C0024_QTBT
        const UInt *scan = (log2BlockWidth==3 && log2BlockHeight==3) ? g_auiCoefScanFirstCG8x8[uiScanIdx] : g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth    ][ log2BlockHeight    ];
#else
        const UInt *scan = uiLog2BlockSize==3 ? g_auiCoefScanFirstCG8x8[uiScanIdx] : g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth    ][ log2BlockHeight    ];
#endif
#endif
#else
#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
#else
        const UInt *scan = g_scanOrder[ SCAN_GROUPED_4x4 ][ uiScanIdx ][ log2BlockWidth    ][ log2BlockHeight    ];
#endif
#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
#else
          if( uiIntraMode == DM_CHROMA_IDX )
          {
#if JVET_C0024_QTBT
            if( pcCU->getSlice()->isIntra() )
            {
              uiIntraMode = pcCU->getPic()->getCtu(pcCU->getCtuRsAddr())->getIntraDir(CHANNEL_TYPE_LUMA, pcCU->getZorderIdxInCtu()+uiAbsPartIdx);
            }
            else
            {
#endif
            uiIntraMode = pcCU->getIntraDir( CHANNEL_TYPE_LUMA, uiAbsPartIdx );
#if JVET_C0024_QTBT
            }
#endif
          }
#if COM16_C806_LMCHROMA
          else if( uiIntraMode == LM_CHROMA_IDX )
          {
            uiIntraMode = PLANAR_IDX;
          }
#endif


#if JVET_E0077_ENHANCED_LM
          if (IsLMMode(uiIntraMode))
          {
              uiIntraMode = PLANAR_IDX;
          }
#endif

#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 )
                  {//[0][1][2][3]是第一行,[0][4][8][12]是第一列
                    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
              }
#else
              FwdNsst4x4( NSST_MATRIX, g_NsstLut[uiIntraMode], ucNsstIdx-1 );
#endif
#else
#if JVET_D0120_NSST_IMPROV
              if ( iSbSize>4 )
              {
                FwdNsst8x8( NSST_MATRIX, g_NsstLut[uiIntraMode], pcCU->getROTIdx(uiAbsPartIdx)-1 );
              }
              else 
              {
                FwdNsst4x4( NSST_MATRIX, g_NsstLut[uiIntraMode], pcCU->getROTIdx(uiAbsPartIdx)-1 );
              }
#else
              FwdNsst4x4( NSST_MATRIX, g_NsstLut[uiIntraMode], pcCU->getROTIdx(uiAbsPartIdx)-1 );
#endif
#endif

              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);//设置cbf,如果uiAbsSum大于0,则为1,否则为0
#else
  pcCU->setCbfPartRange((((uiAbsSum > 0) ? 1 : 0) << uiOrgTrDepth), compID, uiAbsPartIdx, rTu.GetAbsPartIdxNumParts(compID));
#endif
}
Void TComTrQuant::xT( const Int channelBitDepth, Bool useDST, Pel* piBlkResi, UInt uiStride, TCoeff* psCoeff, Int iWidth, Int iHeight, const Int maxLog2TrDynamicRange 
#if COM16_C806_EMT
                     , UChar ucMode
                     , UChar ucTrIdx
#endif
#if VCEG_AZ08_KLT_COMMON
                     , Bool useKLT
#endif
                     )
{
#if MATRIX_MULT
  if( iWidth == iHeight)
  {
#if COM16_C806_EMT
    if( ucTrIdx!=DCT2_HEVC )
    {
      xTr_EMT(channelBitDepth, piBlkResi, psCoeff, uiStride, (UInt)iWidth, useDST, maxLog2TrDynamicRange, ucMode, ucTrIdx );
    }
    else
#endif
    xTr(channelBitDepth, piBlkResi, psCoeff, uiStride, (UInt)iWidth, useDST, maxLog2TrDynamicRange);
    return;
  }
#endif

  TCoeff block[ MAX_TU_SIZE * MAX_TU_SIZE ];
  TCoeff coeff[ MAX_TU_SIZE * MAX_TU_SIZE ];

  for (Int y = 0; y < iHeight; y++)
  {
    for (Int x = 0; x < iWidth; x++)
    {
      block[(y * iWidth) + x] = piBlkResi[(y * uiStride) + x];//先把残差数据赋值给临时数组block
    }
  }
#if COM16_C806_EMT
#if VCEG_AZ08_KLT_COMMON
  if( ucTrIdx!=DCT2_HEVC && useKLT == false)//不是DCT2_HEVC且不使用KLT时进行EMT
#else
  if( ucTrIdx!=DCT2_HEVC )
#endif
  {
    xTrMxN_EMT(channelBitDepth, block, coeff, iWidth, iHeight, useDST, maxLog2TrDynamicRange, ucMode, ucTrIdx );
  }
  else// ucTrIdx==DCT2_HEVC || useKLT==true
#endif

#if VCEG_AZ08_KLT_COMMON
  xTrMxN( channelBitDepth, block, coeff, iWidth, iHeight, useDST, maxLog2TrDynamicRange, useKLT);
#else
  xTrMxN( channelBitDepth, block, coeff, iWidth, iHeight, useDST, maxLog2TrDynamicRange );
#endif
  memcpy(psCoeff, coeff, (iWidth * iHeight * sizeof(TCoeff)));//把变换后的系数赋值给psCoeff
}
Void TComTrQuant::xQuant(       TComTU       &rTu,
                                TCoeff      * pSrc,
                                TCoeff      * pDes,
#if ADAPTIVE_QP_SELECTION
                                TCoeff      *pArlDes,
#endif
                                TCoeff       &uiAbsSum,
                          const ComponentID   compID,
                          const QpParam      &cQP 
                          )
{
  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 Int channelBitDepth = pcCU->getSlice()->getSPS()->getBitDepth(toChannelType(compID));

  TCoeff* piCoef    = pSrc;
  TCoeff* piQCoef   = pDes;
#if ADAPTIVE_QP_SELECTION
  TCoeff* piArlCCoef = pArlDes;
#endif

  const Bool useTransformSkip      = pcCU->getTransformSkip(uiAbsPartIdx, compID);
  const Int  maxLog2TrDynamicRange = pcCU->getSlice()->getSPS()->getMaxLog2TrDynamicRange(toChannelType(compID));

  Bool useRDOQ = useTransformSkip ? m_useRDOQTS : m_useRDOQ;//使用率失真优化量化
#if JVET_C0024_QTBT
  if (uiWidth<4 || uiHeight<4)//宽或高小于4,则不使用率失真优化量化
  {
    useRDOQ = false;
  }
#endif
  if ( useRDOQ && (isLuma(compID) || RDOQ_CHROMA) )
  {
#if T0196_SELECTIVE_RDOQ
    if ( !m_useSelectiveRDOQ || xNeedRDOQ( rTu, piCoef, compID, cQP ) )
    {
#endif
#if ADAPTIVE_QP_SELECTION
      xRateDistOptQuant( rTu, piCoef, pDes, pArlDes, uiAbsSum, compID, cQP );//率失真优化量化;
#else
      xRateDistOptQuant( rTu, piCoef, pDes, uiAbsSum, compID, cQP );
#endif
#if T0196_SELECTIVE_RDOQ
    }
    else//否则直接将量化后系数设置为0
    {
      memset( pDes, 0, sizeof( TCoeff ) * uiWidth *uiHeight );
      uiAbsSum = 0;
    }
#endif
  }
  else//不使用RDOQ或者不是亮度分量
  {
    TUEntropyCodingParameters codingParameters;
    getTUEntropyCodingParameters(codingParameters, rTu, compID);

    const TCoeff entropyCodingMinimum = -(1 << maxLog2TrDynamicRange);//熵编码的最小值,-2^15
    const TCoeff entropyCodingMaximum =  (1 << maxLog2TrDynamicRange) - 1;//熵编码的最大值,2^15

    TCoeff deltaU[MAX_TU_SIZE * MAX_TU_SIZE];

    const UInt uiLog2TrSize = rTu.GetEquivalentLog2TrSize(compID);  

    Int scalingListType = getScalingListType(pcCU->getPredictionMode(uiAbsPartIdx), compID);
    assert(scalingListType < SCALING_LIST_NUM);
#if JVET_C0024_QTBT
    const UInt uiLog2TrWidth = g_aucConvertToBit[uiWidth] + MIN_CU_LOG2;
    const UInt uiLog2TrHeight = g_aucConvertToBit[uiHeight] + MIN_CU_LOG2;
    Int *piQuantCoeff = getQuantCoeff(scalingListType, cQP.rem, uiLog2TrWidth-1, uiLog2TrHeight-1);
#else
    Int *piQuantCoeff = getQuantCoeff(scalingListType, cQP.rem, uiLog2TrSize-2);
#endif
	//指示是否使用加权量化矩阵
    const Bool enableScalingLists             = getUseScalingList(uiWidth, uiHeight, (pcCU->getTransformSkip(uiAbsPartIdx, compID) != 0));
    const Int  defaultQuantisationCoefficient = g_quantScales[cQP.rem];

    /* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be
     * implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the
     * uiLog2TrSize applied in iTransformShift, such that the result is 1/sqrt(2) the required result (i.e. smaller)
     * Then a QP+3 (sqrt(2)) or QP-3 (1/sqrt(2)) method could be used to get the required result
     */

    // Represents scaling through forward transform
    Int iTransformShift = getTransformShift(channelBitDepth, uiLog2TrSize, maxLog2TrDynamicRange);
    if (useTransformSkip && pcCU->getSlice()->getSPS()->getSpsRangeExtension().getExtendedPrecisionProcessingFlag())
    {
      iTransformShift = std::max<Int>(0, iTransformShift);
    }

#if JVET_C0024_QTBT
  Int iWHScale = 1;
  if ((g_aucConvertToBit[ uiWidth ] + g_aucConvertToBit[ uiHeight ] + (MIN_CU_LOG2<<1))%2 !=0)
  {
    iTransformShift += 7;
    iWHScale = 181;
  }
#endif

    const Int iQBits = QUANT_SHIFT + cQP.per + iTransformShift;
    // QBits will be OK for any internal bit depth as the reduction in transform shift is balanced by an increase in Qp_per due to QpBDOffset

#if ADAPTIVE_QP_SELECTION
    Int iQBitsC = MAX_INT;
    Int iAddC   = MAX_INT;

    if (m_bUseAdaptQpSelect)
    {
      iQBitsC = iQBits - ARL_C_PRECISION;
      iAddC   = 1 << (iQBitsC-1);
    }
#endif

    const Int64 iAdd   = (Int64)(pcCU->getSlice()->getSliceType()==I_SLICE ? 171 : 85) << ((Int64)iQBits-9);
    const Int qBits8 = iQBits - 8;

    for( Int uiBlockPos = 0; uiBlockPos < uiWidth*uiHeight; uiBlockPos++ )//遍历该CU的每个变换后系数
    {
      const TCoeff iLevel   = piCoef[uiBlockPos];//系数值
      const TCoeff iSign    = (iLevel < 0 ? -1: 1);//该系数的符号
	  //量化,enableScalingLists等于true则使用加权量化矩阵,否则使用默认的量化系数
      const Int64  tmpLevel = (Int64)abs(iLevel) * (enableScalingLists ? piQuantCoeff[uiBlockPos] : defaultQuantisationCoefficient);

#if ADAPTIVE_QP_SELECTION
      if( m_bUseAdaptQpSelect )
      {
#if JVET_C0024_QTBT
      piArlCCoef[uiBlockPos] = (TCoeff)((tmpLevel * iWHScale + iAddC ) >> iQBitsC);
#else
        piArlCCoef[uiBlockPos] = (TCoeff)((tmpLevel + iAddC ) >> iQBitsC);
#endif
      }
#endif

#if JVET_C0024_QTBT
      const TCoeff quantisedMagnitude = TCoeff((tmpLevel * iWHScale + iAdd ) >> iQBits);//量化后的幅值
    deltaU[uiBlockPos] = (TCoeff)((tmpLevel * iWHScale - ((Int64)quantisedMagnitude<<iQBits) )>> qBits8);
#else
      const TCoeff quantisedMagnitude = TCoeff((tmpLevel + iAdd ) >> iQBits);
      deltaU[uiBlockPos] = (TCoeff)((tmpLevel - (quantisedMagnitude<<iQBits) )>> qBits8);
#endif

      uiAbsSum += quantisedMagnitude;
      const TCoeff quantisedCoefficient = quantisedMagnitude * iSign;//量化系数等于量化幅值乘以符号

      piQCoef[uiBlockPos] = Clip3<TCoeff>( entropyCodingMinimum, entropyCodingMaximum, quantisedCoefficient );
    } // for n

#if JVET_C0024_QTBT
    if( pcCU->getSlice()->getPPS()->getSignHideFlag() && uiWidth>=4 && uiHeight>=4)//如果宽和高大于等于4且可以使用符号比特隐藏技术
#else
    if( pcCU->getSlice()->getPPS()->getSignHideFlag() )
#endif
    {
      if(uiAbsSum >= 2) //this prevents TUs with only one coefficient of value 1 from being tested
      {
        signBitHidingHDQ( piQCoef, piCoef, deltaU, codingParameters, maxLog2TrDynamicRange ) ;
      }
    }
  } //if RDOQ
  //return;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值