VVC/JEM代码学习14:loopFilterPic

26 篇文章 2 订阅

在代码学习13中,记录了SAO技术的详细过程,其实在执行SAO之前,要先对重建图像进行去方块滤波;去方块滤波和样点自适应补偿合并称为环路滤波。今天就记录一下去方块滤波的详细过程。

   去方块滤波的原理:由于在编码时各个块的变换量化相互独立,对不同的块使用了不同的量化参数,导致每个块引入的量化误差大小不一致,导致相邻块边界的不连续性。此外,运动补偿预测过程中,相邻块的预测值可能来自不同图像的不同位置,导致预测残差信号在块边界不连续;另外,时域预测技术使得参考图像中存在的边界不连续可能会传递给后续编码的图像;所以在编码端加入去方块滤波模块已减少方块效应,同时也能减少方块效应对后续编码图像的影响。

    相关函数解析:

Void TComLoopFilter::loopFilterPic( TComPic* pcPic )
{
  // Horizontal filtering,水平滤波
  for ( UInt ctuRsAddr = 0; ctuRsAddr < pcPic->getNumberOfCtusInFrame(); ctuRsAddr++ )//遍历CTU
  {
    TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr );

    ::memset( m_aapucBS       [EDGE_VER], 0, sizeof( UChar ) * m_uiNumPartitions );
    ::memset( m_aapbEdgeFilter[EDGE_VER], 0, sizeof( Bool  ) * m_uiNumPartitions );

    // CU-based deblocking,基于CU的去方块
#if JVET_C0024_QTBT
    pCtu->getSlice()->setTextType(CHANNEL_TYPE_LUMA);//将分量设置为亮度
    UInt uiCTUSize = pCtu->getSlice()->getSPS()->getCTUSize() ;
    xDeblockCU( pCtu, 0, 0, uiCTUSize, uiCTUSize,EDGE_VER );//执行去方块滤波的主函数;
    if (pCtu->getSlice()->isIntra())//如果是I帧
    {
      ::memset( m_aapucBS       [EDGE_VER], 0, sizeof( UChar ) * m_uiNumPartitions );
      ::memset( m_aapbEdgeFilter[EDGE_VER], 0, sizeof( Bool  ) * m_uiNumPartitions );

      pCtu->getSlice()->setTextType(CHANNEL_TYPE_CHROMA);//将分量设置为色度
      xDeblockCU( pCtu, 0, 0, uiCTUSize, uiCTUSize, EDGE_VER );//对色度分量执行去方块滤波
    }
#else
    xDeblockCU( pCtu, 0, 0, EDGE_VER );
#endif
  }

  // Vertical filtering,当整幅图像都执行完垂直去方块滤波后再执行水平去方块滤波
  for ( UInt ctuRsAddr = 0; ctuRsAddr < pcPic->getNumberOfCtusInFrame(); ctuRsAddr++ )
  {
    TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr );

    ::memset( m_aapucBS       [EDGE_HOR], 0, sizeof( UChar ) * m_uiNumPartitions );
    ::memset( m_aapbEdgeFilter[EDGE_HOR], 0, sizeof( Bool  ) * m_uiNumPartitions );

    // CU-based deblocking
#if JVET_C0024_QTBT
    pCtu->getSlice()->setTextType(CHANNEL_TYPE_LUMA);
    UInt uiCTUSize = pCtu->getSlice()->getSPS()->getCTUSize() ;
    xDeblockCU( pCtu, 0, 0, uiCTUSize, uiCTUSize, EDGE_HOR );//先执行I帧亮度分量和B和P帧亮度色度的去方块滤波
    if (pCtu->getSlice()->isIntra())
    {
      ::memset( m_aapucBS       [EDGE_HOR], 0, sizeof( UChar ) * m_uiNumPartitions );
      ::memset( m_aapbEdgeFilter[EDGE_HOR], 0, sizeof( Bool  ) * m_uiNumPartitions );

      pCtu->getSlice()->setTextType(CHANNEL_TYPE_CHROMA);
      xDeblockCU( pCtu, 0, 0, uiCTUSize, uiCTUSize, EDGE_HOR );//再执行I帧色度分量的去方块滤波
    }
#else
    xDeblockCU( pCtu, 0, 0, EDGE_HOR );
#endif
  }
}
#if JVET_C0024_QTBT
Void TComLoopFilter::xDeblockCU( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, UInt uiWidth, UInt uiHeight, DeblockEdgeDir edgeDir )
#else
Void TComLoopFilter::xDeblockCU( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, DeblockEdgeDir edgeDir )
#endif
{
#if JVET_C0024_QTBT 
  if(pcCU->getPic()==0)
#else
  if(pcCU->getPic()==0||pcCU->getPartitionSize(uiAbsZorderIdx)==NUMBER_OF_PART_SIZES)
#endif
  {
    return;
  }
  TComPic* pcPic     = pcCU->getPic();
  UInt uiCurNumParts = pcPic->getNumPartitionsInCtu() >> (uiDepth<<1);
  UInt uiQNumParts   = uiCurNumParts>>2;
  const TComSPS &sps = *(pcCU->getSlice()->getSPS());

  if( pcCU->getDepth(uiAbsZorderIdx) > uiDepth )//还没到最大深度
  {
    for ( UInt uiPartIdx = 0; uiPartIdx < 4; uiPartIdx++, uiAbsZorderIdx+=uiQNumParts )//四叉树划分,递归四次
    {
      UInt uiLPelX   = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsZorderIdx] ];
      UInt uiTPelY   = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsZorderIdx] ];
      if( ( uiLPelX < sps.getPicWidthInLumaSamples() ) && ( uiTPelY < sps.getPicHeightInLumaSamples() ) )//不是边界
      {
#if JVET_C0024_QTBT
        xDeblockCU( pcCU, uiAbsZorderIdx, uiDepth+1, uiWidth>>1, uiHeight>>1, edgeDir );
#else
        xDeblockCU( pcCU, uiAbsZorderIdx, uiDepth+1, edgeDir );
#endif
      }
    }
    return;
  }

