本文考察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;
}