From 16b61dc71dadbec294a995f31d92e89b04761ea5 Mon Sep 17 00:00:00 2001 From: Hang Huang <huanghang@oppo.com> Date: Mon, 11 Nov 2024 06:23:33 +0000 Subject: [PATCH] JVET-AJ0081: Chroma TMRL (Test 2.18) --- source/Lib/CommonLib/CommonDef.h | 6 + source/Lib/CommonLib/Contexts.h | 3 + source/Lib/CommonLib/Contexts_ecm14.0.inl | 25 ++ source/Lib/CommonLib/IntraPrediction.cpp | 489 +++++++++++++++++++++- source/Lib/CommonLib/IntraPrediction.h | 6 + source/Lib/CommonLib/TypeDef.h | 1 + source/Lib/CommonLib/Unit.cpp | 15 + source/Lib/CommonLib/Unit.h | 5 + source/Lib/CommonLib/UnitTools.cpp | 17 + source/Lib/CommonLib/UnitTools.h | 3 + source/Lib/DecoderLib/CABACReader.cpp | 25 ++ source/Lib/DecoderLib/CABACReader.h | 3 + source/Lib/DecoderLib/DecCu.cpp | 37 +- source/Lib/EncoderLib/CABACWriter.cpp | 24 ++ source/Lib/EncoderLib/CABACWriter.h | 3 + source/Lib/EncoderLib/EncCu.cpp | 16 + source/Lib/EncoderLib/IntraSearch.cpp | 272 ++++++++++++ source/Lib/EncoderLib/IntraSearch.h | 4 + 18 files changed, 945 insertions(+), 9 deletions(-) diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 207e85c6e..16f3f31c1 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -703,6 +703,12 @@ static const int MRL_IDX_RICE_CODE_DIVISOR = 4; static const int TMRL_MPM_SIZE = 10; static const int TMRL_MODECOST = NUM_LUMA_MODE * MAX_REF_LINE_IDX; static const int EXT_REF_LINE_IDX[] = { 1, 3, 5, 7, 12 }; +#if JVET_AJ0081_CHROMA_TMRL +static const int CHROMA_TMRL_LIST_SIZE = 6; +static const int CHROMA_TMRL_MPM_SIZE = 8; +static const int MAX_CHROMA_MRL_IDX = 3; +static const int CHROMA_MULTI_REF_LINE_IDX[MAX_CHROMA_MRL_IDX] = { 1, 3, 5 }; +#endif #endif #if JVET_AG0058_EIP static const int EIP_IDX = 201; diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 11d9324cc..277ce562f 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -795,6 +795,9 @@ public: #endif #if JVET_AB0157_TMRL static const CtxSet TmrlDerive; +#if JVET_AJ0081_CHROMA_TMRL + static const CtxSet ChromaTmrlFlag; +#endif #endif #if JVET_AE0059_INTER_CCCM static const CtxSet InterCccmFlag; diff --git a/source/Lib/CommonLib/Contexts_ecm14.0.inl b/source/Lib/CommonLib/Contexts_ecm14.0.inl index 5b9830d97..ed52c9ee4 100644 --- a/source/Lib/CommonLib/Contexts_ecm14.0.inl +++ b/source/Lib/CommonLib/Contexts_ecm14.0.inl @@ -6519,5 +6519,30 @@ const CtxSet ContextSetCfg::SeparateTree = ContextSetCfg::addCtxSet { DWO, DWO, DWO }, }); #endif +#if JVET_AJ0081_CHROMA_TMRL +const CtxSet ContextSetCfg::ChromaTmrlFlag = ContextSetCfg::addCtxSet +({ + { CNU, }, + { CNU, }, + { CNU, }, + { CNU, }, + { DWS, }, + { DWS, }, + { DWS, }, + { DWS, }, + { DWE, }, + { DWE, }, + { DWE, }, + { DWE, }, + { DWO, }, + { DWO, }, + { DWO, }, + { DWO, }, + { DWO, }, + { DWO, }, + { DWO, }, + { DWO, }, + }); +#endif // CONTEXTS WSA STOP #endif diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index f800a2da5..979a708f4 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -3576,7 +3576,11 @@ void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompA #else m_ipaParam.isModeVer = predMode >= DIA_IDX; #endif - m_ipaParam.multiRefIndex = isLuma (chType) ? pu.multiRefIdx : 0 ; +#if JVET_AJ0081_CHROMA_TMRL + m_ipaParam.multiRefIndex = isLuma(chType) ? pu.multiRefIdx : pu.chromaMrlIdx; +#else + m_ipaParam.multiRefIndex = isLuma(chType) ? pu.multiRefIdx : 0; +#endif m_ipaParam.refFilterFlag = false; m_ipaParam.interpolationFlag = false; m_ipaParam.applyPDPC = (puSize.width >= MIN_TB_SIZEY && puSize.height >= MIN_TB_SIZEY) && m_ipaParam.multiRefIndex == 0; @@ -5794,7 +5798,11 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf const SPS &sps = *cs.sps; const PreCalcValues &pcv = *cs.pcv; +#if JVET_AJ0081_CHROMA_TMRL + const int multiRefIdx = (area.compID == COMPONENT_Y) ? cu.firstPU->multiRefIdx : cu.firstPU->chromaMrlIdx; +#else const int multiRefIdx = (area.compID == COMPONENT_Y) ? cu.firstPU->multiRefIdx : 0; +#endif const int tuWidth = area.width; const int tuHeight = area.height; @@ -6159,7 +6167,11 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel const SPS &sps = *cs.sps; const PreCalcValues &pcv = *cs.pcv; +#if JVET_AJ0081_CHROMA_TMRL + const int multiRefIdx = cu.firstPU->multiRefIdx; +#else const int multiRefIdx = 0; +#endif const int tuWidth = area.width; const int tuHeight = area.height; @@ -6172,9 +6184,18 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel const int unitWidth = tuWidth <= 2 && cu.ispMode && isLuma(area.compID) ? tuWidth : pcv.minCUWidth >> (noShift ? 0 : getComponentScaleX(area.compID, sps.getChromaFormatIdc())); const int unitHeight = tuHeight <= 2 && cu.ispMode && isLuma(area.compID) ? tuHeight : pcv.minCUHeight >> (noShift ? 0 : getComponentScaleY(area.compID, sps.getChromaFormatIdc())); +#if JVET_AJ0081_CHROMA_TMRL + int leftMrlUnitNum = multiRefIdx / unitHeight; + int aboveMrlUnitNum = multiRefIdx / unitWidth; +#endif + const int totalAboveUnits = (predSize + (unitWidth - 1)) / unitWidth; const int totalLeftUnits = (predHSize + (unitHeight - 1)) / unitHeight; +#if JVET_AJ0081_CHROMA_TMRL + const int totalUnits = totalAboveUnits + totalLeftUnits + 1 + leftMrlUnitNum + aboveMrlUnitNum; // for top-left and mrl +#else const int totalUnits = totalAboveUnits + totalLeftUnits + 1; //+1 for top-left +#endif const int numAboveUnits = std::max<int>(tuWidth / unitWidth, 1); const int numLeftUnits = std::max<int>(tuHeight / unitHeight, 1); @@ -6184,11 +6205,84 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel CHECK(numAboveUnits <= 0 || numLeftUnits <= 0 || numAboveRightUnits <= 0 || numLeftBelowUnits <= 0, "Size not supported"); // ----- Step 1: analyze neighborhood ----- +#if JVET_AJ0081_CHROMA_TMRL + bool neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + MAX_REF_LINE_IDX + 1]; +#else bool neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1]; +#endif int numIntraNeighbor = 0; memset(neighborFlags, 0, totalUnits); +#if JVET_AJ0081_CHROMA_TMRL + //top-left + neighborFlags[totalLeftUnits + leftMrlUnitNum] = (area.x - multiRefIdx) > 0 && (area.y - multiRefIdx) > 0; + numIntraNeighbor += neighborFlags[totalLeftUnits + leftMrlUnitNum] ? 1 : 0; + //mrl above + numIntraNeighbor += ((area.x - aboveMrlUnitNum * unitWidth) > 0 && (area.y - multiRefIdx) > 0) ? aboveMrlUnitNum : 0; + for (int i = totalLeftUnits + leftMrlUnitNum + 1; i < totalLeftUnits + leftMrlUnitNum + 1 + aboveMrlUnitNum; i++) + { + neighborFlags[i] = ((area.x - aboveMrlUnitNum * unitWidth) > 0 && (area.y - multiRefIdx) > 0) ? true : false; + } + //above + numIntraNeighbor += (area.y - multiRefIdx) > 0 ? numAboveUnits : 0; + for (int i = totalLeftUnits + leftMrlUnitNum + 1 + aboveMrlUnitNum; i < totalLeftUnits + leftMrlUnitNum + 1 + aboveMrlUnitNum + numAboveUnits; i++) + { + neighborFlags[i] = (area.y - multiRefIdx) > 0 ? true : false; + } + //above right + int picWidth = sps.getMaxPicWidthInLumaSamples(); + int ctuWidth = sps.getCTUSize(); + int ctuWidthInNum = area.x / ctuWidth; + int wUnit = std::min((picWidth - area.x - tuWidth) / unitWidth, ((ctuWidthInNum + 1) * ctuWidth - area.x - tuWidth) / unitWidth); +#if JVET_AI0136_ADAPTIVE_DUAL_TREE // to fix chroma ipm reorderding + if (cu.slice->isIntra()) +#endif + numIntraNeighbor += (area.y - multiRefIdx) > 0 ? std::min(numAboveRightUnits, wUnit) : 0; + for (int i = totalLeftUnits + leftMrlUnitNum + 1 + aboveMrlUnitNum + numAboveUnits; i < totalLeftUnits + leftMrlUnitNum + 1 + aboveMrlUnitNum + numAboveUnits + numAboveRightUnits; i++) + { + neighborFlags[i] = (area.y - multiRefIdx) > 0 ? (i - (totalLeftUnits + 1 + numAboveUnits) < wUnit ? true : false) : false; +#if JVET_AI0136_ADAPTIVE_DUAL_TREE // to fix chroma ipm reorderding + if (!cu.slice->isIntra()) + { + neighborFlags[i] = false; + } +#endif + } + //mrl left + numIntraNeighbor += ((area.x - multiRefIdx) > 0 && (area.y - leftMrlUnitNum * unitHeight) > 0) ? leftMrlUnitNum : 0; + for (int i = totalLeftUnits + leftMrlUnitNum - 1; i > totalLeftUnits - 1; i--) + { + neighborFlags[i] = ((area.x - multiRefIdx) > 0 && (area.y - leftMrlUnitNum * unitHeight) > 0) ? true : false; + } + //left + numIntraNeighbor += (area.x - multiRefIdx) > 0 ? numLeftUnits : 0; + for (int i = totalLeftUnits - 1; i > totalLeftUnits - 1 - numLeftUnits; i--) + { + neighborFlags[i] = (area.x - multiRefIdx) > 0 ? true : false; + } + //left below + int picHeight = sps.getMaxPicHeightInLumaSamples(); + int ctuHeight = sps.getCTUSize(); + int ctuHeightInNum = area.y / ctuHeight; + int hUnit = std::min((picHeight - area.y - tuHeight) / unitHeight, ((ctuHeightInNum + 1) * ctuHeight - area.y - tuHeight) / unitHeight); +#if JVET_AI0136_ADAPTIVE_DUAL_TREE + if (cu.slice->isIntra()) +#endif + numIntraNeighbor += (area.x - multiRefIdx) > 0 ? std::min(numLeftBelowUnits, hUnit) : 0; + int y = 0; + for (int i = totalLeftUnits - 1 - numLeftUnits; i > totalLeftUnits - 1 - numLeftUnits - numLeftBelowUnits; i--) + { + neighborFlags[i] = (area.x - multiRefIdx) > 0 ? (y < hUnit ? true : false) : false; +#if JVET_AI0136_ADAPTIVE_DUAL_TREE // to fix chroma ipm reorderding + if (!cu.slice->isIntra()) + { + neighborFlags[i] = false; + } +#endif + y++; + } +#else neighborFlags[totalLeftUnits] = area.x > 0 && area.y > 0; numIntraNeighbor += neighborFlags[totalLeftUnits] ? 1 : 0; numIntraNeighbor += area.y > 0 ? numAboveUnits : 0; @@ -6203,10 +6297,10 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel #if JVET_AI0136_ADAPTIVE_DUAL_TREE // to fix chroma ipm reorderding if (cu.slice->isIntra()) #endif - numIntraNeighbor += area.y > 0 ? std::min(numAboveRightUnits, wUnit) : 0; + numIntraNeighbor += area.y > 0 ? std::min(numAboveRightUnits, wUnit) : 0; for (int i = totalLeftUnits + 1 + numAboveUnits; i < totalLeftUnits + 1 + numAboveUnits + numAboveRightUnits; i++) { - neighborFlags[i] = area.y > 0 ? ( i - (totalLeftUnits + 1 + numAboveUnits) < wUnit ? true : false) : false; + neighborFlags[i] = area.y > 0 ? (i - (totalLeftUnits + 1 + numAboveUnits) < wUnit ? true : false) : false; #if JVET_AI0136_ADAPTIVE_DUAL_TREE // to fix chroma ipm reorderding if (!cu.slice->isIntra()) { @@ -6226,7 +6320,7 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel #if JVET_AI0136_ADAPTIVE_DUAL_TREE if (cu.slice->isIntra()) #endif - numIntraNeighbor += area.x > 0 ? std::min(numLeftBelowUnits, hUnit) : 0; + numIntraNeighbor += area.x > 0 ? std::min(numLeftBelowUnits, hUnit) : 0; int y = 0; for (int i = totalLeftUnits - 1 - numLeftUnits; i > totalLeftUnits - 1 - numLeftUnits - numLeftBelowUnits; i--) { @@ -6239,6 +6333,7 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel #endif y++; } +#endif // ----- Step 2: fill reference samples (depending on neighborhood) ----- @@ -6289,9 +6384,15 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel } // Fill left & below-left samples if available (downwards) +#if JVET_AJ0081_CHROMA_TMRL + ptrSrc += (1 + multiRefIdx - leftMrlUnitNum * unitHeight) * srcStride; + ptrDst += (1 + multiRefIdx - leftMrlUnitNum * unitHeight) + predStride; + for (int unitIdx = totalLeftUnits + leftMrlUnitNum - 1; unitIdx > 0; unitIdx--) +#else ptrSrc += (1 + multiRefIdx) * srcStride; ptrDst += (1 + multiRefIdx) + predStride; for (int unitIdx = totalLeftUnits - 1; unitIdx > 0; unitIdx--) +#endif { if (neighborFlags[unitIdx]) { @@ -6314,9 +6415,15 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel } // Fill above & above-right samples if available (left-to-right) +#if JVET_AJ0081_CHROMA_TMRL + ptrSrc = srcBuf - srcStride * (1 + multiRefIdx) - aboveMrlUnitNum * unitWidth; + ptrDst = refBufUnfiltered + 1 + multiRefIdx - aboveMrlUnitNum * unitWidth; + for (int unitIdx = totalLeftUnits + leftMrlUnitNum + 1; unitIdx < totalUnits - 1; unitIdx++) +#else ptrSrc = srcBuf - srcStride * (1 + multiRefIdx); ptrDst = refBufUnfiltered + 1 + multiRefIdx; for (int unitIdx = totalLeftUnits + 1; unitIdx < totalUnits - 1; unitIdx++) +#endif { if (neighborFlags[unitIdx]) { @@ -6353,6 +6460,20 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel int firstAvailRow = -1; int firstAvailCol = 0; +#if JVET_AJ0081_CHROMA_TMRL + if (firstAvailUnit < totalLeftUnits + leftMrlUnitNum) + { + firstAvailRow = (totalLeftUnits + leftMrlUnitNum - firstAvailUnit) * unitHeight + multiRefIdx - leftMrlUnitNum * unitHeight; + } + else if (firstAvailUnit == totalLeftUnits + leftMrlUnitNum) + { + firstAvailRow = multiRefIdx - leftMrlUnitNum * unitHeight; + } + else + { + firstAvailCol = (firstAvailUnit - totalLeftUnits - leftMrlUnitNum - 1) * unitWidth + 1 + multiRefIdx - aboveMrlUnitNum * unitWidth; + } +#else if (firstAvailUnit < totalLeftUnits) { firstAvailRow = (totalLeftUnits - firstAvailUnit) * unitHeight + multiRefIdx; @@ -6365,6 +6486,7 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel { firstAvailCol = (firstAvailUnit - totalLeftUnits - 1) * unitWidth + 1 + multiRefIdx; } +#endif const Pel firstAvailSample = ptrDst[firstAvailRow < 0 ? firstAvailCol : firstAvailRow + predStride]; @@ -6396,6 +6518,20 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel // last available sample int lastAvailRow = -1; int lastAvailCol = 0; +#if JVET_AJ0081_CHROMA_TMRL + if (lastAvailUnit < totalLeftUnits + leftMrlUnitNum) + { + lastAvailRow = (totalLeftUnits + leftMrlUnitNum - lastAvailUnit - 1) * unitHeight + multiRefIdx - leftMrlUnitNum * unitHeight + 1; + } + else if (lastAvailUnit == totalLeftUnits + leftMrlUnitNum) + { + lastAvailCol = multiRefIdx - leftMrlUnitNum * unitHeight; + } + else + { + lastAvailCol = (lastAvailUnit - totalLeftUnits - leftMrlUnitNum) * unitWidth + multiRefIdx - aboveMrlUnitNum * unitWidth; + } +#else if (lastAvailUnit < totalLeftUnits) { lastAvailRow = (totalLeftUnits - lastAvailUnit - 1) * unitHeight + multiRefIdx + 1; @@ -6408,9 +6544,38 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel { lastAvailCol = (lastAvailUnit - totalLeftUnits) * unitWidth + multiRefIdx; } +#endif const Pel lastAvailSample = ptrDst[lastAvailRow < 0 ? lastAvailCol : lastAvailRow + predStride]; // fill current unit with last available sample +#if JVET_AJ0081_CHROMA_TMRL + if (currUnit < totalLeftUnits + leftMrlUnitNum) + { + for (int i = lastAvailRow - 1; i >= lastAvailRow - unitHeight; i--) + { + ptrDst[i + predStride] = lastAvailSample; + } + } + else if (currUnit == totalLeftUnits + leftMrlUnitNum) + { + for (int i = 0; i < multiRefIdx - leftMrlUnitNum * unitHeight + 1; i++) + { + ptrDst[i + predStride] = lastAvailSample; + } + for (int j = 0; j < multiRefIdx - aboveMrlUnitNum * unitWidth + 1; j++) + { + ptrDst[j] = lastAvailSample; + } + } + else + { + int numSamplesInUnit = (currUnit == totalUnits - 1) ? ((predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth) : unitWidth; + for (int j = lastAvailCol + 1; j <= lastAvailCol + numSamplesInUnit; j++) + { + ptrDst[j] = lastAvailSample; + } + } +#else if (currUnit < totalLeftUnits) { for (int i = lastAvailRow - 1; i >= lastAvailRow - unitHeight; i--) @@ -6437,6 +6602,7 @@ void IntraPrediction::xFillReferenceSamplesForCoLuma(const CPelBuf &recoBuf, Pel ptrDst[j] = lastAvailSample; } } +#endif } lastAvailUnit = currUnit; currUnit++; @@ -27342,6 +27508,321 @@ void IntraPrediction::getTmrlList(CodingUnit& cu) } #endif +#if JVET_AJ0081_CHROMA_TMRL +void IntraPrediction::getChromaTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlRefList, uint8_t* tmrlIntraList, uint8_t& sizeRef, uint8_t& sizeMode) +{ + const CompArea& area = pu.Cb(); + CodingUnit& cu = *pu.cu; + int aboveLines = cu.block(COMPONENT_Cb).y; + sizeRef = 0; + + for (; sizeRef < MAX_CHROMA_MRL_IDX; sizeRef++) + { + tmrlRefList[sizeRef] = CHROMA_MULTI_REF_LINE_IDX[sizeRef]; + if (CHROMA_MULTI_REF_LINE_IDX[sizeRef] >= aboveLines) + { + break; + } + } + + sizeMode = CHROMA_TMRL_MPM_SIZE; + uint8_t chromaDirMode; + int vaildNum = 0; + bool hasMode[67] = { false }; + hasMode[PLANAR_IDX] = true; + chromaDirMode = PU::getCoLocatedIntraLumaMode(pu); + if (hasMode[chromaDirMode] == false) + { + hasMode[chromaDirMode] = true; + tmrlIntraList[vaildNum] = chromaDirMode; + vaildNum++; + } + chromaDirMode = cu.dimdChromaMode; + if (hasMode[chromaDirMode] == false) + { + hasMode[chromaDirMode] = true; + tmrlIntraList[vaildNum] = chromaDirMode; + vaildNum++; + } + chromaDirMode = cu.dimdChromaModeSecond; + if (hasMode[chromaDirMode] == false) + { + hasMode[chromaDirMode] = true; + tmrlIntraList[vaildNum] = chromaDirMode; + vaildNum++; + } + chromaDirMode = DC_IDX; + if (hasMode[chromaDirMode] == false) + { + hasMode[chromaDirMode] = true; + tmrlIntraList[vaildNum] = chromaDirMode; + vaildNum++; + } + // get co-located modes + CompArea lumaArea = CompArea(COMPONENT_Y, pu.chromaFormat, pu.Cb().lumaPos(), recalcSize(pu.chromaFormat, CHANNEL_TYPE_CHROMA, CHANNEL_TYPE_LUMA, pu.Cb().size())); + lumaArea = clipArea(lumaArea, pu.cs->picture->block(COMPONENT_Y)); + + Position posList[5] = { lumaArea.center(), lumaArea.topLeft(), lumaArea.topRight(), lumaArea.bottomLeft(), lumaArea.bottomRight() }; + for (int n = 0; n < 5; n++) + { + if (vaildNum < sizeMode) + { +#if JVET_AI0136_ADAPTIVE_DUAL_TREE + const PredictionUnit* lumaPU = (CS::isDualITree(*pu.cs) || (pu.cu->isSST && pu.cu->separateTree)) + ? pu.cs->getLumaPU(posList[n], CHANNEL_TYPE_LUMA) + : pu.cs->getPU(posList[n], CHANNEL_TYPE_LUMA); +#else + const PredictionUnit* lumaPU = pu.cs->picture->cs->getPU(posList[n], CHANNEL_TYPE_LUMA); +#endif + if (lumaPU->cu->timd || lumaPU->cu->tmrlFlag) + { + chromaDirMode = MAP131TO67(PU::getIntraDirLuma(*lumaPU, 0)); + } + else + { + chromaDirMode = PU::getIntraDirLuma(*lumaPU, 0); + } + if (hasMode[chromaDirMode] == false) + { + hasMode[chromaDirMode] = true; + tmrlIntraList[vaildNum] = chromaDirMode; + vaildNum++; + } + } + } + + // get neighboring modes + const Position posCand[5] = + { + pu.chromaPos().offset(-1, area.height - 1), + pu.chromaPos().offset(area.width - 1, -1), + pu.chromaPos().offset(-1, area.height), + pu.chromaPos().offset(area.width, -1), + pu.chromaPos().offset(-1, -1) + }; + + for (const Position& posLT : posCand) + { + if (vaildNum < sizeMode) + { + const PredictionUnit* puRef = PU::getPUFromPos(pu, CHANNEL_TYPE_CHROMA, posLT); +#if JVET_AH0136_CHROMA_REORDERING +#if JVET_AI0136_ADAPTIVE_DUAL_TREE + if (puRef != nullptr && CU::isIntra(*puRef->cu) && !PU::isLMCMode(puRef->intraDir[1]) && !PU::isDbvMode(puRef->intraDir[1]) + && (puRef->intraDir[1] != DM_CHROMA_IDX || puRef->cu->slice->isIntra()) + && (puRef->intraDir[1] != DIMD_CHROMA_IDX || puRef->cu->slice->isIntra())) +#else + if (puRef != nullptr && CU::isIntra(*puRef->cu) && !PU::isLMCMode(puRef->intraDir[1]) && !PU::isDbvMode(puRef->intraDir[1])) +#endif +#else + if (puRef != nullptr && CU::isIntra(*puRef->cu) && !PU::isLMCMode(puRef->intraDir[1]) && puRef->intraDir[1] != DBV_CHROMA_IDX) +#endif + { + chromaDirMode = PU::getFinalIntraMode(*puRef, CHANNEL_TYPE_CHROMA); + if (hasMode[chromaDirMode] == false) + { + hasMode[chromaDirMode] = true; + tmrlIntraList[vaildNum] = chromaDirMode; + vaildNum++; + } + } + } + } + + fillMPMList(pu, tmrlIntraList, sizeMode, vaildNum, false); +} +void IntraPrediction::predChromaTmrlIntraAng(PredictionUnit& pu, const ComponentID compID, Pel* pPred, uint32_t uiStride) +{ + const CPelBuf& srcBuf = CPelBuf(m_refBuffer[compID][0], m_refBufferStride[compID], 2); + const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compID)); + + switch (pu.intraDir[1]) + { + case(DC_IDX): xPredTmrlIntraDc(srcBuf, pPred, uiStride); break; + default: xPredTmrlIntraAng(srcBuf, clpRng, pPred, uiStride); break; + } +} +void IntraPrediction::getChromaTmrlList(const CPelBuf& recoBufY, const CPelBuf& recoBufCb, const CPelBuf& recoBufCr, const CompArea& areaY, const CompArea& areaCb, const CompArea& areaCr, CodingUnit& cu, PredictionUnit& pu + , InterPrediction* pcInterPred) +{ + if (!CS::isDualITree(*pu.cs) || !pu.cs->sps->getUseTmrl()) + { + return; + } + // step-1. prepare buffers, cost functions, initialize size. + UnitArea area(CHROMA_420, areaY); + CodingUnit lumaCU(area); + PredictionUnit lumaPU(area); + lumaPU.cu = &lumaCU; + lumaCU.firstPU = &lumaPU; + lumaCU.cs = cu.cs; + lumaPU.cs = pu.cs; + lumaCU.slice = cu.slice; +#if JVET_AI0136_ADAPTIVE_DUAL_TREE + lumaCU.isSST = cu.isSST; + lumaCU.separateTree = cu.separateTree; +#endif + int width = areaY.width; + int height = areaY.height; + const UnitArea localUnitArea(CHROMA_420, Area(0, 0, width, height)); + PelBuf predY = m_tempBuffer[0].getBuf(localUnitArea.Y()); + DistParam cDistParamSatd; + m_timdSatdCost->setDistParam(cDistParamSatd, recoBufY, predY, pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, true); + cDistParamSatd.applyWeight = false; + cDistParamSatd.useMR = false; + + int intraDir = pu.intraDir[1]; + tmrlInfo.uiWidth = areaCb.width; + tmrlInfo.uiHeight = areaCb.height; + tmrlInfo.uiTemplateAbove = TMRL_TPL_SIZE; + tmrlInfo.uiTemplateLeft = TMRL_TPL_SIZE; + tmrlInfo.uiRefWidth = areaCb.width + TMRL_TPL_SIZE; + tmrlInfo.uiRefHeight = areaCb.height + TMRL_TPL_SIZE; + int line = TMRL_TPL_SIZE; + const UnitArea localUnitArea2(CHROMA_420, Area(0, 0, (areaCb.width + line) * 2, (areaCb.height + line) * 2)); + PelBuf predCb = m_tempBuffer[0].getBuf(localUnitArea2.Cb()); + PelBuf predCr = m_tempBuffer[0].getBuf(localUnitArea2.Cr()); + int iRefX = 0; + int iRefY = 0; + uint32_t uiRefWidth = 0; + uint32_t uiRefHeight = 0; + TemplateType eTplType = CU::deriveTimdRefType(areaCb.x, areaCb.y, areaCb.width, areaCb.height, line, line, iRefX, + iRefY, uiRefWidth, uiRefHeight); + const Pel* piCb = recoBufCb.buf; + int iCbStride = recoBufCb.stride; + piCb += (iRefY - areaCb.y) * iCbStride + (iRefX - areaCb.x); + const Pel* piCr = recoBufCr.buf; + int iCrStride = recoBufCr.stride; + piCr += (iRefY - areaCr.y) * iCrStride + (iRefX - areaCr.x); + + DistParam distParamSatd[2][2]; // above, left + distParamSatd[0][0].applyWeight = false; + distParamSatd[0][0].useMR = false; + distParamSatd[0][1].applyWeight = false; + distParamSatd[0][1].useMR = false; + distParamSatd[1][0].applyWeight = false; + distParamSatd[1][0].useMR = false; + distParamSatd[1][1].applyWeight = false; + distParamSatd[1][1].useMR = false; + if (eTplType == LEFT_ABOVE_NEIGHBOR) + { + m_timdSatdCost->setTimdDistParam(distParamSatd[0][0], piCb + line, predCb.buf + line, iCbStride, predCb.stride, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, areaCb.width, line, 0, 1, false); + m_timdSatdCost->setTimdDistParam(distParamSatd[0][1], piCb + line * iCbStride, predCb.buf + line * predCb.stride, iCbStride, predCb.stride, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, line, areaCb.height, 0, 1, false); + m_timdSatdCost->setTimdDistParam(distParamSatd[1][0], piCr + line, predCr.buf + line, iCrStride, predCr.stride, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, areaCr.width, line, 0, 1, false); + m_timdSatdCost->setTimdDistParam(distParamSatd[1][1], piCr + line * iCrStride, predCr.buf + line * predCr.stride, iCrStride, predCr.stride, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, line, areaCr.height, 0, 1, false); + } + else if (eTplType == LEFT_NEIGHBOR) + { + m_timdSatdCost->setTimdDistParam(distParamSatd[0][1], piCb, predCb.buf + line * predCb.stride, iCbStride, predCb.stride, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, line, areaCb.height, 0, 1, false); + m_timdSatdCost->setTimdDistParam(distParamSatd[1][1], piCr, predCr.buf + line * predCr.stride, iCrStride, predCr.stride, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, line, areaCr.height, 0, 1, false); + } + else if (eTplType == ABOVE_NEIGHBOR) + { + m_timdSatdCost->setTimdDistParam(distParamSatd[0][0], piCb, predCb.buf + line, iCbStride, predCb.stride, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, areaCb.width, line, 0, 1, false); + m_timdSatdCost->setTimdDistParam(distParamSatd[1][0], piCr, predCr.buf + line, iCrStride, predCr.stride, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, areaCr.width, line, 0, 1, false); + } + + int logW = floorLog2(areaCb.width); + int logH = floorLog2(areaCb.height); + int logN = floorLog2(line); + + // step-2. define search range. + int8_t tmrlRefList[MAX_CHROMA_MRL_IDX]{ 0 }; + uint8_t tmrlIntraModeList[NUM_LUMA_MODE]{ 0 }; + uint8_t sizeRef, sizeMode; + getChromaTmrlSearchRange(pu, tmrlRefList, tmrlIntraModeList, sizeRef, sizeMode); + + // step-3. search and sort + static_vector<TmrlMode, MRL_LIST_SIZE> uiModeList; + static_vector<uint64_t, MRL_LIST_SIZE> uiCostList; + + int iBestN = CHROMA_TMRL_LIST_SIZE; + + if (!pu.cs->pcv->isEncoder) + { + iBestN = pu.chromaTmrlIdx + 1; + } + + for (uint8_t refIdx = 0; refIdx < sizeRef; refIdx++) + { + lumaPU.multiRefIdx = tmrlRefList[refIdx] << 1; + m_topRefLength = (areaCb.width + line) << 1; + m_leftRefLength = (areaCb.height + line) << 1; + pu.chromaMrlIdx = tmrlRefList[refIdx]; + xFillReferenceSamples(recoBufCb, m_refBuffer[COMPONENT_Cb][PRED_BUF_UNFILTERED], areaCb, *pu.cu); + xFillReferenceSamples(recoBufCr, m_refBuffer[COMPONENT_Cr][PRED_BUF_UNFILTERED], areaCr, *pu.cu); + for (uint8_t modeIdx = 0; modeIdx < sizeMode; modeIdx++) + { + Distortion uiCost = 0; + lumaPU.intraDir[0] = tmrlIntraModeList[modeIdx]; + // pred co-located luma area + predCoLuma(areaY, recoBufY, lumaPU, lumaPU.intraDir[0], predY, pcInterPred, cu); + uiCost += cDistParamSatd.distFunc(cDistParamSatd); + + // chroma + m_topRefLength = (areaCb.width + line) << 1; + m_leftRefLength = (areaCb.height + line) << 1; + pu.intraDir[1] = tmrlIntraModeList[modeIdx]; + if (eTplType != NO_NEIGHBOR) + { + Distortion costCbA = 0; + Distortion costCbL = 0; + Distortion costCrA = 0; + Distortion costCrL = 0; + initPredIntraParams(pu, areaCb, *(pu.cs->sps)); + predChromaTmrlIntraAng(pu, COMPONENT_Cb, predCb.buf, predCb.stride); + initPredIntraParams(pu, areaCr, *(pu.cs->sps)); + predChromaTmrlIntraAng(pu, COMPONENT_Cr, predCr.buf, predCr.stride); + + if (eTplType == LEFT_ABOVE_NEIGHBOR) + { + costCbA += distParamSatd[0][0].distFunc(distParamSatd[0][0]); + costCbL += distParamSatd[0][1].distFunc(distParamSatd[0][1]); + + costCrA += distParamSatd[1][0].distFunc(distParamSatd[1][0]); + costCrL += distParamSatd[1][1].distFunc(distParamSatd[1][1]); + uiCost += 8 * uiCost + ((costCbA + costCrA) << (logH + 2 - logN)) + ((costCbL + costCrL) << (logW + 2 - logN)); + } + else if (eTplType == LEFT_NEIGHBOR) + { + costCbL += distParamSatd[0][1].distFunc(distParamSatd[0][1]); + costCrL += distParamSatd[1][1].distFunc(distParamSatd[1][1]); + uiCost += 8 * uiCost + ((costCbL + costCrL) << (logW + 2 - logN)); + } + else if (eTplType == ABOVE_NEIGHBOR) + { + costCbA += distParamSatd[0][0].distFunc(distParamSatd[0][0]); + costCrA += distParamSatd[1][0].distFunc(distParamSatd[1][0]); + uiCost += 8 * uiCost + ((costCbA + costCrA) << (logH + 2 - logN)); + } + else + { + CHECK(true, "wrong template type!"); + } + } + + if (uiCostList.size() >= iBestN) + { + uint64_t uiCostMax = uiCostList[iBestN - 1]; + if (uiCost > uiCostMax) + { + continue; + } + } + updateCandList(TmrlMode(tmrlRefList[refIdx], tmrlIntraModeList[modeIdx]), uiCost, uiModeList, uiCostList, iBestN); + } + } + + // step-4. fill the list + for (auto i = 0; i < uiModeList.size(); i++) + { + m_chromaTmrlList[i] = uiModeList[i]; + } + pu.chromaMrlIdx = 0; + pu.intraDir[1] = intraDir; +} +#endif + #if JVET_AG0058_EIP int64_t IntraPrediction::calcAeipGroupSum(const Pel* src1, const Pel* src2, const int numSamples) { diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index 486b1f6e9..b833e2b26 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -940,6 +940,12 @@ public: void getTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlRefList, uint8_t* tmrlIntraList, uint8_t& sizeRef, uint8_t& sizeMode); TmrlMode m_tmrlList[MRL_LIST_SIZE]; void getTmrlList(CodingUnit& cu); +#if JVET_AJ0081_CHROMA_TMRL + TmrlMode m_chromaTmrlList[CHROMA_TMRL_LIST_SIZE]; + void getChromaTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlRefList, uint8_t* tmrlIntraList, uint8_t& sizeRef, uint8_t& sizeMode); + void predChromaTmrlIntraAng(PredictionUnit& pu, const ComponentID compID, Pel* pPred, uint32_t uiStride); + void getChromaTmrlList(const CPelBuf& recoBufY, const CPelBuf& recoBufCb, const CPelBuf& recoBufCr, const CompArea& areaY, const CompArea& areaCb, const CompArea& areaCr, CodingUnit& cu, PredictionUnit& pu, InterPrediction* pcInterPred); +#endif #endif #if JVET_AG0058_EIP void initEipParams(const PredictionUnit& pu, const ComponentID compId); diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 8d1d8515f..b46230864 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -194,6 +194,7 @@ #if JVET_AB0157_TMRL #define JVET_AD0082_TMRL_CONFIG 1 // JVET-AD0082: a configuration option for TMRL #define JVET_AD0085_TMRL_EXTENSION 1 // JVET-AD0085: TMRL angular extension and intra candidate list modifications +#define JVET_AJ0081_CHROMA_TMRL 1 // JVET-AJ0081: Chroma TMRL #endif #define JVET_AB0157_INTRA_FUSION 1 // JVET-AB0157: Intra prediction fusion #define JVET_AC0094_REF_SAMPLES_OPT 1 // JVET-AC0094: Optimizing the use of reference samples diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 071886416..98d850376 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -1101,6 +1101,11 @@ void PredictionUnit::initData() #if JVET_AG0059_CCP_MERGE_ENHANCEMENT ccpMergeFusionFlag = 0; ccpMergeFusionType = 0; +#endif +#if JVET_AJ0081_CHROMA_TMRL + chromaMrlIdx = 0; + chromaTmrlFlag = false; + chromaTmrlIdx = 0; #endif // inter data #if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION @@ -1323,6 +1328,11 @@ PredictionUnit& PredictionUnit::operator=(const IntraPredictionData& predData) #if JVET_AG0059_CCP_MERGE_ENHANCEMENT ccpMergeFusionFlag = predData.ccpMergeFusionFlag; ccpMergeFusionType = predData.ccpMergeFusionType; +#endif +#if JVET_AJ0081_CHROMA_TMRL + chromaMrlIdx = predData.chromaMrlIdx; + chromaTmrlFlag = predData.chromaTmrlFlag; + chromaTmrlIdx = predData.chromaTmrlIdx; #endif return *this; } @@ -1555,6 +1565,11 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other ) #if JVET_AG0059_CCP_MERGE_ENHANCEMENT ccpMergeFusionFlag = other.ccpMergeFusionFlag; ccpMergeFusionType = other.ccpMergeFusionType; +#endif +#if JVET_AJ0081_CHROMA_TMRL + chromaMrlIdx = other.chromaMrlIdx; + chromaTmrlFlag = other.chromaTmrlFlag; + chromaTmrlIdx = other.chromaTmrlIdx; #endif mergeFlag = other.mergeFlag; #if JVET_AG0276_LIC_FLAG_SIGNALING diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index fb1d0386e..e62a44e5b 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -638,6 +638,11 @@ struct IntraPredictionData int ccpMergeFusionFlag; int ccpMergeFusionType; #endif +#if JVET_AJ0081_CHROMA_TMRL + int chromaMrlIdx; + bool chromaTmrlFlag; + int chromaTmrlIdx; +#endif }; struct InterPredictionData diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index ae9b12e7a..7d0faa132 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -3752,6 +3752,23 @@ bool PU::hasCCPMergeFusionFlag(const PredictionUnit& pu) } #endif +#if JVET_AJ0081_CHROMA_TMRL +bool PU::hasChromaTmrl(const PredictionUnit& pu) +{ + if (CS::isDualITree(*pu.cs)) + { + bool hasChromaTmrl = true; + int aboveLines = pu.block(COMPONENT_Cb).y; + if (aboveLines < 4) + { + hasChromaTmrl = false; + } + return hasChromaTmrl; + } + return false; +} +#endif + #if JVET_AC0071_DBV bool PU::hasChromaBvFlag(const PredictionUnit &pu) { diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index c55bc2be0..49b8239e1 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -963,6 +963,9 @@ namespace PU #if JVET_AG0059_CCP_MERGE_ENHANCEMENT bool hasCCPMergeFusionFlag(const PredictionUnit& pu); #endif +#if JVET_AJ0081_CHROMA_TMRL + bool hasChromaTmrl(const PredictionUnit& pu); +#endif #if JVET_AC0071_DBV bool hasChromaBvFlag(const PredictionUnit &pu); #endif diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 02de8efb9..c5745f088 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -3363,6 +3363,19 @@ void CABACReader::intraChromaFusionMode(PredictionUnit& pu) } #endif +#if JVET_AJ0081_CHROMA_TMRL +void CABACReader::intraChromaTmrl(PredictionUnit& pu) +{ + pu.chromaTmrlIdx = 0; + pu.chromaTmrlFlag = bool(m_BinDecoder.decodeBin(Ctx::ChromaTmrlFlag())); + if (pu.chromaTmrlFlag) + { + pu.chromaTmrlIdx = unary_max_eqprob(CHROMA_TMRL_LIST_SIZE - 1); + } + DTRACE(g_trace_ctx, D_SYNTAX, "intraChromaTmrl() ctx=%d pos=(%d,%d) chromaTmrlFlag=%d chromaTmrlIdx=%d\n", 0, pu.blocks[CHANNEL_TYPE_CHROMA].x, pu.blocks[CHANNEL_TYPE_CHROMA].y, pu.chromaTmrlFlag ? 1 : 0, pu.chromaTmrlIdx); +} +#endif + void CABACReader::intra_chroma_pred_mode(PredictionUnit& pu) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2(STATS__CABAC_BITS__INTRA_DIR_ANG, pu.cu->blocks[pu.chType].lumaSize(), CHANNEL_TYPE_CHROMA); @@ -3389,6 +3402,18 @@ void CABACReader::intra_chroma_pred_mode(PredictionUnit& pu) } } +#if JVET_AJ0081_CHROMA_TMRL + if (PU::hasChromaTmrl(pu) && pu.cs->sps->getUseTmrl()) + { + intraChromaTmrl(pu); + if (pu.chromaTmrlFlag) + { + CHECK(pu.chromaTmrlIdx >= CHROMA_TMRL_LIST_SIZE, "Chroma tmrl index out of bounds"); + return; + } + } +#endif + #if JVET_AC0071_DBV if (PU::hasChromaBvFlag(pu)) { diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 0696b2e94..882603215 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -134,6 +134,9 @@ public: #endif #if JVET_AB0157_TMRL void cuTmrlFlag ( CodingUnit& cu ); +#if JVET_AJ0081_CHROMA_TMRL + void intraChromaTmrl ( PredictionUnit& pu ); +#endif #endif void intra_chroma_pred_modes ( CodingUnit& cu ); bool intra_chroma_lmc_mode ( PredictionUnit& pu ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 606cc7859..4ce223339 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -668,11 +668,19 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) #if JVET_AG0059_CCP_MERGE_ENHANCEMENT #if JVET_AH0136_CHROMA_REORDERING #if JVET_AI0136_ADAPTIVE_DUAL_TREE - if ( ( (!PU::isLMCMode(pu.intraDir[1]) && compID == COMPONENT_Cb && !pu.cu->bdpcmModeChroma) - && (CS::isDualITree(cs) || (pu.cu->isSST && pu.cu->separateTree) ) && pu.cs->sps->getUseChromaReordering() && pu.cs->slice->isIntra() - ) +#if JVET_AJ0081_CHROMA_TMRL + if (((!PU::isLMCMode(pu.intraDir[1]) && compID == COMPONENT_Cb && !pu.cu->bdpcmModeChroma) + && (CS::isDualITree(cs) || (pu.cu->isSST && pu.cu->separateTree)) && pu.cs->sps->getUseChromaReordering() && pu.cs->slice->isIntra() + ) + || ((pu.intraDir[1] == DIMD_CHROMA_IDX || pu.ccpMergeFusionType == 1 || pu.chromaTmrlFlag) && compID == COMPONENT_Cb) + ) +#else + if (((!PU::isLMCMode(pu.intraDir[1]) && compID == COMPONENT_Cb && !pu.cu->bdpcmModeChroma) + && (CS::isDualITree(cs) || (pu.cu->isSST && pu.cu->separateTree)) && pu.cs->sps->getUseChromaReordering() && pu.cs->slice->isIntra() + ) || ((pu.intraDir[1] == DIMD_CHROMA_IDX || pu.ccpMergeFusionType == 1) && compID == COMPONENT_Cb) ) +#endif #else if (((!PU::isLMCMode(pu.intraDir[1]) && compID == COMPONENT_Cb && !pu.cu->bdpcmModeChroma) && CS::isDualITree(cs) && pu.cs->sps->getUseChromaReordering()) || ((pu.intraDir[1] == DIMD_CHROMA_IDX || pu.ccpMergeFusionType == 1) && compID == COMPONENT_Cb)) #endif @@ -702,12 +710,31 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) #endif } #endif +#if JVET_AJ0081_CHROMA_TMRL + if (pu.chromaTmrlFlag && compID == COMPONENT_Cb && CS::isDualITree(cs)) + { + CompArea areaCb = pu.Cb(); + CompArea areaCr = pu.Cr(); + CompArea lumaArea = CompArea(COMPONENT_Y, pu.chromaFormat, areaCb.lumaPos(), recalcSize(pu.chromaFormat, CHANNEL_TYPE_CHROMA, CHANNEL_TYPE_LUMA, areaCb.size())); + m_pcIntraPred->getChromaTmrlList(cs.picture->getRecoBuf(lumaArea), cs.picture->getRecoBuf(areaCb), cs.picture->getRecoBuf(areaCr), lumaArea, areaCb, areaCr, *pu.cu, pu, m_pcInterPred); + pu.chromaMrlIdx = m_pcIntraPred->m_chromaTmrlList[pu.chromaTmrlIdx].multiRefIdx; + pu.intraDir[1] = m_pcIntraPred->m_chromaTmrlList[pu.chromaTmrlIdx].intraDir; + CHECK(pu.intraDir[1] >= NUM_LUMA_MODE, "error intra mode") + } +#endif #if JVET_AH0136_CHROMA_REORDERING #if JVET_AI0136_ADAPTIVE_DUAL_TREE +#if JVET_AJ0081_CHROMA_TMRL if ( - (!PU::isLMCMode(pu.intraDir[1]) && compID == COMPONENT_Cb && !pu.cu->bdpcmModeChroma) - && (CS::isDualITree(cs) || (pu.cu->isSST && pu.cu->separateTree) ) && pu.cs->sps->getUseChromaReordering() && pu.cu->slice->isIntra() + (!PU::isLMCMode(pu.intraDir[1]) && !pu.chromaTmrlFlag && compID == COMPONENT_Cb && !pu.cu->bdpcmModeChroma) + && (CS::isDualITree(cs) || (pu.cu->isSST && pu.cu->separateTree)) && pu.cs->sps->getUseChromaReordering() && pu.cu->slice->isIntra() ) +#else + if ( + (!PU::isLMCMode(pu.intraDir[1]) && compID == COMPONENT_Cb && !pu.cu->bdpcmModeChroma) + && (CS::isDualITree(cs) || (pu.cu->isSST && pu.cu->separateTree)) && pu.cs->sps->getUseChromaReordering() && pu.cu->slice->isIntra() + ) +#endif #else if ((!PU::isLMCMode(pu.intraDir[1]) && compID == COMPONENT_Cb && !pu.cu->bdpcmModeChroma) && CS::isDualITree(cs) && pu.cs->sps->getUseChromaReordering()) #endif diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 125796186..a3a12b0b4 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -3050,6 +3050,19 @@ void CABACWriter::intraChromaFusionMode(const PredictionUnit& pu) } #endif +#if JVET_AJ0081_CHROMA_TMRL +void CABACWriter::intraChromaTmrl(const PredictionUnit& pu) +{ + m_BinEncoder.encodeBin(pu.chromaTmrlFlag ? 1 : 0, Ctx::ChromaTmrlFlag()); + if (pu.chromaTmrlFlag) + { + CHECK(pu.chromaTmrlIdx >= CHROMA_TMRL_LIST_SIZE, "Chroma tmrl index out of bounds"); + unary_max_eqprob(pu.chromaTmrlIdx, CHROMA_TMRL_LIST_SIZE - 1); + } + DTRACE(g_trace_ctx, D_SYNTAX, "intraChromaTmrl() ctx=%d pos=(%d,%d) chromaTmrlFlag=%d chromaTmrlIdx=%d\n", 0, pu.blocks[CHANNEL_TYPE_CHROMA].x, pu.blocks[CHANNEL_TYPE_CHROMA].y, pu.chromaTmrlFlag ? 1 : 0, pu.chromaTmrlIdx); +} +#endif + #if JVET_AD0120_LBCCP void CABACWriter::ccInsideFilterFlag(const PredictionUnit &pu) { @@ -3093,6 +3106,17 @@ void CABACWriter::intra_chroma_pred_mode(const PredictionUnit& pu) } } +#if JVET_AJ0081_CHROMA_TMRL + if (PU::hasChromaTmrl(pu) && pu.cs->sps->getUseTmrl()) + { + intraChromaTmrl(pu); + if (pu.chromaTmrlFlag) + { + return; + } + } +#endif + #if JVET_AC0071_DBV #if JVET_AH0136_CHROMA_REORDERING bool hasDBV = false; diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 2460594ca..cc52dfb8f 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -170,6 +170,9 @@ public: #endif #if JVET_AB0157_TMRL void cuTmrlFlag ( const CodingUnit& cu ); +#if JVET_AJ0081_CHROMA_TMRL + void intraChromaTmrl ( const PredictionUnit& pu ); +#endif #endif void intra_chroma_pred_modes ( const CodingUnit& cu ); void intra_chroma_lmc_mode ( const PredictionUnit& pu ); diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 7afe537db..81a2b847f 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -3518,6 +3518,22 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS dimdChromaMode = cu.dimdChromaMode; dimdChromaModeSecond = cu.dimdChromaModeSecond; +#if JVET_AJ0081_CHROMA_TMRL + if (tempCS->slice->getSPS()->getUseTmrl()) + { + PredictionUnit pu(tempCS->area); + pu.cu = &cu; + cu.firstPU = &pu; + pu.cs = bestCS; + cu.cs = bestCS; + + if (PU::hasChromaTmrl(pu)) + { + m_pcIntraSearch->getChromaTmrlList(bestCS->picture->getRecoBuf(lumaArea), bestCS->picture->getRecoBuf(areaCb), bestCS->picture->getRecoBuf(areaCr), lumaArea, areaCb, areaCr, cu, pu, m_pcInterSearch); + } + } +#endif + #if JVET_AH0136_CHROMA_REORDERING for (int i = 0; i < 5; i++) { diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index d180b2b11..4d0e0cfda 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -207,6 +207,13 @@ void IntraSearch::destroy() m_pSharedPredTransformSkip[ch] = nullptr; } +#if JVET_AJ0081_CHROMA_TMRL + for (uint32_t i = 0; i < CHROMA_TMRL_LIST_SIZE; i++) + { + m_chromaMrlStorage[i].destroy(); + } +#endif + #if JVET_AC0119_LM_CHROMA_FUSION for (uint32_t i = 0; i < 2; i++) { @@ -382,6 +389,13 @@ void IntraSearch::init( EncCfg* pcEncCfg, m_tmpStorageLCU.create(UnitArea(cform, Area(0, 0, maxCUWidth, maxCUHeight))); m_colorTransResiBuf.create(UnitArea(cform, Area(0, 0, maxCUWidth, maxCUHeight))); +#if JVET_AJ0081_CHROMA_TMRL + for (uint32_t i = 0; i < CHROMA_TMRL_LIST_SIZE; i++) + { + m_chromaMrlStorage[i].create(UnitArea(cform, Area(0, 0, maxCUWidth, maxCUHeight))); + } +#endif + #if JVET_AC0119_LM_CHROMA_FUSION for (uint32_t i = 0; i < 2; i++) { @@ -4192,6 +4206,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner int bestCcpMergeFusionFlag = 0; int bestCcpMergeFusionType = 0; #endif +#if JVET_AJ0081_CHROMA_TMRL + bool bestChromaTmrlFlag = false; + int bestChromaTmrlIdx = 0; +#endif //----- init mode list ---- { @@ -5517,6 +5535,13 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner fusionStorage[i] = m_fusionStorage[i].getBuf(localArea); } #endif +#if JVET_AJ0081_CHROMA_TMRL + PelUnitBuf chromaMrlStorage[CHROMA_TMRL_LIST_SIZE]; + for (uint32_t i = 0; i < CHROMA_TMRL_LIST_SIZE; i++) + { + chromaMrlStorage[i] = m_chromaMrlStorage[i].getBuf(localArea); + } +#endif #if JVET_AF0066_ENABLE_DBV_4_SINGLE_TREE if (singleTreeLumaIntraTmp) { @@ -6039,6 +6064,209 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner cs.setDecomp(pu.Cb(), false); #endif +#if JVET_AJ0081_CHROMA_TMRL + pu.chromaTmrlFlag = false; + pu.chromaTmrlIdx = 0; + if (PU::hasChromaTmrl(pu) && pu.cs->sps->getUseTmrl()) + { + pu.chromaTmrlFlag = true; + bool mrlIsEnable[CHROMA_TMRL_LIST_SIZE]; + int32_t mrlMap[CHROMA_TMRL_LIST_SIZE][2]; + double satdChromaMrlCost[CHROMA_TMRL_LIST_SIZE]; + int satdChromaMrlList[CHROMA_TMRL_LIST_SIZE]; + const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda() * FRAC_BITS_SCALE; + for (int i = 0; i < CHROMA_TMRL_LIST_SIZE; i++) + { + mrlIsEnable[i] = false; + mrlMap[i][0] = mrlMap[i][1] = 0; + satdChromaMrlCost[i] = MAX_DOUBLE; + satdChromaMrlList[i] = i; + } + + Distortion sad = 0; + Distortion sadCb = 0, satdCb = 0; + Distortion sadCr = 0, satdCr = 0; + CodingStructure& cs = *(pu.cs); + DistParam distParamSadCb, distParamSatdCb; + DistParam distParamSadCr, distParamSatdCr; + + m_pcRdCost->setDistParam(distParamSadCb, cs.getOrgBuf(pu.Cb()), chromaMrlStorage[0].Cb(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, false); + m_pcRdCost->setDistParam(distParamSatdCb, cs.getOrgBuf(pu.Cb()), chromaMrlStorage[0].Cb(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, true); + m_pcRdCost->setDistParam(distParamSadCr, cs.getOrgBuf(pu.Cr()), chromaMrlStorage[0].Cr(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, false); + m_pcRdCost->setDistParam(distParamSatdCr, cs.getOrgBuf(pu.Cr()), chromaMrlStorage[0].Cr(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, true); + + distParamSadCb.applyWeight = false; + distParamSatdCb.applyWeight = false; + distParamSadCr.applyWeight = false; + distParamSatdCr.applyWeight = false; + + for (auto multiRefIdx : CHROMA_MULTI_REF_LINE_IDX) + { + pu.chromaMrlIdx = multiRefIdx; + initIntraPatternChType(cu, pu.Cb()); + initIntraPatternChType(cu, pu.Cr()); + + for (auto i = 0; i < CHROMA_TMRL_LIST_SIZE; i++) + { + if (m_chromaTmrlList[i].multiRefIdx != multiRefIdx) + { + continue; + } + pu.intraDir[1] = m_chromaTmrlList[i].intraDir; + pu.chromaTmrlIdx = i; + initPredIntraParams(pu, pu.Cb(), *pu.cs->sps); + predIntraAng(COMPONENT_Cb, chromaMrlStorage[i].Cb(), pu); + initPredIntraParams(pu, pu.Cr(), *pu.cs->sps); + predIntraAng(COMPONENT_Cr, chromaMrlStorage[i].Cr(), pu); + + distParamSadCb.cur = chromaMrlStorage[i].Cb(); + distParamSatdCb.cur = chromaMrlStorage[i].Cb(); + distParamSadCr.cur = chromaMrlStorage[i].Cr(); + distParamSatdCr.cur = chromaMrlStorage[i].Cr(); + + sadCb = distParamSadCb.distFunc(distParamSadCb) * 2; + satdCb = distParamSatdCb.distFunc(distParamSatdCb); + sad = std::min(sadCb, satdCb); + sadCr = distParamSadCr.distFunc(distParamSadCr) * 2; + satdCr = distParamSatdCr.distFunc(distParamSatdCr); + sad += std::min(sadCr, satdCr); + + m_CABACEstimator->getCtx() = ctxStart; + m_CABACEstimator->resetBits(); + m_CABACEstimator->intraChromaTmrl(pu); + uint64_t estbits = m_CABACEstimator->getEstFracBits(); + double curCost = (double)sad + sqrtLambdaForFirstPass * (double)estbits; + + mrlMap[i][0] = pu.intraDir[1]; + mrlMap[i][1] = pu.chromaMrlIdx; + satdChromaMrlCost[i] = curCost; + mrlIsEnable[i] = true; + } + } + + for (int i = 0; i < 1; i++) + { + for (int j = i + 1; j < CHROMA_TMRL_LIST_SIZE; j++) + { + if (satdChromaMrlCost[j] < satdChromaMrlCost[i]) + { + std::swap(satdChromaMrlList[i], satdChromaMrlList[j]); + std::swap(satdChromaMrlCost[i], satdChromaMrlCost[j]); + } + } + } + + for (int i = 1; i < CHROMA_TMRL_LIST_SIZE; i++) + { + mrlIsEnable[satdChromaMrlList[i]] = false; + } + for (int32_t lstIdx = 0; lstIdx < 1; lstIdx++) + { + int iModedx = satdChromaMrlList[lstIdx]; + pu.chromaTmrlIdx = iModedx; + if (!mrlIsEnable[iModedx]) + { + break; + } + int chromaIntraMode = mrlMap[iModedx][0]; + pu.chromaMrlIdx = mrlMap[iModedx][1]; + cs.setDecomp(pu.Cb(), false); + cs.dist = baseDist; + //----- restore context models ----- + m_CABACEstimator->getCtx() = ctxStart; + + //----- chroma coding ----- + pu.intraDir[1] = chromaIntraMode; + xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType + , chromaMrlStorage[iModedx] +#if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS + , pcInterPred +#endif + ); + 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 JVET_AG0154_DECODER_DERIVED_CCP_FUSION + if (uiDist < bestDist) + { + bestDist = uiDist; + } +#endif + 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)); +#if JVET_Z0118_GDR + cs.updateReconMotIPM(area); +#else + cs.picture->getRecoBuf(area).copyFrom(cs.getRecoBuf(area)); +#endif + + 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; +#if JVET_Z0050_DIMD_CHROMA_FUSION + isChromaFusion = pu.isChromaFusion; +#endif + bestChromaTmrlFlag = pu.chromaTmrlFlag; + bestChromaTmrlIdx = pu.chromaTmrlIdx; +#if JVET_AD0188_CCP_MERGE + if (isChromaFusion == 1) + { + ccpModelBest = pu.curCand; + } + else + { + ccpModelBest.type = CCP_TYPE_NONE; + } +#endif + } + } + pu.chromaMrlIdx = 0; + pu.chromaTmrlFlag = false; + pu.chromaTmrlIdx = 0; + initPredIntraParams(pu, pu.Cb(), *pu.cs->sps); + Pel* refBufUnfiltered = m_refBuffer[COMPONENT_Cb][PRED_BUF_UNFILTERED]; + xFillReferenceSamples(cs.picture->getRecoBuf(cu.Cb()), refBufUnfiltered, cu.Cb(), cu); + initPredIntraParams(pu, pu.Cr(), *pu.cs->sps); + refBufUnfiltered = m_refBuffer[COMPONENT_Cr][PRED_BUF_UNFILTERED]; + xFillReferenceSamples(cs.picture->getRecoBuf(cu.Cr()), refBufUnfiltered, cu.Cr(), cu); + } + +#endif + #if JVET_Z0050_CCLM_SLOPE #if MMLM for (int32_t uiMode = 0; uiMode < 2; uiMode++) @@ -6132,6 +6360,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_Z0050_DIMD_CHROMA_FUSION isChromaFusion = pu.isChromaFusion; #endif +#if JVET_AJ0081_CHROMA_TMRL + bestChromaTmrlFlag = pu.chromaTmrlFlag; + bestChromaTmrlIdx = pu.chromaTmrlIdx; +#endif #if JVET_AA0126_GLM bestGlmIdc = pu.glmIdc; #endif @@ -6431,6 +6663,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_Z0050_DIMD_CHROMA_FUSION isChromaFusion = pu.isChromaFusion; #endif +#if JVET_AJ0081_CHROMA_TMRL + bestChromaTmrlFlag = pu.chromaTmrlFlag; + bestChromaTmrlIdx = pu.chromaTmrlIdx; +#endif #if JVET_Z0050_CCLM_SLOPE bestCclmOffsets = pu.cclmOffsets; #endif @@ -6632,6 +6868,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_Z0050_DIMD_CHROMA_FUSION isChromaFusion = pu.isChromaFusion; #endif +#if JVET_AJ0081_CHROMA_TMRL + bestChromaTmrlFlag = pu.chromaTmrlFlag; + bestChromaTmrlIdx = pu.chromaTmrlIdx; +#endif #if JVET_Z0050_CCLM_SLOPE bestCclmOffsets = pu.cclmOffsets; #endif @@ -7022,6 +7262,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_Z0050_DIMD_CHROMA_FUSION isChromaFusion = pu.isChromaFusion; #endif +#if JVET_AJ0081_CHROMA_TMRL + bestChromaTmrlFlag = pu.chromaTmrlFlag; + bestChromaTmrlIdx = pu.chromaTmrlIdx; +#endif #if JVET_Z0050_CCLM_SLOPE bestCclmOffsets = pu.cclmOffsets; #endif @@ -7129,6 +7373,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_Z0050_DIMD_CHROMA_FUSION isChromaFusion = pu.isChromaFusion; #endif +#if JVET_AJ0081_CHROMA_TMRL + bestChromaTmrlFlag = pu.chromaTmrlFlag; + bestChromaTmrlIdx = pu.chromaTmrlIdx; +#endif #if JVET_Z0050_CCLM_SLOPE bestCclmOffsets = pu.cclmOffsets; #endif @@ -7260,6 +7508,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_Z0050_DIMD_CHROMA_FUSION isChromaFusion = pu.isChromaFusion; #endif +#if JVET_AJ0081_CHROMA_TMRL + bestChromaTmrlFlag = pu.chromaTmrlFlag; + bestChromaTmrlIdx = pu.chromaTmrlIdx; +#endif #if JVET_Z0050_CCLM_SLOPE bestCclmOffsets = pu.cclmOffsets; #endif @@ -7385,6 +7637,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner bestBDPCMMode = cu.bdpcmModeChroma; #if JVET_Z0050_DIMD_CHROMA_FUSION isChromaFusion = 0; +#endif +#if JVET_AJ0081_CHROMA_TMRL + bestChromaTmrlFlag = false; + bestChromaTmrlIdx = 0; #endif decoderDerivedCcpModeBest = pu.decoderDerivedCcpMode; #if JVET_AA0057_CCCM @@ -7491,6 +7747,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_Z0050_DIMD_CHROMA_FUSION pu.isChromaFusion = isChromaFusion; #endif +#if JVET_AJ0081_CHROMA_TMRL + pu.chromaTmrlFlag = bestChromaTmrlFlag; + pu.chromaTmrlIdx = bestChromaTmrlIdx; +#endif #if JVET_AA0126_GLM pu.glmIdc = bestGlmIdc; #endif @@ -12621,6 +12881,15 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio } else { +#if JVET_AJ0081_CHROMA_TMRL + if (pu.cs->slice->isIntra() && pu.chromaTmrlFlag && !predStorage.bufs.empty()) + { + piPredCb.copyFrom(predStorage.Cb()); + piPredCr.copyFrom(predStorage.Cr()); + } + else + { +#endif #if JVET_AC0119_LM_CHROMA_FUSION if (pu.cs->slice->isIntra() && pu.isChromaFusion && !predStorage.bufs.empty()) { @@ -12680,6 +12949,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio #endif #if JVET_AC0119_LM_CHROMA_FUSION } +#endif +#if JVET_AJ0081_CHROMA_TMRL + } #endif } diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index bee4cf923..731b16b60 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -674,6 +674,10 @@ private: PelStorage m_fusionStorage[6]; #endif +#if JVET_AJ0081_CHROMA_TMRL + PelStorage m_chromaMrlStorage[CHROMA_TMRL_LIST_SIZE]; +#endif + #if JVET_AD0120_LBCCP PelStorage m_lmPredFiltStorage[LBCCP_FILTER_MMLMNUM]; struct lmPredFiltModeInfo -- GitLab