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