diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 7fb8e912451565566a46ba98e4ebc1a00826bef4..43cb9d353839ba3f377b8f4cd91b1cbaa374cc7f 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -816,6 +816,20 @@ static const int CCCM_DECIM_BITS = 22; static const int CCCM_DECIM_ROUND = ( 1 << (CCCM_DECIM_BITS - 1 ) ); #endif +#if JVET_AA0126_GLM +#if JVET_AA0057_CCCM +#define NUM_GLM_WEIGHT 0 +static const int NUM_GLM_PATTERN = 4; +static const int NUM_GLM_PATTERN_BITS = 2; +static const int NUM_GLM_IDC = 5; +#else +#define NUM_GLM_WEIGHT 2 +static const int NUM_GLM_PATTERN = 16; +static const int NUM_GLM_PATTERN_BITS = 4; +static const int NUM_GLM_IDC = 33; +#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 static constexpr int FAST_METHOD_HOR_XOR_VER = 0x0002; diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 705198c0beea465dadf9cad4e114382a6930fa63..544e8124335118a113837b7d26b6b95e4ad93fef 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -2832,6 +2832,23 @@ const CtxSet ContextSetCfg::CclmDeltaFlags = ContextSetCfg::addCtxSet }); #endif +#if JVET_AA0126_GLM +const CtxSet ContextSetCfg::GlmFlags = ContextSetCfg::addCtxSet +({ + { CNU, CNU, CNU, CNU, CNU, }, + { CNU, CNU, CNU, CNU, CNU, }, + { CNU, CNU, CNU, CNU, CNU, }, + { DWS, DWS, DWS, DWS, DWS, }, + { DWS, DWS, DWS, DWS, DWS, }, + { DWS, DWS, DWS, DWS, DWS, }, + { DWE, DWE, DWE, DWE, DWE, }, + { DWE, DWE, DWE, DWE, DWE, }, + { DWE, DWE, DWE, DWE, DWE, }, + { DWO, DWO, DWO, DWO, DWO, }, + { DWO, DWO, DWO, DWO, DWO, }, +}); +#endif + #if JVET_AA0057_CCCM const CtxSet ContextSetCfg::CccmFlag = ContextSetCfg::addCtxSet ({ @@ -4352,6 +4369,18 @@ const CtxSet ContextSetCfg::CclmDeltaFlags = ContextSetCfg::addCtxSet }); #endif +#if JVET_AA0126_GLM +const CtxSet ContextSetCfg::GlmFlags = ContextSetCfg::addCtxSet +({ + { CNU, CNU, CNU, CNU, CNU, }, + { CNU, CNU, CNU, CNU, CNU, }, + { CNU, CNU, CNU, CNU, CNU, }, + { DWS, DWS, DWS, DWS, DWS, }, + { DWS, DWS, DWS, DWS, DWS, }, + { DWS, DWS, DWS, DWS, DWS, }, +}); +#endif + #if JVET_AA0057_CCCM const CtxSet ContextSetCfg::CccmFlag = ContextSetCfg::addCtxSet ({ @@ -5435,6 +5464,16 @@ const CtxSet ContextSetCfg::CclmDeltaFlags = ContextSetCfg::addCtxSet }); #endif +#if JVET_AA0126_GLM +const CtxSet ContextSetCfg::GlmFlags = ContextSetCfg::addCtxSet +({ + { CNU, CNU, CNU, CNU, CNU, }, + { CNU, CNU, CNU, CNU, CNU, }, + { CNU, CNU, CNU, CNU, CNU, }, + { DWS, DWS, DWS, DWS, DWS, }, +}); +#endif + #if JVET_AA0057_CCCM const CtxSet ContextSetCfg::CccmFlag = ContextSetCfg::addCtxSet ({ diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index fe9c0360a79efb5a162089bb4dd11bdb1a6af5d3..9b051f6e040db202ca019b82d4ced09d6f9f10b2 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -494,6 +494,9 @@ public: #if JVET_Z0050_CCLM_SLOPE static const CtxSet CclmDeltaFlags; #endif +#if JVET_AA0126_GLM + static const CtxSet GlmFlags; +#endif #if JVET_AA0057_CCCM static const CtxSet CccmFlag; #endif diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index f8e0a663193035b457196dffb6d478e3cdfc1432..181f18601588648479fd25005766efc33e23e45a 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -106,6 +106,13 @@ IntraPrediction::IntraPrediction() #endif m_piTemp = nullptr; m_pMdlmTemp = nullptr; +#if JVET_AA0126_GLM + for (int i = 0; i < NUM_GLM_IDC; i++) + { + m_glmTempCb[i] = nullptr; + m_glmTempCr[i] = nullptr; + } +#endif #if MMLM m_encPreRDRun = false; #endif @@ -142,6 +149,13 @@ void IntraPrediction::destroy() m_piTemp = nullptr; delete[] m_pMdlmTemp; m_pMdlmTemp = nullptr; +#if JVET_AA0126_GLM + for (int i = 0; i < NUM_GLM_IDC; i++) + { + delete[] m_glmTempCb[i]; m_glmTempCb[i] = nullptr; + delete[] m_glmTempCr[i]; m_glmTempCr[i] = nullptr; + } +#endif for( auto &buffer : m_tempBuffer ) { @@ -234,7 +248,13 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth { m_pMdlmTemp = new Pel[(2 * MAX_CU_SIZE + 1)*(2 * MAX_CU_SIZE + 1)];//MDLM will use top-above and left-below samples. } - +#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)]; + } +#endif for( auto &buffer : m_tempBuffer ) { @@ -1157,6 +1177,17 @@ void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf &piPred { int iLumaStride = 0; PelBuf Temp; +#if JVET_AA0126_GLM + if (pu.glmIdc.isActive()) + { + int glmIdc = pu.glmIdc.getIdc(compID, 0); + Pel* glmTemp = compID == COMPONENT_Cb ? m_glmTempCb[glmIdc] : m_glmTempCr[glmIdc]; + iLumaStride = 2 * MAX_CU_SIZE + 1; + Temp = PelBuf(glmTemp + iLumaStride + 1, iLumaStride, Size(chromaArea)); + } + else + { +#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)) #else @@ -1171,7 +1202,10 @@ void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf &piPred iLumaStride = MAX_CU_SIZE + 1; Temp = PelBuf(m_piTemp + iLumaStride + 1, iLumaStride, Size(chromaArea)); } - +#if JVET_AA0126_GLM + } +#endif + CclmModel cclmModel; if ( createModel ) @@ -4743,6 +4777,223 @@ int isBelowLeftAvailable(const CodingUnit &cu, const ChannelType &chType, const return numIntra; } +#if JVET_AA0126_GLM +Pel IntraPrediction::xGlmGetLumaVal(const int s[6], const int c[6], const int glmIdx, const Pel val) const +{ + 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 + return (glmIdx >= NUM_GLM_PATTERN ? val + grad : grad); +#else + return grad; +#endif +} + +void IntraPrediction::xGetLumaRecPixelsGlmAll(const PredictionUnit &pu, CompArea chromaArea) +{ + int c[6] = { 0 }; + + int iDstStride = 2 * MAX_CU_SIZE + 1; + Pel* pDst0Cb[NUM_GLM_IDC]; + Pel* pDst0Cr[NUM_GLM_IDC]; + + for (int k = 0; k < NUM_GLM_IDC; k++) + { + pDst0Cb[k] = m_glmTempCb[k] + iDstStride + 1; + pDst0Cr[k] = m_glmTempCr[k] + iDstStride + 1; + } + + //assert 420 chroma subsampling + CompArea lumaArea = CompArea( COMPONENT_Y, pu.chromaFormat, chromaArea.lumaPos(), recalcSize( pu.chromaFormat, CHANNEL_TYPE_CHROMA, CHANNEL_TYPE_LUMA, chromaArea.size() ) );//needed for correct pos/size (4x4 Tus) + + CHECK(lumaArea.width == chromaArea.width && CHROMA_444 != pu.chromaFormat, ""); + CHECK(lumaArea.height == chromaArea.height && CHROMA_444 != pu.chromaFormat && CHROMA_422 != pu.chromaFormat, ""); + + const SizeType uiCWidth = chromaArea.width; + const SizeType uiCHeight = chromaArea.height; + + const CPelBuf Src = pu.cs->picture->getRecoBuf( lumaArea ); + Pel const* pRecSrc0 = Src.bufAt( 0, 0 ); + int iRecStride = Src.stride; + int logSubWidthC = getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, pu.chromaFormat); + int logSubHeightC = getChannelTypeScaleY(CHANNEL_TYPE_CHROMA, pu.chromaFormat); + + int iRecStride2 = iRecStride << logSubHeightC; + + const CodingUnit& lumaCU = isChroma( pu.chType ) ? *pu.cs->picture->cs->getCU( lumaArea.pos(), CH_L ) : *pu.cu; + const CodingUnit& cu = *pu.cu; + + const CompArea& area = isChroma( pu.chType ) ? chromaArea : lumaArea; + + const uint32_t uiTuWidth = area.width; + const uint32_t uiTuHeight = area.height; + + int iBaseUnitSize = ( 1 << MIN_CU_LOG2 ); + + const int iUnitWidth = iBaseUnitSize >> getComponentScaleX( area.compID, area.chromaFormat ); + const int iUnitHeight = iBaseUnitSize >> getComponentScaleY(area.compID, area.chromaFormat); + + const int iTUWidthInUnits = uiTuWidth / iUnitWidth; + const int iTUHeightInUnits = uiTuHeight / iUnitHeight; + const int iAboveUnits = iTUWidthInUnits; + const int iLeftUnits = iTUHeightInUnits; + const int chromaUnitWidth = iBaseUnitSize >> getComponentScaleX(COMPONENT_Cb, area.chromaFormat); + const int chromaUnitHeight = iBaseUnitSize >> getComponentScaleY(COMPONENT_Cb, area.chromaFormat); + const int topTemplateSampNum = 2 * uiCWidth; // for MDLM, the number of template samples is 2W or 2H. + const int leftTemplateSampNum = 2 * uiCHeight; + assert(m_topRefLength >= topTemplateSampNum); + assert(m_leftRefLength >= leftTemplateSampNum); + const int totalAboveUnits = (topTemplateSampNum + (chromaUnitWidth - 1)) / chromaUnitWidth; + const int totalLeftUnits = (leftTemplateSampNum + (chromaUnitHeight - 1)) / chromaUnitHeight; + const int totalUnits = totalLeftUnits + totalAboveUnits + 1; + const int aboveRightUnits = totalAboveUnits - iAboveUnits; + const int leftBelowUnits = totalLeftUnits - iLeftUnits; + + int avaiAboveRightUnits = 0; + int avaiLeftBelowUnits = 0; + bool bNeighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1]; + memset(bNeighborFlags, 0, totalUnits); + bool aboveIsAvailable, leftIsAvailable; + + int availlableUnit = isLeftAvailable(isChroma(pu.chType) ? cu : lumaCU, toChannelType(area.compID), area.pos(), + iLeftUnits, iUnitHeight, (bNeighborFlags + iLeftUnits + leftBelowUnits - 1)); + + leftIsAvailable = availlableUnit == iTUHeightInUnits; + + availlableUnit = isAboveAvailable(isChroma(pu.chType) ? cu : lumaCU, toChannelType(area.compID), area.pos(), + iAboveUnits, iUnitWidth, (bNeighborFlags + iLeftUnits + leftBelowUnits + 1)); + + aboveIsAvailable = availlableUnit == iTUWidthInUnits; + + if (leftIsAvailable) // if left is not available, then the below left is not available + { + avaiLeftBelowUnits = isBelowLeftAvailable(isChroma(pu.chType) ? cu : lumaCU, toChannelType(area.compID), area.bottomLeftComp(area.compID), leftBelowUnits, iUnitHeight, (bNeighborFlags + leftBelowUnits - 1)); + } + + if (aboveIsAvailable) // if above is not available, then the above right is not available. + { + avaiAboveRightUnits = isAboveRightAvailable(isChroma(pu.chType) ? cu : lumaCU, toChannelType(area.compID), area.topRightComp(area.compID), aboveRightUnits, iUnitWidth, (bNeighborFlags + iLeftUnits + leftBelowUnits + iAboveUnits + 1)); + } + + Pel* pDstCb[NUM_GLM_IDC]; + Pel* pDstCr[NUM_GLM_IDC]; + Pel const* piSrc = nullptr; + + if (aboveIsAvailable) + { + for (int k = 0; k < NUM_GLM_IDC; k++) + { + pDstCb[k] = pDst0Cb[k] - iDstStride; + pDstCr[k] = pDst0Cr[k] - iDstStride; + } + + int addedAboveRight = avaiAboveRightUnits*chromaUnitWidth; + + for (int i = 0; i < uiCWidth + addedAboveRight; i++) + { + const int l = (i == 0 && !leftIsAvailable) ? 0 : 1; + { + piSrc = pRecSrc0 - iRecStride2; + int s[6] = { piSrc[2 * i - l], piSrc[2 * i ], piSrc[2 * i + 1], + piSrc[2 * i + iRecStride - l], piSrc[2 * i + iRecStride ], piSrc[2 * i + iRecStride + 1] }; + int val = (1 * s[0] + 2 * s[1] + 1 * s[2] + + 1 * s[3] + 2 * s[4] + 1 * s[5] + 4) >> 3; + pDstCb[0][i] = val; + pDstCr[0][i] = val; + + for (int k = 1; k < NUM_GLM_IDC; k++) + { + int p = (k - 1 < NUM_GLM_PATTERN) ? (k - 1) : (k - 1 - NUM_GLM_PATTERN); + 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 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]; + pDstCb[k][i] = (k - 1 < NUM_GLM_PATTERN) ? grad : val + grad; + pDstCr[k][i] = (k - 1 < NUM_GLM_PATTERN) ? grad : val + grad; + } + } + } + } + + if (leftIsAvailable) + { + for (int k = 0; k < NUM_GLM_IDC; k++) + { + pDstCb[k] = pDst0Cb[k] - 1; + pDstCr[k] = pDst0Cr[k] - 1; + } + piSrc = pRecSrc0 - 1 - logSubWidthC; + + int addedLeftBelow = avaiLeftBelowUnits*chromaUnitHeight; + + for (int j = 0; j < uiCHeight + addedLeftBelow; j++) + { + { + int s[6] = { piSrc[ - 1], piSrc[ 0], piSrc[ 1], + piSrc[iRecStride - 1], piSrc[iRecStride ], piSrc[iRecStride + 1] }; + int val = (1 * s[0] + 2 * s[1] + 1 * s[2] + + 1 * s[3] + 2 * s[4] + 1 * s[5] + 4) >> 3; + pDstCb[0][0] = val; + pDstCr[0][0] = val; + + for (int k = 1; k < NUM_GLM_IDC; k++) + { + int p = (k - 1 < NUM_GLM_PATTERN) ? (k - 1) : (k - 1 - NUM_GLM_PATTERN); + 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 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]; + pDstCb[k][0] = (k - 1 < NUM_GLM_PATTERN) ? grad : val + grad; + pDstCr[k][0] = (k - 1 < NUM_GLM_PATTERN) ? grad : val + grad; + } + } + + piSrc += iRecStride2; + for (int k = 0; k < NUM_GLM_IDC; k++) + { + pDstCb[k] += iDstStride; + pDstCr[k] += iDstStride; + } + } + } + + // inner part from reconstructed picture buffer + for( int j = 0; j < uiCHeight; j++ ) + { + for( int i = 0; i < uiCWidth; i++ ) + { + const int l = (i == 0 && !leftIsAvailable) ? 0 : 1; + { + int s[6] = { pRecSrc0[2 * i - l], pRecSrc0[2 * i ], pRecSrc0[2 * i + 1], + pRecSrc0[2 * i + iRecStride - l], pRecSrc0[2 * i + iRecStride ], pRecSrc0[2 * i + iRecStride + 1] }; + int val = (1 * s[0] + 2 * s[1] + 1 * s[2] + + 1 * s[3] + 2 * s[4] + 1 * s[5] + 4) >> 3; + pDst0Cb[0][i] = val; + pDst0Cr[0][i] = val; + + for (int k = 1; k < NUM_GLM_IDC; k++) + { + int p = (k - 1 < NUM_GLM_PATTERN) ? (k - 1) : (k - 1 - NUM_GLM_PATTERN); + 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 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]; + pDst0Cb[k][i] = (k - 1 < NUM_GLM_PATTERN) ? grad : val + grad; + pDst0Cr[k][i] = (k - 1 < NUM_GLM_PATTERN) ? grad : val + grad; + } + } + } + + for (int k = 0; k < NUM_GLM_IDC; k++) + { + pDst0Cb[k] += iDstStride; + pDst0Cr[k] += iDstStride; + } + pRecSrc0 += iRecStride2; + } +} +#endif + // LumaRecPixels void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea) { @@ -4753,10 +5004,36 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom return; } #endif - + +#if JVET_AA0126_GLM + ComponentID compID = chromaArea.compID; + int glmIdc = pu.glmIdc.getIdc(compID, 0); + int c[6] = { 0 }; + CHECK(glmIdc < 0 || glmIdc >= NUM_GLM_IDC, "glmIdc out of range"); + + if (glmIdc != 0) + { + int glmIdx = glmIdc - 1; + int p = glmIdx >= NUM_GLM_PATTERN ? glmIdx - NUM_GLM_PATTERN : glmIdx; + CHECK(p < 0 || p >= NUM_GLM_PATTERN, "glmPattern out of range"); + 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]; + } +#endif + int iDstStride = 0; Pel* pDst0 = 0; int curChromaMode = pu.intraDir[1]; +#if JVET_AA0126_GLM + if (pu.glmIdc.isActive()) + { + iDstStride = 2 * MAX_CU_SIZE + 1; + Pel* glmTemp = compID == COMPONENT_Cb ? m_glmTempCb[glmIdc] : m_glmTempCr[glmIdc]; + pDst0 = glmTemp + iDstStride + 1; + } + else + { +#endif #if MMLM if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX) || (curChromaMode == MMLM_L_IDX) || (curChromaMode == MMLM_T_IDX)) #else @@ -4771,6 +5048,9 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom iDstStride = MAX_CU_SIZE + 1; pDst0 = m_piTemp + iDstStride + 1; //MMLM_SAMPLE_NEIGHBOR_LINES; } +#if JVET_AA0126_GLM + } +#endif //assert 420 chroma subsampling CompArea lumaArea = CompArea( COMPONENT_Y, pu.chromaFormat, chromaArea.lumaPos(), recalcSize( pu.chromaFormat, CHANNEL_TYPE_CHROMA, CHANNEL_TYPE_LUMA, chromaArea.size() ) );//needed for correct pos/size (4x4 Tus) @@ -4907,6 +5187,16 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom s += piSrc[2 * i + iRecStride - (leftPadding ? 0 : 1)]; pDst[i] = s >> 3; } +#if JVET_AA0126_GLM + if (glmIdc != 0) + { + piSrc = pRecSrc0 - iRecStride2; + int l = leftPadding ? 0 : 1; + int s[6] = { piSrc[2 * i - l], piSrc[2 * i ], piSrc[2 * i + 1], + piSrc[2 * i + iRecStride - l], piSrc[2 * i + iRecStride ], piSrc[2 * i + iRecStride + 1] }; + pDst[i] = xGlmGetLumaVal(s, c, glmIdc - 1, pDst[i]); + } +#endif } } @@ -4962,6 +5252,14 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom s += piSrc[iRecStride - 1]; pDst[0] = s >> 3; } +#if JVET_AA0126_GLM + if (glmIdc != 0) + { + int s[6] = { piSrc[ - 1], piSrc[ 0], piSrc[ 1], + piSrc[iRecStride - 1], piSrc[iRecStride ], piSrc[iRecStride + 1] }; + pDst[0] = xGlmGetLumaVal(s, c, glmIdc - 1, pDst[0]); + } +#endif piSrc += iRecStride2; pDst += iDstStride; @@ -5014,6 +5312,16 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom s += pRecSrc0[2 * i + iRecStride - (leftPadding ? 0 : 1)]; pDst0[i] = s >> 3; } +#if JVET_AA0126_GLM + if (glmIdc != 0) + { + const bool leftPadding = i == 0 && !leftIsAvailable; + int l = leftPadding ? 0 : 1; + int s[6] = { pRecSrc0[2 * i - l], pRecSrc0[2 * i ], pRecSrc0[2 * i + 1], + pRecSrc0[2 * i + iRecStride - l], pRecSrc0[2 * i + iRecStride ], pRecSrc0[2 * i + iRecStride + 1] }; + pDst0[i] = xGlmGetLumaVal(s, c, glmIdc - 1, pDst0[i]); + } +#endif } pDst0 += iDstStride; @@ -5956,6 +6264,17 @@ void IntraPrediction::xGetLMParametersLMS(const PredictionUnit &pu, const Compon int srcStride; PelBuf temp; +#if JVET_AA0126_GLM + if (pu.glmIdc.isActive()) + { + int glmIdc = pu.glmIdc.getIdc(compID, 0); + Pel* glmTemp = compID == COMPONENT_Cb ? m_glmTempCb[glmIdc] : m_glmTempCr[glmIdc]; + srcStride = 2 * MAX_CU_SIZE + 1; + temp = PelBuf(glmTemp + srcStride + 1, srcStride, Size(chromaArea)); + } + else + { +#endif #if MMLM if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX) || (curChromaMode == MMLM_L_IDX) || (curChromaMode == MMLM_T_IDX) || (m_encPreRDRun && curChromaMode == MMLM_CHROMA_IDX)) @@ -5971,6 +6290,9 @@ void IntraPrediction::xGetLMParametersLMS(const PredictionUnit &pu, const Compon srcStride = MAX_CU_SIZE + 1; temp = PelBuf(m_piTemp + srcStride + 1, srcStride, Size(chromaArea)); } +#if JVET_AA0126_GLM + } +#endif srcColor0 = temp.bufAt(0, 0); curChroma0 = getPredictorPtr(compID); diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index 1dbf3b02ec2889e231e059907532328bb1c18a85..10bc05f7979efd9211ab3db3fc787f75e4a88a5e 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -219,6 +219,10 @@ private: Pel* m_piTemp; Pel* m_pMdlmTemp; // for MDLM mode +#if JVET_AA0126_GLM + Pel* m_glmTempCb[NUM_GLM_IDC]; + Pel* m_glmTempCr[NUM_GLM_IDC]; +#endif MatrixIntraPrediction m_matrixIntraPred; @@ -374,6 +378,10 @@ 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); +#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; +#endif /// set parameters from CU data for accessing intra data void initIntraPatternChType (const CodingUnit &cu, const CompArea &area, const bool forceRefFilterFlag = false); // use forceRefFilterFlag to get both filtered and unfiltered buffers void initIntraPatternChTypeISP (const CodingUnit& cu, const CompArea& area, PelBuf& piReco, const bool forceRefFilterFlag = false); // use forceRefFilterFlag to get both filtered and unfiltered buffers diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp index 4cf51287e5a6f6d48f09d6fcf98188657436325f..475a5bc33ee5764455010dd29ba56fd99bc55952 100644 --- a/source/Lib/CommonLib/Rom.cpp +++ b/source/Lib/CommonLib/Rom.cpp @@ -5275,4 +5275,17 @@ int g_gradDivTable[16] = { 0, 7, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 0 }; #if JVET_AA0107_RMVF_AFFINE_MERGE_DERIVATION int g_rmvfMultApproxTbl[3 << sizeof(int64_t)]; #endif +#if JVET_AA0126_GLM +const int8_t g_glmPattern[NUM_GLM_PATTERN][6] = +{ + { 1, 0, -1, 1, 0, -1, }, { 1, 2, 1, -1, -2, -1, }, { 2, 1, -1, 1, -1, -2, }, { -1, 1, 2, -2, -1, 1, }, +#if NUM_GLM_PATTERN > 4 + { 0, 2, -2, 0, 1, -1, }, { 1, 1, 1, -1, -1, -1, }, { 1, 1, -1, 1, -1, -1, }, { -1, 1, 1, -1, -1, 1, }, +#if NUM_GLM_PATTERN > 8 + { 0, 1, -1, 0, 1, -1, }, { 0, 1, 1, 0, -1, -1, }, { 1, 1, 0, 0, -1, -1, }, { 0, 1, 1, -1, -1, 0, }, + { 1, -1, 0, 1, -1, 0, }, { 1, 1, 0, -1, -1, 0, }, { 1, 2, 0, 0, -2, -1, }, { 0, 2, 1, -1, -2, 0, }, +#endif +#endif +}; +#endif //! \} diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h index b4e11e8d28b40f270bf4e6e3d2b4e864bea4b637..81cd7ac835d1ee02c6b9f97021e9a8a01619e1be 100644 --- a/source/Lib/CommonLib/Rom.h +++ b/source/Lib/CommonLib/Rom.h @@ -383,5 +383,8 @@ extern int g_gradDivTable[16]; #if JVET_AA0107_RMVF_AFFINE_MERGE_DERIVATION extern int g_rmvfMultApproxTbl[3 << sizeof(int64_t)]; #endif +#if JVET_AA0126_GLM +extern const int8_t g_glmPattern[NUM_GLM_PATTERN][6]; +#endif #endif //__TCOMROM__ diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 67201d86365cf5d7001b502058153ac20ee4303e..2b4421ed749839f9dd284359ac50d77a3c5fe252 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -132,7 +132,7 @@ #define JVET_Z0050_DIMD_CHROMA_FUSION 1 // JVET-Z0050: DIMD chroma mode and fusion of chroma intra prediction modes #define JVET_Z0050_CCLM_SLOPE 1 // JVET-Z0050: CCLM with slope adjustments #define JVET_AA0057_CCCM 1 // JVET-AA0057: Convolutional cross-component model (CCCM) - +#define JVET_AA0126_GLM 1 // JVET-AA0126: Gradient linear model //IBC #define JVET_Y0058_IBC_LIST_MODIFY 1 // JVET-Y0058: Modifications of IBC merge/AMVP list construction, ARMC-TM-IBC part is included under JVET_W0090_ARMC_TM @@ -1396,6 +1396,21 @@ struct CclmOffsets }; #endif +#if JVET_AA0126_GLM +struct GlmIdc +{ + int8_t cb0 = 0, cr0 = 0; + int8_t cb1 = 0, cr1 = 0; + + bool isActive() const { return cb0 || cr0 || cb1 || cr1; } + bool isActive(ComponentID c) const { return (c == COMPONENT_Cb) ? (cb0 || cb1) : (cr0 || cr1); } + void setAllZero() { cb0 = 0; cr0 = 0; cb1 = 0; cr1 = 0; } + void setIdcs(int b0, int r0, int b1, int r1) { cb0 = b0; cr0 = r0; cb1 = b1; cr1 = r1; } + void setIdc(ComponentID c, int model, int v) { (c == COMPONENT_Cb) ? (model == 0 ? cb0 = v : cb1 = v) : (model == 0 ? cr0 = v : cr1 = v); } + int getIdc(ComponentID c, int model) const { return (c == COMPONENT_Cb) ? (model == 0 ? cb0 : cb1) : (model == 0 ? cr0 : cr1); } +}; +#endif + struct BitDepths { int recon[MAX_NUM_CHANNEL_TYPE]; ///< the bit depth as indicated in the SPS diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 4b17a450b2f8462a2e1d0f4fc699455670f71cfa..5334899da0caff9cdb7db0b27d523cd68f4ee94d 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -648,6 +648,9 @@ void PredictionUnit::initData() #if JVET_Z0050_CCLM_SLOPE cclmOffsets = {}; #endif +#if JVET_AA0126_GLM + glmIdc = {}; +#endif #if JVET_AA0057_CCCM cccmFlag = 0; #endif @@ -769,6 +772,9 @@ PredictionUnit& PredictionUnit::operator=(const IntraPredictionData& predData) #if JVET_Z0050_CCLM_SLOPE cclmOffsets = predData.cclmOffsets; #endif +#if JVET_AA0126_GLM + glmIdc = predData.glmIdc; +#endif #if JVET_AA0057_CCCM cccmFlag = predData.cccmFlag; #endif @@ -887,6 +893,9 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other ) #if JVET_Z0050_CCLM_SLOPE cclmOffsets = other.cclmOffsets; #endif +#if JVET_AA0126_GLM + glmIdc = other.glmIdc; +#endif #if JVET_AA0057_CCCM cccmFlag = other.cccmFlag; #endif diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 72b66531d4fa420513d258aa052281d180bea337..b42323711cc317d6d87f3258c5a62e78153163cc 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -430,6 +430,9 @@ struct IntraPredictionData #if JVET_Z0050_CCLM_SLOPE CclmOffsets cclmOffsets; #endif +#if JVET_AA0126_GLM + GlmIdc glmIdc; +#endif #if JVET_AA0057_CCCM int cccmFlag; #endif diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 96efd102c1e39b3696602fe30d87b61f0597feb7..ad7ff53e50f9ce158f65c325a4f4a79df754cb9d 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -1654,11 +1654,27 @@ void PU::getIntraChromaCandModes(const PredictionUnit &pu, unsigned modeList[NUM bool hasDeltaFlag = chrMode == LM_CHROMA_IDX; #endif hasDeltaFlag &= pu.Cb().width * pu.Cb().height >= 128; +#if JVET_AA0126_GLM + hasDeltaFlag &= !pu.glmIdc.isActive(); +#endif return hasDeltaFlag; } #endif +#if JVET_AA0126_GLM +bool PU::hasGlmFlag(const PredictionUnit &pu, const int mode) +{ + int chrMode = mode < 0 ? pu.intraDir[1] : mode; + bool hasGlmFlag = chrMode == LM_CHROMA_IDX || chrMode == MDLM_L_IDX || chrMode == MDLM_T_IDX; +#if JVET_AA0057_CCCM + hasGlmFlag &= !pu.cccmFlag; +#endif + + return hasGlmFlag; +} +#endif + bool PU::isLMCMode(unsigned mode) { #if MMLM diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 12f2a13350218a528d9433756bcfec9f07025cf9..45e62908c74bac66460919662fe5234b1140b07e 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -459,6 +459,9 @@ namespace PU #if JVET_Z0050_CCLM_SLOPE bool hasCclmDeltaFlag(const PredictionUnit &pu, const int mode = -1); #endif +#if JVET_AA0126_GLM + bool hasGlmFlag (const PredictionUnit &pu, const int mode = -1); +#endif #if JVET_AA0057_CCCM void getCccmRefLineNum (const PredictionUnit& pu, int& th, int& tv); bool cccmSingleModeAvail(const PredictionUnit& pu, int intraMode); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 7341fc244d9f1dc9ad49031d5a4e509f1c4cdf07..dbb2221d430a793a888ec3a50dffdbcc56bdbffb 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -2239,6 +2239,53 @@ void CABACReader::cclmDeltaSlope(PredictionUnit& pu) } #endif +#if JVET_AA0126_GLM +void CABACReader::glmIdc(PredictionUnit& pu) +{ + if ( PU::hasGlmFlag( pu ) ) + { + bool glmActive = m_BinDecoder.decodeBin(Ctx::GlmFlags(0)); + + if ( glmActive ) + { + bool bothActive = m_BinDecoder.decodeBin(Ctx::GlmFlags(3)); + + pu.glmIdc.cb0 = bothActive; + pu.glmIdc.cr0 = bothActive; + + if ( !bothActive ) + { + pu.glmIdc.cb0 = m_BinDecoder.decodeBin(Ctx::GlmFlags(1)); + pu.glmIdc.cr0 = !pu.glmIdc.cb0; + } + + if ( pu.glmIdc.cb0 ) + { +#if NUM_GLM_WEIGHT + pu.glmIdc.cb0 += m_BinDecoder.decodeBin(Ctx::GlmFlags(2)) ? NUM_GLM_PATTERN : 0; +#endif + pu.glmIdc.cb0 += m_BinDecoder.decodeBinsEP(NUM_GLM_PATTERN_BITS); + } + + if ( pu.glmIdc.cr0 ) + { +#if NUM_GLM_WEIGHT + pu.glmIdc.cr0 += m_BinDecoder.decodeBin(Ctx::GlmFlags(4)) ? NUM_GLM_PATTERN : 0; +#endif + pu.glmIdc.cr0 += m_BinDecoder.decodeBinsEP(NUM_GLM_PATTERN_BITS); + } + +#if MMLM + if ( PU::isMultiModeLM( pu.intraDir[1] ) ) + { + pu.glmIdc.cb1 = pu.glmIdc.cb0; + pu.glmIdc.cr1 = pu.glmIdc.cr0; + } +#endif + } + } +} +#endif bool CABACReader::intra_chroma_lmc_mode(PredictionUnit& pu) { #if MMLM @@ -2285,7 +2332,9 @@ bool CABACReader::intra_chroma_lmc_mode(PredictionUnit& pu) #if JVET_AA0057_CCCM cccmFlag( pu ); #endif - +#if JVET_AA0126_GLM + glmIdc( pu ); +#endif #if JVET_Z0050_CCLM_SLOPE cclmDeltaSlope( pu ); #endif diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 3e04bfaa9d565f66a70da822b123b5bb6ad22315..3825af393018ae55d76c0d3b2ac144af430b7ade 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -195,6 +195,9 @@ public: void cclmDelta ( PredictionUnit& pu, int8_t &delta ); void cclmDeltaSlope ( PredictionUnit& pu ); #endif +#if JVET_AA0126_GLM + void glmIdc ( PredictionUnit& pu ); +#endif // transform tree (clause 7.3.8.8) diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 431aeb02ec198406c54976929fec121fc055fa60..0997db26016f3abb2f14fa26d7484f39515ae100 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -1967,6 +1967,57 @@ void CABACWriter::cclmDeltaSlope(const PredictionUnit& pu) } #endif +#if JVET_AA0126_GLM +void CABACWriter::glmIdc(const PredictionUnit& pu) +{ + if ( PU::hasGlmFlag( pu ) ) + { + bool glmActive = pu.glmIdc.isActive(); + + m_BinEncoder.encodeBin( glmActive ? 1 : 0, Ctx::GlmFlags(0) ); + + if ( glmActive ) + { + bool bothActive = pu.glmIdc.cb0 && pu.glmIdc.cr0; + + m_BinEncoder.encodeBin( bothActive ? 1 : 0, Ctx::GlmFlags(3) ); + + if ( !bothActive ) + { + m_BinEncoder.encodeBin( pu.glmIdc.cb0 ? 1 : 0, Ctx::GlmFlags(1) ); + } + + if ( pu.glmIdc.cb0 ) + { + int glmIdx = pu.glmIdc.cb0 - 1; +#if NUM_GLM_WEIGHT + m_BinEncoder.encodeBin( glmIdx >= NUM_GLM_PATTERN ? 1 : 0, Ctx::GlmFlags(2) ); + glmIdx -= glmIdx >= NUM_GLM_PATTERN ? NUM_GLM_PATTERN : 0; +#endif + m_BinEncoder.encodeBinsEP( glmIdx, NUM_GLM_PATTERN_BITS ); + } + + if ( pu.glmIdc.cr0 ) + { + int glmIdx = pu.glmIdc.cr0 - 1; +#if NUM_GLM_WEIGHT + m_BinEncoder.encodeBin( glmIdx >= NUM_GLM_PATTERN ? 1 : 0, Ctx::GlmFlags(4) ); + glmIdx -= glmIdx >= NUM_GLM_PATTERN ? NUM_GLM_PATTERN : 0; +#endif + m_BinEncoder.encodeBinsEP( glmIdx, NUM_GLM_PATTERN_BITS ); + } + +#if MMLM + if ( PU::isMultiModeLM( pu.intraDir[1] ) ) + { + CHECK(pu.glmIdc.cb0 != pu.glmIdc.cb1 + || pu.glmIdc.cr0 != pu.glmIdc.cr1, "GLM cb0 != cb1 || cr0 != cr1") + } +#endif + } + } +} +#endif void CABACWriter::intra_chroma_lmc_mode(const PredictionUnit& pu) { const unsigned intraDir = pu.intraDir[1]; @@ -2019,7 +2070,9 @@ void CABACWriter::intra_chroma_lmc_mode(const PredictionUnit& pu) #if JVET_AA0057_CCCM cccmFlag( pu ); #endif - +#if JVET_AA0126_GLM + glmIdc( pu ); +#endif #if JVET_Z0050_CCLM_SLOPE cclmDeltaSlope( pu ); #endif diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 706ab6ffc6b27408e7ad102900f941f30c2b19dc..05c2bf5d0c05c19e5e70dbf0bb09b08cd816a831 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -222,6 +222,9 @@ public: void cclmDelta ( const PredictionUnit& pu, int8_t delta); void cclmDeltaSlope ( const PredictionUnit& pu ); #endif +#if JVET_AA0126_GLM + void glmIdc ( const PredictionUnit& pu ); +#endif // transform tree (clause 7.3.8.8) void transform_tree ( const CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, const PartSplit ispType = TU_NO_ISP, const int subTuIdx = -1 ); diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 5fd007e74fccf2d1c8a421ba5f2839fc13d5408b..297129b1727b571c49dc12866404011ef3b7d72e 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -1887,6 +1887,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner CclmOffsets satdCclmOffsetsBest[NUM_CHROMA_MODE]; int64_t satdCclmCosts [NUM_CHROMA_MODE] = { 0 }; #endif +#if JVET_AA0126_GLM + GlmIdc bestGlmIdc = {}; + GlmIdc satdGlmIdcBest [NUM_CHROMA_MODE]; + int64_t satdGlmCosts [NUM_CHROMA_MODE] = { 0 }; +#endif #if JVET_Z0050_DIMD_CHROMA_FUSION bool isChromaFusion = false; #endif @@ -1998,6 +2003,47 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner initIntraPatternChType(cu, pu.Cb()); initIntraPatternChType(cu, pu.Cr()); xGetLumaRecPixels(pu, pu.Cb()); + +#if JVET_AA0126_GLM + if ( PU::isLMCModeEnabled( pu, LM_CHROMA_IDX ) && PU::hasGlmFlag( pu, LM_CHROMA_IDX ) ) + { + // Generate all GLM templates at encoder + xGetLumaRecPixelsGlmAll(pu, pu.Cb()); + + for ( int mode = LM_CHROMA_IDX; mode <= MMLM_T_IDX; mode++ ) + { + satdGlmIdcBest[mode - LM_CHROMA_IDX].setAllZero(); + + if ( PU::hasGlmFlag( pu, mode ) ) + { + for ( int comp = COMPONENT_Cb; comp <= COMPONENT_Cr; comp++ ) + { + ComponentID compID = ComponentID( comp ); + int idcBest = 0; + int64_t satdBest = 0; + GlmIdc& idcsBest = satdGlmIdcBest[mode - LM_CHROMA_IDX]; + + pu.intraDir[1] = mode; + pu.glmIdc.setAllZero(); + + xFindBestGlmIdcSATD(pu, compID, idcBest, satdBest ); + + idcsBest.setIdc(compID, 0, idcBest); + idcsBest.setIdc(compID, 1, idcBest); + + satdGlmCosts[mode - LM_CHROMA_IDX] += satdBest; // Summing up Cb and Cr cost + } + + if ( !satdGlmIdcBest[0].isActive() ) + { + break; + } + } + } + } + + pu.glmIdc.setAllZero(); +#endif #if JVET_Z0050_CCLM_SLOPE if ( PU::isLMCModeEnabled( pu, LM_CHROMA_IDX ) && PU::hasCclmDeltaFlag( pu, LM_CHROMA_IDX ) ) @@ -2256,6 +2302,82 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #endif } +#if JVET_AA0126_GLM + for (int32_t uiMode = 0; uiMode < NUM_LMC_MODE; uiMode++) + { + int chromaIntraMode = LM_CHROMA_IDX + uiMode; + if ( PU::isLMCModeEnabled( pu, chromaIntraMode ) && PU::hasGlmFlag( pu, chromaIntraMode ) ) + { + if ( satdGlmIdcBest[chromaIntraMode - LM_CHROMA_IDX].isActive() ) + { + pu.intraDir[1] = chromaIntraMode; + pu.glmIdc = satdGlmIdcBest[chromaIntraMode - LM_CHROMA_IDX]; + + // RD search replicated from above + cs.setDecomp( pu.Cb(), false ); + cs.dist = baseDist; + //----- restore context models ----- + m_CABACEstimator->getCtx() = ctxStart; + + xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType ); + if( lumaUsesISP && cs.dist == MAX_UINT ) + { + continue; + } + + if (cs.sps->getTransformSkipEnabledFlag()) + { + m_CABACEstimator->getCtx() = ctxStart; + } + + uint64_t fracBits = xGetIntraFracBitsQT( cs, partitioner, false, true, -1, ispType ); + Distortion uiDist = cs.dist; + double dCost = m_pcRdCost->calcRdCost( fracBits, uiDist - baseDist ); + + //----- compare ----- + if( dCost < dBestCost ) + { + if( lumaUsesISP && dCost < bestCostSoFar ) + { + bestCostSoFar = dCost; + } + for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ ) + { + const CompArea &area = pu.blocks[i]; + + saveCS.getRecoBuf ( area ).copyFrom( cs.getRecoBuf ( area ) ); +#if KEEP_PRED_AND_RESI_SIGNALS + saveCS.getPredBuf ( area ).copyFrom( cs.getPredBuf ( area ) ); + saveCS.getResiBuf ( area ).copyFrom( cs.getResiBuf ( area ) ); +#endif + saveCS.getPredBuf ( area ).copyFrom( cs.getPredBuf (area ) ); + cs.picture->getPredBuf( area ).copyFrom( cs.getPredBuf (area ) ); + cs.picture->getRecoBuf( area ).copyFrom( cs.getRecoBuf( area ) ); + + for( uint32_t j = 0; j < saveCS.tus.size(); j++ ) + { + saveCS.tus[j]->copyComponentFrom( *orgTUs[j], area.compID ); + } + } + + dBestCost = dCost; + uiBestDist = uiDist; + uiBestMode = chromaIntraMode; + bestBDPCMMode = cu.bdpcmModeChroma; + bestGlmIdc = pu.glmIdc; + } + + if ( chromaIntraMode == LM_CHROMA_IDX && !bestGlmIdc.isActive() ) + { + break; + } + } + } + } + + pu.glmIdc.setAllZero(); +#endif + #if JVET_Z0050_DIMD_CHROMA_FUSION // RDO for chroma fusion mode for (int32_t uiMode = 0; uiMode < 1; uiMode++) @@ -2321,6 +2443,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner uiBestMode = chromaIntraMode; bestBDPCMMode = cu.bdpcmModeChroma; isChromaFusion = pu.isChromaFusion; +#if JVET_AA0126_GLM + bestGlmIdc = pu.glmIdc; +#endif } } pu.isChromaFusion = false; @@ -2401,6 +2526,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner bestCclmOffsets = pu.cclmOffsets; #if JVET_Z0050_DIMD_CHROMA_FUSION isChromaFusion = pu.isChromaFusion; +#endif +#if JVET_AA0126_GLM + bestGlmIdc = pu.glmIdc; #endif } } @@ -2486,6 +2614,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner bestCclmOffsets = pu.cclmOffsets; #endif cccmModeBest = pu.cccmFlag; +#if JVET_AA0126_GLM + bestGlmIdc = pu.glmIdc; +#endif } } } @@ -2528,6 +2659,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #endif #if JVET_Z0050_DIMD_CHROMA_FUSION pu.isChromaFusion = isChromaFusion; +#endif +#if JVET_AA0126_GLM + pu.glmIdc = bestGlmIdc; #endif } @@ -2612,6 +2746,48 @@ void IntraSearch::xFindBestCclmDeltaSlopeSATD(PredictionUnit &pu, ComponentID co } #endif +#if JVET_AA0126_GLM +void IntraSearch::xFindBestGlmIdcSATD(PredictionUnit &pu, ComponentID compID, int &idcBest, int64_t &sadBest ) +{ + CodingStructure& cs = *(pu.cs); + CompArea area = compID == COMPONENT_Cb ? pu.Cb() : pu.Cr(); + PelBuf orgBuf = cs.getOrgBuf(area); + PelBuf predBuf = cs.getPredBuf(area); + int maxIdc = NUM_GLM_IDC - 1; + int mode = pu.intraDir[1]; + + DistParam distParamSad; + DistParam distParamSatd; + + m_pcRdCost->setDistParam(distParamSad, orgBuf, predBuf, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), compID, false); + m_pcRdCost->setDistParam(distParamSatd, orgBuf, predBuf, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), compID, true); + + distParamSad.applyWeight = false; + distParamSatd.applyWeight = false; + + sadBest = -1; + + // Search positive idcs + for ( int idc = 0; idc <= maxIdc; idc++ ) + { + pu.glmIdc.setIdc(compID, 0, idc); + pu.glmIdc.setIdc(compID, 1, idc); + + predIntraChromaLM( compID, predBuf, pu, area, mode ); + + int64_t sad = distParamSad.distFunc(distParamSad) * 2; + int64_t satd = distParamSatd.distFunc(distParamSatd); + int64_t sadThis = std::min(sad, satd); + + if ( sadBest == -1 || sadThis < sadBest ) + { + sadBest = sadThis; + idcBest = idc; + } + } +} +#endif + #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS void IntraSearch::saveCuAreaCostInSCIPU( Area area, double cost ) { @@ -6770,6 +6946,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio { xGetLumaRecPixels( pu, cbArea ); predIntraChromaLM( COMPONENT_Cb, piPredCb, pu, cbArea, predMode ); +#if JVET_AA0126_GLM + xGetLumaRecPixels( pu, crArea ); // generate GLM luma samples for Cr prediction +#endif predIntraChromaLM( COMPONENT_Cr, piPredCr, pu, crArea, predMode ); } else if (PU::isMIP(pu, CHANNEL_TYPE_CHROMA)) diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 2cd402227ce590389ca828ae66b2c79a52580e53..b3a1280a0877e75078e113a6c95f9ebaee3fb84f 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -543,6 +543,9 @@ protected: #if JVET_Z0050_CCLM_SLOPE void xFindBestCclmDeltaSlopeSATD ( PredictionUnit &pu, ComponentID compID, int cclmModel, int &deltaBest, int64_t &satdBest ); #endif +#if JVET_AA0126_GLM + void xFindBestGlmIdcSATD ( PredictionUnit &pu, ComponentID compID, int &idcBest, int64_t &satdBest ); +#endif };// END CLASS DEFINITION EncSearch //! \}