#if JVET_C0024_QTBT
  UInt uiBTDepth = pcCU->getBTDepth(uiAbsZorderIdx, uiWidth, uiHeight);//二叉树深度;
  UInt uiMinCUW = pcCU->getPic()->getMinCUWidth();
  UInt uiMinCUH = pcCU->getPic()->getMinCUHeight();

  if (pcCU->getBTSplitModeForBTDepth(uiAbsZorderIdx, uiBTDepth)==1)//如果是二叉树水平划分
  {
    for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//递归两次
    {
      if (uiPartUnitIdx==1)
      {
        uiAbsZorderIdx = g_auiRasterToZscan[g_auiZscanToRaster[uiAbsZorderIdx] 
        + (uiHeight>>1)/uiMinCUH*pcCU->getPic()->getNumPartInCtuWidth()];
      }
      xDeblockCU( pcCU, uiAbsZorderIdx, uiDepth, uiWidth, uiHeight>>1, edgeDir );
    }
    return;
  }
  else if (pcCU->getBTSplitModeForBTDepth(uiAbsZorderIdx, uiBTDepth)==2)//二叉树垂直划分
  {
    for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//递归两次
    {
      if (uiPartUnitIdx==1)
      {
        uiAbsZorderIdx = g_auiRasterToZscan[g_auiZscanToRaster[uiAbsZorderIdx] 
        + (uiWidth>>1)/uiMinCUW];
      }
      xDeblockCU( pcCU, uiAbsZorderIdx, uiDepth, uiWidth>>1, uiHeight, edgeDir );
    }
    return;
  }
#endif

  xSetLoopfilterParam( pcCU, uiAbsZorderIdx );//设置环路滤波参数,即确定图像内部边界,左边界和上边界的滤波标记
#if JVET_C0024_QTBT
  xSetEdgefilterCU   ( pcCU, uiAbsZorderIdx, uiWidth, uiHeight);//确定一个CU内部base unit的边界滤波标记
#else
  TComTURecurse tuRecurse(pcCU, uiAbsZorderIdx);
  xSetEdgefilterTU   ( tuRecurse );
  xSetEdgefilterPU   ( pcCU, uiAbsZorderIdx );
#endif

#if JVET_C0024_QTBT
 // const UInt uiPelsInPart = sps.getCTUSize() >> sps.getMaxTotalCUDepth();
  for (UInt j=0; j<(edgeDir==EDGE_VER ? uiHeight: 1); j+=uiMinCUH)//遍历每个cu
  {
    for (UInt i=0; i<(edgeDir==EDGE_VER ? 1: uiWidth); i+=uiMinCUW)
    {
      UInt uiRaster = j/uiMinCUH * pcCU->getPic()->getNumPartInCtuWidth() + i/uiMinCUW + g_auiZscanToRaster[uiAbsZorderIdx];
      UInt uiPartIdx = g_auiRasterToZscan[uiRaster];
      UInt uiBSCheck = 1;
#else
  const UInt uiPelsInPart = sps.getMaxCUWidth() >> sps.getMaxTotalCUDepth();

  for( UInt uiPartIdx = uiAbsZorderIdx; uiPartIdx < uiAbsZorderIdx + uiCurNumParts; uiPartIdx++ )
  {
    UInt uiBSCheck;
    if( uiPelsInPart == 4 )
    {
      uiBSCheck = (edgeDir == EDGE_VER && uiPartIdx%2 == 0) || (edgeDir == EDGE_HOR && (uiPartIdx-((uiPartIdx>>2)<<2))/2 == 0);
    }
    else
    {
      uiBSCheck = 1;
    }

#endif
    if ( m_aapbEdgeFilter[edgeDir][uiPartIdx] && uiBSCheck )//对于需要进行滤波的边界才计算滤波强度
    {
      xGetBoundaryStrengthSingle ( pcCU, edgeDir, uiPartIdx );//计算边界强度,即BS=0,还是1还是2
    }
#if JVET_C0024_QTBT
    }
  }

  UInt uiSizeInPU = 1;
  UInt PartIdxIncr = 1;
#else
  }
