目录
xEdgeFilterLuma函数
xEdgeFilterLuma函数是对亮度像素的一边界进行去块滤波,基本过程如下:
以长度4为单位遍历该边界,对于垂直边界,如下图右所示;对于水平边界,如下图左所示。
对于每一个长度为4的边界,进行如下过程:
- 获取滤波开关和滤波强度阈值参数:根据P块和Q块两侧的Qp值计算索引值,根据索引查表获得参数Tc和β
- 滤波开关决策,计算边界两侧像素的变化率dL(调用deriveLADFShift函数推导重建像素的平均亮度级)
- 如果dL小于β,表明该边界需要进行滤波。
- 对于需要滤波的边界,进行滤波强度决策,通过xUseStrongFiltering函数判断是否使用强滤波
- 调用xPelFilterLuma函数进行滤波过程
xEdgeFilterLuma函数代码及注释如下:
void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge )
{
const CompArea& lumaArea = cu.block(COMPONENT_Y);
const PreCalcValues& pcv = *cu.cs->pcv;
PelBuf picYuvRec = m_enc ? m_encPicYuvBuffer.getBuf( lumaArea ) : cu.cs->getRecoBuf( lumaArea );
Pel *piSrc = picYuvRec.buf;
const int iStride = picYuvRec.stride;
Pel *piTmpSrc = piSrc;
const PPS &pps = *(cu.cs->pps);
const SPS &sps = *(cu.cs->sps);
const Slice &slice = *(cu.slice);
const bool spsPaletteEnabledFlag = sps.getPLTMode();
const int bitDepthLuma = sps.getBitDepth(CHANNEL_TYPE_LUMA);
const ClpRng& clpRng( cu.cs->slice->clpRng(COMPONENT_Y) );
int iQP = 0;
// 4x4区域数
unsigned uiNumParts = ( ( ( edgeDir == EDGE_VER ) ? lumaArea.height / pcv.minCUHeight : lumaArea.width / pcv.minCUWidth ) );
int pelsInPart = pcv.minCUWidth; // 4
unsigned uiBsAbsIdx = 0, uiBs = 0;
int iOffset, iSrcStep;
bool bPartPNoFilter = false;
bool bPartQNoFilter = false;
int betaOffsetDiv2 = slice.getDeblockingFilterBetaOffsetDiv2();//beta
int tcOffsetDiv2 = slice.getDeblockingFilterTcOffsetDiv2();//tC
int xoffset, yoffset;
Position pos;
if (edgeDir == EDGE_VER) //垂直滤波所需信息
{
xoffset = 0;
yoffset = pelsInPart;
iOffset = 1;
iSrcStep = iStride;
piTmpSrc += iEdge * pelsInPart;
pos = Position{ lumaArea.x + iEdge * pelsInPart, lumaArea.y - yoffset };
}
else // (edgeDir == EDGE_HOR)
{
xoffset = pelsInPart;
yoffset = 0;
iOffset = iStride;
iSrcStep = 1;
piTmpSrc += iEdge*pelsInPart*iStride;
pos = Position{ lumaArea.x - xoffset, lumaArea.y + iEdge * pelsInPart };
}
const int iBitdepthScale = 1 << (bitDepthLuma - 8);
// dec pos since within the loop we first calc the pos 遍历所有的minCU
// 对于垂直边界,遍历该垂直边界中的所有长度为4的区域,因此iSrcStep=iStride;
// 垂直边界滤波处理的是水平方向的像素,因此iOffset=1
// 对于水平边界,遍历该水平边界中的所有长度为4的区域,因此iSrcStep=1
// 水平边界滤波处理的是垂直方向的像素,因此iOffset=iStride
for( int iIdx = 0; iIdx < uiNumParts; iIdx++ )
{
pos.x += xoffset;
pos.y += yoffset;
// Deblock luma boundaries on 4x4 grid only 只以亮度4x4网格作为边界,否则不滤波
if (edgeDir == EDGE_HOR && (pos.y % 4) != 0)
{
continue;
}
if (edgeDir == EDGE_VER && (pos.x % 4) != 0)
{
continue;
}
uiBsAbsIdx = getRasterIdx( pos, pcv );//获取网格索引
uiBs = BsGet(m_aapucBS[edgeDir][uiBsAbsIdx], COMPONENT_Y);//获取对应边界的边界强度
if( uiBs )
{
const CodingUnit& cuQ = cu; //当前CU
// 相邻CU
const CodingUnit& cuP = *cu.cs->getCU(pos.offset(xoffset - pelsInPart, yoffset - pelsInPart), cu.chType);
// Derive neighboring PU index
if (edgeDir == EDGE_VER)
{
if (!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(),
!( pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag() && pps.getSubPicFromCU(cuP).getloopFilterAcrossEnabledFlag())))
{
m_aapucBS[edgeDir][uiBsAbsIdx] = uiBs = 0;
continue;
}
}
else // (iDir == EDGE_HOR)
{
if (!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(),
!( pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag() && pps.getSubPicFromCU(cuP).getloopFilterAcrossEnabledFlag())))
{
m_aapucBS[edgeDir][uiBsAbsIdx] = uiBs = 0;
continue;
}
}
iQP = (cuP.qp + cuQ.qp + 1) >> 1;//获取QP作为第一维索引,后面还要加一个shift
#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET
if ( sps.getLadfEnabled() )
{
int iShift = 0;
deriveLADFShift( piTmpSrc + iSrcStep * (iIdx*pelsInPart), iStride, iShift, edgeDir, sps );
iQP += iShift;
}
#endif
bool sidePisLarge = false;
bool sideQisLarge = false;
// P和Q的最大滤波长度
int maxFilterLengthP = m_maxFilterLengthP[COMPONENT_Y][pos.x-m_ctuXLumaSamples][pos.y-m_ctuYLumaSamples];
int maxFilterLengthQ = m_maxFilterLengthQ[COMPONENT_Y][pos.x-m_ctuXLumaSamples][pos.y-m_ctuYLumaSamples];
if (maxFilterLengthP > 3)
{
sidePisLarge = true;
if ( maxFilterLengthP > 5 )
{
// restrict filter length if sub-blocks are used (e.g affine or ATMVP)如果使用子块,则限制过滤器长度(例如,affine或ATMVP)
if (cuP.affine)
{
maxFilterLengthP = std::min(maxFilterLengthP, 5);
}
}
}
if (maxFilterLengthQ > 3)
{
sideQisLarge = true;
}
if (edgeDir == EDGE_HOR && pos.y % slice.getSPS()->getCTUSize() == 0)
{
sidePisLarge = false;
}
/**************** 获取查表得到的tc,beta数值 ****************/
const int iIndexTC = Clip3(0, MAX_QP + DEFAULT_INTRA_TC_OFFSET, int(iQP + DEFAULT_INTRA_TC_OFFSET*(uiBs - 1) + (tcOffsetDiv2 << 1)));
const int iIndexB = Clip3(0, MAX_QP, iQP + (betaOffsetDiv2 << 1));
const int iTc = bitDepthLuma < 10 ? ((sm_tcTable[iIndexTC] + (1 << (9 - bitDepthLuma))) >> (10 - bitDepthLuma)) : ((sm_tcTable[iIndexTC]) << (bitDepthLuma - 10));
const int iBeta = sm_betaTable[iIndexB ] * iBitdepthScale;
const int iSideThreshold = ( iBeta + ( iBeta >> 1 ) ) >> 3;
const int iThrCut = iTc * 10;
const unsigned uiBlocksInPart = pelsInPart / 4 ? pelsInPart / 4 : 1;
for( int iBlkIdx = 0; iBlkIdx < uiBlocksInPart; iBlkIdx++ ) //遍历每个minCU中的4x4的块
{
/****************** 1.2 根据像素的变化率,来进行一次滤波开关决策,与QP找到的beta有关 ******************/
//对于垂直边界,计算水平方向的变化率;对于水平边界,计算垂直方向的变化率
const int dp0 = xCalcDP(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 0), iOffset);
const int dq0 = xCalcDQ(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 0), iOffset);
const int dp3 = xCalcDP(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 3), iOffset);
const int dq3 = xCalcDQ(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 3), iOffset);
int dp0L = dp0;//对大块变化率的初始化
int dq0L = dq0;
int dp3L = dp3;
int dq3L = dq3;
//对于大块情况,计算变化率时使用的像素变多
if (sidePisLarge)//如果P是大块
{
dp0L = (dp0L + xCalcDP(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 0) - 3 * iOffset, iOffset) + 1) >> 1;
dp3L = (dp3L + xCalcDP(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 3) - 3 * iOffset, iOffset) + 1) >> 1;
}
if (sideQisLarge)//如果Q是大块
{
dq0L = (dq0L + xCalcDQ(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 0) + 3 * iOffset, iOffset) + 1) >> 1;
dq3L = (dq3L + xCalcDQ(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + 3) + 3 * iOffset, iOffset) + 1) >> 1;
}
bool useLongtapFilter = false;
/****************** 大块:双线性强滤波 ******************/
if (sidePisLarge || sideQisLarge)//如果其中一个是大块
{
int d0L = dp0L + dq0L;
int d3L = dp3L + dq3L;
int dpL = dp0L + dp3L;
int dqL = dq0L + dq3L;
int dL = d0L + d3L;//总变化率
bPartPNoFilter = bPartQNoFilter = false;
if (spsPaletteEnabledFlag)
{
// check if each of PUs is palette coded
bPartPNoFilter = bPartPNoFilter || CU::isPLT(cuP);
bPartQNoFilter = bPartQNoFilter || CU::isPLT(cuQ);
}
/****************** 1.3 根据像素的变化率,来进行一次滤波强弱选择,与beta和tc都有关 ******************/
if (dL < iBeta) //滤波开关判断
{
const bool filterP = (dpL < iSideThreshold);
const bool filterQ = (dqL < iSideThreshold);
//对于垂直边界,src0和src3表示第0行和第3行的像素;对于水平边界,src0和src3表示第0列和第3列的像素
Pel* src0 = piTmpSrc + iSrcStep * (iIdx*pelsInPart + iBlkIdx * 4 + 0);
Pel* src3 = piTmpSrc + iSrcStep * (iIdx*pelsInPart + iBlkIdx * 4 + 3);
// adjust decision so that it is not read beyond p5 is maxFilterLengthP is 5 and q5 if maxFilterLengthQ is 5
// 调整决策,使其读数不超过p5为maxFilterLengthP为5,如果maxFilterLengthQ为5,则为q5
const bool swL = xUseStrongFiltering(src0, iOffset, 2 * d0L, iBeta, iTc, sidePisLarge, sideQisLarge, maxFilterLengthP, maxFilterLengthQ)
&& xUseStrongFiltering(src3, iOffset, 2 * d3L, iBeta, iTc, sidePisLarge, sideQisLarge, maxFilterLengthP, maxFilterLengthQ);
if (swL) //更强滤波
{
useLongtapFilter = true;
// 对于垂直边界,滤波四行的像素
// 对于水平边界,滤波四列的像素
for (int i = 0; i < DEBLOCK_SMALLEST_BLOCK / 2; i++)
{
xPelFilterLuma(piTmpSrc + iSrcStep*(iIdx*pelsInPart + iBlkIdx * 4 + i), iOffset, iTc, swL, bPartPNoFilter, bPartQNoFilter, iThrCut, filterP, filterQ, clpRng, sidePisLarge, sideQisLarge, maxFilterLengthP, maxFilterLengthQ);
}
}
}
}
if (!useLongtapFilter)
{
const int d0 = dp0 + dq0;
const int d3 = dp3 + dq3;
const int dp = dp0 + dp3;
const int dq = dq0 + dq3;
const int d = d0 + d3;
bPartPNoFilter = bPartQNoFilter = false;
if (spsPaletteEnabledFlag)
{
// check if each of PUs is palette coded
bPartPNoFilter = bPartPNoFilter || CU::isPLT(cuP);
bPartQNoFilter = bPartQNoFilter || CU::isPLT(cuQ);
}
if (d < iBeta) //滤波开关决策
{
bool bFilterP = false;
bool bFilterQ = false;
if (maxFilterLengthP > 1 && maxFilterLengthQ > 1)
{
bFilterP = (dp < iSideThreshold);
bFilterQ = (dq < iSideThreshold);
}
bool sw = false; //滤波强度决策
if (maxFilterLengthP > 2 && maxFilterLengthQ > 2)
{
sw = xUseStrongFiltering(piTmpSrc + iSrcStep * (iIdx * pelsInPart + iBlkIdx * 4 + 0), iOffset, 2 * d0,
iBeta, iTc)
&& xUseStrongFiltering(piTmpSrc + iSrcStep * (iIdx * pelsInPart + iBlkIdx * 4 + 3), iOffset, 2 * d3,
iBeta, iTc);
}
for (int i = 0; i < DEBLOCK_SMALLEST_BLOCK / 2; i++)
{
xPelFilterLuma(piTmpSrc + iSrcStep * (iIdx * pelsInPart + iBlkIdx * 4 + i), iOffset, iTc, sw,
bPartPNoFilter, bPartQNoFilter, iThrCut, bFilterP, bFilterQ, clpRng);
}
}
}
}
}
}
}
xUseStrongFiltering函数
xUseStrongFiltering函数进行滤波强度决策,代码及注释如下:
/**
- Decision between strong and weak filter 滤波强度决策
.
\param offset offset value for picture data
\param d d value
\param beta beta value
\param tc tc value
\param piSrc pointer to picture data
*/
inline bool LoopFilter::xUseStrongFiltering(Pel* piSrc, const int iOffset, const int d, const int beta, const int tc, bool sidePisLarge, bool sideQisLarge, int maxFilterLengthP, int maxFilterLengthQ, bool isChromaHorCTBBoundary) const
{
const Pel m4 = piSrc[ 0 ];// ** ** ** **
const Pel m3 = piSrc[-iOffset ];// m0 m1 m2 m3 m4 m5 m6 m7
const Pel m7 = piSrc[ iOffset * 3];// |
const Pel m0 = piSrc[-iOffset * 4];// ** 当前起始位置[0](Q块)
const Pel m2 = piSrc[-iOffset * 2];
int sp3 = abs(m0 - m3);//最左边的位置减去左侧边缘
if (isChromaHorCTBBoundary)//如果是色度CTU边缘,则看相邻边缘
{
sp3 = abs(m2 - m3);
}
int sq3 = abs(m7 - m4);//最右边的位置减去右侧边缘
const int d_strong = sp3 + sq3; // 两者的差距
if (sidePisLarge || sideQisLarge)//对于大块,进一步增加长度
{
Pel mP4;
Pel m11;
if (sidePisLarge) //如果P是大块
{
if (maxFilterLengthP == 7) //如果P块滤波长度为7,则扩展到左侧第七个像素
{
const Pel mP5 = piSrc[-iOffset * 5];
const Pel mP6 = piSrc[-iOffset * 6];
const Pel mP7 = piSrc[-iOffset * 7];;
mP4 = piSrc[-iOffset * 8];
sp3 = sp3 + abs(mP5 - mP6 - mP7 + mP4);
}
else
{
mP4 = piSrc[-iOffset * 6];
}
sp3 = (sp3 + abs(m0 - mP4) + 1) >> 1;
}
if (sideQisLarge) //如果Q是大块
{
if (maxFilterLengthQ == 7)
{
const Pel m8 = piSrc[iOffset * 4];
const Pel m9 = piSrc[iOffset * 5];
const Pel m10 = piSrc[iOffset * 6];;
m11 = piSrc[iOffset * 7];
sq3 = sq3 + abs(m8 - m9 - m10 + m11);
}
else
{
m11 = piSrc[iOffset * 5];
}
sq3 = (sq3 + abs(m11 - m7) + 1) >> 1;
}
return ((sp3 + sq3) < (beta * 3 >> 5)) && (d < (beta >> 4)) && (abs(m3 - m4) < ((tc * 5 + 1) >> 1));
}
else
{
return ((d_strong < (beta >> 3)) && (d < (beta >> 2)) && (abs(m3 - m4) < ((tc * 5 + 1) >> 1)));
}
}
xPelFilterLuma函数
xPelFilterLuma函数进行亮度像素的滤波处理过程。对于大块(大于等于32)的强滤波,调用xFilteringPandQ函数执行双线性滤波。否则,执行普通的强滤波或者弱滤波过程。
inline void LoopFilter::xPelFilterLuma(Pel* piSrc, const int iOffset, const int tc, const bool sw, const bool bPartPNoFilter, const bool bPartQNoFilter, const int iThrCut, const bool bFilterSecondP, const bool bFilterSecondQ, const ClpRng& clpRng, bool sidePisLarge, bool sideQisLarge, int maxFilterLengthP, int maxFilterLengthQ) const
{
int delta;
/******** 初始化像素位置、像素值 *******/
const Pel m4 = piSrc[ 0 ];
const Pel m3 = piSrc[-iOffset ];
const Pel m5 = piSrc[ iOffset ];
const Pel m2 = piSrc[-iOffset * 2];
const Pel m6 = piSrc[ iOffset * 2];
const Pel m1 = piSrc[-iOffset * 3];
const Pel m7 = piSrc[ iOffset * 3];
const Pel m0 = piSrc[-iOffset * 4];
const Pel mP1 = piSrc[-iOffset * 5];
const Pel mP2 = piSrc[-iOffset * 6];
const Pel mP3 = piSrc[-iOffset * 7];
const Pel m8 = piSrc[ iOffset * 4];
const Pel m9 = piSrc[ iOffset * 5];
const Pel m10 = piSrc[ iOffset * 6];
const char tc3[3] = { 3, 2, 1};
if (sw) //强滤波
{
if (sidePisLarge || sideQisLarge) //如果是大块,那么进行双线性滤波
{
xFilteringPandQ(piSrc, iOffset, sidePisLarge ? maxFilterLengthP : 3, sideQisLarge ? maxFilterLengthQ : 3, tc);
}
else // 普通的强滤波
{
piSrc[-iOffset] = Clip3(m3 - tc3[0] * tc, m3 + tc3[0] * tc, ((m1 + 2 * m2 + 2 * m3 + 2 * m4 + m5 + 4) >> 3));
piSrc[0] = Clip3(m4 - tc3[0] * tc, m4 + tc3[0] * tc, ((m2 + 2 * m3 + 2 * m4 + 2 * m5 + m6 + 4) >> 3));
piSrc[-iOffset * 2] = Clip3(m2 - tc3[1] * tc, m2 + tc3[1] * tc, ((m1 + m2 + m3 + m4 + 2) >> 2));
piSrc[iOffset] = Clip3(m5 - tc3[1] * tc, m5 + tc3[1] * tc, ((m3 + m4 + m5 + m6 + 2) >> 2));
piSrc[-iOffset * 3] = Clip3(m1 - tc3[2] * tc, m1 + tc3[2] * tc, ((2 * m0 + 3 * m1 + m2 + m3 + m4 + 4) >> 3));
piSrc[iOffset * 2] = Clip3(m6 - tc3[2] * tc, m6 + tc3[2] * tc, ((m3 + m4 + m5 + 3 * m6 + 2 * m7 + 4) >> 3));
}
}
else
{
/* Weak filter 弱滤波 */
delta = ( 9 * ( m4 - m3 ) - 3 * ( m5 - m2 ) + 8 ) >> 4;
if ( abs(delta) < iThrCut ) //如果不满足该条件,说明不连续可能是内容导致的
{
delta = Clip3( -tc, tc, delta );
piSrc[-iOffset] = ClipPel( m3 + delta, clpRng);
piSrc[0] = ClipPel( m4 - delta, clpRng);
const int tc2 = tc >> 1;
if( bFilterSecondP )
{
const int delta1 = Clip3( -tc2, tc2, ( ( ( ( m1 + m3 + 1 ) >> 1 ) - m2 + delta ) >> 1 ) );
piSrc[-iOffset * 2] = ClipPel( m2 + delta1, clpRng);
}
if( bFilterSecondQ )
{
const int delta2 = Clip3( -tc2, tc2, ( ( ( ( m6 + m4 + 1 ) >> 1 ) - m5 - delta ) >> 1 ) );
piSrc[iOffset] = ClipPel( m5 + delta2, clpRng);
}
}
}
if(bPartPNoFilter)
{
piSrc[-iOffset ] = m3;
piSrc[-iOffset * 2] = m2;
piSrc[-iOffset * 3] = m1;
if (sidePisLarge)
{
piSrc[-iOffset * 4] = m0;
piSrc[-iOffset * 5] = mP1;
piSrc[-iOffset * 6] = mP2;
piSrc[-iOffset * 7] = mP3;
}
}
if(bPartQNoFilter)
{
piSrc[ 0 ] = m4;
piSrc[ iOffset ] = m5;
piSrc[ iOffset * 2] = m6;
if (sideQisLarge)
{
piSrc[iOffset * 3] = m7;
piSrc[iOffset * 4] = m8;
piSrc[iOffset * 5] = m9;
piSrc[iOffset * 6] = m10;
}
}
}
xEdgeFilterChroma函数
xEdgeFilterChroma函数过程和亮度xEdgeFilterLuma类似,不同的是该过程遍历边界时是以2为单位进行遍历的
void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge)
{
const Position lumaPos = cu.Y().valid() ? cu.Y().pos() : recalcPosition( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].pos() );
const Size lumaSize = cu.Y().valid() ? cu.Y().size() : recalcSize( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].size() );
const PreCalcValues& pcv = *cu.cs->pcv;
unsigned rasterIdx = getRasterIdx( lumaPos, pcv );
PelBuf picYuvRecCb = m_enc ? m_encPicYuvBuffer.getBuf(cu.block(COMPONENT_Cb)) : cu.cs->getRecoBuf(cu.block(COMPONENT_Cb));
PelBuf picYuvRecCr = m_enc ? m_encPicYuvBuffer.getBuf(cu.block(COMPONENT_Cr)) : cu.cs->getRecoBuf(cu.block(COMPONENT_Cr));
Pel *piSrcCb = picYuvRecCb.buf;
Pel *piSrcCr = picYuvRecCr.buf;
const int iStride = picYuvRecCb.stride;
const SPS &sps = *cu.cs->sps;
const PPS &pps = *cu.cs->pps;
const Slice &slice = *cu.slice;
const ChromaFormat nChromaFormat = sps.getChromaFormatIdc();
const unsigned uiPelsInPartChromaH = pcv.minCUWidth >> ::getComponentScaleX(COMPONENT_Cb, nChromaFormat);
const unsigned uiPelsInPartChromaV = pcv.minCUHeight >> ::getComponentScaleY(COMPONENT_Cb, nChromaFormat);
int iOffset, iSrcStep;
unsigned uiLoopLength;
bool bPartPNoFilter = false;
bool bPartQNoFilter = false;
const int tcOffsetDiv2[2] = { slice.getDeblockingFilterCbTcOffsetDiv2(), slice.getDeblockingFilterCrTcOffsetDiv2() };
const int betaOffsetDiv2[2] = { slice.getDeblockingFilterCbBetaOffsetDiv2(), slice.getDeblockingFilterCrBetaOffsetDiv2() };
// Vertical Position 垂直位置
unsigned uiEdgeNumInCtuVert = rasterIdx % pcv.partsInCtuWidth + iEdge;
unsigned uiEdgeNumInCtuHor = rasterIdx / pcv.partsInCtuWidth + 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;
}
unsigned uiNumParts = ( edgeDir == EDGE_VER ) ? lumaSize.height / pcv.minCUHeight : lumaSize.width / pcv.minCUWidth ;
int uiNumPelsLuma = pcv.minCUWidth;
unsigned uiBsAbsIdx;
unsigned bS[2];
Pel* piTmpSrcCb = piSrcCb;
Pel* piTmpSrcCr = piSrcCr;
int xoffset, yoffset;
Position pos( lumaPos.x, lumaPos.y );
if( edgeDir == EDGE_VER ) //垂直边界
{
xoffset = 0;
yoffset = uiNumPelsLuma;
iOffset = 1;
iSrcStep = iStride;
piTmpSrcCb += iEdge*uiPelsInPartChromaH;
piTmpSrcCr += iEdge*uiPelsInPartChromaH;
uiLoopLength = uiPelsInPartChromaV;//滤波长度
pos = Position{ lumaPos.x + iEdge*uiNumPelsLuma, lumaPos.y - yoffset };
}
else // (edgeDir == EDGE_HOR) 水平边界
{
xoffset = uiNumPelsLuma;
yoffset = 0;
iOffset = iStride;
iSrcStep = 1;
piTmpSrcCb += iEdge*iStride*uiPelsInPartChromaV;
piTmpSrcCr += iEdge*iStride*uiPelsInPartChromaV;
uiLoopLength = uiPelsInPartChromaH;
pos = Position{ lumaPos.x - xoffset, lumaPos.y + iEdge*uiNumPelsLuma };
}
const int iBitdepthScale = 1 << (sps.getBitDepth(CHANNEL_TYPE_CHROMA) - 8);
// 遍历该色度块边界的所有长度为2的区域
for( int iIdx = 0; iIdx < uiNumParts; iIdx++ )
{
pos.x += xoffset;
pos.y += yoffset;
uiBsAbsIdx = getRasterIdx( pos, pcv );
unsigned tmpBs = m_aapucBS[edgeDir][uiBsAbsIdx];
tmpBs = m_aapucBS[edgeDir][uiBsAbsIdx];
bS[0] = BsGet(tmpBs, COMPONENT_Cb);
bS[1] = BsGet(tmpBs, COMPONENT_Cr);
if (bS[0] > 0 || bS[1] > 0)
{
const CodingUnit& cuQ = cu;
CodingUnit& cuP1 = *cu.cs->getCU( recalcPosition( cu.chromaFormat, CHANNEL_TYPE_LUMA, cu.chType, pos.offset( xoffset - uiNumPelsLuma, yoffset - uiNumPelsLuma ) ), cu.chType );
CodingUnit& cuP = *cu.cs->getCU( recalcPosition( cu.chromaFormat, CHANNEL_TYPE_LUMA, (cuP1.isSepTree() ? CHANNEL_TYPE_CHROMA : cu.chType), pos.offset( xoffset - uiNumPelsLuma, yoffset - uiNumPelsLuma ) ), (cuP1.isSepTree() ? CHANNEL_TYPE_CHROMA : cu.chType));
if (edgeDir == EDGE_VER)
{
CHECK(!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(),
!( pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag() && pps.getSubPicFromCU(cuP).getloopFilterAcrossEnabledFlag())), "Neighbour not available");
}
else // (iDir == EDGE_HOR)
{
CHECK(!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(),
!( pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag() && pps.getSubPicFromCU(cuP).getloopFilterAcrossEnabledFlag())), "Neighbour not available");
}
bPartPNoFilter = bPartQNoFilter = false;
if ( sps.getPLTMode())
{
// check if each of PUs is palette coded
bPartPNoFilter = bPartPNoFilter || CU::isPLT(cuP);
bPartQNoFilter = bPartQNoFilter || CU::isPLT(cuQ);
}
const int maxFilterLengthP = m_maxFilterLengthP[COMPONENT_Cb][(pos.x-m_ctuXLumaSamples)>>m_shiftHor][(pos.y-m_ctuYLumaSamples)>>m_shiftVer];
const int maxFilterLengthQ = m_maxFilterLengthQ[COMPONENT_Cb][(pos.x-m_ctuXLumaSamples)>>m_shiftHor][(pos.y-m_ctuYLumaSamples)>>m_shiftVer];
bool largeBoundary = false;
bool isChromaHorCTBBoundary = false;
if ( maxFilterLengthP >= 3 && maxFilterLengthQ >= 3 ) //长边界
{
largeBoundary = true;
}
if (edgeDir == EDGE_HOR && pos.y % cuP.slice->getSPS()->getCTUSize() == 0)
{
isChromaHorCTBBoundary = true;
}
for( int chromaIdx = 0; chromaIdx < 2; chromaIdx++ )
{
// 如果边界强度为2或者边界强度为1且为大块边界
if ((bS[chromaIdx] == 2) || (largeBoundary && (bS[chromaIdx] == 1)))
{
const ClpRng &clpRng(cu.cs->slice->clpRng(ComponentID(chromaIdx + 1)));
Pel * piTmpSrcChroma = (chromaIdx == 0) ? piTmpSrcCb : piTmpSrcCr;
const TransformUnit &tuQ = *cuQ.cs->getTU(
recalcPosition(cu.chromaFormat, CHANNEL_TYPE_LUMA, CHANNEL_TYPE_CHROMA, pos), CHANNEL_TYPE_CHROMA);
const TransformUnit &tuP =
*cuP.cs->getTU(recalcPosition(cu.chromaFormat, CHANNEL_TYPE_LUMA, CHANNEL_TYPE_CHROMA,
(edgeDir == EDGE_VER) ? pos.offset(-1, 0) : pos.offset(0, -1)),
CHANNEL_TYPE_CHROMA);
const QpParam cQP(tuP, ComponentID(chromaIdx + 1), -MAX_INT, false);
const QpParam cQQ(tuQ, ComponentID(chromaIdx + 1), -MAX_INT, false);
const int qpBdOffset = tuP.cs->sps->getQpBDOffset(toChannelType(ComponentID(chromaIdx + 1)));
int baseQp_P = cQP.Qp(0) - qpBdOffset;
int baseQp_Q = cQQ.Qp(0) - qpBdOffset;
int iQP = ((baseQp_Q + baseQp_P + 1) >> 1);
const int iIndexTC =
Clip3<int>(0, MAX_QP + DEFAULT_INTRA_TC_OFFSET,
iQP + DEFAULT_INTRA_TC_OFFSET * (bS[chromaIdx] - 1) + (tcOffsetDiv2[chromaIdx] << 1));
const int bitDepthChroma = sps.getBitDepth(CHANNEL_TYPE_CHROMA);
const int iTc = bitDepthChroma < 10
? ((sm_tcTable[iIndexTC] + (1 << (9 - bitDepthChroma))) >> (10 - bitDepthChroma))
: ((sm_tcTable[iIndexTC]) << (bitDepthChroma - 10));
bool useLongFilter = false;
if (largeBoundary) //强滤波
{
const int indexB = Clip3<int>(0, MAX_QP, iQP + (betaOffsetDiv2[chromaIdx] << 1));
const int beta = sm_betaTable[indexB] * iBitdepthScale;
const int dp0 =
xCalcDP(piTmpSrcChroma + iSrcStep * (iIdx * uiLoopLength + 0), iOffset, isChromaHorCTBBoundary);
const int dq0 = xCalcDQ(piTmpSrcChroma + iSrcStep * (iIdx * uiLoopLength + 0), iOffset);
const int subSamplingShift = (edgeDir == EDGE_VER) ? m_shiftVer : m_shiftHor;
const int dp3 =
(subSamplingShift == 1)
? xCalcDP(piTmpSrcChroma + iSrcStep * (iIdx * uiLoopLength + 1), iOffset, isChromaHorCTBBoundary)
: xCalcDP(piTmpSrcChroma + iSrcStep * (iIdx * uiLoopLength + 3), iOffset, isChromaHorCTBBoundary);
const int dq3 = (subSamplingShift == 1)
? xCalcDQ(piTmpSrcChroma + iSrcStep * (iIdx * uiLoopLength + 1), iOffset)
: xCalcDQ(piTmpSrcChroma + iSrcStep * (iIdx * uiLoopLength + 3), iOffset);
const int d0 = dp0 + dq0;
const int d3 = dp3 + dq3;
const int d = d0 + d3;
if (d < beta)
{
useLongFilter = true;
const bool sw = xUseStrongFiltering(piTmpSrcChroma + iSrcStep * (iIdx * uiLoopLength + 0), iOffset,
2 * d0, beta, iTc, false, false, 7, 7, isChromaHorCTBBoundary)
&& xUseStrongFiltering(
piTmpSrcChroma + iSrcStep * (iIdx * uiLoopLength + ((subSamplingShift == 1) ? 1 : 3)),
iOffset, 2 * d3, beta, iTc, false, false, 7, 7, isChromaHorCTBBoundary);
for (unsigned step = 0; step < uiLoopLength; step++)
{
xPelFilterChroma(piTmpSrcChroma + iSrcStep * (step + iIdx * uiLoopLength), iOffset, iTc, sw,
bPartPNoFilter, bPartQNoFilter, clpRng, largeBoundary, isChromaHorCTBBoundary);
}
}
}
if (!useLongFilter)
{
for (unsigned step = 0; step < uiLoopLength; step++)
{
xPelFilterChroma(piTmpSrcChroma + iSrcStep * (step + iIdx * uiLoopLength), iOffset, iTc, false,
bPartPNoFilter, bPartQNoFilter, clpRng, largeBoundary, isChromaHorCTBBoundary);
}
}
}
}
}
}
}