diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index f2934a764eded8cb3368edf624360d7f354ba51c..a6aeaf7a147bc4c7460ee4a7045aa50171f7907d 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -1028,6 +1028,13 @@ static const double CCCM_NO_SUB_WEIGHT = 1.1; static const int CCCM_LOC_SHIFT = 3; static const int CCCM_LOC_OFFSET = (1 << CCCM_LOC_SHIFT); #endif +#if JVET_AD0202_CCCM_MDF +static const int CCCM_NUM_PRED_FILTER = 4; +static const int TOTAL_NUM_CCCM_MODES = CCCM_NUM_MODES * CCCM_NUM_PRED_FILTER; +static const int VALID_NUM_CCCM_MODES = TOTAL_NUM_CCCM_MODES - 6; +static const int CCCM_MULTI_PRED_FILTER_NUM_PARAMS = 10; +static const int CCCM_MULTI_PRED_FILTER_NUM_PARAMS2 = 11; +#endif #endif #if JVET_AA0126_GLM diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 45e3e711b5dd452a1633db007b65f28a94d5090e..1e3c94757e62e1942e1b2bea3ebb52372b618b84 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -3254,6 +3254,23 @@ const CtxSet ContextSetCfg::CccmFlag = ContextSetCfg::addCtxSet { DWO, }, #endif }); + +#if JVET_AD0202_CCCM_MDF +const CtxSet ContextSetCfg::CccmMpfFlag = ContextSetCfg::addCtxSet +({ + { CNU, CNU, CNU, }, + { CNU, CNU, CNU, }, + { CNU, CNU, CNU, }, + { DWS, DWS, DWS, }, + { DWS, DWS, DWS, }, + { DWS, DWS, DWS, }, + { DWE, DWE, DWE, }, + { DWE, DWE, DWE, }, + { DWE, DWE, DWE, }, + { DWO, DWO, DWO, }, + { DWO, DWO, DWO, }, +}); +#endif #endif #if JVET_AC0119_LM_CHROMA_FUSION diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 5729dc52c25a308d2f8112cdc1ced728cdedf461..f21ab30db9395dc13a07b69d1a05205c8919dd80 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -546,6 +546,9 @@ public: #if JVET_AA0057_CCCM static const CtxSet CccmFlag; #endif +#if JVET_AD0202_CCCM_MDF + static const CtxSet CccmMpfFlag; +#endif #if JVET_AB0157_TMRL static const CtxSet TmrlDerive; #endif diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index a9c5681c65fab2f338814f28173031011df7bdcb..8c27698ea59465039ed655c7c000c901869ca79f 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -130,8 +130,15 @@ IntraPrediction::IntraPrediction() #endif #if JVET_AA0057_CCCM #if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AD0202_CCCM_MDF + for (int i = 0; i < (CCCM_NUM_PRED_FILTER + 1); i++) + { + m_cccmLumaBuf[i] = nullptr; + } +#else m_cccmLumaBuf[0] = nullptr; m_cccmLumaBuf[1] = nullptr; +#endif #else m_cccmLumaBuf = nullptr; #endif @@ -229,11 +236,19 @@ void IntraPrediction::destroy() #if JVET_AA0057_CCCM #if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AD0202_CCCM_MDF + for (int i = 0; i < (CCCM_NUM_PRED_FILTER + 1); i++) + { + delete[] m_cccmLumaBuf[i]; + m_cccmLumaBuf[i] = nullptr; + } +#else delete[] m_cccmLumaBuf[0]; m_cccmLumaBuf[0] = nullptr; delete[] m_cccmLumaBuf[1]; m_cccmLumaBuf[1] = nullptr; +#endif #else delete[] m_cccmLumaBuf; m_cccmLumaBuf = nullptr; @@ -406,6 +421,23 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth #if JVET_AA0057_CCCM #if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AD0202_CCCM_MDF + if (m_cccmLumaBuf[0] == nullptr) + { + const int chromaScaleX = getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, chromaFormatIDC); + const int chromaScaleY = getChannelTypeScaleY(CHANNEL_TYPE_CHROMA, chromaFormatIDC); + + m_cccmLumaBuf[0] = new Pel[(2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + (CCCM_FILTER_PADDING << chromaScaleX) + (CCCM_FILTER_PADDING << chromaScaleY)) * (2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + (CCCM_FILTER_PADDING << chromaScaleX) + (CCCM_FILTER_PADDING << chromaScaleY))]; + } + + for (int i = 1; i < (CCCM_NUM_PRED_FILTER + 1); i++) + { + if (m_cccmLumaBuf[i] == nullptr) + { + m_cccmLumaBuf[i] = new Pel[(2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + 2 * CCCM_FILTER_PADDING) * (2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + 2 * CCCM_FILTER_PADDING)]; + } + } +#else if( m_cccmLumaBuf[0] == nullptr ) { m_cccmLumaBuf[0] = new Pel[(2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + 2 * CCCM_FILTER_PADDING) * (2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + 2 * CCCM_FILTER_PADDING)]; @@ -418,6 +450,7 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth m_cccmLumaBuf[1] = new Pel[(2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + (CCCM_FILTER_PADDING << chromaScaleX) + (CCCM_FILTER_PADDING << chromaScaleY)) * (2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + (CCCM_FILTER_PADDING << chromaScaleX) + (CCCM_FILTER_PADDING << chromaScaleY))]; } +#endif #else if (m_cccmLumaBuf == nullptr) { @@ -8281,7 +8314,11 @@ void IntraPrediction::xGetLumaRecPixelsGlmAll(const PredictionUnit &pu, CompArea #endif // LumaRecPixels -void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea) +void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea +#if JVET_AD0202_CCCM_MDF + , int downsFilterIdx +#endif +) { #if JVET_AA0057_CCCM if ( pu.cccmFlag ) @@ -8293,7 +8330,11 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom return; } #endif - xCccmCreateLumaRef(pu, chromaArea); + xCccmCreateLumaRef(pu, chromaArea +#if JVET_AD0202_CCCM_MDF + , downsFilterIdx +#endif + ); return; } #endif @@ -10816,7 +10857,11 @@ void IntraPrediction::xCccmSetLumaRefValue(const PredictionUnit& pu) #endif // Calculate a single downsampled luma reference value (copied from IntraPrediction::xGetLumaRecPixels) -Pel IntraPrediction::xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, const int x, const int y) const +Pel IntraPrediction::xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, const int x, const int y +#if JVET_AD0202_CCCM_MDF + , int downsFilterIdx +#endif +) const { const Pel* piSrc = pi.buf; const int iRecStride = pi.stride; @@ -10852,6 +10897,65 @@ Pel IntraPrediction::xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, } else { +#if JVET_AD0202_CCCM_MDF + const int lumaPosPicX1 = 2 * x; + const int lumaPosPicY1 = 2 * y; + int lumaPosPicX0 = lumaPosPicX1 - 1; lumaPosPicX0 = lumaPosPicX0 < 0 ? 0 : lumaPosPicX0; + const int lumaPosPicX2 = lumaPosPicX1 + 1; + const int lumaPosPicY2 = lumaPosPicY1 + 1; + const int shift0 = iRecStride * lumaPosPicY1; + const int shift1 = iRecStride * lumaPosPicY2; + + if (downsFilterIdx == 0) + { + int s = 4; + + s += piSrc[lumaPosPicX1 + shift0] * 2; + s += piSrc[lumaPosPicX0 + shift0]; + s += piSrc[lumaPosPicX2 + shift0]; + s += piSrc[lumaPosPicX1 + shift1] * 2; + s += piSrc[lumaPosPicX0 + shift1]; + s += piSrc[lumaPosPicX2 + shift1]; + ypval = s >> 3; + } + else if (downsFilterIdx == 1) + { + int s = 0; + + s += piSrc[lumaPosPicX0 + shift0]; + s -= piSrc[lumaPosPicX2 + shift0]; + s += piSrc[lumaPosPicX0 + shift1]; + s -= piSrc[lumaPosPicX2 + shift1]; + + ypval = s < 0 ? 0 : s; + } + else if (downsFilterIdx == 2) + { + int s = 0; + + s += piSrc[lumaPosPicX0 + shift0]; + s += piSrc[lumaPosPicX1 + shift0] * 2; + s += piSrc[lumaPosPicX2 + shift0]; + s -= piSrc[lumaPosPicX0 + shift1]; + s -= piSrc[lumaPosPicX1 + shift1] * 2; + s -= piSrc[lumaPosPicX2 + shift1]; + + ypval = s < 0 ? 0 : s; + } + else + { + int s = 0; + + s -= piSrc[lumaPosPicX0 + shift0]; + s += piSrc[lumaPosPicX1 + shift0]; + s += piSrc[lumaPosPicX2 + shift0] * 2; + s -= piSrc[lumaPosPicX0 + shift1] * 2; + s -= piSrc[lumaPosPicX1 + shift1]; + s += piSrc[lumaPosPicX2 + shift1]; + + ypval = s < 0 ? 0 : s; + } +#else int s = 4; int offLeft = x > 0 ? -1 : 0; s += piSrc[2 * x + iRecStride * y * 2] * 2; @@ -10861,6 +10965,7 @@ Pel IntraPrediction::xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, s += piSrc[2 * x + offLeft + iRecStride * (y * 2 + 1)]; s += piSrc[2 * x + 1 + iRecStride * (y * 2 + 1)]; ypval = s >> 3; +#endif } #if JVET_AB0174_CCCM_DIV_FREE @@ -10905,6 +11010,67 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P } } else +#endif +#if JVET_AD0202_CCCM_MDF + if (pu.cccmMultiFilterIdx == 1) + { + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCb(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)); + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCr(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)); + +#if JVET_AB0143_CCCM_TS + if (intraDir == LM_CHROMA_IDX || intraDir == MDLM_L_IDX || intraDir == MDLM_T_IDX) +#else + if (PU::cccmSingleModeAvail(pu, intraDir)) +#endif + { + xCccmCalcModels2(pu, cccmModelCb, cccmModelCr, 0, 0); + xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb, 0, 0, predCb); + xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr, 0, 0, predCr); + } + else + { + // Multimode case + int modelThr = xCccmCalcRefAver(pu); + + xCccmCalcModels2(pu, cccmModelCb, cccmModelCr, 1, modelThr); + xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb, 1, modelThr, predCb); + xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr, 1, modelThr, predCr); + + xCccmCalcModels2(pu, cccmModelCb, cccmModelCr, 2, modelThr); + xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb, 2, modelThr, predCb); + xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr, 2, modelThr, predCr); + } + } + else if (pu.cccmMultiFilterIdx > 1) + { + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModelCb(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)); + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModelCr(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)); + +#if JVET_AB0143_CCCM_TS + if (intraDir == LM_CHROMA_IDX || intraDir == MDLM_L_IDX || intraDir == MDLM_T_IDX) +#else + if (PU::cccmSingleModeAvail(pu, intraDir)) +#endif + { + xCccmCalcModels3(pu, cccmModelCb, cccmModelCr, 0, 0); + xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb, 0, 0, predCb); + xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr, 0, 0, predCr); + } + else + { + // Multimode case + int modelThr = xCccmCalcRefAver(pu); + + xCccmCalcModels3(pu, cccmModelCb, cccmModelCr, 1, modelThr); + xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb, 1, modelThr, predCb); + xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr, 1, modelThr, predCr); + + xCccmCalcModels3(pu, cccmModelCb, cccmModelCr, 2, modelThr); + xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb, 2, modelThr, predCb); + xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr, 2, modelThr, predCr); + } + } + else #endif if ( pu.cccmFlag ) { @@ -11479,6 +11645,327 @@ void IntraPrediction::xCccmCreateLumaNoSubRef( const PredictionUnit& pu, CompAre } #endif +#if JVET_AD0202_CCCM_MDF +void IntraPrediction::xCccmCalcModels2(const PredictionUnit& pu, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModelCb, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModelCr, int modelId, int modelThr) +{ + int areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY; + +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + CHECK(pu.cccmNoSubFlag, "cccmNoSubFlag shall be disabled"); +#endif + + const CPelBuf recoCb = pu.cs->picture->getRecoBuf(COMPONENT_Cb); + const CPelBuf recoCr = pu.cs->picture->getRecoBuf(COMPONENT_Cr); + + PelBuf refLuma1, refLuma2, refLuma3; + PelBuf refLuma = xCccmGetLumaRefBuf(pu, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY, 0, 3, &refLuma1, &refLuma3, &refLuma2); + + int sampleNum = 0; + +#if JVET_AB0174_CCCM_DIV_FREE + int chromaOffsetCb = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 1); + int chromaOffsetCr = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 1); + + if (refSizeX || refSizeY) + { + int refPosX = refSizeX > 0 ? refSizeX - 1 : 0; + int refPosY = refSizeY > 0 ? refSizeY - 1 : 0; + + chromaOffsetCb = recoCb.at(refPosPicX + refPosX, refPosPicY + refPosY); + chromaOffsetCr = recoCr.at(refPosPicX + refPosX, refPosPicY + refPosY); + } +#endif + + // Collect reference data to input matrix A and target vector Y + static Pel A[CCCM_MULTI_PRED_FILTER_NUM_PARAMS][CCCM_MAX_REF_SAMPLES]; + static Pel YCb[CCCM_MAX_REF_SAMPLES]; + static Pel YCr[CCCM_MAX_REF_SAMPLES]; + +#if JVET_AB0143_CCCM_TS + int yStart = pu.cccmFlag == 2 ? refSizeY : 0; + int yEnd = pu.cccmFlag == 3 ? refSizeY : areaHeight; + int xStart = pu.cccmFlag == 3 ? refSizeX : 0; + int xEnd = pu.cccmFlag == 2 ? refSizeX : areaWidth; + + for (int y = yStart; y < yEnd; y++) + { + for (int x = xStart; x < xEnd; x++) + { +#else + for (int y = 0; y < areaHeight; y++) + { + for (int x = 0; x < areaWidth; x++) + { +#endif + if (x >= refSizeX && y >= refSizeY) + { + continue; + } + + if (modelId == 1 && refLuma.at(x, y) > modelThr) // Model 1: Include only samples below or equal to the threshold + { + continue; + } + if (modelId == 2 && refLuma.at(x, y) <= modelThr) // Model 2: Include only samples above the threshold + { + continue; + } + + // 7-tap cross + A[0][sampleNum] = refLuma.at(x, y); + A[1][sampleNum] = refLuma1.at(x, y); + A[2][sampleNum] = refLuma2.at(x, y); + A[3][sampleNum] = refLuma3.at(x, y); + A[4][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x, y)); + A[5][sampleNum] = cccmModelCb.nonlinear(refLuma1.at(x, y)); + A[6][sampleNum] = cccmModelCb.nonlinear(refLuma2.at(x, y)); + A[7][sampleNum] = ((y + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + A[8][sampleNum] = ((x + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + A[9][sampleNum] = cccmModelCb.bias(); + + YCb[sampleNum] = recoCb.at(refPosPicX + x, refPosPicY + y); + YCr[sampleNum++] = recoCr.at(refPosPicX + x, refPosPicY + y); + } + } + + if (!sampleNum) // Number of samples can go to zero in the multimode case + { + cccmModelCb.clearModel(); + cccmModelCr.clearModel(); + } + else + { +#if JVET_AB0174_CCCM_DIV_FREE + m_cccmMultiDownSolver.solve2(A, YCb, YCr, sampleNum, chromaOffsetCb, chromaOffsetCr, cccmModelCb, cccmModelCr); +#else + m_cccmMultiDownSolver.solve2(A, YCb, YCr, sampleNum, cccmModelCb, cccmModelCr); +#endif + } +} + +void IntraPrediction::xCccmApplyModel2(const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const +{ + const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compId)); + static Pel samples[CCCM_MULTI_PRED_FILTER_NUM_PARAMS]; + +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + CHECK(pu.cccmNoSubFlag, "cccmNoSubFlag shall be disabled"); +#endif +#if JVET_AC0054_GLCCCM + int refSizeX = m_cccmBlkArea.x - m_cccmRefArea.x; // Reference lines available left and above + int refSizeY = m_cccmBlkArea.y - m_cccmRefArea.y; +#endif + CPelBuf refLumaBlk1, refLumaBlk2, refLumaBlk3; + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu, 0, 3, &refLumaBlk1, &refLumaBlk3, &refLumaBlk2); + + for (int y = 0; y < refLumaBlk.height; y++) + { + for (int x = 0; x < refLumaBlk.width; x++) + { + if (modelId == 1 && refLumaBlk.at(x, y) > modelThr) // Model 1: Include only samples below or equal to the threshold + { + continue; + } + if (modelId == 2 && refLumaBlk.at(x, y) <= modelThr) // Model 2: Include only samples above the threshold + { + continue; + } + + // 7-tap cross + samples[0] = refLumaBlk.at(x, y); // C + samples[1] = refLumaBlk1.at(x, y); // W + samples[2] = refLumaBlk2.at(x, y); // E + samples[3] = refLumaBlk3.at(x, y); + samples[4] = cccmModel.nonlinear(refLumaBlk.at(x, y)); + samples[5] = cccmModel.nonlinear(refLumaBlk1.at(x, y)); + samples[6] = cccmModel.nonlinear(refLumaBlk2.at(x, y)); + samples[7] = ((y + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[8] = ((x + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[9] = cccmModel.bias(); + + piPred.at(x, y) = ClipPel<Pel>(cccmModel.convolve(samples), clpRng); + } + } +} + +void IntraPrediction::xCccmCalcModels3(const PredictionUnit& pu, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModelCb, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModelCr, int modelId, int modelThr) +{ + int areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY; + +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + CHECK(pu.cccmNoSubFlag, "cccmNoSubFlag shall be disabled"); +#endif + + const CPelBuf recoCb = pu.cs->picture->getRecoBuf(COMPONENT_Cb); + const CPelBuf recoCr = pu.cs->picture->getRecoBuf(COMPONENT_Cr); + PelBuf refLuma1, refLuma3; + PelBuf refLuma = xCccmGetLumaRefBuf(pu, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY, 0, 2, &refLuma1, &refLuma3); + + int sampleNum = 0; + +#if JVET_AB0174_CCCM_DIV_FREE + int chromaOffsetCb = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 1); + int chromaOffsetCr = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 1); + + if (refSizeX || refSizeY) + { + int refPosX = refSizeX > 0 ? refSizeX - 1 : 0; + int refPosY = refSizeY > 0 ? refSizeY - 1 : 0; + + chromaOffsetCb = recoCb.at(refPosPicX + refPosX, refPosPicY + refPosY); + chromaOffsetCr = recoCr.at(refPosPicX + refPosX, refPosPicY + refPosY); + } +#endif + + // Collect reference data to input matrix A and target vector Y + static Pel A[CCCM_MULTI_PRED_FILTER_NUM_PARAMS2][CCCM_MAX_REF_SAMPLES]; + static Pel YCb[CCCM_MAX_REF_SAMPLES]; + static Pel YCr[CCCM_MAX_REF_SAMPLES]; + +#if JVET_AB0143_CCCM_TS + int yStart = pu.cccmFlag == 2 ? refSizeY : 0; + int yEnd = pu.cccmFlag == 3 ? refSizeY : areaHeight; + int xStart = pu.cccmFlag == 3 ? refSizeX : 0; + int xEnd = pu.cccmFlag == 2 ? refSizeX : areaWidth; + + for (int y = yStart; y < yEnd; y++) + { + for (int x = xStart; x < xEnd; x++) + { +#else + for (int y = 0; y < areaHeight; y++) + { + for (int x = 0; x < areaWidth; x++) + { +#endif + if (x >= refSizeX && y >= refSizeY) + { + continue; + } + + if (modelId == 1 && refLuma.at(x, y) > modelThr) // Model 1: Include only samples below or equal to the threshold + { + continue; + } + if (modelId == 2 && refLuma.at(x, y) <= modelThr) // Model 2: Include only samples above the threshold + { + continue; + } + + // 7-tap cross + if (pu.cccmMultiFilterIdx == 2) + { + A[0][sampleNum] = refLuma.at(x, y); // C + A[1][sampleNum] = refLuma.at(x - 1, y); // W + A[2][sampleNum] = refLuma.at(x + 1, y); // E + A[3][sampleNum] = refLuma1.at(x, y); // C + A[4][sampleNum] = refLuma1.at(x - 1, y); // W + A[5][sampleNum] = refLuma1.at(x + 1, y); // E + A[6][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x, y)); + A[7][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x - 1, y)); + A[8][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x + 1, y)); + A[9][sampleNum] = ((x + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + A[10][sampleNum] = cccmModelCb.bias(); + } + else + { + A[0][sampleNum] = refLuma.at(x, y); // C + A[1][sampleNum] = refLuma.at(x + 1, y - 1); // EN + A[2][sampleNum] = refLuma.at(x - 1, y + 1); // WS + A[3][sampleNum] = refLuma3.at(x, y); // C + A[4][sampleNum] = refLuma3.at(x + 1, y - 1); // EN + A[5][sampleNum] = refLuma3.at(x - 1, y + 1); // WS + A[6][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x, y)); + A[7][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x + 1, y - 1)); + A[8][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x - 1, y + 1)); + A[9][sampleNum] = ((y + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + A[10][sampleNum] = cccmModelCb.bias(); + } + + YCb[sampleNum] = recoCb.at(refPosPicX + x, refPosPicY + y); + YCr[sampleNum++] = recoCr.at(refPosPicX + x, refPosPicY + y); + } + } + + if (!sampleNum) // Number of samples can go to zero in the multimode case + { + cccmModelCb.clearModel(); + cccmModelCr.clearModel(); + } + else + { +#if JVET_AB0174_CCCM_DIV_FREE + m_cccmMultiDownSolver2.solve2(A, YCb, YCr, sampleNum, chromaOffsetCb, chromaOffsetCr, cccmModelCb, cccmModelCr); +#else + m_cccmMultiDownSolver.solve2(A, YCb, YCr, sampleNum, cccmModelCb, cccmModelCr); +#endif + } +} + +void IntraPrediction::xCccmApplyModel3(const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const +{ + const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compId)); + static Pel samples[CCCM_MULTI_PRED_FILTER_NUM_PARAMS2]; + +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + CHECK(pu.cccmNoSubFlag, "cccmNoSubFlag shall be disabled"); +#endif +#if JVET_AC0054_GLCCCM + int refSizeX = m_cccmBlkArea.x - m_cccmRefArea.x; // Reference lines available left and above + int refSizeY = m_cccmBlkArea.y - m_cccmRefArea.y; +#endif + CPelBuf refLumaBlk1, refLumaBlk3; + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu, 0, 2, &refLumaBlk1, &refLumaBlk3); + + for (int y = 0; y < refLumaBlk.height; y++) + { + for (int x = 0; x < refLumaBlk.width; x++) + { + if (modelId == 1 && refLumaBlk.at(x, y) > modelThr) // Model 1: Include only samples below or equal to the threshold + { + continue; + } + if (modelId == 2 && refLumaBlk.at(x, y) <= modelThr) // Model 2: Include only samples above the threshold + { + continue; + } + + // 7-tap cross + if (pu.cccmMultiFilterIdx == 2) + { + samples[0] = refLumaBlk.at(x, y); // C + samples[1] = refLumaBlk.at(x - 1, y); // W + samples[2] = refLumaBlk.at(x + 1, y); // E + samples[3] = refLumaBlk1.at(x, y); // C + samples[4] = refLumaBlk1.at(x - 1, y); // W + samples[5] = refLumaBlk1.at(x + 1, y); // E + samples[6] = cccmModel.nonlinear(refLumaBlk.at(x, y)); + samples[7] = cccmModel.nonlinear(refLumaBlk.at(x - 1, y)); + samples[8] = cccmModel.nonlinear(refLumaBlk.at(x + 1, y)); + samples[9] = ((x + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[10] = cccmModel.bias(); + } + else + { + samples[0] = refLumaBlk.at(x, y); // C + samples[1] = refLumaBlk.at(x + 1, y - 1); // EN + samples[2] = refLumaBlk.at(x - 1, y + 1); // WS + samples[3] = refLumaBlk3.at(x, y); // C + samples[4] = refLumaBlk3.at(x + 1, y - 1); // EN + samples[5] = refLumaBlk3.at(x - 1, y + 1); // WS + samples[6] = cccmModel.nonlinear(refLumaBlk.at(x, y)); + samples[7] = cccmModel.nonlinear(refLumaBlk.at(x + 1, y - 1)); + samples[8] = cccmModel.nonlinear(refLumaBlk.at(x - 1, y + 1)); + samples[9] = ((y + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[10] = cccmModel.bias(); + } + + piPred.at(x, y) = ClipPel<Pel>(cccmModel.convolve(samples), clpRng); + } + } +} +#endif + // Using the same availability checking as in IntraPrediction::xFillReferenceSamples void IntraPrediction::xCccmCalcRefArea(const PredictionUnit& pu, CompArea chromaArea) { @@ -11527,7 +12014,11 @@ void IntraPrediction::xCccmCalcRefArea(const PredictionUnit& pu, CompArea chroma } // Return downsampled luma buffer that contains PU and the reference areas above and left of the PU -PelBuf IntraPrediction::xCccmGetLumaRefBuf(const PredictionUnit& pu, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY ) const +PelBuf IntraPrediction::xCccmGetLumaRefBuf(const PredictionUnit& pu, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY +#if JVET_AD0202_CCCM_MDF + , int cccmDownsamplesFilterIdx, int numBuffer, PelBuf* refLuma1, PelBuf* refLuma3, PelBuf* refLuma2 +#endif +) const { #if JVET_AC0147_CCCM_NO_SUBSAMPLING if( pu.cccmNoSubFlag ) @@ -11544,7 +12035,11 @@ PelBuf IntraPrediction::xCccmGetLumaRefBuf(const PredictionUnit& pu, int &areaWi int refStride = areaWidth + 2 * (CCCM_FILTER_PADDING << chromaScaleX); // Including paddings required for the 2D filter int refOrigin = refStride * (CCCM_FILTER_PADDING << chromaScaleY) + (CCCM_FILTER_PADDING << chromaScaleX); +#if JVET_AD0202_CCCM_MDF + return PelBuf(m_cccmLumaBuf[0] + refOrigin, refStride, areaWidth, areaHeight); // Points to the top-left corner of the reference area +#else return PelBuf( m_cccmLumaBuf[1] + refOrigin, refStride, areaWidth, areaHeight ); // Points to the top-left corner of the reference area +#endif } #endif @@ -11559,14 +12054,38 @@ PelBuf IntraPrediction::xCccmGetLumaRefBuf(const PredictionUnit& pu, int &areaWi int refOrigin = refStride * CCCM_FILTER_PADDING + CCCM_FILTER_PADDING; #if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AD0202_CCCM_MDF + if (numBuffer == 0) + { + return PelBuf(m_cccmLumaBuf[cccmDownsamplesFilterIdx + 1] + refOrigin, refStride, areaWidth, areaHeight); // Points to the top-left corner of the reference area +} + else if (numBuffer == 2) + { + *refLuma1 = PelBuf(m_cccmLumaBuf[2] + refOrigin, refStride, areaWidth, areaHeight); + *refLuma3 = PelBuf(m_cccmLumaBuf[4] + refOrigin, refStride, areaWidth, areaHeight); + return PelBuf(m_cccmLumaBuf[1] + refOrigin, refStride, areaWidth, areaHeight); // Points to the top-left corner of the reference area + } + else + { + *refLuma1 = PelBuf(m_cccmLumaBuf[2] + refOrigin, refStride, areaWidth, areaHeight); + *refLuma2 = PelBuf(m_cccmLumaBuf[3] + refOrigin, refStride, areaWidth, areaHeight); + *refLuma3 = PelBuf(m_cccmLumaBuf[4] + refOrigin, refStride, areaWidth, areaHeight); + return PelBuf(m_cccmLumaBuf[1] + refOrigin, refStride, areaWidth, areaHeight); // Points to the top-left corner of the reference area + } +#else return PelBuf( m_cccmLumaBuf[0] + refOrigin, refStride, areaWidth, areaHeight ); // Points to the top-left corner of the reference area +#endif #else return PelBuf(m_cccmLumaBuf + refOrigin, refStride, areaWidth, areaHeight); // Points to the top-left corner of the reference area #endif } // Return downsampled luma buffer for a PU -PelBuf IntraPrediction::xCccmGetLumaPuBuf(const PredictionUnit& pu) const +PelBuf IntraPrediction::xCccmGetLumaPuBuf(const PredictionUnit& pu +#if JVET_AD0202_CCCM_MDF + , int cccmDownsamplesFilterIdx, int numBuffer, CPelBuf* refLuma1, CPelBuf* refLuma3, CPelBuf* refLuma2 +#endif +) const { #if JVET_AC0147_CCCM_NO_SUBSAMPLING if( pu.cccmNoSubFlag ) @@ -11581,7 +12100,11 @@ PelBuf IntraPrediction::xCccmGetLumaPuBuf(const PredictionUnit& pu) const int refStride = (m_cccmRefArea.width + 2 * CCCM_FILTER_PADDING) << chromaScaleX; // Including paddings required for the 2D filter int refOrigin = refStride * (refSizeY + (CCCM_FILTER_PADDING << chromaScaleY)) + refSizeX + (CCCM_FILTER_PADDING << chromaScaleX); +#if JVET_AD0202_CCCM_MDF + return PelBuf(m_cccmLumaBuf[0] + refOrigin, refStride, tuWidth, tuHeight); // Points to the top-left corner of the block +#else return PelBuf( m_cccmLumaBuf[1] + refOrigin, refStride, tuWidth, tuHeight ); // Points to the top-left corner of the block +#endif } #endif @@ -11593,7 +12116,27 @@ PelBuf IntraPrediction::xCccmGetLumaPuBuf(const PredictionUnit& pu) const int refOrigin = refStride * (refSizeY + CCCM_FILTER_PADDING) + refSizeX + CCCM_FILTER_PADDING; #if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AD0202_CCCM_MDF + if (numBuffer == 0) + { + return PelBuf(m_cccmLumaBuf[1] + refOrigin, refStride, tuWidth, tuHeight); // Points to the top-left corner of the block + } + else if (numBuffer == 2) + { + *refLuma1 = PelBuf(m_cccmLumaBuf[2] + refOrigin, refStride, tuWidth, tuHeight); + *refLuma3 = PelBuf(m_cccmLumaBuf[4] + refOrigin, refStride, tuWidth, tuHeight); + return PelBuf(m_cccmLumaBuf[1] + refOrigin, refStride, tuWidth, tuHeight); // Points to the top-left corner of the block + } + else + { + *refLuma1 = PelBuf(m_cccmLumaBuf[2] + refOrigin, refStride, tuWidth, tuHeight); + *refLuma2 = PelBuf(m_cccmLumaBuf[3] + refOrigin, refStride, tuWidth, tuHeight); + *refLuma3 = PelBuf(m_cccmLumaBuf[4] + refOrigin, refStride, tuWidth, tuHeight); + return PelBuf(m_cccmLumaBuf[1] + refOrigin, refStride, tuWidth, tuHeight); // Points to the top-left corner of the block + } +#else return PelBuf( m_cccmLumaBuf[0] + refOrigin, refStride, tuWidth, tuHeight ); // Points to the top-left corner of the block +#endif #else return PelBuf(m_cccmLumaBuf + refOrigin, refStride, tuWidth, tuHeight); // Points to the top-left corner of the block #endif @@ -11663,7 +12206,11 @@ int IntraPrediction::xCccmCalcRefAver(const PredictionUnit& pu) const #endif } -void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chromaArea) +void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chromaArea +#if JVET_AD0202_CCCM_MDF + , int downsFilterIdx +#endif +) { const CPelBuf recoLuma = pu.cs->picture->getRecoBuf(COMPONENT_Y); const int maxPosPicX = pu.cs->picture->chromaSize().width - 1; @@ -11673,7 +12220,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro int areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY; - PelBuf refLuma = xCccmGetLumaRefBuf(pu, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY); + PelBuf refLuma = xCccmGetLumaRefBuf(pu, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY +#if JVET_AD0202_CCCM_MDF + , downsFilterIdx +#endif + ); int puBorderX = refSizeX + m_cccmBlkArea.width; int puBorderY = refSizeY + m_cccmBlkArea.height; @@ -11699,7 +12250,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro chromaPosPicX = chromaPosPicX < 0 ? 0 : chromaPosPicX > maxPosPicX ? maxPosPicX : chromaPosPicX; chromaPosPicY = chromaPosPicY < 0 ? 0 : chromaPosPicY > maxPosPicY ? maxPosPicY : chromaPosPicY; - refLuma.at( x, y ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, chromaPosPicY); + refLuma.at( x, y ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, chromaPosPicY +#if JVET_AD0202_CCCM_MDF + , downsFilterIdx +#endif + ); } } @@ -11757,7 +12312,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro int chromaPosPicY = refPosPicY + y; chromaPosPicY = chromaPosPicY < 0 ? 0 : chromaPosPicY > maxPosPicY ? maxPosPicY : chromaPosPicY; - refLuma.at( areaWidth, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY); + refLuma.at( areaWidth, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY +#if JVET_AD0202_CCCM_MDF + , downsFilterIdx +#endif + ); } } @@ -11771,7 +12330,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro int chromaPosPicY = refPosPicY + y; chromaPosPicY = chromaPosPicY < 0 ? 0 : chromaPosPicY > maxPosPicY ? maxPosPicY : chromaPosPicY; - refLuma.at( puBorderX, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY); + refLuma.at( puBorderX, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY +#if JVET_AD0202_CCCM_MDF + , downsFilterIdx +#endif + ); } } @@ -11785,7 +12348,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro int chromaPosPicY = refPosPicY + y; chromaPosPicY = chromaPosPicY < 0 ? 0 : chromaPosPicY > maxPosPicY ? maxPosPicY : chromaPosPicY; - refLuma.at( refSizeX, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY); + refLuma.at( refSizeX, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY +#if JVET_AD0202_CCCM_MDF + , downsFilterIdx +#endif + ); } } @@ -11799,7 +12366,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro int chromaPosPicX = refPosPicX + x; chromaPosPicX = chromaPosPicX < 0 ? 0 : chromaPosPicX > maxPosPicX ? maxPosPicX : chromaPosPicX; - refLuma.at( x, areaHeight ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY); + refLuma.at( x, areaHeight ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY +#if JVET_AD0202_CCCM_MDF + , downsFilterIdx +#endif + ); } } @@ -11813,7 +12384,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro int chromaPosPicX = refPosPicX + x; chromaPosPicX = chromaPosPicX < 0 ? 0 : chromaPosPicX > maxPosPicX ? maxPosPicX : chromaPosPicX; - refLuma.at( x, puBorderY ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY); + refLuma.at( x, puBorderY ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY +#if JVET_AD0202_CCCM_MDF + , downsFilterIdx +#endif + ); } } @@ -11832,7 +12407,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro int chromaPosPicX = refPosPicX + x; chromaPosPicX = chromaPosPicX < 0 ? 0 : chromaPosPicX > maxPosPicX ? maxPosPicX : chromaPosPicX; - refLuma.at( x, refSizeY ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY); + refLuma.at( x, refSizeY ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY +#if JVET_AD0202_CCCM_MDF + , downsFilterIdx +#endif + ); } } } diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index fc4b8541f476834337bf0b8969145775677d0d42..5a8106f8e994257f6c04f48dd43188a18d8f38e1 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -216,7 +216,11 @@ private: #if JVET_AA0057_CCCM Area m_cccmRefArea; #if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AD0202_CCCM_MDF + Pel* m_cccmLumaBuf[CCCM_NUM_PRED_FILTER + 1]; +#else Pel* m_cccmLumaBuf[2]; +#endif #else Pel* m_cccmLumaBuf; #endif @@ -322,6 +326,10 @@ protected: #if JVET_AA0057_CCCM CccmCovariance<CCCM_NUM_PARAMS, CCCM_MAX_REF_SAMPLES> m_cccmSolver; +#if JVET_AD0202_CCCM_MDF + CccmCovariance<CCCM_MULTI_PRED_FILTER_NUM_PARAMS, CCCM_MAX_REF_SAMPLES> m_cccmMultiDownSolver; + CccmCovariance<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2, CCCM_MAX_REF_SAMPLES> m_cccmMultiDownSolver2; +#endif #endif #if JVET_AB0092_GLM_WITH_LUMA CccmCovariance<GLM_NUM_PARAMS, GLM_MAX_REF_SAMPLES> m_glmSolver; @@ -419,7 +427,11 @@ public: void init (ChromaFormat chromaFormatIDC, const unsigned bitDepthY); #if JVET_AA0057_CCCM || JVET_AC0119_LM_CHROMA_FUSION - Pel xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, const int x, const int y) const; + Pel xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, const int x, const int y +#if JVET_AD0202_CCCM_MDF + , int downsFilterIdx = 0 +#endif + ) const; #if JVET_AB0174_CCCM_DIV_FREE void xCccmSetLumaRefValue(const PredictionUnit& pu); #endif @@ -428,9 +440,21 @@ public: void predIntraCCCM (const PredictionUnit& pu, PelBuf &predCb, PelBuf &predCr, int intraDir); void xCccmCalcModels (const PredictionUnit& pu, CccmModel<CCCM_NUM_PARAMS> &cccmModelCb, CccmModel<CCCM_NUM_PARAMS> &cccmModelCr, int modelId, int modelThr); void xCccmApplyModel (const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_NUM_PARAMS> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const; - void xCccmCreateLumaRef (const PredictionUnit& pu, CompArea chromaArea); - PelBuf xCccmGetLumaRefBuf (const PredictionUnit& pu, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY) const; - PelBuf xCccmGetLumaPuBuf (const PredictionUnit& pu) const; + void xCccmCreateLumaRef (const PredictionUnit& pu, CompArea chromaArea +#if JVET_AD0202_CCCM_MDF + , int downsFilterIdx +#endif + ); + PelBuf xCccmGetLumaRefBuf (const PredictionUnit& pu, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY +#if JVET_AD0202_CCCM_MDF + , int cccmDownsamplesFilterIdx = 0, int numBuffer = 0, PelBuf* refLuma1 = NULL, PelBuf* refLuma3 = NULL, PelBuf* refLuma2 = NULL +#endif + ) const; + PelBuf xCccmGetLumaPuBuf (const PredictionUnit& pu +#if JVET_AD0202_CCCM_MDF + , int cccmDownsamplesFilterIdx = 0, int numBuffer = 0, CPelBuf* refLuma1 = NULL, CPelBuf* refLuma3 = NULL, CPelBuf* refLuma2 = NULL +#endif + ) const; int xCccmCalcRefAver (const PredictionUnit& pu) const; void xCccmCalcRefArea (const PredictionUnit& pu, CompArea chromaArea); #if JVET_AC0147_CCCM_NO_SUBSAMPLING @@ -438,6 +462,12 @@ public: void xCccmApplyModel ( const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_NO_SUB_NUM_PARAMS> &cccmModel, int modelId, int modelThr, PelBuf &piPred ) const; void xCccmCalcModels ( const PredictionUnit& pu, CccmModel<CCCM_NO_SUB_NUM_PARAMS> &cccmModelCb, CccmModel<CCCM_NO_SUB_NUM_PARAMS> &cccmModelCr, int modelId, int modelThr ); #endif +#if JVET_AD0202_CCCM_MDF + void xCccmCalcModels2(const PredictionUnit& pu, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModelCb, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModelCr, int modelId, int modelThr); + void xCccmApplyModel2(const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const; + void xCccmCalcModels3(const PredictionUnit& pu, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModelCb, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModelCr, int modelId, int modelThr); + void xCccmApplyModel3(const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const; +#endif #endif #if JVET_AB0092_GLM_WITH_LUMA void xGlmCalcModel (const PredictionUnit& pu, const ComponentID compId, const CompArea& chromaArea, CccmModel<GLM_NUM_PARAMS> &glmModel); @@ -586,7 +616,11 @@ public: // Cross-component Chroma void predIntraChromaLM(const ComponentID compID, PelBuf &piPred, const PredictionUnit &pu, const CompArea& chromaArea, int intraDir, bool createModel = true, CclmModel *cclmModelStored = nullptr); - void xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea); + void xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea +#if JVET_AD0202_CCCM_MDF + , int downsFilterIdx = 0 +#endif + ); #if JVET_AA0126_GLM void xGetLumaRecPixelsGlmAll(const PredictionUnit &pu, CompArea chromaArea); Pel xGlmGetLumaVal (const int s[6], const int c[6], const int glmIdx, const Pel val) const; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 6a53b54cd4bd59cb56fd866829b89fd9936d3241..9e750f43f2ae7f065ab7e6abf7dbf2b552c64504 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -156,6 +156,7 @@ #define JVET_AB0143_CCCM_TS 1 // JVET-AB0143: CCCM template selection #define JVET_AC0147_CCCM_NO_SUBSAMPLING 1 // JVET-AC0147: Subsampling is not applied to CCCM #define JVET_AC0054_GLCCCM 1 // JVET_AC0054: Gradient and location based CCCM +#define JVET_AD0202_CCCM_MDF 1 // JVET_AD0202: CCCM with multiple downsampling filters #endif #define JVET_AA0126_GLM 1 // JVET-AA0126: Gradient linear model #if JVET_AA0126_GLM diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index fbeeffca3f5ddc4bdc60f0d169677b9cd7b1f87b..4b7b7319934faecd80e494383ab2c91178973306 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -816,6 +816,9 @@ void PredictionUnit::initData() #if JVET_AC0054_GLCCCM glCccmFlag = 0; #endif +#if JVET_AD0202_CCCM_MDF + cccmMultiFilterIdx = 0; +#endif #endif // inter data #if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION @@ -970,6 +973,9 @@ PredictionUnit& PredictionUnit::operator=(const IntraPredictionData& predData) #if JVET_AC0054_GLCCCM glCccmFlag = predData.glCccmFlag; #endif +#if JVET_AD0202_CCCM_MDF + cccmMultiFilterIdx = predData.cccmMultiFilterIdx; +#endif #endif return *this; } @@ -1124,6 +1130,9 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other ) #if JVET_AC0054_GLCCCM glCccmFlag = other.glCccmFlag; #endif +#if JVET_AD0202_CCCM_MDF + cccmMultiFilterIdx = other.cccmMultiFilterIdx; +#endif #endif mergeFlag = other.mergeFlag; diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 8c0524a6065a621eeda552c0e81ce2bafd1faf19..337e2ba14648523609283ce8725719c21f04d827 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -519,6 +519,9 @@ struct IntraPredictionData #if JVET_AC0054_GLCCCM int glCccmFlag; #endif +#if JVET_AD0202_CCCM_MDF + int cccmMultiFilterIdx; +#endif #endif }; diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 840300c2281f83bdbf88e4eec5e8e1c8c91d5133..a24f4fc6da9ed5af622fb970be8e44116b5e56ba 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -2279,6 +2279,33 @@ bool PU::isTopCccmMode(const PredictionUnit& pu, int intraMode) return modeIsOk && area.x && area.y; } + +#if JVET_AD0202_CCCM_MDF +bool PU::isMultiCccmWithMdf(const PredictionUnit& pu, int intraMode) +{ + const Area area = pu.blocks[COMPONENT_Cb]; + int th, tv; + PU::getCccmRefLineNum(pu, area, th, tv); + int nsamples; + bool nSampleCheck; + if (intraMode == MMLM_CHROMA_IDX) + { + nsamples = ((area.width + th) * (area.height + tv) - (area.area())); + nSampleCheck = (nsamples >= 96); + } + else if (intraMode == MMLM_L_IDX) + { + nsamples = th * area.height; + nSampleCheck = (nsamples >= 256); + } + else + { + nsamples = tv * area.width; + nSampleCheck = (nsamples >= 256); + } + return nSampleCheck; +} +#endif #endif #endif diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index f4f5cb12822a7f1613ad9dc87bf4bd2cb12d4aab..1a5f04953b7868ea0b494171c66f8ebf5d7cc786 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -613,6 +613,9 @@ namespace PU #if JVET_AB0143_CCCM_TS bool isLeftCccmMode(const PredictionUnit& pu, int intraMode); bool isTopCccmMode(const PredictionUnit& pu, int intraMode); +#if JVET_AD0202_CCCM_MDF + bool isMultiCccmWithMdf(const PredictionUnit& pu, int intraMode); +#endif #endif #endif #if JVET_Z0050_DIMD_CHROMA_FUSION diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index c1514feaa2017a4af814a26eb72756dd132280c1..5eab24f9ed9a2690ea602e79b760f2aeb18e50ac 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -2526,7 +2526,41 @@ void CABACReader::cccmFlag(PredictionUnit& pu) #else pu.cccmFlag = (intraDir == MDLM_T_IDX) ? 3 : (intraDir == MDLM_L_IDX) ? 2 : 1; #endif - +#if JVET_AD0202_CCCM_MDF + bool isCccmWithMdfEnabled = true; + if (intraDir == MMLM_CHROMA_IDX) + { + isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_CHROMA_IDX); + } + else if (intraDir == MMLM_L_IDX) + { + isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_L_IDX); + } + else if (intraDir == MMLM_T_IDX) + { + isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_T_IDX); + } + + if (isCccmWithMdfEnabled) + { + pu.cccmMultiFilterIdx = m_BinDecoder.decodeBin(Ctx::CccmMpfFlag(0)); + if (pu.cccmMultiFilterIdx > 0) + { + pu.cccmMultiFilterIdx += m_BinDecoder.decodeBin(Ctx::CccmMpfFlag(1)); + if (pu.cccmMultiFilterIdx > 1) + { + pu.cccmMultiFilterIdx += m_BinDecoder.decodeBin(Ctx::CccmMpfFlag(2)); + } + } + } + else + { + pu.cccmMultiFilterIdx = 0; + } + + if (!pu.cccmMultiFilterIdx) + { +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING pu.cccmNoSubFlag = 0; if ( pu.cs->sps->getUseCccm() == 2 ) @@ -2545,6 +2579,9 @@ void CABACReader::cccmFlag(PredictionUnit& pu) { pu.glCccmFlag = m_BinDecoder.decodeBin( Ctx::CccmFlag( ctxId ) ); } +#endif +#if JVET_AD0202_CCCM_MDF + } #endif } #endif diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 0bf108475f6f4fb77bc43d2e96f4344ed30a7552..e82b0e9e8f66c26a3b4b6c9995d1c5bf0f7acc9f 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -620,10 +620,38 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) // Create both Cb and Cr predictions when here for Cb if( compID == COMPONENT_Cb ) { +#if JVET_AD0202_CCCM_MDF + PredictionUnit& pu = *tu.cu->firstPU; +#else const PredictionUnit& pu = *tu.cu->firstPU; +#endif PelBuf predCr = cs.getPredBuf( tu.blocks[COMPONENT_Cr] ); +#if JVET_AD0202_CCCM_MDF + if (pu.cccmMultiFilterIdx == 1) + { + m_pcIntraPred->xGetLumaRecPixels(pu, area, 0); + m_pcIntraPred->xGetLumaRecPixels(pu, area, 1); + m_pcIntraPred->xGetLumaRecPixels(pu, area, 2); + m_pcIntraPred->xGetLumaRecPixels(pu, area, 3); + } + else if (pu.cccmMultiFilterIdx == 2) + { + m_pcIntraPred->xGetLumaRecPixels(pu, area, 0); + m_pcIntraPred->xGetLumaRecPixels(pu, area, 1); + } + else if (pu.cccmMultiFilterIdx == 3) + { + m_pcIntraPred->xGetLumaRecPixels(pu, area, 0); + m_pcIntraPred->xGetLumaRecPixels(pu, area, 3); + } + else + { + m_pcIntraPred->xGetLumaRecPixels(pu, area); + } +#else m_pcIntraPred->xGetLumaRecPixels( pu, area ); +#endif m_pcIntraPred->predIntraCCCM( pu, piPred, predCr, uiChFinalMode ); } } diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index ea6a716bd682fc0375ffd90bf6f550aa10c86814..80a8e4c8408331a639d4e921f5d9ed02bb516a3f 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -2257,6 +2257,40 @@ void CABACWriter::cccmFlag(const PredictionUnit& pu) #endif { m_BinEncoder.encodeBin( pu.cccmFlag ? 1 : 0, Ctx::CccmFlag( 0 ) ); +#if JVET_AD0202_CCCM_MDF + if (pu.cccmFlag) + { + bool isCccmWithMdfEnabled = true; + if (intraDir == MMLM_CHROMA_IDX) + { + isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_CHROMA_IDX); + } + else if (intraDir == MMLM_L_IDX) + { + isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_L_IDX); + } + else if (intraDir == MMLM_T_IDX) + { + isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_T_IDX); + } + + if (isCccmWithMdfEnabled) + { + m_BinEncoder.encodeBin(pu.cccmMultiFilterIdx > 0 ? 1 : 0, Ctx::CccmMpfFlag(0)); + if (pu.cccmMultiFilterIdx > 0) + { + m_BinEncoder.encodeBin(pu.cccmMultiFilterIdx > 1 ? 1 : 0, Ctx::CccmMpfFlag(1)); + if (pu.cccmMultiFilterIdx > 1) + { + m_BinEncoder.encodeBin(pu.cccmMultiFilterIdx > 2 ? 1 : 0, Ctx::CccmMpfFlag(2)); + } + } + } + } + + if (!pu.cccmMultiFilterIdx) + { +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING if ( pu.cccmFlag && ( pu.cs->sps->getUseCccm() == 2 ) ) { @@ -2274,6 +2308,9 @@ void CABACWriter::cccmFlag(const PredictionUnit& pu) { m_BinEncoder.encodeBin( pu.glCccmFlag ? 1 : 0, Ctx::CccmFlag( ctxId ) ); } +#endif +#if JVET_AD0202_CCCM_MDF + } #endif } } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 97819cdd4201e69c57382655ddd7e8696d9b09ff..4bf6f9e6f211bd9ff4358c40eeec92a2aa673d9b 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -2466,6 +2466,9 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS #endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING m_pcIntraSearch->m_skipCCCMSATD = false; +#endif +#if JVET_AD0202_CCCM_MDF + m_pcIntraSearch->m_skipCCCMwithMdfSATD = false; #endif for( int trGrpIdx = 0; trGrpIdx < grpNumMax; trGrpIdx++ ) { diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 6e06a23afa0cf52b9d17c66baed780c9a387e361..fba1a8f1ca7f6c25a176c4954dc01d5941894c84 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -195,7 +195,11 @@ void IntraSearch::destroy() #endif #if JVET_AB0143_CCCM_TS +#if JVET_AD0202_CCCM_MDF + for (uint32_t cccmIdx = 0; cccmIdx < TOTAL_NUM_CCCM_MODES; cccmIdx++) +#else for (uint32_t cccmIdx = 0; cccmIdx < CCCM_NUM_MODES; cccmIdx++) +#endif { #if JVET_AC0147_CCCM_NO_SUBSAMPLING m_cccmStorage[0][cccmIdx].destroy(); @@ -314,7 +318,11 @@ void IntraSearch::init( EncCfg* pcEncCfg, #endif #if JVET_AB0143_CCCM_TS +#if JVET_AD0202_CCCM_MDF + for (uint32_t cccmIdx = 0; cccmIdx < TOTAL_NUM_CCCM_MODES; cccmIdx++) +#else for (uint32_t cccmIdx = 0; cccmIdx < CCCM_NUM_MODES; cccmIdx++) +#endif { #if JVET_AC0147_CCCM_NO_SUBSAMPLING m_cccmStorage[0][cccmIdx].create(UnitArea(cform, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE))); @@ -2608,6 +2616,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_AC0054_GLCCCM int glCccmBest = 0; #endif +#if JVET_AD0202_CCCM_MDF + int cccmMultiFilterIdxBest = 0; +#endif #endif #if JVET_Z0050_CCLM_SLOPE CclmOffsets bestCclmOffsets = {}; @@ -2981,11 +2992,38 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #endif #endif +#if JVET_AD0202_CCCM_MDF + int satdCccmFilterIndex[TOTAL_NUM_CCCM_MODES]; +#if JVET_AC0054_GLCCCM + int satdCccmFlagList[TOTAL_NUM_CCCM_MODES]; +#endif +#else #if JVET_AC0054_GLCCCM int satdCccmFlagList[CCCM_NUM_MODES]; #endif +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AD0202_CCCM_MDF + int64_t satdCccmSortedCost[2][TOTAL_NUM_CCCM_MODES]; + int satdCccmModeList[2][TOTAL_NUM_CCCM_MODES]; + for (int i = 0; i < CCCM_NUM_PRED_FILTER; i++) + { + int startIdx = i * CCCM_NUM_MODES; + for (int j = 0; j < CCCM_NUM_MODES; j++) + { + int currCccmModeIdx = startIdx + j; + satdCccmSortedCost[0][currCccmModeIdx] = LLONG_MAX; // for the mode not pre-select by SATD, do RDO by default, so set the initial value 0. + satdCccmSortedCost[1][currCccmModeIdx] = LLONG_MAX; // for the mode not pre-select by SATD, do RDO by default, so set the initial value 0. + satdCccmModeList[0][currCccmModeIdx] = chromaCandCccmModes[j]; + satdCccmModeList[1][currCccmModeIdx] = chromaCandCccmModes[j]; +#if JVET_AC0054_GLCCCM + satdCccmFlagList[currCccmModeIdx] = j < (CCCM_NUM_MODES / 2) ? 1 : 2; // 1: cccm, 2: glCccm +#endif + satdCccmFilterIndex[currCccmModeIdx] = i; + } + } +#else int64_t satdCccmSortedCost[2][CCCM_NUM_MODES]; int satdCccmModeList[2][CCCM_NUM_MODES]; @@ -2999,6 +3037,7 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner satdCccmFlagList[i] = i < (CCCM_NUM_MODES / 2) ? 1 : 2; // 1: cccm, 2: glCccm #endif } +#endif int64_t bestCccmCost[2] = { LLONG_MAX, LLONG_MAX}; bool isCccmFullEnabled = PU::cccmSingleModeAvail(pu, LM_CHROMA_IDX); @@ -3009,17 +3048,38 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner bool isMultiCccmLeftEnabled = PU::cccmMultiModeAvail(pu, MMLM_L_IDX); bool isMultiCccmTopEnabled = PU::cccmMultiModeAvail(pu, MMLM_T_IDX); #endif +#if JVET_AD0202_CCCM_MDF + bool isMultiCccmFullEnabled2 = PU::isMultiCccmWithMdf(pu, MMLM_CHROMA_IDX); + bool isMultiCccmLeftEnabled2 = PU::isMultiCccmWithMdf(pu, MMLM_L_IDX); + bool isMultiCccmTopEnabled2 = PU::isMultiCccmWithMdf(pu, MMLM_T_IDX); +#endif const UnitArea localUnitArea(cs.area.chromaFormat, Area(0, 0, (pu.Cb().width) << 1, (pu.Cb().height) << 1)); +#if JVET_AD0202_CCCM_MDF + PelUnitBuf cccmStorage[2][TOTAL_NUM_CCCM_MODES]; +#else PelUnitBuf cccmStorage[2][CCCM_NUM_MODES]; +#endif pu.cccmFlag = 1; +#if JVET_AD0202_CCCM_MDF + pu.cccmNoSubFlag = 1; + xGetLumaRecPixels(pu, pu.Cb()); + pu.cccmNoSubFlag = 0; + xGetLumaRecPixels(pu, pu.Cb()); + xGetLumaRecPixels(pu, pu.Cb(), 1); + xGetLumaRecPixels(pu, pu.Cb(), 2); + xGetLumaRecPixels(pu, pu.Cb(), 3); +#endif + for (int sub = 0; sub < pu.cu->slice->getSPS()->getUseCccm(); sub++) { pu.cccmNoSubFlag = sub; +#if !JVET_AD0202_CCCM_MDF xGetLumaRecPixels(pu, pu.Cb()); +#endif bool isCCCMEnabled = false; @@ -3090,11 +3150,68 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner pu.cccmFlag = idx == 3 ? 1 : idx == 4 ? 2 : 3; #endif + +#if JVET_AD0202_CCCM_MDF + if (isCCCMEnabled) + { + if (m_skipCCCMwithMdfSATD) + { + if (m_isCccmWithMdfEnabledInRdo[4][mode] == 0) + { + continue; + } + } + } +#endif } #endif if (isCCCMEnabled) { +#if JVET_AD0202_CCCM_MDF + for (int32_t filterIdx = 0; filterIdx < CCCM_NUM_PRED_FILTER; filterIdx++) + { + if (filterIdx > 0) + { + if (sub == 1 || idx > 5) + { + continue; + } + + if (m_skipCCCMwithMdfSATD) + { + if (m_isCccmWithMdfEnabledInRdo[filterIdx][mode] == 0) + { + continue; + } + } + + if (mode == MMLM_CHROMA_IDX && !isMultiCccmFullEnabled2) + { + continue; + } + else if (mode == MMLM_L_IDX && !isMultiCccmLeftEnabled2) + { + continue; + } + else if (mode == MMLM_T_IDX && !isMultiCccmTopEnabled2) + { + continue; + } + } + else if (sub == 0 && idx <= 5) + { + if (m_skipCCCMwithMdfSATD) + { + if (m_isCccmWithMdfEnabledInRdo[filterIdx][mode] == 0) + { + continue; + } + } + } + + pu.cccmMultiFilterIdx = filterIdx; +#endif pu.intraDir[1] = mode; // temporary assigned, for SATD checking. if ( ( sub == 1 ) && m_skipCCCMSATD ) @@ -3117,24 +3234,42 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner DistParam distParamSadCr; DistParam distParamSatdCr; +#if JVET_AD0202_CCCM_MDF + const int cccmBufferIdx = filterIdx * CCCM_NUM_MODES + idx; + cccmStorage[sub][cccmBufferIdx] = m_cccmStorage[sub][cccmBufferIdx].getBuf(localUnitArea); +#else cccmStorage[sub][idx] = m_cccmStorage[sub][idx].getBuf(localUnitArea); +#endif CompArea areaCb = pu.Cb(); PelBuf orgCb = cs.getOrgBuf(areaCb); CompArea areaCr = pu.Cr(); PelBuf orgCr = cs.getOrgBuf(areaCr); +#if JVET_AD0202_CCCM_MDF + m_pcRdCost->setDistParam(distParamSadCb, orgCb, cccmStorage[sub][cccmBufferIdx].Cb(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, false); + m_pcRdCost->setDistParam(distParamSatdCb, orgCb, cccmStorage[sub][cccmBufferIdx].Cb(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, true); +#else m_pcRdCost->setDistParam(distParamSadCb, orgCb, cccmStorage[sub][idx].Cb(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, false); m_pcRdCost->setDistParam(distParamSatdCb, orgCb, cccmStorage[sub][idx].Cb(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, true); +#endif distParamSadCb.applyWeight = false; distParamSatdCb.applyWeight = false; +#if JVET_AD0202_CCCM_MDF + m_pcRdCost->setDistParam(distParamSadCr, orgCr, cccmStorage[sub][cccmBufferIdx].Cr(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, false); + m_pcRdCost->setDistParam(distParamSatdCr, orgCr, cccmStorage[sub][cccmBufferIdx].Cr(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, true); +#else m_pcRdCost->setDistParam(distParamSadCr, orgCr, cccmStorage[sub][idx].Cr(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, false); m_pcRdCost->setDistParam(distParamSatdCr, orgCr, cccmStorage[sub][idx].Cr(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, true); - +#endif distParamSadCr.applyWeight = false; distParamSatdCr.applyWeight = false; +#if JVET_AD0202_CCCM_MDF + predIntraCCCM(pu, cccmStorage[sub][cccmBufferIdx].Cb(), cccmStorage[sub][cccmBufferIdx].Cr(), mode); +#else predIntraCCCM(pu, cccmStorage[sub][idx].Cb(), cccmStorage[sub][idx].Cr(), mode); +#endif sadCb = distParamSadCb.distFunc(distParamSadCb) * 2; satdCb = distParamSatdCb.distFunc(distParamSatdCb); @@ -3143,12 +3278,19 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner satdCr = distParamSatdCr.distFunc(distParamSatdCr); sad += std::min(sadCr, satdCr); +#if JVET_AD0202_CCCM_MDF + satdCccmSortedCost[sub][cccmBufferIdx] = sad; +#else satdCccmSortedCost[sub][idx] = sad; +#endif if (sad < bestCccmCost[sub]) { bestCccmCost[sub] = sad; } +#if JVET_AD0202_CCCM_MDF + } +#endif } } } @@ -3158,7 +3300,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner int tempCccmIdx = 0; int64_t tempCccmCost = 0; #if JVET_AC0054_GLCCCM +#if JVET_AD0202_CCCM_MDF + for (int i = 1; i < 7; i++) +#else for (int i = 1; i < CCCM_NUM_MODES; i++) +#endif #else #if MMLM for (int i = 1; i < 4; i++) @@ -3167,7 +3313,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #endif #endif { +#if JVET_AD0202_CCCM_MDF + for (int j = i + 1; j < VALID_NUM_CCCM_MODES; j++) +#else for (int j = i + 1; j < CCCM_NUM_MODES; j++) +#endif { if (satdCccmSortedCost[0][j] < satdCccmSortedCost[0][i]) { @@ -3182,6 +3332,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner tempGlCccmFlag = satdCccmFlagList[i]; satdCccmFlagList[i] = satdCccmFlagList[j]; satdCccmFlagList[j] = tempGlCccmFlag; +#endif +#if JVET_AD0202_CCCM_MDF + tempCccmIdx = satdCccmFilterIndex[i]; + satdCccmFilterIndex[i] = satdCccmFilterIndex[j]; + satdCccmFilterIndex[j] = tempCccmIdx; #endif } } @@ -3189,16 +3344,26 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if MMLM bool isCccmModeEnabledInRdo[2][MMLM_T_IDX + 1] = { false }; +#if !JVET_AD0202_CCCM_MDF isCccmModeEnabledInRdo[0][satdCccmModeList[0][0]] = true; +#endif #if JVET_AC0054_GLCCCM bool isGlCccmModeEnabledInRdo[MMLM_T_IDX + 1] = { false }; +#if !JVET_AD0202_CCCM_MDF if (satdCccmFlagList[0] == 2) { isCccmModeEnabledInRdo[0][satdCccmModeList[0][0]] = false; isGlCccmModeEnabledInRdo[satdCccmModeList[0][0]] = true; } #endif +#endif +#if JVET_AD0202_CCCM_MDF + bool isCccmWithMulDownSamplingEnabledInRdo[MMLM_T_IDX + 1][CCCM_NUM_PRED_FILTER] = { false }; + isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][0]][satdCccmFilterIndex[0]] = true; + for (int i = 1; i < 7; i++) +#else for (int i = 1; i < 4; i++) +#endif #else bool isCccmModeEnabledInRdo[MDLM_T_IDX + 1] = { false }; isCccmModeEnabledInRdo[satdCccmModeList[0]] = true; @@ -3224,27 +3389,57 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner } else { +#if JVET_AD0202_CCCM_MDF + isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][i]][satdCccmFilterIndex[i]] = true; +#else isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]] = true; +#endif } #else isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]] = true; #endif } +#if JVET_AD0202_CCCM_MDF + if (m_skipCCCMwithMdfSATD == false) + { + m_skipCCCMwithMdfSATD = true; + for (int i = LM_CHROMA_IDX; i <= MMLM_T_IDX; i++) + { + m_isCccmWithMdfEnabledInRdo[4][i] = isGlCccmModeEnabledInRdo[i] ? 1 : 0; + + for (int j = 0; j < 4; j++) + { + m_isCccmWithMdfEnabledInRdo[j][i] = isCccmWithMulDownSamplingEnabledInRdo[i][j] ? 1 : 0; + } + } + } +#endif if (pu.cu->slice->getSPS()->getUseCccm() == 2) { if (bestCccmCost[1] < bestCccmCost[0]) { #if MMLM +#if JVET_AD0202_CCCM_MDF + for (int i = 1; i < 7; i++) +#else for (int i = 0; i < 4; i++) +#endif #else for (int i = 0; i < 3; i++) #endif { +#if JVET_AD0202_CCCM_MDF + if (isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][i]][satdCccmFilterIndex[i]] && (satdCccmSortedCost[0][i] >= 1.2 * bestCccmCost[1])) + { + isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][i]][satdCccmFilterIndex[i]] = false; + } +#else if (isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]] && (satdCccmSortedCost[0][i] >= 1.2 * bestCccmCost[1])) { isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]] = false; } +#endif else { bestCccmCost[0] = satdCccmSortedCost[0][i]; @@ -3280,6 +3475,7 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner { if (satdCccmSortedCost[1][i] >= CCCM_NO_SUB_WEIGHT * bestCccmCost[1]) { +#if !JVET_AD0202_CCCM_MDF #if JVET_AC0054_GLCCCM if (satdCccmSortedCost[1][i - 1] > bestCccmCost[0] && satdCccmFlagList[0] != 2) #else @@ -3289,10 +3485,16 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner bestCccmCost[0] = satdCccmSortedCost[1][i - 1]; } bestCccmCost[1] = satdCccmSortedCost[1][i - 1]; +#endif break; } isCccmModeEnabledInRdo[1][satdCccmModeList[1][i]] = true; } +#if JVET_AD0202_CCCM_MDF + bestCccmCost[1] = (isCccmModeEnabledInRdo[1][satdCccmModeList[1][1]] && satdCccmSortedCost[1][0] < satdCccmSortedCost[1][1]) ? satdCccmSortedCost[1][1] : satdCccmSortedCost[1][0]; + bestCccmCost[0] = (bestCccmCost[1] > bestCccmCost[0]) ? bestCccmCost[1] : bestCccmCost[0]; + bestCccmCost[0] = (satdCccmSortedCost[0][0] > bestCccmCost[0]) ? satdCccmSortedCost[0][0] : bestCccmCost[0]; +#endif if (m_skipCCCMSATD == false) { m_skipCCCMSATD = true; @@ -3307,6 +3509,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_AC0054_GLCCCM pu.glCccmFlag = 0; #endif +#if JVET_AD0202_CCCM_MDF + pu.cccmMultiFilterIdx = 0; +#endif #else int64_t satdCccmSortedCost[CCCM_NUM_MODES]; int satdCccmModeList[CCCM_NUM_MODES]; @@ -3501,31 +3706,59 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner if (pu.cu->slice->getSPS()->getUseCccm() == 2) { #if JVET_AC0054_GLCCCM +#if JVET_AD0202_CCCM_MDF + int32_t lastModeIdx = uiMaxMode - 1 - reducedModeNumber; ; + if (satdSortedCost[lastModeIdx] > bestCccmCost[0]) +#else if (satdSortedCost[uiMaxMode - 1 - reducedModeNumber] > bestCccmCost[0] && satdCccmFlagList[uiMaxMode - 1 - reducedModeNumber] != 2) +#endif #else if (satdSortedCost[uiMaxMode - 1 - reducedModeNumber] > bestCccmCost[0]) #endif +#if JVET_AD0202_CCCM_MDF + { + modeIsEnable[satdModeList[lastModeIdx]] = 0; // disable the last reducedModeNumber modes + } + else if (satdSortedCost[lastModeIdx] < bestCccmCost[0]) + { + for (int i = 6; i > 0; i--) +#else { modeIsEnable[satdModeList[uiMaxMode - 1 - reducedModeNumber]] = 0; // disable the last reducedModeNumber modes } else if (satdSortedCost[uiMaxMode - 1 - reducedModeNumber] < bestCccmCost[0]) { for (int i = 3; i > 0; i--) +#endif { #if JVET_AC0054_GLCCCM +#if JVET_AD0202_CCCM_MDF + if ((satdCccmSortedCost[0][i] > satdSortedCost[lastModeIdx]) && isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][i]][satdCccmFilterIndex[i]]) +#else if ((satdCccmSortedCost[0][i] > satdSortedCost[uiMaxMode - 1 - reducedModeNumber]) && (isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]]) && satdCccmFlagList[uiMaxMode - 1 - reducedModeNumber] != 2) +#endif #else if ((satdCccmSortedCost[0][i] > satdSortedCost[uiMaxMode - 1 - reducedModeNumber]) && (isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]])) #endif { +#if JVET_AD0202_CCCM_MDF + isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][i]][satdCccmFilterIndex[i]] = false; +#else isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]] = false; +#endif break; } } } +#if JVET_AD0202_CCCM_MDF + if (satdSortedCost[lastModeIdx] < bestCccmCost[1]) + { + if ((satdCccmSortedCost[1][1] > satdSortedCost[lastModeIdx]) && (isCccmModeEnabledInRdo[1][satdCccmModeList[1][1]])) +#else if (satdSortedCost[uiMaxMode - 1 - reducedModeNumber] < bestCccmCost[1]) { if ((satdCccmSortedCost[1][1] > satdSortedCost[uiMaxMode - 1 - reducedModeNumber]) && (isCccmModeEnabledInRdo[1][satdCccmModeList[1][1]])) +#endif { isCccmModeEnabledInRdo[1][satdCccmModeList[1][1]] = false; } @@ -4133,10 +4366,12 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner continue; } } +#if !JVET_AD0202_CCCM_MDF else { +#endif #endif // JVET_AC0054_GLCCCM - +#if !JVET_AD0202_CCCM_MDF #if JVET_AC0147_CCCM_NO_SUBSAMPLING if (!isCccmModeEnabledInRdo[0][chromaIntraModeInCCCM] && !isCccmModeEnabledInRdo[1][chromaIntraModeInCCCM]) #else @@ -4147,6 +4382,7 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner } #if JVET_AC0054_GLCCCM } +#endif #endif if (isCCCMEnabled) @@ -4170,13 +4406,33 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_AC0147_CCCM_NO_SUBSAMPLING for (int sub = 0; sub < pu.cu->slice->getSPS()->getUseCccm(); sub++) { +#if JVET_AD0202_CCCM_MDF + for (int32_t filterIdx = 0; filterIdx < CCCM_NUM_PRED_FILTER; filterIdx++) + { + if (filterIdx > 0 && (sub == 1 || uiMode > 5)) + { + continue; + } + pu.cccmMultiFilterIdx = filterIdx; +#endif pu.cccmNoSubFlag = sub; #if JVET_AC0054_GLCCCM if (sub && ((uiMode >= CCCM_NUM_MODES / 2) || pu.glCccmFlag)) { continue; } +#if JVET_AD0202_CCCM_MDF + else if (sub == 0 && uiMode < 6) + { + if (!isCccmWithMulDownSamplingEnabledInRdo[chromaIntraModeInCCCM][filterIdx]) + { + continue; + } + } + else if (sub) +#else else +#endif { if (!isCccmModeEnabledInRdo[sub][chromaIntraModeInCCCM]) { @@ -4202,7 +4458,12 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner pu.intraDir[1] = chromaIntraModeInCCCM; #if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AD0202_CCCM_MDF + const int cccmBufferIdx = filterIdx * CCCM_NUM_MODES + uiMode; + xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, cccmStorage[sub][cccmBufferIdx]); +#else xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, cccmStorage[sub][uiMode]); +#endif #else xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, cccmStorage[uiMode]); #endif @@ -4274,15 +4535,24 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_AC0054_GLCCCM glCccmBest = pu.glCccmFlag; #endif +#if JVET_AD0202_CCCM_MDF + cccmMultiFilterIdxBest = pu.cccmMultiFilterIdx; +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING cccmNoSubBest = pu.cccmNoSubFlag; } +#endif +#if JVET_AD0202_CCCM_MDF + } #endif } } } pu.cccmFlag = 0; +#if JVET_AD0202_CCCM_MDF + pu.cccmMultiFilterIdx = 0; +#endif #endif for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ ) { @@ -4323,6 +4593,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_AC0054_GLCCCM pu.glCccmFlag = glCccmBest; #endif +#if JVET_AD0202_CCCM_MDF + pu.cccmMultiFilterIdx = cccmMultiFilterIdxBest; +#endif #endif #if JVET_Z0050_DIMD_CHROMA_FUSION pu.isChromaFusion = isChromaFusion; diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 40df261b1366c78413b27b33f34d78b84b2b742e..4583288416b91437b21b9a7123ff45e8a7f28898 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -493,7 +493,11 @@ private: PelStorage m_colorTransResiBuf; #if JVET_AB0143_CCCM_TS #if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AD0202_CCCM_MDF + PelStorage m_cccmStorage[2][TOTAL_NUM_CCCM_MODES]; +#else PelStorage m_cccmStorage[2][CCCM_NUM_MODES]; +#endif #else PelStorage m_cccmStorage[CCCM_NUM_MODES]; #endif @@ -540,6 +544,10 @@ public: bool m_skipCCCMSATD; int m_isCccmNoSubModeEnabledInRdo[MMLM_T_IDX + 1]; #endif +#if JVET_AD0202_CCCM_MDF + bool m_skipCCCMwithMdfSATD; + int m_isCccmWithMdfEnabledInRdo[5][MMLM_T_IDX + 1]; +#endif IntraSearch(); ~IntraSearch();