#endif

  for ( Int iEdge = 0; iEdge < uiSizeInPU ; iEdge+=PartIdxIncr)
  {
#if JVET_C0024_QTBT
    if (isLuma(pcCU->getTextType()))//如果是亮度分量
    {
#endif
    xEdgeFilterLuma     ( pcCU, uiAbsZorderIdx, uiDepth, edgeDir, iEdge );//对亮度分量进行去方块滤波
#if JVET_C0024_QTBT
    }
    if ((isChroma(pcCU->getTextType()) || !pcCU->getSlice()->isIntra()) && pcPic->getChromaFormat()!=CHROMA_400)//如果是色度分量或者是B或者P slice
    {
#else
    if ( chFmt!=CHROMA_400 && (bAlwaysDoChroma ||
                               (uiPelsInPart>DEBLOCK_SMALLEST_BLOCK) ||
                               (iEdge % ( (DEBLOCK_SMALLEST_BLOCK<<shiftFactor)/uiPelsInPart ) ) == 0
                              )
       )
#endif
    {
      xEdgeFilterChroma   ( pcCU, uiAbsZorderIdx, uiDepth, edgeDir, iEdge );//对色度分量进行去方块滤波
    }
#if JVET_C0024_QTBT
    }
#endif
  }
}

#if JVET_C0024_QTBT
Void TComLoopFilter::xSetEdgefilterCU( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiWidth, UInt uiHeight )
{
  const TComSPS &sps=*(pcCU->getSlice()->getSPS());

  UInt uiWidthInBaseUnits  = uiWidth / (sps.getCTUSize()  >> sps.getMaxTotalCUDepth());
  UInt uiHeightInBaseUnits = uiHeight / (sps.getCTUSize()  >> sps.getMaxTotalCUDepth());
  //设置CU内部边界垂直滤波的标记;
  xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, 0, EDGE_VER, 0, m_stLFCUParam.bInternalEdge, uiWidthInBaseUnits, uiHeightInBaseUnits );
  //设置CU内部边界水平滤波的标记;
  xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, 0, EDGE_HOR, 0, m_stLFCUParam.bInternalEdge, uiWidthInBaseUnits, uiHeightInBaseUnits );
  //设置CU左边界垂直滤波的标记;
  xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, 0, EDGE_VER, 0, m_stLFCUParam.bLeftEdge, uiWidthInBaseUnits, uiHeightInBaseUnits );
  //设置CU上边界水平滤波的标记;
  xSetEdgefilterMultiple( pcCU, uiAbsZorderIdx, 0, EDGE_HOR, 0, m_stLFCUParam.bTopEdge, uiWidthInBaseUnits, uiHeightInBaseUnits );
}
#else
Void TComLoopFilter::xGetBoundaryStrengthSingle ( TComDataCU* pCtu, DeblockEdgeDir edgeDir, UInt uiAbsPartIdx4x4BlockWithinCtu )
{
  TComSlice * const pcSlice = pCtu->getSlice();

  const Bool lfCrossSliceBoundaryFlag=pCtu->getSlice()->getLFCrossSliceBoundaryFlag();

  const UInt uiPartQ = uiAbsPartIdx4x4BlockWithinCtu;
  TComDataCU* const pcCUQ = pCtu;

  UInt uiPartP;
  TComDataCU* pcCUP;
  UInt uiBs = 0;

  //-- Calculate Block Index
  if (edgeDir == EDGE_VER)//垂直边界,获取左相邻块
  {
    pcCUP = pcCUQ->getPULeft(uiPartP, uiPartQ, !lfCrossSliceBoundaryFlag, !m_bLFCrossTileBoundary);
  }
  else  // (edgeDir == EDGE_HOR),水平边界,获取上相邻块
  {
    pcCUP = pcCUQ->getPUAbove(uiPartP, uiPartQ, !pCtu->getSlice()->getLFCrossSliceBoundaryFlag(), false, !m_bLFCrossTileBoundary);
  }

  //-- Set BS for Intra MB : BS = 4 or 3
  if ( pcCUP->isIntra(uiPartP) || pcCUQ->isIntra(uiPartQ) )//如果P块或者Q块中有一个使用帧内预测,则BS=2;
  {
    uiBs = 2;
  }

  //-- Set BS for not Intra MB : BS = 2 or 1 or 0
#if JVET_C0024_QTBT
  if ( isLuma(pCtu->getTextType()) && (!pcCUP->isIntra(uiPartP) && !pcCUQ->isIntra(uiPartQ)) )//P块和Q块都不是帧内预测且是亮度分量(色度不需要进行强滤波还是弱滤波)
#else
  if ( !pcCUP->isIntra(uiPartP) && !pcCUQ->isIntra(uiPartQ) )
#endif
  {
    UInt nsPartQ = uiPartQ;
    UInt nsPartP = uiPartP;
#if JVET_C0024_QTBT
    if ( m_aapucBS[edgeDir][uiAbsPartIdx4x4BlockWithinCtu] && (pcCUQ->getCbf( nsPartQ, COMPONENT_Y, 0) != 0 || pcCUP->getCbf( nsPartP, COMPONENT_Y, 0 ) != 0) )
#else
    if ( m_aapucBS[edgeDir][uiAbsPartIdx4x4BlockWithinCtu] && (pcCUQ->getCbf( nsPartQ, COMPONENT_Y, pcCUQ->getTransformIdx(nsPartQ)) != 0 || pcCUP->getCbf( nsPartP, COMPONENT_Y, pcCUP->getTransformIdx(nsPartP) ) != 0) )
#endif
    {//如果P块或者Q块有非零变换系数,则BS=1;
      uiBs = 1;
    }
    else//P和Q都没有非零变换系数
    {
#if VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE
      Int nThreshold = 4 << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
#endif
      if (pcSlice->isInterB() || pcCUP->getSlice()->isInterB())//如果P或者Q是B SLICE
      {
        Int iRefIdx;
        TComPic *piRefP0, *piRefP1, *piRefQ0, *piRefQ1;
		//获取P的参考列表
        iRefIdx = pcCUP->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartP);
        piRefP0 = (iRefIdx < 0) ? NULL : pcCUP->getSlice()->getRefPic(REF_PIC_LIST_0, iRefIdx);
        iRefIdx = pcCUP->getCUMvField(REF_PIC_LIST_1)->getRefIdx(uiPartP);
        piRefP1 = (iRefIdx < 0) ? NULL : pcCUP->getSlice()->getRefPic(REF_PIC_LIST_1, iRefIdx);
		//获取Q的参考列表
        iRefIdx = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartQ);
        piRefQ0 = (iRefIdx < 0) ? NULL : pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx);
        iRefIdx = pcCUQ->getCUMvField(REF_PIC_LIST_1)->getRefIdx(uiPartQ);
        piRefQ1 = (iRefIdx < 0) ? NULL : pcSlice->getRefPic(REF_PIC_LIST_1, iRefIdx);
		//获取P的MV;
        TComMv pcMvP0 = pcCUP->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartP);
        TComMv pcMvP1 = pcCUP->getCUMvField(REF_PIC_LIST_1)->getMv(uiPartP);
		//获取Q的MV;
        TComMv pcMvQ0 = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartQ);
        TComMv pcMvQ1 = pcCUQ->getCUMvField(REF_PIC_LIST_1)->getMv(uiPartQ);

        if (piRefP0 == NULL)
        {
          pcMvP0.setZero();
        }
        if (piRefP1 == NULL)
        {
          pcMvP1.setZero();
        }
        if (piRefQ0 == NULL)
        {
          pcMvQ0.setZero();
        }
        if (piRefQ1 == NULL)
        {
          pcMvQ1.setZero();
        }

        if ( ((piRefP0==piRefQ0)&&(piRefP1==piRefQ1)) || ((piRefP0==piRefQ1)&&(piRefP1==piRefQ0)) )//P和Q使用相同的参考帧
        {
          if ( piRefP0 != piRefP1 )   // Different L0 & L1,P有两个参考帧
          {
            if ( piRefP0 == piRefQ0 )//P的参考帧0等于Q的参考帧0,P的参考帧1等于Q的参考帧1
            {
#if VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE
              uiBs  = ((abs(pcMvQ0.getHor() - pcMvP0.getHor()) >= nThreshold) ||
                       (abs(pcMvQ0.getVer() - pcMvP0.getVer()) >= nThreshold) ||
                       (abs(pcMvQ1.getHor() - pcMvP1.getHor()) >= nThreshold) ||
                       (abs(pcMvQ1.getVer() - pcMvP1.getVer()) >= nThreshold)) ? 1 : 0;//P与Q的MV差值的绝对值大于等于16是BS=1;否则等于0
#else
              uiBs  = ((abs(pcMvQ0.getHor() - pcMvP0.getHor()) >= 4) ||
                       (abs(pcMvQ0.getVer() - pcMvP0.getVer()) >= 4) ||
                       (abs(pcMvQ1.getHor() - pcMvP1.getHor()) >= 4) ||
                       (abs(pcMvQ1.getVer() - pcMvP1.getVer()) >= 4)) ? 1 : 0;
#endif
            }
            else//P的参考帧0不等于Q的参考帧0,即P的参考帧0等于Q的参考帧1,P的参考帧1等于Q的参考帧0
            {
#if VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE
              uiBs  = ((abs(pcMvQ1.getHor() - pcMvP0.getHor()) >= nThreshold) ||
                       (abs(pcMvQ1.getVer() - pcMvP0.getVer()) >= nThreshold) ||
                       (abs(pcMvQ0.getHor() - pcMvP1.getHor()) >= nThreshold) ||
                       (abs(pcMvQ0.getVer() - pcMvP1.getVer()) >= nThreshold)) ? 1 : 0;//P与Q的MV差值的绝对值大于等于16是BS=1;否则等于0
#else
              uiBs  = ((abs(pcMvQ1.getHor() - pcMvP0.getHor()) >= 4) ||
                       (abs(pcMvQ1.getVer() - pcMvP0.getVer()) >= 4) ||
                       (abs(pcMvQ0.getHor() - pcMvP1.getHor()) >= 4) ||
                       (abs(pcMvQ0.getVer() - pcMvP1.getVer()) >= 4)) ? 1 : 0;
#endif
            }
          }
          else    // Same L0 & L1,即P只有一个参考帧,Q也只有一个参考帧
          {
#if VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE
            uiBs  = ((abs(pcMvQ0.getHor() - pcMvP0.getHor()) >= nThreshold) ||
                     (abs(pcMvQ0.getVer() - pcMvP0.getVer()) >= nThreshold) ||
                     (abs(pcMvQ1.getHor() - pcMvP1.getHor()) >= nThreshold) ||
                     (abs(pcMvQ1.getVer() - pcMvP1.getVer()) >= nThreshold)) &&
                    ((abs(pcMvQ1.getHor() - pcMvP0.getHor()) >= nThreshold) ||
                     (abs(pcMvQ1.getVer() - pcMvP0.getVer()) >= nThreshold) ||
                     (abs(pcMvQ0.getHor() - pcMvP1.getHor()) >= nThreshold) ||
                     (abs(pcMvQ0.getVer() - pcMvP1.getVer()) >= nThreshold)) ? 1 : 0;//P与Q的MV差值的绝对值大于等于16是BS=1;否则等于0
#else
            uiBs  = ((abs(pcMvQ0.getHor() - pcMvP0.getHor()) >= 4) ||
                     (abs(pcMvQ0.getVer() - pcMvP0.getVer()) >= 4) ||
                     (abs(pcMvQ1.getHor() - pcMvP1.getHor()) >= 4) ||
                     (abs(pcMvQ1.getVer() - pcMvP1.getVer()) >= 4)) &&
                    ((abs(pcMvQ1.getHor() - pcMvP0.getHor()) >= 4) ||
                     (abs(pcMvQ1.getVer() - pcMvP0.getVer()) >= 4) ||
                     (abs(pcMvQ0.getHor() - pcMvP1.getHor()) >= 4) ||
                     (abs(pcMvQ0.getVer() - pcMvP1.getVer()) >= 4)) ? 1 : 0;
#endif
          }
        }
        else // for all different Ref_Idx,P和Q使用不同的参考帧,则BS=1
        {
          uiBs = 1;
        }
      }
      else  // pcSlice->isInterP(),P和Q都是P SLICE
      {
        Int iRefIdx;
        TComPic *piRefP0, *piRefQ0;
		//获取P的参考帧
        iRefIdx = pcCUP->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartP);
        piRefP0 = (iRefIdx < 0) ? NULL : pcCUP->getSlice()->getRefPic(REF_PIC_LIST_0, iRefIdx);
		//获取Q的参考帧
        iRefIdx = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartQ);
        piRefQ0 = (iRefIdx < 0) ? NULL : pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx);
        TComMv pcMvP0 = pcCUP->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartP);//获取P的mv
        TComMv pcMvQ0 = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartQ);//获取Q的mv

        if (piRefP0 == NULL)
        {
          pcMvP0.setZero();
        }
        if (piRefQ0 == NULL)
        {
          pcMvQ0.setZero();
        }

