HEVC學習(三十三) —— 去方塊濾波之四

本文考察Boundary Strength (BS)的獲取過程:

Void TComLoopFilter::xGetBoundaryStrengthSingle ( TComDataCU* pcCU, UInt uiAbsZorderIdx, Int iDir, UInt uiAbsPartIdx )
{
  TComSlice* const pcSlice = pcCU->getSlice();
  
  const UInt uiPartQ = uiAbsPartIdx; //!< 當前CU的地址
  TComDataCU* const pcCUQ = pcCU; //!< 當前CU的指針
  
  UInt uiPartP;
  TComDataCU* pcCUP;
  UInt uiBs = 0;
  
  //-- Calculate Block Index
  if (iDir == EDGE_VER) //!< 垂直邊界濾波,獲取左鄰CU
  {
    pcCUP = pcCUQ->getPULeft(uiPartP, uiPartQ, !pcCU->getSlice()->getLFCrossSliceBoundaryFlag(), false, !m_bLFCrossTileBoundary);
  }
  else  // (iDir == EDGE_HOR) //!< 水平邊界濾波,獲取上鄰CU
  {
#if LINEBUF_CLEANUP
    pcCUP = pcCUQ->getPUAbove(uiPartP, uiPartQ, !pcCU->getSlice()->getLFCrossSliceBoundaryFlag(), false, false, !m_bLFCrossTileBoundary);
#else
    pcCUP = pcCUQ->getPUAbove(uiPartP, uiPartQ, !pcCU->getSlice()->getLFCrossSliceBoundaryFlag(), false, false, false, !m_bLFCrossTileBoundary);
#endif
  }
  
  //-- Set BS for Intra MB : BS = 4 or 3
  if ( pcCUP->isIntra(uiPartP) || pcCUQ->isIntra(uiPartQ) ) //!< 至少有一個CU是幀內預測模式
  {
    uiBs = 2;
  }
  //! 討論CU不是幀內預測模式的情況
  //-- Set BS for not Intra MB : BS = 2 or 1 or 0
  if ( !pcCUP->isIntra(uiPartP) && !pcCUQ->isIntra(uiPartQ) )
  {
    UInt nsPartQ = uiPartQ;
    UInt nsPartP = uiPartP;
    //!< 至少有一個鄰塊具有非零殘差係數且該邊界爲TU邊界
    if ( m_aapucBS[iDir][uiAbsPartIdx] && (pcCUQ->getCbf( nsPartQ, TEXT_LUMA, pcCUQ->getTransformIdx(nsPartQ)) != 0 || pcCUP->getCbf( nsPartP, TEXT_LUMA, pcCUP->getTransformIdx(nsPartP) ) != 0) )
    {
      uiBs = 1;
    }
    else
    {
      if (iDir == EDGE_HOR)
      {
#if LINEBUF_CLEANUP
        pcCUP = pcCUQ->getPUAbove(uiPartP, uiPartQ, !pcCU->getSlice()->getLFCrossSliceBoundaryFlag(), false, false, !m_bLFCrossTileBoundary);
#else
        pcCUP = pcCUQ->getPUAbove(uiPartP, uiPartQ, !pcCU->getSlice()->getLFCrossSliceBoundaryFlag(), false, true, false, !m_bLFCrossTileBoundary);
#endif
      }//! 接下來的是P slice 和 B slice的情況,咋一看,代碼顯得比較囉嗦,特別是B slice的情況。但是,不要被這個表象給迷惑了,其實這部分代碼對應於    draft 8.7.2.3中關於變量bS[xDi][yDj]的推導過程的描述。先把那部分的內容看了,再回過頭來看下面代碼,會覺得一點都不復雜,甚至是理所當然的。
      if (pcSlice->isInterB()) //!< 當前片爲B slice
      {//! 根據P塊和Q塊所參考的參考圖像是否相同(此時要討論list0和list1的情況)、它們的運動矢量(水平、垂直兩個分量)差值的絕對值是否超過4(即以1/4像素爲單位)來設定BS
		  Int iRefIdx;
		  Int *piRefP0, *piRefP1, *piRefQ0, *piRefQ1;
		  iRefIdx = pcCUP->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartP);
		  piRefP0 = (iRefIdx < 0) ? NULL :  (Int*) pcCUP->getSlice()->getRefPic(REF_PIC_LIST_0, iRefIdx);
		  iRefIdx = pcCUP->getCUMvField(REF_PIC_LIST_1)->getRefIdx(uiPartP);
		  piRefP1 = (iRefIdx < 0) ? NULL :  (Int*) pcCUP->getSlice()->getRefPic(REF_PIC_LIST_1, iRefIdx);
		  iRefIdx = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartQ);
		  piRefQ0 = (iRefIdx < 0) ? NULL :  (Int*) pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx);
		  iRefIdx = pcCUQ->getCUMvField(REF_PIC_LIST_1)->getRefIdx(uiPartQ);
		  piRefQ1 = (iRefIdx < 0) ? NULL :  (Int*) pcSlice->getRefPic(REF_PIC_LIST_1, iRefIdx);


		  TComMv pcMvP0 = pcCUP->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartP);
		  TComMv pcMvP1 = pcCUP->getCUMvField(REF_PIC_LIST_1)->getMv(uiPartP);
		  TComMv pcMvQ0 = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartQ);
		  TComMv pcMvQ1 = pcCUQ->getCUMvField(REF_PIC_LIST_1)->getMv(uiPartQ);

		  if ( ((piRefP0==piRefQ0)&&(piRefP1==piRefQ1)) || ((piRefP0==piRefQ1)&&(piRefP1==piRefQ0)) )
		  {
			  uiBs = 0;
			  if ( piRefP0 != piRefP1 )   // Different L0 & L1
			  {
				  if ( piRefP0 == piRefQ0 )
				  {
					  pcMvP0 -= pcMvQ0;   pcMvP1 -= pcMvQ1;
					  uiBs = (pcMvP0.getAbsHor() >= 4) | (pcMvP0.getAbsVer() >= 4) |
						  (pcMvP1.getAbsHor() >= 4) | (pcMvP1.getAbsVer() >= 4);
				  }
				  else
				  {
					  pcMvP0 -= pcMvQ1;   pcMvP1 -= pcMvQ0;
					  uiBs = (pcMvP0.getAbsHor() >= 4) | (pcMvP0.getAbsVer() >= 4) |
						  (pcMvP1.getAbsHor() >= 4) | (pcMvP1.getAbsVer() >= 4);
				  }
			  }
			  else    // Same L0 & L1
			  {
				  TComMv pcMvSub0 = pcMvP0 - pcMvQ0;
				  TComMv pcMvSub1 = pcMvP1 - pcMvQ1;
				  pcMvP0 -= pcMvQ1;   pcMvP1 -= pcMvQ0;
				  uiBs = ( (pcMvP0.getAbsHor() >= 4) | (pcMvP0.getAbsVer() >= 4) |
					  (pcMvP1.getAbsHor() >= 4) | (pcMvP1.getAbsVer() >= 4) ) &&
					  ( (pcMvSub0.getAbsHor() >= 4) | (pcMvSub0.getAbsVer() >= 4) |
					  (pcMvSub1.getAbsHor() >= 4) | (pcMvSub1.getAbsVer() >= 4) );
			  }
		  }
		  else // for all different Ref_Idx
		  {
			  uiBs = 1;
		  }

      }
      else  // pcSlice->isInterP() //!< 當前片爲P slice
      {//! 根據P塊和Q塊所參考的參考圖像是否相同、它們的運動矢量(水平、垂直兩個分量)差值的絕對值是否超過4(即以1/4像素爲單位)來設定BS
		  Int iRefIdx;
		  Int *piRefP0, *piRefQ0;
		  iRefIdx = pcCUP->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartP);
		  piRefP0 = (iRefIdx < 0) ? NULL :  (Int*) pcCUP->getSlice()->getRefPic(REF_PIC_LIST_0, iRefIdx);
		  iRefIdx = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getRefIdx(uiPartQ);
		  piRefQ0 = (iRefIdx < 0) ? NULL :  (Int*) pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx);
		  TComMv pcMvP0 = pcCUP->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartP);
		  TComMv pcMvQ0 = pcCUQ->getCUMvField(REF_PIC_LIST_0)->getMv(uiPartQ);

		  pcMvP0 -= pcMvQ0;
		  uiBs = (piRefP0 != piRefQ0) | (pcMvP0.getAbsHor() >= 4) | (pcMvP0.getAbsVer() >= 4);

      }
    }   // enf of "if( one of BCBP == 0 )"
  }   // enf of "if( not Intra )"
  
  m_aapucBS[iDir][uiAbsPartIdx] = uiBs;
}


 

發佈了97 篇原創文章 · 獲贊 855 · 訪問量 106萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章