正好时隔一年,做回了老本行——环路滤波。
针对ALF,我去年夏天时看过一阵子,对早期BMS版本的ALF一知半解,可参考:H.266/VVC代码学习2:有关ALF
刚刚回归从O2002上看了看最新的ALF,明显感受到了简化,但也很多看不懂了,参考:H.266/VVC代码学习39:自适应环路滤波器算法简介(ALF,翻译自JVET-O2002)
嗯,下面,再一次开启我的ALF之旅。
在AlfFilterShape类中,构造函数的重要参数有如下内容
// 色度 亮度
AlfFilterType filterType; //滤波器类型 0 和 1
int filterLength; //滤波器长度: 5 和 7
int numCoeff; //滤波器抽头数: 7 和 13 (需理解见pattern)
int filterSize; //滤波器大小: 5 和 7
std::vector<int> pattern; //滤波图形
std::vector<int> weights; //滤波权重
赋值过程如下:
AlfFilterShape( int size )
: filterLength( size ),
numCoeff( size * size / 4 + 1 ),
filterSize( size * size / 2 + 1 )
ALF有两种滤波器:亮度7x7菱形滤波器,色度5x5菱形滤波器。代码中如下:
enum AlfFilterType //滤波器种类
{
ALF_FILTER_5, //色度的5x5滤波器
ALF_FILTER_7, //亮度的7x7滤波器
ALF_NUM_OF_FILTER_TYPES //2种
};
对应的,滤波器形状及权重如下
{
if( size == 5 )
{
pattern = {
0,
1, 2, 3,
4, 5, 6, 5, 4,
3, 2, 1,
0
};
weights = {
2,
2, 2, 2,
2, 2, 1, 1
};
filterType = ALF_FILTER_5;
}
else if( size == 7 )
{
pattern = {
0,
1, 2, 3,
4, 5, 6, 7, 8,
9, 10, 11, 12, 11, 10, 9,
8, 7, 6, 5, 4,
3, 2, 1,
0
};
weights = {
2,
2, 2, 2,
2, 2, 2, 2, 2,
2, 2, 2, 1, 1
};
filterType = ALF_FILTER_7;
}
else
{
filterType = ALF_NUM_OF_FILTER_TYPES;
CHECK( 0, "Wrong ALF filter shape" );
}
}
struct AlfParam
{
bool enabledFlag[MAX_NUM_COMPONENT]; // alf_slice_enable_flag, alf_chroma_idc—— 各通道每一帧是否使用ALF[三个通道]
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
bool nonLinearFlag[MAX_NUM_CHANNEL_TYPE][MAX_NUM_ALF_ALTERNATIVES_CHROMA]; // alf_[luma/chroma]_clip_flag—— 是否存在嵌位值??
#else
bool nonLinearFlag[MAX_NUM_CHANNEL_TYPE]; // alf_nonlinear_enable_flag[Luma/Chroma]
#endif
short lumaCoeff[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; // alf_coeff_luma_delta[i][j]——亮度滤波器系数[25类 x 13值]
short lumaClipp[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; // alf_clipp_luma_[i][j]——亮度滤波器嵌位值[25类 x 13值]
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
int numAlternativesChroma; // alf_chroma_num_alts_minus_one + 1 —— 色度可用ALF数量
short chromaCoeff[MAX_NUM_ALF_ALTERNATIVES_CHROMA][MAX_NUM_ALF_CHROMA_COEFF]; // alf_coeff_chroma[i]——色度滤波器系数[8类 x 7值]
short chromaClipp[MAX_NUM_ALF_ALTERNATIVES_CHROMA][MAX_NUM_ALF_CHROMA_COEFF]; // alf_clipp_chroma[i]——色度滤波器限幅值[8类 x 7值]
#else
short chromaCoeff[MAX_NUM_ALF_CHROMA_COEFF]; // alf_coeff_chroma[i]
short chromaClipp[MAX_NUM_ALF_CHROMA_COEFF]; // alf_clipp_chroma[i]
#endif
short filterCoeffDeltaIdx[MAX_NUM_ALF_CLASSES]; // filter_coeff_delta[i] —— 亮度Delta索引????
bool alfLumaCoeffFlag[MAX_NUM_ALF_CLASSES]; // alf_luma_coeff_flag[i] —— 亮度ALF启用标志
int numLumaFilters; // number_of_filters_minus1 + 1 —— 亮度ALF可用数量
bool alfLumaCoeffDeltaFlag; // alf_luma_coeff_delta_flag —— 亮度Delta发出标志????
#if !JVET_O0669_REMOVE_ALF_COEFF_PRED
bool alfLumaCoeffDeltaPredictionFlag; // alf_luma_coeff_delta_prediction_flag
#endif
std::vector<AlfFilterShape>* filterShapes;//滤波器形状
int tLayer;
bool newFilterFlag[MAX_NUM_CHANNEL_TYPE];//新的滤波器使用标志??????
#if !JVET_O0669_REMOVE_ALF_COEFF_PRED
int fixedFilterPattern;
int fixedFilterIdx[MAX_NUM_ALF_CLASSES];
int fixedFilterSetIndex;
#endif
};
static const int m_classToFilterMapping[NUM_FIXED_FILTER_SETS][MAX_NUM_ALF_CLASSES]; //分类->固定滤波器 的映射表
static const int m_fixedFilterSetCoeff[ALF_FIXED_FILTER_NUM][MAX_NUM_ALF_LUMA_COEFF];//固定滤波器设置滤波系数
short m_fixedFilterSetCoeffDec[NUM_FIXED_FILTER_SETS][MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF];//固定滤波器系数[固定滤波器数量16][亮度系数数量25*13]
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB || JVET_O_MAX_NUM_ALF_APS_8
short m_coeffApsLuma[ALF_CTB_MAX_NUM_APS][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES];//APS滤波器系数[APS滤波器数量8][亮度系数数量25*13]
short m_clippApsLuma[ALF_CTB_MAX_NUM_APS][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES];//APS滤波器嵌位值[APS滤波器数量8][亮度系数数量25*13]
#else
short m_coeffApsLuma[6][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES];
short m_clippApsLuma[6][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES];
#endif
short m_clipDefault[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF];//固定滤波器嵌位值[固定滤波器数量16][亮度系数数量25*13]
bool m_created = false;
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
short m_chromaCoeffFinal[MAX_NUM_ALF_ALTERNATIVES_CHROMA][MAX_NUM_ALF_CHROMA_COEFF];//最终色度系数[色度种类8][抽头位置7]
AlfParam* m_alfParamChroma;//色度系数
#else
short m_chromaCoeffFinal[MAX_NUM_ALF_LUMA_COEFF];
#endif
Pel m_alfClippingValues[MAX_NUM_CHANNEL_TYPE][MaxAlfNumClippingValues];//每种分量的限幅值
std::vector<AlfFilterShape> m_filterShapes[MAX_NUM_CHANNEL_TYPE];
AlfClassifier** m_classifier;//最终分类:二维数组[第几个分类25][第几种几何变换方式4]
short m_coeffFinal[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF];//最终选到的滤波器集的系数[亮度系数数量25*13]
short m_clippFinal[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF];//最终选到的滤波器集的嵌位值[亮度系数数量25*13]
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
short m_chromaClippFinal[MAX_NUM_ALF_ALTERNATIVES_CHROMA][MAX_NUM_ALF_CHROMA_COEFF];//最终色度嵌位值[色度种类][抽头位置]
#else
short m_chromaClippFinal[MAX_NUM_ALF_LUMA_COEFF];
#endif
int** m_laplacian[NUM_DIRECTIONS];//拉普拉斯活动性:三维数组[四种梯度方向][第i行][第j列]
uint8_t* m_ctuEnableFlag[MAX_NUM_COMPONENT];//CTU是否使用ALF标志[通道数][CTU标志]
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
uint8_t* m_ctuAlternative[MAX_NUM_COMPONENT];//CTU是否哪种色度ALF[通道数][CTU标志]
const EncCfg* m_encCfg;//获取cfg
AlfCovariance*** m_alfCovariance[MAX_NUM_COMPONENT]; //CTU级每一种情况的ALF协方差:四维数组[3个通道][1个形状][CTU位置][classIdx]
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
AlfCovariance** m_alfCovarianceFrame[MAX_NUM_CHANNEL_TYPE]; //帧级每一种情况的ALF协方差:三维数组[3个通道][1个形状][25个亮度分类/8种色度滤波器],比上面少了个CTU位置索引
uint8_t* m_ctuEnableFlagTmp[MAX_NUM_COMPONENT];//临时存储亮度CTU是否滤波[通道索引][CTU索引]
uint8_t* m_ctuEnableFlagTmp2[MAX_NUM_COMPONENT];//临时存储亮度CTU是否滤波[通道索引][CTU索引]
uint8_t* m_ctuAlternativeTmp[MAX_NUM_COMPONENT];//临时存储色度CTU使用的滤波器种类[通道索引][CTU索引]
#else
AlfCovariance** m_alfCovarianceFrame[MAX_NUM_CHANNEL_TYPE]; // [CHANNEL][shapeIdx][classIdx]
uint8_t* m_ctuEnableFlagTmp[MAX_NUM_COMPONENT];
#endif
//for RDO
AlfParam m_alfParamTemp;//用于RDO的临时ALF参数!!!很有用
ParameterSetMap<APS>* m_apsMap;//获取APS(自适应参数集)映射表
AlfCovariance m_alfCovarianceMerged[ALF_NUM_OF_FILTER_TYPES][MAX_NUM_ALF_CLASSES + 2];//协方差矩阵[滤波器种类][分类]
int m_alfClipMerged[ALF_NUM_OF_FILTER_TYPES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF];
CABACWriter* m_CABACEstimator;//CABAC
CtxCache* m_CtxCache;//上下文缓存
double m_lambda[MAX_NUM_COMPONENT];//三个通道的lambda值
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
int** m_filterCoeffSet; // [lumaClassIdx/chromaAltIdx][coeffIdx] 最终最终滤波系数集
int** m_filterClippSet; // [lumaClassIdx/chromaAltIdx][coeffIdx] 滤波幅值集
#else
int** m_filterCoeffSet;
int** m_filterClippSet;
#endif
int** m_diffFilterCoeff;//不同滤波系数???
#if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING
int m_kMinTab[MAX_NUM_ALF_LUMA_COEFF];
int m_bitsCoeffScan[m_MAX_SCAN_VAL][m_MAX_EXP_GOLOMB];
#endif
short m_filterIndices[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES];
unsigned m_bitsNewFilter[MAX_NUM_CHANNEL_TYPE];//新滤波器
int m_apsIdStart;//起始APS序号
double *m_ctbDistortionFixedFilter;//固定滤波器失真[]
double *m_ctbDistortionUnfilter[MAX_NUM_COMPONENT];//不滤波的失真[]
std::vector<short> m_alfCtbFilterSetIndexTmp;//临时滤波器集索引[]
AlfParam m_alfParamTempNL;
int m_clipDefaultEnc[MAX_NUM_ALF_LUMA_COEFF];
int m_filterTmp[MAX_NUM_ALF_LUMA_COEFF];//临时滤波器系数值[抽头数]
int m_clipTmp[MAX_NUM_ALF_LUMA_COEFF];//临时滤波器嵌位值[抽头数]
void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs)
{
if (!cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y) && !cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) && !cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr))
{
return;
}
// set clipping range
m_clpRngs = cs.slice->getClpRngs();//获取嵌位值
// set CTU enable flags
for( int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++ )//获取CTU标志
{
m_ctuEnableFlag[compIdx] = cs.picture->getAlfCtuEnableFlag( compIdx );
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
m_ctuAlternative[compIdx] = cs.picture->getAlfCtuAlternativeData( compIdx );
#endif
}
//获取APS的系数
reconstructCoeffAPSs(cs, true, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) || cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr), false);
short* alfCtuFilterIndex = cs.slice->getPic()->getAlfCtbFilterIndex();
PelUnitBuf recYuv = cs.getRecoBuf();//获取重构像素值
m_tempBuf.copyFrom( recYuv );
PelUnitBuf tmpYuv = m_tempBuf.getBuf( cs.area );//临时像素值:先存储重构像素值,后用于存储alf滤波后的
tmpYuv.extendBorderPel( MAX_ALF_FILTER_LENGTH >> 1 );
const PreCalcValues& pcv = *cs.pcv;//获取图像信息
int ctuIdx = 0;//CTU索引
bool clipTop = false, clipBottom = false, clipLeft = false, clipRight = false;
int numHorVirBndry = 0, numVerVirBndry = 0;
int horVirBndryPos[] = { 0, 0, 0 };
int verVirBndryPos[] = { 0, 0, 0 };
for( int yPos = 0; yPos < pcv.lumaHeight; yPos += pcv.maxCUHeight )
{
for( int xPos = 0; xPos < pcv.lumaWidth; xPos += pcv.maxCUWidth )//遍历每个128x128
{
const int width = ( xPos + pcv.maxCUWidth > pcv.lumaWidth ) ? ( pcv.lumaWidth - xPos ) : pcv.maxCUWidth;
const int height = ( yPos + pcv.maxCUHeight > pcv.lumaHeight ) ? ( pcv.lumaHeight - yPos ) : pcv.maxCUHeight;
/**** 当前CTU是否使用ALF ****/
bool ctuEnableFlag = m_ctuEnableFlag[COMPONENT_Y][ctuIdx];//亮度获取当前CTU的CTU是否使用标志
for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ )//两个色度获取当前CTU的CTU使用何种ALF
{
ctuEnableFlag |= m_ctuEnableFlag[compIdx][ctuIdx] > 0;
}
if( ctuEnableFlag && isCrossedByVirtualBoundaries( xPos, yPos, width, height, clipTop, clipBottom, clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos, cs.slice->getPPS() ) )
{
int yStart = yPos;
for( int i = 0; i <= numHorVirBndry; i++ )
{
const int yEnd = i == numHorVirBndry ? yPos + height : horVirBndryPos[i];
const int h = yEnd - yStart;
const bool clipT = ( i == 0 && clipTop ) || ( i > 0 ) || ( yStart == 0 );
const bool clipB = ( i == numHorVirBndry && clipBottom ) || ( i < numHorVirBndry ) || ( yEnd == pcv.lumaHeight );
int xStart = xPos;
for( int j = 0; j <= numVerVirBndry; j++ )
{
const int xEnd = j == numVerVirBndry ? xPos + width : verVirBndryPos[j];
const int w = xEnd - xStart;
const bool clipL = ( j == 0 && clipLeft ) || ( j > 0 ) || ( xStart == 0 );
const bool clipR = ( j == numVerVirBndry && clipRight ) || ( j < numVerVirBndry ) || ( xEnd == pcv.lumaWidth );
const int wBuf = w + (clipL ? 0 : MAX_ALF_PADDING_SIZE) + (clipR ? 0 : MAX_ALF_PADDING_SIZE);
const int hBuf = h + (clipT ? 0 : MAX_ALF_PADDING_SIZE) + (clipB ? 0 : MAX_ALF_PADDING_SIZE);
PelUnitBuf buf = m_tempBuf2.subBuf( UnitArea( cs.area.chromaFormat, Area( 0, 0, wBuf, hBuf ) ) );
buf.copyFrom( tmpYuv.subBuf( UnitArea( cs.area.chromaFormat, Area( xStart - (clipL ? 0 : MAX_ALF_PADDING_SIZE), yStart - (clipT ? 0 : MAX_ALF_PADDING_SIZE), wBuf, hBuf ) ) ) );
buf.extendBorderPel( MAX_ALF_PADDING_SIZE );
buf = buf.subBuf( UnitArea ( cs.area.chromaFormat, Area( clipL ? 0 : MAX_ALF_PADDING_SIZE, clipT ? 0 : MAX_ALF_PADDING_SIZE, w, h ) ) );
if( m_ctuEnableFlag[COMPONENT_Y][ctuIdx] )
{
const Area blkSrc( 0, 0, w, h );
const Area blkDst( xStart, yStart, w, h );
deriveClassification( m_classifier, buf.get(COMPONENT_Y), blkDst, blkSrc );
const Area blkPCM( xStart, yStart, w, h );
resetPCMBlkClassInfo( cs, m_classifier, buf.get(COMPONENT_Y), blkPCM );
short filterSetIndex = alfCtuFilterIndex[ctuIdx];
short *coeff;
short *clip;
if (filterSetIndex >= NUM_FIXED_FILTER_SETS)
{
coeff = m_coeffApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS];
clip = m_clippApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS];
}
else
{
coeff = m_fixedFilterSetCoeffDec[filterSetIndex];
clip = m_clipDefault;
}
m_filter7x7Blk(m_classifier, recYuv, buf, blkDst, blkSrc, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs
, m_alfVBLumaCTUHeight
, ((yPos + pcv.maxCUHeight >= pcv.lumaHeight) ? pcv.lumaHeight : m_alfVBLumaPos)
);
}
for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ )
{
ComponentID compID = ComponentID( compIdx );
const int chromaScaleX = getComponentScaleX( compID, tmpYuv.chromaFormat );
const int chromaScaleY = getComponentScaleY( compID, tmpYuv.chromaFormat );
if( m_ctuEnableFlag[compIdx][ctuIdx] )
{
const Area blkSrc( 0, 0, w >> chromaScaleX, h >> chromaScaleY );
const Area blkDst( xStart >> chromaScaleX, yStart >> chromaScaleY, w >> chromaScaleX, h >> chromaScaleY );
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx];
m_filter5x5Blk(m_classifier, recYuv, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs
#else
m_filter5x5Blk(m_classifier, recYuv, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal, m_chromaClippFinal, m_clpRngs.comp[compIdx], cs
#endif
, m_alfVBChmaCTUHeight
, ((yPos + pcv.maxCUHeight >= pcv.lumaHeight) ? pcv.lumaHeight : m_alfVBChmaPos));
}
}
xStart = xEnd;
}
yStart = yEnd;
}
}
else
{
/**** 亮度ALF滤波 ****/
const UnitArea area( cs.area.chromaFormat, Area( xPos, yPos, width, height ) );
if( m_ctuEnableFlag[COMPONENT_Y][ctuIdx] )
{
Area blk( xPos, yPos, width, height );
deriveClassification( m_classifier, tmpYuv.get( COMPONENT_Y ), blk, blk );//获取分类
Area blkPCM(xPos, yPos, width, height);
resetPCMBlkClassInfo(cs, m_classifier, tmpYuv.get(COMPONENT_Y), blkPCM);//没有任何操作
short filterSetIndex = alfCtuFilterIndex[ctuIdx];//当前CTU所使用的滤波器集合
short *coeff;
short *clip;
if (filterSetIndex >= NUM_FIXED_FILTER_SETS)//如果使用的是APS滤波器,则filterSetIndex一定大于等于16
{
coeff = m_coeffApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS];
clip = m_clippApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS];
}
else//使用的是固定滤波器
{
coeff = m_fixedFilterSetCoeffDec[filterSetIndex];
clip = m_clipDefault;
}
//进行滤波
m_filter7x7Blk(m_classifier, recYuv, tmpYuv, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs
, m_alfVBLumaCTUHeight
, ((yPos + pcv.maxCUHeight >= pcv.lumaHeight) ? pcv.lumaHeight : m_alfVBLumaPos)
);
}
/**** 色度ALF滤波 ****/
for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ )
{
ComponentID compID = ComponentID( compIdx );
const int chromaScaleX = getComponentScaleX( compID, tmpYuv.chromaFormat );
const int chromaScaleY = getComponentScaleY( compID, tmpYuv.chromaFormat );
if( m_ctuEnableFlag[compIdx][ctuIdx] )
{
Area blk( xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY );
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx];
m_filter5x5Blk(m_classifier, recYuv, tmpYuv, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs
#else
m_filter5x5Blk(m_classifier, recYuv, tmpYuv, blk, blk, compID, m_chromaCoeffFinal, m_chromaClippFinal, m_clpRngs.comp[compIdx], cs
#endif
, m_alfVBChmaCTUHeight
, ((yPos + pcv.maxCUHeight >= pcv.lumaHeight) ? pcv.lumaHeight : m_alfVBChmaPos));
}
}
}
ctuIdx++;//下一个CTU
}
}
}
void AdaptiveLoopFilter::reconstructCoeffAPSs(CodingStructure& cs, bool luma, bool chroma, bool isRdo)
{
//luma
APS** aps = cs.slice->getAlfAPSs();
AlfParam alfParamTmp;
APS* curAPS;
if (luma)
{
for (int i = 0; i < cs.slice->getTileGroupNumAps(); i++)
{
int apsIdx = cs.slice->getTileGroupApsIdLuma()[i];//获取亮度的APS索引(索引为0~7????)
curAPS = aps[apsIdx];//得到当前APS信息
CHECK(curAPS == NULL, "invalid APS");
alfParamTmp = curAPS->getAlfAPSParam();
reconstructCoeff(alfParamTmp, CHANNEL_TYPE_LUMA, isRdo, true);//根据APS获得系数,存进m_coeffFinal
memcpy(m_coeffApsLuma[i], m_coeffFinal, sizeof(m_coeffFinal));//把325个m_coeffFinal的值存进m_coeffApsLuma[i]
memcpy(m_clippApsLuma[i], m_clippFinal, sizeof(m_clippFinal));
}
}
//chroma
if (chroma)
{
int apsIdxChroma = cs.slice->getTileGroupApsIdChroma();
curAPS = aps[apsIdxChroma];
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
m_alfParamChroma = &curAPS->getAlfAPSParam();
alfParamTmp = *m_alfParamChroma;
#else
alfParamTmp = curAPS->getAlfAPSParam();
#endif
reconstructCoeff(alfParamTmp, CHANNEL_TYPE_CHROMA, isRdo, true);
}
}
void AdaptiveLoopFilter::reconstructCoeff( AlfParam& alfParam, ChannelType channel, const bool isRdo, const bool isRedo )
{
/********************** 初始化 **********************/
int factor = isRdo ? 0 : (1 << (m_NUM_BITS - 1));//中间位置的值:0
AlfFilterType filterType = isLuma( channel ) ? ALF_FILTER_7 : ALF_FILTER_5;
int numClasses = isLuma( channel ) ? MAX_NUM_ALF_CLASSES : 1;//滤波种类数量
int numCoeff = filterType == ALF_FILTER_5 ? 7 : 13;//滤波系数数量
int numCoeffMinus1 = numCoeff - 1;
#if !JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
int numFilters = isLuma( channel ) ? alfParam.numLumaFilters : 1;
short* coeff = isLuma( channel ) ? alfParam.lumaCoeff : alfParam.chromaCoeff;
short* clipp = isLuma( channel ) ? alfParam.lumaClipp : alfParam.chromaClipp;
#endif
#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
const int numAlts = isLuma( channel ) ? 1 : alfParam.numAlternativesChroma;//亮度1次,色度遍历4次
for( int altIdx = 0; altIdx < numAlts; ++ altIdx )
{
int numFilters = isLuma( channel ) ? alfParam.numLumaFilters : 1;//亮度为6,色度为1
short* coeff = isLuma( channel ) ? alfParam.lumaCoeff : alfParam.chromaCoeff[altIdx];//获取指针指向alfParam系数
short* clipp = isLuma( channel ) ? alfParam.lumaClipp : alfParam.chromaClipp[altIdx];//亮度拉成了一维:325位 = 25类 X 13抽头
//色度依然是二维:325位 = 4类 X 7抽头
#if !JVET_O0669_REMOVE_ALF_COEFF_PRED
if( alfParam.alfLumaCoeffDeltaPredictionFlag && isLuma( channel ) )
{
for( int i = 1; i < numFilters; i++ )
{
for( int j = 0; j < numCoeffMinus1; j++ )
{
coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] += coeff[( i - 1 ) * MAX_NUM_ALF_LUMA_COEFF + j];
}
}
}
#endif
/*********** 设置最中间的系数 **********/
for( int filterIdx = 0; filterIdx < numFilters; filterIdx++ )
{
coeff[filterIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = factor;//处理最中间的系数,设为128
}
/************** 对色度:直接获取系数和嵌位值 **************/
if( isChroma( channel ) )
{
for( int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx )
{
m_chromaCoeffFinal[altIdx][coeffIdx] = coeff[coeffIdx];
int clipIdx = alfParam.nonLinearFlag[channel][altIdx] ? clipp[coeffIdx] : 0;
m_chromaClippFinal[altIdx][coeffIdx] = isRdo ? clipIdx : m_alfClippingValues[channel][clipIdx];
}
m_chromaCoeffFinal[altIdx][numCoeffMinus1] = factor;
m_chromaClippFinal[altIdx][numCoeffMinus1] = isRdo ? 0 : m_alfClippingValues[channel][0];
continue;
}
/************** 对亮度:直接获取系数和嵌位值 *************/
for( int classIdx = 0; classIdx < numClasses; classIdx++ )//遍历0~25的每一个种类
{
int filterIdx = alfParam.filterCoeffDeltaIdx[classIdx];
#if !JVET_O0669_REMOVE_ALF_COEFF_PRED
int fixedFilterIdx = alfParam.fixedFilterSetIndex;
if (fixedFilterIdx > 0 && alfParam.fixedFilterIdx[classIdx] > 0)
{
fixedFilterIdx = m_classToFilterMapping[fixedFilterIdx - 1][classIdx];
}
else
{
fixedFilterIdx = -1;
}
#endif
/*对系数的获取*/
for (int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx)//遍历12个系数
{
m_coeffFinal[classIdx * MAX_NUM_ALF_LUMA_COEFF + coeffIdx] = coeff[filterIdx * MAX_NUM_ALF_LUMA_COEFF + coeffIdx];//把系数填进去
#if !JVET_O0669_REMOVE_ALF_COEFF_PRED
//fixed filter
if (fixedFilterIdx >= 0)
{
m_coeffFinal[classIdx * MAX_NUM_ALF_LUMA_COEFF + coeffIdx] += m_fixedFilterSetCoeff[fixedFilterIdx][coeffIdx];
}
#endif
}
m_coeffFinal[classIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = factor;//赋值最中间的第13个滤波系数为128
/*对限幅值的获取*/
m_clippFinal[classIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = isRdo ? 0 : m_alfClippingValues[channel][0];//最中间位置的限幅值
for( int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx )//遍历12个限幅值
{
int clipIdx = alfParam.nonLinearFlag[channel][altIdx] ? (clipp + filterIdx * MAX_NUM_ALF_LUMA_COEFF)[coeffIdx] : 0;
(m_clippFinal + classIdx * MAX_NUM_ALF_LUMA_COEFF)[coeffIdx] = isRdo ? clipIdx : m_alfClippingValues[channel][clipIdx];
}
m_clippFinal[classIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] =
isRdo ? 0 :
m_alfClippingValues[channel][0];//赋值最中间的第13个限幅值
}
}
#if !JVET_O0669_REMOVE_ALF_COEFF_PRED
if( isChroma( channel ) )
return;
if( isRedo && alfParam.alfLumaCoeffDeltaPredictionFlag )
{
int numFilters = alfParam.numLumaFilters;
short* coeff = alfParam.lumaCoeff;
for( int i = numFilters - 1; i > 0; i-- )
{
for( int j = 0; j < numCoeffMinus1; j++ )
{
coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] = coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] - coeff[( i - 1 ) * MAX_NUM_ALF_LUMA_COEFF + j];
}
}
}
#endif
#else
#if !JVET_O0669_REMOVE_ALF_COEFF_PRED
if( alfParam.alfLumaCoeffDeltaPredictionFlag && isLuma( channel ) )
{
for( int i = 1; i < numFilters; i++ )
{
for( int j = 0; j < numCoeffMinus1; j++ )
{
coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] += coeff[( i - 1 ) * MAX_NUM_ALF_LUMA_COEFF + j];
}
}
}
#endif
for( int filterIdx = 0; filterIdx < numFilters; filterIdx++ )
{
coeff[filterIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = factor;
}
if( isChroma( channel ) )
{
for( int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx )
{
m_chromaCoeffFinal[coeffIdx] = alfParam.chromaCoeff[coeffIdx];
int clipIdx = alfParam.nonLinearFlag[channel] ? clipp[coeffIdx] : 0;
m_chromaClippFinal[coeffIdx] = isRdo ? clipIdx : m_alfClippingValues[channel][clipIdx];
}
m_chromaCoeffFinal[numCoeffMinus1] = factor;
m_chromaClippFinal[numCoeffMinus1] = isRdo ? 0 : m_alfClippingValues[channel][0];
return;
}
for( int classIdx = 0; classIdx < numClasses; classIdx++ )
{
int filterIdx = alfParam.filterCoeffDeltaIdx[classIdx];
#if !JVET_O0669_REMOVE_ALF_COEFF_PRED
int fixedFilterIdx = alfParam.fixedFilterSetIndex;
if (fixedFilterIdx > 0 && alfParam.fixedFilterIdx[classIdx] > 0)
{
fixedFilterIdx = m_classToFilterMapping[fixedFilterIdx - 1][classIdx];
}
else
{
fixedFilterIdx = -1;
}
#endif
for (int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx)
{
m_coeffFinal[classIdx * MAX_NUM_ALF_LUMA_COEFF + coeffIdx] = coeff[filterIdx * MAX_NUM_ALF_LUMA_COEFF + coeffIdx];
#if !JVET_O0669_REMOVE_ALF_COEFF_PRED
//fixed filter
if (fixedFilterIdx >= 0)
{
m_coeffFinal[classIdx * MAX_NUM_ALF_LUMA_COEFF + coeffIdx] += m_fixedFilterSetCoeff[fixedFilterIdx][coeffIdx];
}
#endif
}
m_coeffFinal[classIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = factor;
m_clippFinal[classIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = isRdo ? 0 : m_alfClippingValues[channel][0];
for( int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx )
{
int clipIdx = alfParam.nonLinearFlag[channel] ? (clipp + filterIdx * MAX_NUM_ALF_LUMA_COEFF)[coeffIdx] : 0;
(m_clippFinal + classIdx * MAX_NUM_ALF_LUMA_COEFF)[coeffIdx] = isRdo ? clipIdx : m_alfClippingValues[channel][clipIdx];
}
}
#if !JVET_O0669_REMOVE_ALF_COEFF_PRED
if(isRedo && alfParam.alfLumaCoeffDeltaPredictionFlag )
{
for( int i = numFilters - 1; i > 0; i-- )
{
for( int j = 0; j < numCoeffMinus1; j++ )
{
coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] = coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] - coeff[( i - 1 ) * MAX_NUM_ALF_LUMA_COEFF + j];
}
}
}
#endif
#endif
}