#if VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE
        uiBs  = ((piRefP0 != piRefQ0) ||
                 (abs(pcMvQ0.getHor() - pcMvP0.getHor()) >= nThreshold) ||
                 (abs(pcMvQ0.getVer() - pcMvP0.getVer()) >= nThreshold)) ? 1 : 0;//P与Q的MV差值的绝对值大于等于16是BS=1;否则等于0
#else
        uiBs  = ((piRefP0 != piRefQ0) ||
                 (abs(pcMvQ0.getHor() - pcMvP0.getHor()) >= 4) ||
                 (abs(pcMvQ0.getVer() - pcMvP0.getVer()) >= 4)) ? 1 : 0;
#endif
      }
    }   // enf of "if( one of BCBP == 0 )"
  }   // enf of "if( not Intra )"

  m_aapucBS[edgeDir][uiAbsPartIdx4x4BlockWithinCtu] = uiBs;
}

Void TComLoopFilter::xEdgeFilterLuma( TComDataCU* const pcCU, const UInt uiAbsZorderIdx, const UInt uiDepth, const DeblockEdgeDir edgeDir, const Int iEdge  )
{
        TComPicYuv *pcPicYuvRec                   = pcCU->getPic()->getPicYuvRec();
        Pel        *piSrc                         = pcPicYuvRec->getAddr(COMPONENT_Y, pcCU->getCtuRsAddr(), uiAbsZorderIdx );
        Pel        *piTmpSrc                      = piSrc;
  const TComSPS    &sps                           = *(pcCU->getSlice()->getSPS());
  const Bool        ppsTransquantBypassEnableFlag = pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag();
  const Int         bitDepthLuma                  = sps.getBitDepth(CHANNEL_TYPE_LUMA);
  const Bool        lfCrossSliceBoundaryFlag      = pcCU->getSlice()->getLFCrossSliceBoundaryFlag();

  Int  iStride = pcPicYuvRec->getStride(COMPONENT_Y);
  Int iQP = 0;
  Int iQP_P = 0;
  Int iQP_Q = 0;
#if JVET_C0024_QTBT 
  UInt uiNumParts;
  if (edgeDir == EDGE_VER)
  {
    uiNumParts = pcCU->getHeight(uiAbsZorderIdx) / pcCU->getPic()->getMinCUHeight();
  }
  else
  {
    uiNumParts = pcCU->getWidth(uiAbsZorderIdx) / pcCU->getPic()->getMinCUWidth();
  }
#else
  UInt uiNumParts = pcCU->getPic()->getNumPartInCtuWidth()>>uiDepth;
#endif

#if JVET_C0024_QTBT
  UInt  uiPelsInPart = sps.getCTUSize() >> sps.getMaxTotalCUDepth();
#else
  UInt  uiPelsInPart = sps.getMaxCUWidth() >> sps.getMaxTotalCUDepth();
#endif
  UInt  uiBsAbsIdx = 0, uiBs = 0;
  Int   iOffset, iSrcStep;

#if JVET_C0024_DF_MODIFY
  const UInt uiLCUWidthInBaseUnits = pcCU->getPic()->getNumPartInCtuWidth();
  UInt uiEdgeNumInLCUVert = g_auiZscanToRaster[uiAbsZorderIdx]%uiLCUWidthInBaseUnits + iEdge;
  UInt uiEdgeNumInLCUHor = g_auiZscanToRaster[uiAbsZorderIdx]/uiLCUWidthInBaseUnits + iEdge;
  
  if ( (uiPelsInPart < DEBLOCK_SMALLEST_BLOCK) && (( (uiEdgeNumInLCUVert%(DEBLOCK_SMALLEST_BLOCK/uiPelsInPart))&&(edgeDir==EDGE_VER) ) || ( (uiEdgeNumInLCUHor%(DEBLOCK_SMALLEST_BLOCK/uiPelsInPart))&& (edgeDir==EDGE_HOR) ) ))
  {
    return;
  }
#endif

  Bool  bPCMFilter = (sps.getUsePCM() && sps.getPCMFilterDisableFlag())? true : false;
  Bool  bPartPNoFilter = false;
  Bool  bPartQNoFilter = false;
  UInt  uiPartPIdx = 0;
  UInt  uiPartQIdx = 0;
  TComDataCU* pcCUP = pcCU;
  TComDataCU* pcCUQ = pcCU;
  Int  betaOffsetDiv2 = pcCUQ->getSlice()->getDeblockingFilterBetaOffsetDiv2();
  Int  tcOffsetDiv2 = pcCUQ->getSlice()->getDeblockingFilterTcOffsetDiv2();

  if (edgeDir == EDGE_VER)
  {
    iOffset = 1;
    iSrcStep = iStride;
    piTmpSrc += iEdge*uiPelsInPart;
  }
  else  // (edgeDir == EDGE_HOR)
  {
    iOffset = iStride;
    iSrcStep = 1;
    piTmpSrc += iEdge*uiPelsInPart*iStride;
  }

  const Int iBitdepthScale = 1 << (bitDepthLuma-8);

  for ( UInt iIdx = 0; iIdx < uiNumParts; iIdx++ )
  {
    uiBsAbsIdx = xCalcBsIdx( pcCU, uiAbsZorderIdx, edgeDir, iEdge, iIdx);
    uiBs = m_aapucBS[edgeDir][uiBsAbsIdx];
    if ( uiBs )//亮度中只有BS=1或者BS=2的时候才进行滤波
    {
      iQP_Q = pcCU->getQP( uiBsAbsIdx );
      uiPartQIdx = uiBsAbsIdx;
      // Derive neighboring PU index
      if (edgeDir == EDGE_VER)
      {
        pcCUP = pcCUQ->getPULeft (uiPartPIdx, uiPartQIdx,!lfCrossSliceBoundaryFlag, !m_bLFCrossTileBoundary);
      }
      else  // (iDir == EDGE_HOR)
      {
        pcCUP = pcCUQ->getPUAbove(uiPartPIdx, uiPartQIdx,!lfCrossSliceBoundaryFlag, false, !m_bLFCrossTileBoundary);
      }

      iQP_P = pcCUP->getQP(uiPartPIdx);
      iQP = (iQP_P + iQP_Q + 1) >> 1;

      Int iIndexTC = Clip3(0, MAX_QP+DEFAULT_INTRA_TC_OFFSET, Int(iQP + DEFAULT_INTRA_TC_OFFSET*(uiBs-1) + (tcOffsetDiv2 << 1)));
      Int iIndexB = Clip3(0, MAX_QP, iQP + (betaOffsetDiv2 << 1));

      Int iTc =  sm_tcTable[iIndexTC]*iBitdepthScale;
      Int iBeta = sm_betaTable[iIndexB]*iBitdepthScale;
      Int iSideThreshold = (iBeta+(iBeta>>1))>>3;
      Int iThrCut = iTc*10;


#if JVET_C0024_DF_MODIFY
      UInt  uiBlocksInPart = 1;
#else
      UInt  uiBlocksInPart = uiPelsInPart / 4 ? uiPelsInPart / 4 : 1;
#endif//计算块边界的纹理度值,通过该值来判断是否需要进行滤波
      for (UInt iBlkIdx = 0; iBlkIdx<uiBlocksInPart; iBlkIdx ++)
      {
        Int dp0 = xCalcDP( piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+0), iOffset);
        Int dq0 = xCalcDQ( piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+0), iOffset);
#if JVET_C0024_DF_MODIFY
        Int dp3 = xCalcDP( piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+uiPelsInPart-1), iOffset);
        Int dq3 = xCalcDQ( piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+uiPelsInPart-1), iOffset);
