目录
xSetMaxFilterLengthPQFromTransformSizes函数
xSetEdgefilterMultiple函数
xSetEdgefilterMultiple函数遍历全部的边界(垂直或者水平),设置其是否使用滤波
void LoopFilter::xSetEdgefilterMultiple( const CodingUnit& cu,
const DeblockEdgeDir edgeDir,
const Area& area,
const bool bValue,
const bool EdgeIdx )
{
const PreCalcValues& pcv = *cu.cs->pcv;
const unsigned uiAdd = ( edgeDir == EDGE_VER ) ? pcv.partsInCtuWidth : 1;//垂直滤波往下走1个,水平滤波往右走1个
// 4x4边界数目
const unsigned uiNumElem = ( edgeDir == EDGE_VER ) ? ( area.height / pcv.minCUHeight ) : ( area.width / pcv.minCUWidth );
unsigned uiBsIdx = getRasterIdx( area, pcv ); //第一个边界光栅扫描的索引值
for( int ui = 0; ui < uiNumElem; ui++ ) //遍历所有的边界(垂直或者水平)
{
m_aapbEdgeFilter[edgeDir][uiBsIdx] = bValue; //设置是否使用滤波器
if ( m_aapucBS[edgeDir][uiBsIdx] && bValue )
{
m_aapucBS[edgeDir][uiBsIdx] = 3; // both the TU and PU edge 表示既是TU边界也是PU边界
}
else
{
if( ! EdgeIdx )
{
m_aapucBS[edgeDir][uiBsIdx] = bValue;
}
}
uiBsIdx += uiAdd;
}
}
xSetMaxFilterLengthPQFromTransformSizes函数
xSetMaxFilterLengthPQFromTransformSizes函数是根据边界处相邻块的长度判断需要进行滤波的最大像素数,记边界两侧的块分别为P块和Q块
对于垂直边界,需要判断P块和Q块的宽度(width);对于水平边界,需要判断P块和Q块的高度(Height)
对于亮度分量,分为以下三种情况:
- 小块(小于等于4),最多滤波1个像素
- 大块(大于等于32),最多滤波7个像素
- 否则,最多滤波3个像素
对于色度分量,分为以下两种情况:
- 大块(大于等于8),最多滤波3个像素
- 否则,最多滤波1个像素
这里只是计算了每个边界在进行滤波时的最大像素数,其真正进行滤波的像素数还需要根据滤波强度决策来决定。
代码及注释如下:
void LoopFilter::xSetMaxFilterLengthPQFromTransformSizes( const DeblockEdgeDir edgeDir, const CodingUnit& cu, const TransformUnit& currTU )
{
const TransformUnit& tuQ = currTU;// 将Q设置为当前TU
if ( edgeDir == EDGE_HOR ) //水平边界
{ // 遍历所有的颜色分量
for ( int cIdx = 0; cIdx < ::getNumberValidComponents(tuQ.chromaFormat); cIdx++ ) // per component
{
const ComponentID comp = ComponentID(cIdx);
const ChannelType ch = toChannelType(comp);
const int shiftHor = ( ( ch == CH_L ) ? 0 : m_shiftHor );
const int shiftVer = ( ( ch == CH_L ) ? 0 : m_shiftVer );
const int ctuXOff = currTU.block(comp).x - ( m_ctuXLumaSamples >> shiftHor ); // x方向距离左CTU的距离 x offset from left edge of CTU in respective channel sample units
const int ctuYOff = currTU.block(comp).y - ( m_ctuYLumaSamples >> shiftVer ); // y方向距离上CTU的距离 y offset from top edge of CTU in respective channel sample units
const int minCUWidth = cu.cs->pcv->minCUWidth >> shiftHor;
if ( currTU.block(comp).valid() && ( ( currTU.block(comp).y == cu.block(comp).y ) ? m_stLFCUParam.topEdge : m_stLFCUParam.internalEdge ) ) // Edge deblocking needs to be recomputed since ISP contains whole CU chroma transforms in last TU of the CU
{
//边缘去块需要重新计算,因为ISP在CU的最后一个TU中包含整个CU色度变换
for ( int x = 0; x < currTU.blocks[cIdx].width; x += minCUWidth ) //以4x4为单位遍历边界
{
const Position posQ = Position( currTU.blocks[ch].x + x, currTU.blocks[ch].y );
const Position posP = posQ.offset( 0, -1 );
const int sizeQSide = tuQ.block(comp).height;//Q像素长度
const TransformUnit& tuP = *cu.cs->getTU( posP, ch );
const int sizePSide = tuP.block(comp).height;//P像素长度
m_transformEdge[cIdx][ctuXOff+x][ctuYOff] = true;
if ( comp == COMPONENT_Y )
{
bool smallBlock = (sizePSide <= 4) || (sizeQSide <= 4);
if (smallBlock) //对于亮度的小块(小于等于4x4),仅滤波1个像素
{
m_maxFilterLengthQ[cIdx][ctuXOff + x][ctuYOff] = 1;
m_maxFilterLengthP[cIdx][ctuXOff + x][ctuYOff] = 1;
}
else //对于大块(大于等于32),滤波7个像素,否则滤波3个像素
{
m_maxFilterLengthQ[cIdx][ctuXOff + x][ctuYOff] = (sizeQSide >= 32) ? 7 : 3;
m_maxFilterLengthP[cIdx][ctuXOff + x][ctuYOff] = (sizePSide >= 32) ? 7 : 3;
}
}
else
{ //对于色度大块(大于等于8),滤波3个像素,否则滤波1个像素
m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff] = ( sizeQSide >= 8 && sizePSide >= 8 ) ? 3 : 1;
m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff] = ( sizeQSide >= 8 && sizePSide >= 8 ) ? 3 : 1;
}
}
}
}
}
if ( edgeDir == EDGE_VER ) //垂直边界
{
for ( int cIdx = 0; cIdx < ::getNumberValidComponents(tuQ.chromaFormat); cIdx++ ) // per component
{
const ComponentID comp = ComponentID(cIdx);
const ChannelType ch = toChannelType(comp);
const int shiftHor = ( ( ch == CH_L ) ? 0 : m_shiftHor );
const int shiftVer = ( ( ch == CH_L ) ? 0 : m_shiftVer );
const int ctuXOff = currTU.block(comp).x - ( m_ctuXLumaSamples >> shiftHor ); // x offset from left edge of CTU in respective channel sample units
const int ctuYOff = currTU.block(comp).y - ( m_ctuYLumaSamples >> shiftVer ); // y offset from top edge of CTU in respective channel sample units
const int minCUHeight = cu.cs->pcv->minCUHeight >> shiftVer;
if ( currTU.block(comp).valid() && ( ( currTU.block(comp).x == cu.block(comp).x ) ? m_stLFCUParam.leftEdge : m_stLFCUParam.internalEdge ) ) // Edge deblocking needs to be recomputed since ISP contains whole CU chroma transforms in last TU of the CU
{
for ( int y = 0; y < currTU.blocks[cIdx].height; y += minCUHeight )
{
const Position posQ = Position( currTU.blocks[ch].x, currTU.blocks[ch].y + y );
const Position posP = posQ.offset( -1, 0 );
const int sizeQSide = tuQ.block(comp).width;
const TransformUnit& tuP = *cu.cs->getTU( posP, ch );
const int sizePSide = tuP.block(comp).width;
m_transformEdge[cIdx][ctuXOff][ctuYOff+y] = true;
if ( comp == COMPONENT_Y )
{
bool smallBlock = (sizePSide <= 4) || (sizeQSide <= 4);
if (smallBlock)
{
m_maxFilterLengthQ[cIdx][ctuXOff][ctuYOff + y] = 1;
m_maxFilterLengthP[cIdx][ctuXOff][ctuYOff + y] = 1;
}
else
{
m_maxFilterLengthQ[cIdx][ctuXOff][ctuYOff + y] = (sizeQSide >= 32) ? 7 : 3;
m_maxFilterLengthP[cIdx][ctuXOff][ctuYOff + y] = (sizePSide >= 32) ? 7 : 3;
}
}
else
{
m_maxFilterLengthQ[cIdx][ctuXOff][ctuYOff+y] = ( sizeQSide >= 8 && sizePSide >= 8 ) ? 3 : 1;
m_maxFilterLengthP[cIdx][ctuXOff][ctuYOff+y] = ( sizeQSide >= 8 && sizePSide >= 8 ) ? 3 : 1;
}
}
}
}
}
}
xGetBoundaryStrengthSingle函数
确定最大滤波像素数后,需要根据边界两侧的块的预测模式和编码参数设置边界强度,具体如下表所示。在xGetBoundaryStrengthSingle函数中获取边界强度。
代码及注释如下:
unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const Position& localPos, const ChannelType chType ) const
{
// The boundary strength that is output by the function xGetBoundaryStrengthSingle is a multi component boundary strength that contains boundary strength for luma (bits 0 to 1), cb (bits 2 to 3) and cr (bits 4 to 5).
// 函数xGetBoundaryStrengthSingle输出的边界强度是多分量边界强度,它包含luma(位0到1)、cb(位2到3)和cr(位4到5)的边界强度。
const Slice& sliceQ = *cu.slice;
int shiftHor = cu.Y().valid() ? 0 : ::getComponentScaleX(COMPONENT_Cb, cu.firstPU->chromaFormat);
int shiftVer = cu.Y().valid() ? 0 : ::getComponentScaleY(COMPONENT_Cb, cu.firstPU->chromaFormat);
const Position& posQ = Position{ localPos.x >> shiftHor, localPos.y >> shiftVer };
const Position posP = ( edgeDir == EDGE_VER ) ? posQ.offset( -1, 0 ) : posQ.offset( 0, -1 );
const CodingUnit& cuQ = cu;
const CodingUnit& cuP = (chType == CHANNEL_TYPE_CHROMA && cuQ.chType == CHANNEL_TYPE_LUMA) ?
*cu.cs->getCU(recalcPosition( cu.chromaFormat, CHANNEL_TYPE_LUMA, CHANNEL_TYPE_CHROMA, posP), CHANNEL_TYPE_CHROMA) :
*cu.cs->getCU( posP, cu.chType );
//-- Set BS for Intra MB : BS = 4 or 3
//-----------------相邻块中的至少一个用intra或CIIP模式编码----------------------
if( ( MODE_INTRA == cuP.predMode ) || ( MODE_INTRA == cuQ.predMode ) )
{
if( chType == CHANNEL_TYPE_LUMA )
{
int bsY = (MODE_INTRA == cuP.predMode && cuP.bdpcmMode) && (MODE_INTRA == cuQ.predMode && cuQ.bdpcmMode) ? 0 : 2;
return BsSet(bsY, COMPONENT_Y);
}
else
{
int bsC = (MODE_INTRA == cuP.predMode && cuP.bdpcmModeChroma) && (MODE_INTRA == cuQ.predMode && cuQ.bdpcmModeChroma) ? 0 : 2;
return (BsSet(bsC, COMPONENT_Cb) + BsSet(bsC, COMPONENT_Cr));
}
}
const TransformUnit& tuQ = *cuQ.cs->getTU(posQ, cuQ.chType);
const TransformUnit& tuP = (cuP.chType == CHANNEL_TYPE_CHROMA && cuQ.chType == CHANNEL_TYPE_LUMA) ?
*cuP.cs->getTU(recalcPosition( cu.chromaFormat, CHANNEL_TYPE_LUMA, CHANNEL_TYPE_CHROMA, posP), CHANNEL_TYPE_CHROMA) :
*cuP.cs->getTU(posP, cuQ.chType);
const PreCalcValues& pcv = *cu.cs->pcv;
const unsigned rasterIdx = getRasterIdx( Position{ localPos.x, localPos.y }, pcv );
if (m_aapucBS[edgeDir][rasterIdx] && (cuP.firstPU->ciipFlag || cuQ.firstPU->ciipFlag))
{
if(chType == CHANNEL_TYPE_LUMA)
{
return BsSet(2, COMPONENT_Y);
}
else
{
return BsSet(2, COMPONENT_Cb) + BsSet(2, COMPONENT_Cr);
}
}
unsigned tmpBs = 0;
//------------------------ 相邻块中的至少一个具有非零变换系数-----------------
//-- Set BS for not Intra MB : BS = 2 or 1 or 0
if(chType == CHANNEL_TYPE_LUMA)
{
// Y
if (m_aapucBS[edgeDir][rasterIdx] && (TU::getCbf(tuQ, COMPONENT_Y) || TU::getCbf(tuP, COMPONENT_Y)))
{
tmpBs += BsSet(1, COMPONENT_Y);
}
}
else
{
if (pcv.chrFormat != CHROMA_400)
{
// U
if (m_aapucBS[edgeDir][rasterIdx]
&& (TU::getCbf(tuQ, COMPONENT_Cb) || TU::getCbf(tuP, COMPONENT_Cb) || tuQ.jointCbCr || tuP.jointCbCr))
{
tmpBs += BsSet(1, COMPONENT_Cb);
}
// V
if (m_aapucBS[edgeDir][rasterIdx]
&& (TU::getCbf(tuQ, COMPONENT_Cr) || TU::getCbf(tuP, COMPONENT_Cr) || tuQ.jointCbCr || tuP.jointCbCr))
{
tmpBs += BsSet(1, COMPONENT_Cr);
}
}
}
if (BsGet(tmpBs, COMPONENT_Y) == 1)
{
return tmpBs;
}
if ( !cu.Y().valid() )
{
return tmpBs;
}
// and now the pred
if (m_aapucBS[edgeDir][rasterIdx] != 0 && m_aapucBS[edgeDir][rasterIdx] != 3)
{
return tmpBs;
}
if( chType == CHANNEL_TYPE_CHROMA )
{
return tmpBs;
}
if( cuP.predMode != cuQ.predMode && chType == CHANNEL_TYPE_LUMA )
{
return BsSet(1, COMPONENT_Y);
}
const Position& lumaPosQ = Position{ localPos.x, localPos.y };
const Position lumaPosP = ( edgeDir == EDGE_VER ) ? lumaPosQ.offset( -1, 0 ) : lumaPosQ.offset( 0, -1 );
const MotionInfo& miQ = cuQ.cs->getMotionInfo( lumaPosQ );
const MotionInfo& miP = cuP.cs->getMotionInfo( lumaPosP );
const Slice& sliceP = *cuP.slice;
/************************* 帧间B帧 *********************/
if (sliceQ.isInterB() || sliceP.isInterB())
{
const Picture *piRefP0 = (CU::isIBC(cuP) ? sliceP.getPic() : ((0 > miP.refIdx[0]) ? NULL : sliceP.getRefPic(REF_PIC_LIST_0, miP.refIdx[0])));
const Picture *piRefP1 = (CU::isIBC(cuP) ? NULL : ((0 > miP.refIdx[1]) ? NULL : sliceP.getRefPic(REF_PIC_LIST_1, miP.refIdx[1])));
const Picture *piRefQ0 = (CU::isIBC(cuQ) ? sliceQ.getPic() : ((0 > miQ.refIdx[0]) ? NULL : sliceQ.getRefPic(REF_PIC_LIST_0, miQ.refIdx[0])));
const Picture *piRefQ1 = (CU::isIBC(cuQ) ? NULL : ((0 > miQ.refIdx[1]) ? NULL : sliceQ.getRefPic(REF_PIC_LIST_1, miQ.refIdx[1])));
Mv mvP0, mvP1, mvQ0, mvQ1;
if (0 <= miP.refIdx[0])
{
mvP0 = miP.mv[0];
}
if (0 <= miP.refIdx[1])
{
mvP1 = miP.mv[1];
}
if (0 <= miQ.refIdx[0])
{
mvQ0 = miQ.mv[0];
}
if (0 <= miQ.refIdx[1])
{
mvQ1 = miQ.mv[1];
}
int nThreshold = (1 << MV_FRACTIONAL_BITS_INTERNAL) >> 1;
unsigned uiBs = 0;
//th can be optimized
// P和Q块的参考帧相同,属于相邻块的运动矢量之间的绝对差大于或等于半个亮度样本
if ( ((piRefP0==piRefQ0)&&(piRefP1==piRefQ1)) || ((piRefP0==piRefQ1)&&(piRefP1==piRefQ0)) )
{
if ( piRefP0 != piRefP1 ) // Different L0 & L1 如果参考帧不同,其中一个MVD大于半像素精度,则BS为1
{
if ( piRefP0 == piRefQ0 )
{
uiBs = ((abs(mvQ0.getHor() - mvP0.getHor()) >= nThreshold) || (abs(mvQ0.getVer() - mvP0.getVer()) >= nThreshold) ||
(abs(mvQ1.getHor() - mvP1.getHor()) >= nThreshold) || (abs(mvQ1.getVer() - mvP1.getVer()) >= nThreshold))
? 1 : 0;
}
else
{
uiBs = ((abs(mvQ1.getHor() - mvP0.getHor()) >= nThreshold) || (abs(mvQ1.getVer() - mvP0.getVer()) >= nThreshold) ||
(abs(mvQ0.getHor() - mvP1.getHor()) >= nThreshold) || (abs(mvQ0.getVer() - mvP1.getVer()) >= nThreshold))
? 1 : 0;
}
}
else // Same L0 & L1 如果参考帧相同,同时满足两个MVD大于半像素精度,则BS为1
{
uiBs = ((abs(mvQ0.getHor() - mvP0.getHor()) >= nThreshold) || (abs(mvQ0.getVer() - mvP0.getVer()) >= nThreshold) ||
(abs(mvQ1.getHor() - mvP1.getHor()) >= nThreshold) || (abs(mvQ1.getVer() - mvP1.getVer()) >= nThreshold))
&&
((abs(mvQ1.getHor() - mvP0.getHor()) >= nThreshold) || (abs(mvQ1.getVer() - mvP0.getVer()) >= nThreshold) ||
(abs(mvQ0.getHor() - mvP1.getHor()) >= nThreshold) || (abs(mvQ0.getVer() - mvP1.getVer()) >= nThreshold))
? 1 : 0;
}
}
else // for all different Ref_Idx 参考帧不同,则设置滤波强度为1
{
uiBs = 1;
}
return uiBs + tmpBs;
}
/************************* 帧间P帧:如果MVD大于等于半像素精度 *********************/
// 相邻块中的一个以IBC预测模式编码,另一个以帧间预测模式编码
// pcSlice->isInterP()
CHECK(CU::isInter(cuP) && 0 > miP.refIdx[0], "Invalid reference picture list index");
CHECK(CU::isInter(cuP) && 0 > miQ.refIdx[0], "Invalid reference picture list index");
const Picture *piRefP0 = (CU::isIBC(cuP) ? sliceP.getPic() : sliceP.getRefPic(REF_PIC_LIST_0, miP.refIdx[0]));
const Picture *piRefQ0 = (CU::isIBC(cuQ) ? sliceQ.getPic() : sliceQ.getRefPic(REF_PIC_LIST_0, miQ.refIdx[0]));
if (piRefP0 != piRefQ0)
{
return tmpBs + 1;
}
Mv mvP0 = miP.mv[0];
Mv mvQ0 = miQ.mv[0];
int nThreshold = (1 << MV_FRACTIONAL_BITS_INTERNAL) >> 1;
return ( ( abs( mvQ0.getHor() - mvP0.getHor() ) >= nThreshold ) || ( abs( mvQ0.getVer() - mvP0.getVer() ) >= nThreshold ) ) ? (tmpBs + 1) : tmpBs;
}