diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 73acf278f2526bfa406a049aa6ffbbe5ef86dce7..e659e43397c33bff3d1cae7bc5fa3ad3aa6c7508 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -920,7 +920,7 @@ static const int ADAPTIVE_SUB_GROUP_SIZE_MMVD_AFF = AF_MMVD_MAX_REFINE_NUM; #endif #endif -#if JVET_AA0057_CCCM +#if JVET_AA0057_CCCM || JVET_AB0092_GLM_WITH_LUMA static const int CCCM_WINDOW_SIZE = 6; static const int CCCM_NUM_PARAMS = 7; static const int CCCM_MIN_PU_SIZE = 0; // Set to 0 for no size restriction @@ -938,6 +938,17 @@ static const int CCCM_DECIM_ROUND = ( 1 << (CCCM_DECIM_BITS - 1 ) ); #endif #if JVET_AA0126_GLM +#if JVET_AB0092_GLM_WITH_LUMA +#define NUM_GLM_WEIGHT 2 +#if JVET_AA0057_CCCM +static const int NUM_GLM_PATTERN = 4; +static const int NUM_GLM_IDC = 5; +#else +static const int NUM_GLM_PATTERN = 16; +static const int NUM_GLM_PATTERN_BITS = 4; +static const int NUM_GLM_IDC = 17; +#endif +#else #if JVET_AA0057_CCCM #define NUM_GLM_WEIGHT 0 static const int NUM_GLM_PATTERN = 4; @@ -950,6 +961,7 @@ static const int NUM_GLM_PATTERN_BITS = 4; static const int NUM_GLM_IDC = 33; #endif #endif +#endif #if JVET_Y0152_TT_ENC_SPEEDUP static constexpr int FAST_METHOD_TT_ENC_SPEEDUP = 0x0001; ///< Embedding flag, which, if false, de-activates all the following ABT_ENC_SPEEDUP_* modes diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index 433cfdff5dc5e45f3c6fbac9d311242ea9042ccd..9d9afd03cb7b7cb474b34995f51ee7d2b69374b0 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -111,6 +111,9 @@ IntraPrediction::IntraPrediction() { m_glmTempCb[i] = nullptr; m_glmTempCr[i] = nullptr; +#if JVET_AB0092_GLM_WITH_LUMA + m_glmGradBuf[i] = nullptr; +#endif } #endif #if MMLM @@ -154,6 +157,9 @@ void IntraPrediction::destroy() { delete[] m_glmTempCb[i]; m_glmTempCb[i] = nullptr; delete[] m_glmTempCr[i]; m_glmTempCr[i] = nullptr; +#if JVET_AB0092_GLM_WITH_LUMA + delete[] m_glmGradBuf[i]; m_glmGradBuf[i] = nullptr; +#endif } #endif @@ -251,8 +257,20 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth #if JVET_AA0126_GLM for (int i = 0; i < NUM_GLM_IDC; i++) { - if (m_glmTempCb[i] == nullptr) m_glmTempCb[i] = new Pel[(2 * MAX_CU_SIZE + 1)*(2 * MAX_CU_SIZE + 1)]; - if (m_glmTempCr[i] == nullptr) m_glmTempCr[i] = new Pel[(2 * MAX_CU_SIZE + 1)*(2 * MAX_CU_SIZE + 1)]; + if (m_glmTempCb[i] == nullptr) + { + m_glmTempCb[i] = new Pel[(2 * MAX_CU_SIZE + 1)*(2 * MAX_CU_SIZE + 1)]; + } + if (m_glmTempCr[i] == nullptr) + { + m_glmTempCr[i] = new Pel[(2 * MAX_CU_SIZE + 1)*(2 * MAX_CU_SIZE + 1)]; + } +#if JVET_AB0092_GLM_WITH_LUMA + if (m_glmGradBuf[i] == nullptr) + { + m_glmGradBuf[i] = new Pel[(2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE) * (2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE)]; + } +#endif } #endif @@ -1174,6 +1192,17 @@ void IntraPrediction::xUpdateCclmModel(int &a, int &b, int &iShift, int midLuma, void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf &piPred, const PredictionUnit &pu, const CompArea& chromaArea, int intraDir, bool createModel, CclmModel *cclmModelStored) { +#if JVET_AB0092_GLM_WITH_LUMA + if (pu.glmIdc.getIdc(compID, 0) > NUM_GLM_PATTERN) + { + CccmModel glmModel(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)); + xGlmCalcModel(pu, compID, chromaArea, glmModel); + xGlmApplyModel(pu, compID, chromaArea, glmModel, piPred); + return; + } + else + { +#endif int iLumaStride = 0; PelBuf Temp; #if JVET_AA0126_GLM @@ -1188,35 +1217,35 @@ void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf &piPred { #endif #if MMLM - if ((intraDir == MDLM_L_IDX) || (intraDir == MDLM_T_IDX) || (intraDir == MMLM_L_IDX) || (intraDir == MMLM_T_IDX) || (m_encPreRDRun && intraDir == MMLM_CHROMA_IDX)) + if ((intraDir == MDLM_L_IDX) || (intraDir == MDLM_T_IDX) || (intraDir == MMLM_L_IDX) || (intraDir == MMLM_T_IDX) || (m_encPreRDRun && intraDir == MMLM_CHROMA_IDX)) #else - if ((intraDir == MDLM_L_IDX) || (intraDir == MDLM_T_IDX)) + if ((intraDir == MDLM_L_IDX) || (intraDir == MDLM_T_IDX)) #endif - { - iLumaStride = 2 * MAX_CU_SIZE + 1; - Temp = PelBuf(m_pMdlmTemp + iLumaStride + 1, iLumaStride, Size(chromaArea)); - } - else - { - iLumaStride = MAX_CU_SIZE + 1; - Temp = PelBuf(m_piTemp + iLumaStride + 1, iLumaStride, Size(chromaArea)); - } + { + iLumaStride = 2 * MAX_CU_SIZE + 1; + Temp = PelBuf(m_pMdlmTemp + iLumaStride + 1, iLumaStride, Size(chromaArea)); + } + else + { + iLumaStride = MAX_CU_SIZE + 1; + Temp = PelBuf(m_piTemp + iLumaStride + 1, iLumaStride, Size(chromaArea)); + } #if JVET_AA0126_GLM } #endif CclmModel cclmModel; - if ( createModel ) + if (createModel) { #if LMS_LINEAR_MODEL xGetLMParametersLMS(pu, compID, chromaArea, cclmModel); #else - xGetLMParameters (pu, compID, chromaArea, cclmModel); + xGetLMParameters(pu, compID, chromaArea, cclmModel); #endif - + // Store the created model if storage struct was provided - if ( cclmModelStored != nullptr ) + if (cclmModelStored != nullptr) { *cclmModelStored = cclmModel; } @@ -1228,12 +1257,12 @@ void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf &piPred } #if JVET_Z0050_CCLM_SLOPE - xUpdateCclmModel( cclmModel.a, cclmModel.b, cclmModel.shift, cclmModel.midLuma, compID == COMPONENT_Cb ? pu.cclmOffsets.cb0 : pu.cclmOffsets.cr0 ); + xUpdateCclmModel(cclmModel.a, cclmModel.b, cclmModel.shift, cclmModel.midLuma, compID == COMPONENT_Cb ? pu.cclmOffsets.cb0 : pu.cclmOffsets.cr0); #if MMLM - xUpdateCclmModel( cclmModel.a2, cclmModel.b2, cclmModel.shift2, cclmModel.midLuma2, compID == COMPONENT_Cb ? pu.cclmOffsets.cb1 : pu.cclmOffsets.cr1 ); + xUpdateCclmModel(cclmModel.a2, cclmModel.b2, cclmModel.shift2, cclmModel.midLuma2, compID == COMPONENT_Cb ? pu.cclmOffsets.cb1 : pu.cclmOffsets.cr1); #endif #endif - + ////// final prediction piPred.copyFrom(Temp); #if MMLM @@ -1264,7 +1293,10 @@ void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf &piPred } else #endif - piPred.linearTransform(cclmModel.a, cclmModel.shift, cclmModel.b, true, pu.cs->slice->clpRng(compID)); + piPred.linearTransform(cclmModel.a, cclmModel.shift, cclmModel.b, true, pu.cs->slice->clpRng(compID)); +#if JVET_AB0092_GLM_WITH_LUMA + } +#endif } /** Function for deriving planar intra prediction. This function derives the prediction samples for planar mode (intra coding). @@ -4781,7 +4813,7 @@ Pel IntraPrediction::xGlmGetLumaVal(const int s[6], const int c[6], const int gl { Pel grad = c[0] * s[0] + c[1] * s[1] + c[2] * s[2] + c[3] * s[3] + c[4] * s[4] + c[5] * s[5]; -#if NUM_GLM_WEIGHT +#if NUM_GLM_WEIGHT && !JVET_AB0092_GLM_WITH_LUMA return (glmIdx >= NUM_GLM_PATTERN ? val + grad : grad); #else return grad; @@ -4790,6 +4822,47 @@ Pel IntraPrediction::xGlmGetLumaVal(const int s[6], const int c[6], const int gl void IntraPrediction::xGetLumaRecPixelsGlmAll(const PredictionUnit &pu, CompArea chromaArea) { +#if JVET_AB0092_GLM_WITH_LUMA + const CPelBuf recoLuma = pu.cs->picture->getRecoBuf(COMPONENT_Y); + const int maxPosPicX = pu.cs->picture->chromaSize().width - 1; + const int maxPosPicY = pu.cs->picture->chromaSize().height - 1; + + xGlmCalcRefArea(pu, chromaArea); // Find the reference area + + int areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY; + + PelBuf refGrad[NUM_GLM_IDC]; + for (int i = 0; i < NUM_GLM_IDC; i++) + { + refGrad[i] = xGlmGetGradRefBuf(pu, chromaArea, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY, i); + } + + int puBorderX = refSizeX + chromaArea.width; + int puBorderY = refSizeY + chromaArea.height; + + // Generate down-sampled luma and luma gradients + for (int y = 0; y < areaHeight; y++) + { + for (int x = 0; x < areaWidth; x++) + { + if ((x >= puBorderX && y >= refSizeY) || (y >= puBorderY && x >= refSizeX)) + { + continue; + } + + int chromaPosPicX = refPosPicX + x; + int chromaPosPicY = refPosPicY + y; + + chromaPosPicX = chromaPosPicX < 0 ? 0 : chromaPosPicX > maxPosPicX ? maxPosPicX : chromaPosPicX; + chromaPosPicY = chromaPosPicY < 0 ? 0 : chromaPosPicY > maxPosPicY ? maxPosPicY : chromaPosPicY; + + for (int i = 0; i < NUM_GLM_IDC; i++) + { + refGrad[i].at(x, y) = xGlmGetGradVal(pu, i, recoLuma, chromaPosPicX, chromaPosPicY); + } + } + } +#endif int c[6] = { 0 }; int iDstStride = 2 * MAX_CU_SIZE + 1; @@ -5004,6 +5077,14 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom } #endif +#if JVET_AB0092_GLM_WITH_LUMA + if (pu.glmIdc.getIdc(chromaArea.compID, 0) > NUM_GLM_PATTERN) + { + xGlmCreateGradRef(pu, chromaArea); + return; + } +#endif + #if JVET_AA0126_GLM ComponentID compID = chromaArea.compID; int glmIdc = pu.glmIdc.getIdc(compID, 0); @@ -7897,7 +7978,9 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro } } } +#endif +#if JVET_AA0057_CCCM || JVET_AB0092_GLM_WITH_LUMA // LDL decomposing A to U'*diag*U bool CccmCovarianceInt::ldlDecomp(TE A, TE U, Ty diag, int numEq) const { @@ -8017,4 +8100,409 @@ void CccmCovarianceInt::ldlSolve(TE U, Ty diag, TCccmCoeff* y, TCccmCoeff* x, in } #endif +#if JVET_AB0092_GLM_WITH_LUMA +void IntraPrediction::xGlmApplyModel(const PredictionUnit& pu, const ComponentID compId, const CompArea& chromaArea, CccmModel &glmModel, PelBuf &piPred) const +{ + const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compId)); + static Pel samples[CCCM_NUM_PARAMS]; + + CPelBuf refLumaBlk = xGlmGetGradPuBuf(pu, chromaArea, 0); + CPelBuf refGradBlk = xGlmGetGradPuBuf(pu, chromaArea, pu.glmIdc.getIdc(compId, 0)); + + for (int y = 0; y < refLumaBlk.height; y++) + { + for (int x = 0; x < refLumaBlk.width; x++) + { + + samples[0] = refGradBlk.at(x, y); // luma gradient + samples[1] = refLumaBlk.at(x, y); // luma value + samples[2] = glmModel.bias(); + samples[3] = 0; + samples[4] = 0; + samples[5] = 0; + samples[6] = 0; + + piPred.at(x, y) = ClipPel<Pel>(glmModel.convolve(samples, CCCM_NUM_PARAMS), clpRng); + } + } +} + +void IntraPrediction::xGlmCalcModel(const PredictionUnit& pu, const ComponentID compID, const CompArea& chromaArea, CccmModel &glmModel) const +{ + int areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY; + + const CPelBuf reco = pu.cs->picture->getRecoBuf(compID); + PelBuf refLuma = xGlmGetGradRefBuf(pu, chromaArea, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY, 0); + PelBuf refGrad = xGlmGetGradRefBuf(pu, chromaArea, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY, pu.glmIdc.getIdc(compID, 0)); + + int M = CCCM_NUM_PARAMS; // align CCCM parameter number to reuse CCCM LDL method +#if JVET_AB0174_CCCM_DIV_FREE + int N = 3; +#endif + + int sampleNum = 0; + int sampleInd = 0; + +#if JVET_AB0174_CCCM_DIV_FREE + int chromaOffset = 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; + + chromaOffset = reco.at(refPosPicX + refPosX, refPosPicY + refPosY); + } +#endif + + // Collect reference data to input matrix A and target vector C + static Pel A[CCCM_NUM_PARAMS][CCCM_MAX_REF_SAMPLES]; + static Pel C[CCCM_MAX_REF_SAMPLES]; + + int sizeX = refSizeX + chromaArea.width; + int sizeY = refSizeY + chromaArea.height; + + for (int y = 0; y < areaHeight; y++) + { + for (int x = 0; x < areaWidth; x++) + { + if (x >= refSizeX && y >= refSizeY) + { + continue; + } + if (pu.intraDir[1] == MDLM_L_IDX) + { + if (y < refSizeY) + { + continue; + } + } + else if (pu.intraDir[1] == MDLM_T_IDX) + { + if (x < refSizeX) + { + continue; + } + } + else + { + if (x >= sizeX || y >= sizeY) + { + continue; + } + } + + // 7-tap cross + A[0][sampleInd] = refGrad.at(x, y); // luma gradient + A[1][sampleInd] = refLuma.at(x, y); // luma value + A[2][sampleInd] = glmModel.bias(); + A[3][sampleInd] = 0; + A[4][sampleInd] = 0; + A[5][sampleInd] = 0; + A[6][sampleInd] = 0; + + C[sampleInd] = reco.at(refPosPicX + x, refPosPicY + y); + sampleInd++; + } + } + if (sampleInd == 0) // Number of sample can go to zero in the multimode case + { + glmModel.clearModel(M); + return; + } + else + { + sampleNum = sampleInd; + } + + // Calculate autocorrelation matrix and cross-correlation vector + static CccmCovarianceInt::TE ATA; + static CccmCovarianceInt::Ty ATC; + + memset(ATA, 0x00, sizeof(int64_t) * CCCM_NUM_PARAMS * CCCM_NUM_PARAMS); + memset(ATC, 0x00, sizeof(int64_t) * CCCM_NUM_PARAMS); + + for (int coli0 = 0; coli0 < M; coli0++) + { + for (int coli1 = coli0; coli1 < M; coli1++) + { + Pel *col0 = A[coli0]; + Pel *col1 = A[coli1]; + + for (int rowi = 0; rowi < sampleNum; rowi++) + { + ATA[coli0][coli1] += col0[rowi] * col1[rowi]; + } + } + } + + for (int coli = 0; coli < M; coli++) + { + Pel *col = A[coli]; + + for (int rowi = 0; rowi < sampleNum; rowi++) + { + ATC[coli] += col[rowi] * C[rowi]; + } + } + +#if JVET_AB0174_CCCM_DIV_FREE + // Remove chromaOffset from stats to update cross-correlation + for (int coli = 0; coli < N; coli++) + { + ATC[coli] = ATC[coli] - ((ATA[coli][N - 1] * chromaOffset) >> (glmModel.bd - 1)); + } +#endif + + // Scale the matrix and vector to selected dynamic range + int matrixShift = 28 - 2 * pu.cu->cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA) - ceilLog2(sampleNum); + + if (matrixShift > 0) + { + for (int coli0 = 0; coli0 < M; coli0++) + { + for (int coli1 = coli0; coli1 < M; coli1++) + { + ATA[coli0][coli1] <<= matrixShift; + } + } + + for (int coli = 0; coli < M; coli++) + { + ATC[coli] <<= matrixShift; + } + } + else if (matrixShift < 0) + { + matrixShift = -matrixShift; + + for (int coli0 = 0; coli0 < M; coli0++) + { + for (int coli1 = coli0; coli1 < M; coli1++) + { + ATA[coli0][coli1] >>= matrixShift; + } + } + + for (int coli = 0; coli < M; coli++) + { + ATC[coli] >>= matrixShift; + } + } + + // Solve the filter coefficients using LDL decomposition + CccmCovarianceInt glmSolver; + CccmCovarianceInt::TE U; // Upper triangular L' of ATA's LDL decomposition + CccmCovarianceInt::Ty diag; // Diagonal of D + + bool decompOk = glmSolver.ldlDecompose(ATA, U, diag, M); + glmSolver.ldlSolve(U, diag, ATC, glmModel.params, M, decompOk); + +#if JVET_AB0174_CCCM_DIV_FREE + // Add the chroma offset to bias term (after shifting up by CCCM_DECIM_BITS and down by cccmModelCb.bd - 1) + glmModel.params[N - 1] += chromaOffset << (CCCM_DECIM_BITS - (glmModel.bd - 1)); +#endif +} + +Pel IntraPrediction::xGlmGetGradVal(const PredictionUnit& pu, const int glmIdx, const CPelBuf pi, const int x, const int y) const +{ + const Pel* piSrc = pi.buf; + const int iRecStride = pi.stride; + Pel ypval = 0; + if (glmIdx == 0) + { + if (pu.chromaFormat == CHROMA_444) + { + ypval = piSrc[x + iRecStride * y]; + } + else if (pu.chromaFormat == CHROMA_422) + { + int s = 2; + int offLeft = x > 0 ? -1 : 0; + s += piSrc[2 * x + iRecStride * y] * 2; + s += piSrc[2 * x + offLeft + iRecStride * y]; + s += piSrc[2 * x + 1 + iRecStride * y]; + ypval = s >> 2; + } + else if (pu.cs->sps->getCclmCollocatedChromaFlag()) + { + int s = 4; + int offLeft = x > 0 ? -1 : 0; + int offAbove = y > 0 ? -1 : 0; + s += piSrc[2 * x + iRecStride * 2 * y] * 4; + s += piSrc[2 * x + offLeft + iRecStride * 2 * y]; + s += piSrc[2 * x + 1 + iRecStride * 2 * y]; + s += piSrc[2 * x + iRecStride * (2 * y + 1)]; + s += piSrc[2 * x + iRecStride * (2 * y + offAbove)]; + ypval = s >> 3; + } + else + { + int s = 4; + int offLeft = x > 0 ? -1 : 0; + s += piSrc[2 * x + iRecStride * y * 2] * 2; + s += piSrc[2 * x + offLeft + iRecStride * y * 2]; + s += piSrc[2 * x + 1 + iRecStride * y * 2]; + s += piSrc[2 * x + iRecStride * (y * 2 + 1)] * 2; + s += piSrc[2 * x + offLeft + iRecStride * (y * 2 + 1)]; + s += piSrc[2 * x + 1 + iRecStride * (y * 2 + 1)]; + ypval = s >> 3; + } +#if JVET_AB0174_CCCM_DIV_FREE + ypval -= m_glmLumaOffset; +#endif + } + else + { + int p = glmIdx > NUM_GLM_PATTERN ? glmIdx - NUM_GLM_PATTERN - 1 : glmIdx - 1; + int c[6] = { 0 }; + c[0] = g_glmPattern[p][0], c[1] = g_glmPattern[p][1], c[2] = g_glmPattern[p][2]; + c[3] = g_glmPattern[p][3], c[4] = g_glmPattern[p][4], c[5] = g_glmPattern[p][5]; + + int offLeft = x > 0 ? -1 : 0; + int s[6] = { piSrc[2 * x + offLeft + iRecStride * y * 2], piSrc[2 * x + iRecStride * y * 2], piSrc[2 * x + 1 + iRecStride * y * 2], + piSrc[2 * x + offLeft + iRecStride * (y * 2 + 1)], piSrc[2 * x + iRecStride * (y * 2 + 1)], piSrc[2 * x + 1 + iRecStride * (y * 2 + 1)] }; + + ypval = xGlmGetLumaVal(s, c, p + 1, 0); + } + + return ypval; +} + +void IntraPrediction::xGlmCalcRefArea(const PredictionUnit& pu, CompArea chromaArea) +{ + const ChannelType chType = CHANNEL_TYPE_CHROMA; + const CodingUnit& cu = *pu.cu; + const CodingStructure &cs = *cu.cs; + const SPS &sps = *cs.sps; + const PreCalcValues &pcv = *cs.pcv; + + const int tuWidth = chromaArea.width; + const int tuHeight = chromaArea.height; + + const bool noShift = pcv.noChroma2x2 && chromaArea.width == 4; // don't shift on the lowest level (chroma not-split) + const int compScaleX = getComponentScaleX(chromaArea.compID, sps.getChromaFormatIdc()); + const int compScaleY = getComponentScaleY(chromaArea.compID, sps.getChromaFormatIdc()); + const int unitWidth = pcv.minCUWidth >> (noShift ? 0 : compScaleX); + const int unitHeight = pcv.minCUHeight >> (noShift ? 0 : compScaleY); + + const int totalAboveUnits = (2 * tuWidth + (unitWidth - 1)) / unitWidth; + const int totalLeftUnits = (2 * tuHeight + (unitHeight - 1)) / unitHeight; + const int numAboveUnits = std::max<int>(tuWidth / unitWidth, 1); + const int numLeftUnits = std::max<int>(tuHeight / unitHeight, 1); + const int numAboveRightUnits = totalAboveUnits - numAboveUnits; + const int numLeftBelowUnits = totalLeftUnits - numLeftUnits; + + static bool neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1] = { false }; // Just a dummy array here, content not used + + int avaiAboveRightUnits = isAboveRightAvailable(cu, chType, chromaArea.topRight(), numAboveRightUnits, unitWidth, (neighborFlags + totalLeftUnits + 1 + numAboveUnits)); + int avaiLeftBelowUnits = isBelowLeftAvailable(cu, chType, chromaArea.bottomLeft(), numLeftBelowUnits, unitHeight, (neighborFlags + totalLeftUnits - 1 - numLeftUnits)); + + int refSizeX, refSizeY; + + PU::getCccmRefLineNum(pu, chromaArea, refSizeX, refSizeY); // Reference lines available left and above + + int refWidth = chromaArea.width + refSizeX; // Reference buffer size excluding paddings + int refHeight = chromaArea.height + refSizeY; + + int extWidth = avaiAboveRightUnits * unitWidth; + int extHeight = avaiLeftBelowUnits * unitHeight; + + refWidth += refSizeY ? extWidth : 0; // Add above right if above is available + refHeight += refSizeX ? extHeight : 0; // Add below left if left is available + + m_glmRefArea = Area(chromaArea.x - refSizeX, chromaArea.y - refSizeY, refWidth, refHeight); // Position with respect to the PU +} + +PelBuf IntraPrediction::xGlmGetGradRefBuf(const PredictionUnit& pu, CompArea chromaArea, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY, int glmIdx) const +{ + refSizeX = chromaArea.x - m_glmRefArea.x; // Reference lines available left and above + refSizeY = chromaArea.y - m_glmRefArea.y; + areaWidth = m_glmRefArea.width; // Reference buffer size excluding paddings + areaHeight = m_glmRefArea.height; + refPosPicX = m_glmRefArea.x; // Position of the reference area in picture coordinates + refPosPicY = m_glmRefArea.y; + + int refStride = areaWidth; + + int idx = glmIdx > NUM_GLM_PATTERN ? glmIdx - NUM_GLM_PATTERN : glmIdx; + return PelBuf(m_glmGradBuf[idx], refStride, areaWidth, areaHeight); +} + +PelBuf IntraPrediction::xGlmGetGradPuBuf(const PredictionUnit& pu, CompArea chromaArea, int glmIdx) const +{ + int refSizeX = chromaArea.x - m_glmRefArea.x; // Reference lines available left and above + int refSizeY = chromaArea.y - m_glmRefArea.y; + int tuWidth = chromaArea.width; + int tuHeight = chromaArea.height; + int refStride = m_glmRefArea.width; + int refOrigin = refStride * refSizeY + refSizeX; + + int idx = glmIdx > NUM_GLM_PATTERN ? glmIdx - NUM_GLM_PATTERN : glmIdx; + return PelBuf(m_glmGradBuf[idx] + refOrigin, refStride, tuWidth, tuHeight); +} + +void IntraPrediction::xGlmCreateGradRef(const PredictionUnit& pu, CompArea chromaArea) +{ + const CPelBuf recoLuma = pu.cs->picture->getRecoBuf(COMPONENT_Y); + const int maxPosPicX = pu.cs->picture->chromaSize().width - 1; + const int maxPosPicY = pu.cs->picture->chromaSize().height - 1; + + xGlmCalcRefArea(pu, chromaArea); // Find the reference area + + int areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY; + + PelBuf refLuma = xGlmGetGradRefBuf(pu, chromaArea, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY, 0); + PelBuf refGrad = xGlmGetGradRefBuf(pu, chromaArea, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY, pu.glmIdc.getIdc(chromaArea.compID, 0)); + + int puBorderX = refSizeX + chromaArea.width; + int puBorderY = refSizeY + chromaArea.height; + +#if JVET_AB0174_CCCM_DIV_FREE + xGlmSetLumaRefValue(pu, chromaArea); +#endif + + for (int y = 0; y < areaHeight; y++) + { + for (int x = 0; x < areaWidth; x++) + { + if ((x >= puBorderX && y >= refSizeY) || + (y >= puBorderY && x >= refSizeX)) + { + continue; + } + + int chromaPosPicX = refPosPicX + x; + int chromaPosPicY = refPosPicY + y; + + chromaPosPicX = chromaPosPicX < 0 ? 0 : chromaPosPicX > maxPosPicX ? maxPosPicX : chromaPosPicX; + chromaPosPicY = chromaPosPicY < 0 ? 0 : chromaPosPicY > maxPosPicY ? maxPosPicY : chromaPosPicY; + + refLuma.at(x, y) = xGlmGetGradVal(pu, 0, recoLuma, chromaPosPicX, chromaPosPicY); + refGrad.at(x, y) = xGlmGetGradVal(pu, pu.glmIdc.getIdc(chromaArea.compID, 0), recoLuma, chromaPosPicX, chromaPosPicY); + } + } +} + +#if JVET_AB0174_CCCM_DIV_FREE +void IntraPrediction::xGlmSetLumaRefValue(const PredictionUnit& pu, CompArea chromaArea) +{ + int lumaPosX = chromaArea.x << getComponentScaleX(chromaArea.compID, pu.cu->chromaFormat); + int lumaPosY = chromaArea.y << getComponentScaleY(chromaArea.compID, pu.cu->chromaFormat); + + if (lumaPosX || lumaPosY) + { + lumaPosX = lumaPosX ? lumaPosX - 1 : 0; + lumaPosY = lumaPosY ? lumaPosY - 1 : 0; + + m_glmLumaOffset = pu.cs->picture->getRecoBuf(COMPONENT_Y).at(lumaPosX, lumaPosY); + } + else + { + m_glmLumaOffset = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 1); + } +} +#endif +#endif + //! \} diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index 65cfb9657d49173b593d1b19f1e323648f4ad634..65225dff96000c1ccce2ed826e91ce7cc9c8805f 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -91,7 +91,7 @@ public: typedef short TrainDataType; #endif -#if JVET_AA0057_CCCM +#if JVET_AA0057_CCCM || JVET_AB0092_GLM_WITH_LUMA typedef int64_t TCccmCoeff; #define FIXED_MULT(x, y) TCccmCoeff((int64_t(x)*(y) + CCCM_DECIM_ROUND) >> CCCM_DECIM_BITS ) @@ -228,6 +228,13 @@ private: #if JVET_AA0126_GLM Pel* m_glmTempCb[NUM_GLM_IDC]; Pel* m_glmTempCr[NUM_GLM_IDC]; +#if JVET_AB0092_GLM_WITH_LUMA + Area m_glmRefArea; + Pel* m_glmGradBuf[NUM_GLM_IDC]; +#if JVET_AB0174_CCCM_DIV_FREE + int m_glmLumaOffset; +#endif +#endif #endif MatrixIntraPrediction m_matrixIntraPred; @@ -326,6 +333,18 @@ public: void xCccmSetLumaRefValue (const PredictionUnit& pu); #endif #endif +#if JVET_AB0092_GLM_WITH_LUMA + void xGlmCalcModel (const PredictionUnit& pu, const ComponentID compId, const CompArea& chromaArea, CccmModel &glmModel) const; + void xGlmApplyModel (const PredictionUnit& pu, const ComponentID compId, const CompArea& chromaArea, CccmModel &glmModel, PelBuf &piPred) const; + void xGlmCreateGradRef (const PredictionUnit& pu, CompArea chromaArea); + PelBuf xGlmGetGradRefBuf (const PredictionUnit& pu, CompArea chromaArea, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY, int glmIdx) const; + PelBuf xGlmGetGradPuBuf (const PredictionUnit& pu, CompArea chromaArea, int glmIdx) const; + Pel xGlmGetGradVal (const PredictionUnit& pu, const int glmIdx, const CPelBuf pi, const int x, const int y) const; + void xGlmCalcRefArea (const PredictionUnit& pu, CompArea chromaArea); +#if JVET_AB0174_CCCM_DIV_FREE + void xGlmSetLumaRefValue (const PredictionUnit& pu, CompArea chromaArea); +#endif +#endif #if ENABLE_DIMD static void deriveDimdMode (const CPelBuf &recoBuf, const CompArea &area, CodingUnit &cu); #if JVET_Z0050_DIMD_CHROMA_FUSION && ENABLE_DIMD diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 27102bebead0a48bd509a57025782fd9529370fe..9f04d107643a32c94485b1207436faa2b86dd943 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,7 +50,6 @@ #include <assert.h> #include <cassert> - #define BASE_ENCODER 1 #define BASE_NORMATIVE 1 #define TOOLS 1 @@ -138,9 +137,14 @@ #define JVET_AA0057_CCCM 1 // JVET-AA0057: Convolutional cross-component model (CCCM) #if JVET_AA0057_CCCM #define JVET_AB0143_CCCM_TS 1 // JVET-AB0143: CCCM template selection -#define JVET_AB0174_CCCM_DIV_FREE 1 // JVET-AB0174: CCCM with division free operation #endif #define JVET_AA0126_GLM 1 // JVET-AA0126: Gradient linear model +#if JVET_AA0126_GLM +#define JVET_AB0092_GLM_WITH_LUMA 1 // JVET-AB0092: Gradient linear model with luma value +#endif +#if JVET_AA0057_CCCM || JVET_AB0092_GLM_WITH_LUMA +#define JVET_AB0174_CCCM_DIV_FREE 1 // JVET-AB0174: CCCM with division free operation +#endif #define JVET_AB0061_ITMP_BV_FOR_IBC 1 // JVET-AB0061: Storing IntraTMP BV for IBC BV prediction diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index a07442252e5455b71bb80a44e7803f48843edb39..3028d15f6cb83e4f5f7d6e1fcb2ab4d8bda04ef5 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -1545,7 +1545,7 @@ bool PU::isDMChromaMIP(const PredictionUnit &pu) #endif } -#if JVET_AA0057_CCCM +#if JVET_AA0057_CCCM || JVET_AB0092_GLM_WITH_LUMA void PU::getCccmRefLineNum(const PredictionUnit& pu, const Area area, int& th, int& tv) { th = area.x < CCCM_WINDOW_SIZE ? area.x : CCCM_WINDOW_SIZE; @@ -1560,7 +1560,9 @@ void PU::getCccmRefLineNum(const PredictionUnit& pu, const Area area, int& th, i tv = tv > tvMax ? tvMax : tv; } } +#endif +#if JVET_AA0057_CCCM bool PU::cccmSingleModeAvail(const PredictionUnit& pu, int intraMode) { const Area area = pu.blocks[COMPONENT_Cb]; diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 9dca9dd3661d7f39d4d15675c87b2200b704410a..9227d158ff35fa4cbd208110eb107ab5bfe85bc0 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -489,8 +489,10 @@ namespace PU #if JVET_AA0126_GLM bool hasGlmFlag (const PredictionUnit &pu, const int mode = -1); #endif -#if JVET_AA0057_CCCM +#if JVET_AA0057_CCCM || JVET_AB0092_GLM_WITH_LUMA void getCccmRefLineNum (const PredictionUnit& pu, const Area area, int& th, int& tv); +#endif +#if JVET_AA0057_CCCM bool cccmSingleModeAvail(const PredictionUnit& pu, int intraMode); bool cccmMultiModeAvail (const PredictionUnit& pu, int intraMode); #if JVET_AB0143_CCCM_TS diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 89eec8edce80850e314034cc524c510003c2048d..7803dd7a0d4ce7f2b64f7464834f307894119bfe 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -2255,6 +2255,29 @@ void CABACReader::glmIdc(PredictionUnit& pu) if ( glmActive ) { +#if JVET_AB0092_GLM_WITH_LUMA + pu.glmIdc.cb0 = 1; +#if NUM_GLM_WEIGHT + pu.glmIdc.cb0 += m_BinDecoder.decodeBin(Ctx::GlmFlags(1)) ? NUM_GLM_PATTERN : 0; +#endif +#if JVET_AA0057_CCCM + if (m_BinDecoder.decodeBin(Ctx::GlmFlags(2))) + { + pu.glmIdc.cb0 += 1; + if (m_BinDecoder.decodeBin(Ctx::GlmFlags(3))) + { + pu.glmIdc.cb0 += 1; + if (m_BinDecoder.decodeBin(Ctx::GlmFlags(4))) + { + pu.glmIdc.cb0 += 1; + } + } + } +#else + pu.glmIdc.cb0 += m_BinDecoder.decodeBinsEP(NUM_GLM_PATTERN_BITS); +#endif + pu.glmIdc.cr0 = pu.glmIdc.cb0; +#else bool bothActive = m_BinDecoder.decodeBin(Ctx::GlmFlags(3)); pu.glmIdc.cb0 = bothActive; @@ -2281,6 +2304,7 @@ void CABACReader::glmIdc(PredictionUnit& pu) #endif pu.glmIdc.cr0 += m_BinDecoder.decodeBinsEP(NUM_GLM_PATTERN_BITS); } +#endif #if MMLM if ( PU::isMultiModeLM( pu.intraDir[1] ) ) diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 17c6b97cdba3efbb776eca8aa6749c6acb3100d1..c1f94280388c47a7d5e81a48859124e9043f1328 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -1985,6 +1985,27 @@ void CABACWriter::glmIdc(const PredictionUnit& pu) if ( glmActive ) { +#if JVET_AB0092_GLM_WITH_LUMA + int glmIdx = pu.glmIdc.cb0 - 1; +#if NUM_GLM_WEIGHT + m_BinEncoder.encodeBin(glmIdx >= NUM_GLM_PATTERN ? 1 : 0, Ctx::GlmFlags(1)); + glmIdx -= glmIdx >= NUM_GLM_PATTERN ? NUM_GLM_PATTERN : 0; +#endif + CHECK(pu.glmIdc.cb0 != pu.glmIdc.cr0, "wrong glm idx"); +#if JVET_AA0057_CCCM + m_BinEncoder.encodeBin(glmIdx > 0, Ctx::GlmFlags(2)); + if (glmIdx > 0) + { + m_BinEncoder.encodeBin(glmIdx > 1, Ctx::GlmFlags(3)); + if (glmIdx > 1) + { + m_BinEncoder.encodeBin(glmIdx > 2, Ctx::GlmFlags(4)); + } + } +#else + m_BinEncoder.encodeBinsEP(glmIdx, NUM_GLM_PATTERN_BITS); +#endif +#else bool bothActive = pu.glmIdc.cb0 && pu.glmIdc.cr0; m_BinEncoder.encodeBin( bothActive ? 1 : 0, Ctx::GlmFlags(3) ); @@ -2013,6 +2034,7 @@ void CABACWriter::glmIdc(const PredictionUnit& pu) #endif m_BinEncoder.encodeBinsEP( glmIdx, NUM_GLM_PATTERN_BITS ); } +#endif #if MMLM if ( PU::isMultiModeLM( pu.intraDir[1] ) ) diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index 1f688924db4370b684cb94bcd3c211c61fa99298..4ca8ac885ab6e14e7787feca1e3fe941bcb99885 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -2348,6 +2348,12 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt relatedCU.skipLfnstTest = false; } } +#endif +#if JVET_AB0092_GLM_WITH_LUMA + if (!isLuma(partitioner.chType) && !(bestCU->firstPU->glmIdc.isActive())) + { + relatedCU.skipGLM = true; + } #endif } #if ENABLE_SPLIT_PARALLELISM diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h index ee5734cbb7498c1081dd423c50d1cf0e0d857603..0f7d80f4b737b0b74fdac9a30ea85d359671a28f 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.h +++ b/source/Lib/EncoderLib/EncModeCtrl.h @@ -995,6 +995,9 @@ struct CodedCUInfo uint64_t temporalId; #endif +#if JVET_AB0092_GLM_WITH_LUMA + bool skipGLM; +#endif }; class CacheBlkInfoCtrl diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 8d4ebdf2fb5176ff696e1c49cdc8f20e37d054f2..51d7f4ca7658483bdfd8dd81eebfd68efa02b775 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -2039,11 +2039,20 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner { satdGlmIdcBest[mode - LM_CHROMA_IDX].setAllZero(); +#if JVET_AB0092_GLM_WITH_LUMA + CodedCUInfo& relatedCU = ((EncModeCtrlMTnoRQT *)m_modeCtrl)->getBlkInfo(partitioner.currArea()); + if (PU::hasGlmFlag(pu, mode) && !relatedCU.skipGLM) +#else if ( PU::hasGlmFlag( pu, mode ) ) +#endif { +#if !JVET_AB0092_GLM_WITH_LUMA for ( int comp = COMPONENT_Cb; comp <= COMPONENT_Cr; comp++ ) { ComponentID compID = ComponentID( comp ); +#else + ComponentID compID = COMPONENT_Cb; +#endif int idcBest = 0; int64_t satdBest = 0; GlmIdc& idcsBest = satdGlmIdcBest[mode - LM_CHROMA_IDX]; @@ -2055,14 +2064,21 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner idcsBest.setIdc(compID, 0, idcBest); idcsBest.setIdc(compID, 1, idcBest); + +#if JVET_AB0092_GLM_WITH_LUMA + idcsBest.setIdc(COMPONENT_Cr, 0, idcBest); + idcsBest.setIdc(COMPONENT_Cr, 1, idcBest); +#endif satdGlmCosts[mode - LM_CHROMA_IDX] += satdBest; // Summing up Cb and Cr cost +#if !JVET_AB0092_GLM_WITH_LUMA } if ( !satdGlmIdcBest[0].isActive() ) { break; } +#endif } } } @@ -2557,11 +2573,12 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner bestBDPCMMode = cu.bdpcmModeChroma; bestGlmIdc = pu.glmIdc; } - +#if !JVET_AB0092_GLM_WITH_LUMA if ( chromaIntraMode == LM_CHROMA_IDX && !bestGlmIdc.isActive() ) { break; } +#endif } } } @@ -3003,7 +3020,11 @@ void IntraSearch::xFindBestGlmIdcSATD(PredictionUnit &pu, ComponentID compID, in CompArea area = compID == COMPONENT_Cb ? pu.Cb() : pu.Cr(); PelBuf orgBuf = cs.getOrgBuf(area); PelBuf predBuf = cs.getPredBuf(area); +#if JVET_AB0092_GLM_WITH_LUMA + int maxIdc = NUM_GLM_PATTERN * NUM_GLM_WEIGHT; +#else int maxIdc = NUM_GLM_IDC - 1; +#endif int mode = pu.intraDir[1]; DistParam distParamSad; @@ -3017,6 +3038,21 @@ void IntraSearch::xFindBestGlmIdcSATD(PredictionUnit &pu, ComponentID compID, in sadBest = -1; +#if JVET_AB0092_GLM_WITH_LUMA + CompArea areacr = pu.Cr(); + PelBuf orgBufcr = cs.getOrgBuf(areacr); + PelBuf predBufcr = cs.getPredBuf(areacr); + + DistParam distParamSadcr; + DistParam distParamSatdcr; + + m_pcRdCost->setDistParam(distParamSadcr, orgBufcr, predBufcr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, false); + m_pcRdCost->setDistParam(distParamSatdcr, orgBufcr, predBufcr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, true); + + distParamSadcr.applyWeight = false; + distParamSatdcr.applyWeight = false; +#endif + // Search positive idcs for ( int idc = 0; idc <= maxIdc; idc++ ) { @@ -3028,6 +3064,18 @@ void IntraSearch::xFindBestGlmIdcSATD(PredictionUnit &pu, ComponentID compID, in int64_t sad = distParamSad.distFunc(distParamSad) * 2; int64_t satd = distParamSatd.distFunc(distParamSatd); int64_t sadThis = std::min(sad, satd); + +#if JVET_AB0092_GLM_WITH_LUMA + pu.glmIdc.setIdc(COMPONENT_Cr, 0, idc); + pu.glmIdc.setIdc(COMPONENT_Cr, 1, idc); + + predIntraChromaLM(COMPONENT_Cr, predBufcr, pu, areacr, mode); + + int64_t sadcr = distParamSadcr.distFunc(distParamSadcr) * 2; + int64_t satdcr = distParamSatdcr.distFunc(distParamSatdcr); + int64_t sadThiscr = std::min(sadcr, satdcr); + sadThis += sadThiscr; +#endif if ( sadBest == -1 || sadThis < sadBest ) { @@ -7228,7 +7276,7 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio { xGetLumaRecPixels( pu, cbArea ); predIntraChromaLM( COMPONENT_Cb, piPredCb, pu, cbArea, predMode ); -#if JVET_AA0126_GLM +#if JVET_AA0126_GLM && !JVET_AB0092_GLM_WITH_LUMA xGetLumaRecPixels( pu, crArea ); // generate GLM luma samples for Cr prediction #endif predIntraChromaLM( COMPONENT_Cr, piPredCr, pu, crArea, predMode );