#else
        Int dp3 = xCalcDP( piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+3), iOffset);
        Int dq3 = xCalcDQ( piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+3), iOffset);
#endif
        Int d0 = dp0 + dq0;
        Int d3 = dp3 + dq3;

        Int dp = dp0 + dp3;
        Int dq = dq0 + dq3;
        Int d =  d0 + d3;

        if (bPCMFilter || ppsTransquantBypassEnableFlag)
        {
          // Check if each of PUs is I_PCM with LF disabling
          bPartPNoFilter = (bPCMFilter && pcCUP->getIPCMFlag(uiPartPIdx));
          bPartQNoFilter = (bPCMFilter && pcCUQ->getIPCMFlag(uiPartQIdx));

          // check if each of PUs is lossless coded
          bPartPNoFilter = bPartPNoFilter || (pcCUP->isLosslessCoded(uiPartPIdx) );
          bPartQNoFilter = bPartQNoFilter || (pcCUQ->isLosslessCoded(uiPartQIdx) );
        }

        if (d < iBeta)//满足此条件才执行滤波,即书上的P194
        {
          Bool bFilterP = (dp < iSideThreshold);
          Bool bFilterQ = (dq < iSideThreshold);
		  //判断是否进行强滤波,返回true还是false;
          Bool sw =  xUseStrongFiltering( iOffset, 2*d0, iBeta, iTc, piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+0))
#if JVET_C0024_DF_MODIFY
          && xUseStrongFiltering( iOffset, 2*d3, iBeta, iTc, piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+uiPelsInPart-1));
#else
          && xUseStrongFiltering( iOffset, 2*d3, iBeta, iTc, piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+3));
#endif

#if JVET_C0024_DF_MODIFY
          for ( Int i = 0; i < uiPelsInPart; i++)
#else
          for ( Int i = 0; i < DEBLOCK_SMALLEST_BLOCK/2; i++)
#endif
          {//执行亮度分量最后的滤波
            xPelFilterLuma( piTmpSrc+iSrcStep*(iIdx*uiPelsInPart+iBlkIdx*4+i), iOffset, iTc, sw, bPartPNoFilter, bPartQNoFilter, iThrCut, bFilterP, bFilterQ, bitDepthLuma);
          }
        }
      }
    }
  }
}

Void TComLoopFilter::xEdgeFilterChroma( TComDataCU* const pcCU, const UInt uiAbsZorderIdx, const UInt uiDepth, const DeblockEdgeDir edgeDir, const Int iEdge )
{
        TComPicYuv *pcPicYuvRec    = pcCU->getPic()->getPicYuvRec();
        Int         iStride        = pcPicYuvRec->getStride(COMPONENT_Cb);
        Pel        *piSrcCb        = pcPicYuvRec->getAddr( COMPONENT_Cb, pcCU->getCtuRsAddr(), uiAbsZorderIdx );
        Pel        *piSrcCr        = pcPicYuvRec->getAddr( COMPONENT_Cr, pcCU->getCtuRsAddr(), uiAbsZorderIdx );
  const TComSPS    &sps            = *(pcCU->getSlice()->getSPS());
  const Int         bitDepthChroma = sps.getBitDepth(CHANNEL_TYPE_CHROMA);

#if JVET_C0024_QTBT
  const UInt  uiPelsInPartChromaH = sps.getCTUSize() >> (sps.getMaxTotalCUDepth()+pcPicYuvRec->getComponentScaleX(COMPONENT_Cb));
  const UInt  uiPelsInPartChromaV = sps.getCTUSize() >> (sps.getMaxTotalCUDepth()+pcPicYuvRec->getComponentScaleY(COMPONENT_Cb)); //seems Cr ? a bug in HM16.6?
#else
  const UInt  uiPelsInPartChromaH = sps.getMaxCUWidth() >> (sps.getMaxTotalCUDepth()+pcPicYuvRec->getComponentScaleX(COMPONENT_Cb));
  const UInt  uiPelsInPartChromaV = sps.getMaxCUHeight() >> (sps.getMaxTotalCUDepth()+pcPicYuvRec->getComponentScaleY(COMPONENT_Cb));
#endif

  Int iQP = 0;
  Int iQP_P = 0;
  Int iQP_Q = 0;

  Int   iOffset, iSrcStep;
  UInt  uiLoopLength;

  const UInt uiCtuWidthInBaseUnits = pcCU->getPic()->getNumPartInCtuWidth();

  Bool  bPCMFilter = (pcCU->getSlice()->getSPS()->getUsePCM() && pcCU->getSlice()->getSPS()->getPCMFilterDisableFlag())? true : false;
  Bool  bPartPNoFilter = false;
  Bool  bPartQNoFilter = false;
  TComDataCU* pcCUQ = pcCU;
  Int tcOffsetDiv2 = pcCU->getSlice()->getDeblockingFilterTcOffsetDiv2();

  // Vertical Position
  UInt uiEdgeNumInCtuVert = g_auiZscanToRaster[uiAbsZorderIdx]%uiCtuWidthInBaseUnits + iEdge;
  UInt uiEdgeNumInCtuHor = g_auiZscanToRaster[uiAbsZorderIdx]/uiCtuWidthInBaseUnits + iEdge;

  if ( (uiPelsInPartChromaH < DEBLOCK_SMALLEST_BLOCK) && (uiPelsInPartChromaV < DEBLOCK_SMALLEST_BLOCK) &&
       (
         ( (uiEdgeNumInCtuVert%(DEBLOCK_SMALLEST_BLOCK/uiPelsInPartChromaH)) && (edgeDir==EDGE_VER) ) ||
         ( (uiEdgeNumInCtuHor %(DEBLOCK_SMALLEST_BLOCK/uiPelsInPartChromaV)) && (edgeDir==EDGE_HOR) )
       )
     )
  {
    return;
  }


  const Bool lfCrossSliceBoundaryFlag=pcCU->getSlice()->getLFCrossSliceBoundaryFlag();

#if JVET_C0024_QTBT
  UInt uiNumParts;
  if (edgeDir == EDGE_VER)
  {
    uiNumParts = pcCU->getHeight(uiAbsZorderIdx) / pcCU->getPic()->getMinCUHeight();
  }
  else
  {
    uiNumParts = pcCU->getWidth(uiAbsZorderIdx) / pcCU->getPic()->getMinCUWidth();
  }
#else
  UInt  uiNumParts = pcCU->getPic()->getNumPartInCtuWidth()>>uiDepth;
#endif

  UInt  uiBsAbsIdx;
  UChar ucBs;

  Pel* piTmpSrcCb = piSrcCb;
  Pel* piTmpSrcCr = piSrcCr;

  if (edgeDir == EDGE_VER)
  {
    iOffset   = 1;
    iSrcStep  = iStride;
    piTmpSrcCb += iEdge*uiPelsInPartChromaH;
    piTmpSrcCr += iEdge*uiPelsInPartChromaH;
    uiLoopLength=uiPelsInPartChromaV;
  }
  else  // (edgeDir == EDGE_HOR)
  {
    iOffset   = iStride;
    iSrcStep  = 1;
    piTmpSrcCb += iEdge*iStride*uiPelsInPartChromaV;
    piTmpSrcCr += iEdge*iStride*uiPelsInPartChromaV;
    uiLoopLength=uiPelsInPartChromaH;
  }

  const Int iBitdepthScale = 1 << (pcCU->getSlice()->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA)-8);

  for ( UInt iIdx = 0; iIdx < uiNumParts; iIdx++ )
  {
    uiBsAbsIdx = xCalcBsIdx( pcCU, uiAbsZorderIdx, edgeDir, iEdge, iIdx);
    ucBs = m_aapucBS[edgeDir][uiBsAbsIdx];

    if ( ucBs > 1)//只有BS=2的时候才进行滤波
    {
      iQP_Q = pcCU->getQP( uiBsAbsIdx );
      UInt  uiPartQIdx = uiBsAbsIdx;
      // Derive neighboring PU index
      TComDataCU* pcCUP;
      UInt  uiPartPIdx;

      if (edgeDir == EDGE_VER)
      {
        pcCUP = pcCUQ->getPULeft (uiPartPIdx, uiPartQIdx,!lfCrossSliceBoundaryFlag, !m_bLFCrossTileBoundary);
      }
      else  // (edgeDir == EDGE_HOR)
      {
        pcCUP = pcCUQ->getPUAbove(uiPartPIdx, uiPartQIdx,!lfCrossSliceBoundaryFlag, false, !m_bLFCrossTileBoundary);
      }

      iQP_P = pcCUP->getQP(uiPartPIdx);

      if (bPCMFilter || pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag())
      {
        // Check if each of PUs is I_PCM with LF disabling
        bPartPNoFilter = (bPCMFilter && pcCUP->getIPCMFlag(uiPartPIdx));
        bPartQNoFilter = (bPCMFilter && pcCUQ->getIPCMFlag(uiPartQIdx));

        // check if each of PUs is lossless coded
        bPartPNoFilter = bPartPNoFilter || (pcCUP->isLosslessCoded(uiPartPIdx));
        bPartQNoFilter = bPartQNoFilter || (pcCUQ->isLosslessCoded(uiPartQIdx));
      }

      for ( UInt chromaIdx = 0; chromaIdx < 2; chromaIdx++ )//遍历两种色度分量
      {
        Int chromaQPOffset  = pcCU->getSlice()->getPPS()->getQpOffset(ComponentID(chromaIdx + 1));
        Pel* piTmpSrcChroma = (chromaIdx == 0) ? piTmpSrcCb : piTmpSrcCr;

        iQP = ((iQP_P + iQP_Q + 1) >> 1) + chromaQPOffset;
        if (iQP >= chromaQPMappingTableSize)
        {
          if (pcPicYuvRec->getChromaFormat()==CHROMA_420)
          {
            iQP -=6;
          }
          else if (iQP>51)
          {
            iQP=51;
          }
        }
        else if (iQP >= 0 )
        {
          iQP = getScaledChromaQP(iQP, pcPicYuvRec->getChromaFormat());
        }

        Int iIndexTC = Clip3(0, MAX_QP+DEFAULT_INTRA_TC_OFFSET, iQP + DEFAULT_INTRA_TC_OFFSET*(ucBs - 1) + (tcOffsetDiv2 << 1));
        Int iTc =  sm_tcTable[iIndexTC]*iBitdepthScale;

        for ( UInt uiStep = 0; uiStep < uiLoopLength; uiStep++ )
        {     //对色度分量执行最后的滤波
                    xPelFilterChroma( piTmpSrcChroma + iSrcStep*(uiStep+iIdx*uiLoopLength), iOffset, iTc , bPartPNoFilter, bPartQNoFilter, bitDepthChroma
                  #if JVET_D0033_ADAPTIVE_CLIPPING
                                      , ComponentID(chromaIdx + 1)
                  #endif
                                      );
        }
      }
    }
  }
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值