From 7b46c3c930bb20d5f45221bb87ca44d24787ffa5 Mon Sep 17 00:00:00 2001 From: Ramin Ghaznavi Youvalari <raminyouvalari@xiaomi.com> Date: Tue, 23 Apr 2024 10:59:11 +0000 Subject: [PATCH] JVET-AH0076 (Test 2.2): Occurrence-based intra coding --- source/Lib/CommonLib/CommonDef.h | 5 + source/Lib/CommonLib/Contexts.h | 3 + source/Lib/CommonLib/Contexts_ecm12.inl | 20 + source/Lib/CommonLib/Contexts_ecm13.inl | 25 + source/Lib/CommonLib/IntraPrediction.cpp | 965 ++++++++++++++++++++++- source/Lib/CommonLib/IntraPrediction.h | 5 + source/Lib/CommonLib/TypeDef.h | 1 + source/Lib/CommonLib/Unit.cpp | 18 + source/Lib/CommonLib/Unit.h | 6 + source/Lib/CommonLib/UnitTools.cpp | 205 +++++ source/Lib/CommonLib/UnitTools.h | 6 +- source/Lib/DecoderLib/CABACReader.cpp | 26 +- source/Lib/DecoderLib/CABACReader.h | 3 + source/Lib/DecoderLib/DecCu.cpp | 15 + source/Lib/EncoderLib/CABACWriter.cpp | 32 +- source/Lib/EncoderLib/CABACWriter.h | 3 + source/Lib/EncoderLib/EncCu.cpp | 42 +- source/Lib/EncoderLib/IntraSearch.cpp | 373 ++++++++- source/Lib/EncoderLib/IntraSearch.h | 8 + 19 files changed, 1737 insertions(+), 24 deletions(-) diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index afe29a101..7819b74f6 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -593,6 +593,11 @@ static const int LM_CHROMA_IDX = NUM_LUMA_MODE; ///< chroma mode index for deriv #if ENABLE_DIMD static const int DIMD_IDX = 99; ///< index for intra DIMD mode #endif +#if JVET_AH0076_OBIC +static const int OBIC_IDX = 250; +static const int OBIC_FUSION_NUM = 6; +static const int NUM_OBIC_CUS = 13 + 18; // (13: adjacent, 18: non-adjacent) +#endif #if JVET_AB0155_SGPM static const int SGPM_IDX = 200; ///< index for SGPM mode #endif diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index af293adb4..2ca8497de 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -723,6 +723,9 @@ public: #if ENABLE_DIMD static const CtxSet DimdFlag; #endif +#if JVET_AH0076_OBIC + static const CtxSet obicFlag; +#endif #if JVET_W0123_TIMD_FUSION static const CtxSet TimdFlag; #endif diff --git a/source/Lib/CommonLib/Contexts_ecm12.inl b/source/Lib/CommonLib/Contexts_ecm12.inl index 7d86bb30b..f7a15cabf 100644 --- a/source/Lib/CommonLib/Contexts_ecm12.inl +++ b/source/Lib/CommonLib/Contexts_ecm12.inl @@ -4983,5 +4983,25 @@ const CtxSet ContextSetCfg::CCPMergeFusionType = ContextSetCfg::addCtxSet({ { 107 }, }); #endif +#if JVET_AH0076_OBIC +const CtxSet ContextSetCfg::obicFlag = ContextSetCfg::addCtxSet +({ + { CNU, }, + { CNU, }, + { CNU, }, + { DWS, }, + { DWS, }, + { DWS, }, + { DWE, }, + { DWE, }, + { DWE, }, + { DWO, }, + { DWO, }, + { DWO, }, + { DWO, }, + { DWO, }, + { DWO, }, + }); +#endif // CONTEXTS WSA STOP #endif diff --git a/source/Lib/CommonLib/Contexts_ecm13.inl b/source/Lib/CommonLib/Contexts_ecm13.inl index e7ba65fbe..1b05c9d71 100644 --- a/source/Lib/CommonLib/Contexts_ecm13.inl +++ b/source/Lib/CommonLib/Contexts_ecm13.inl @@ -6273,5 +6273,30 @@ const CtxSet ContextSetCfg::CCPMergeFusionType = ContextSetCfg::addCtxSet({ { 119 }, }); #endif +#if JVET_AH0076_OBIC +const CtxSet ContextSetCfg::obicFlag = 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 ea9f99873..57b1fcc33 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -1496,14 +1496,21 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co #if ENABLE_DIMD #if JVET_AB0157_INTRA_FUSION +#if JVET_AH0076_OBIC + if (pu.cu->dimd && pu.cu->dimdBlending && isLuma(compID) && !pu.cu->obicFlag) +#else if (pu.cu->dimd && pu.cu->dimdBlending && isLuma(compID)) +#endif { int width = piPred.width; int height = piPred.height; const UnitArea localUnitArea( pu.chromaFormat, Area( 0, 0, width, height ) ); PelBuf planarBuffer = m_tempBuffer[0].getBuf( localUnitArea.Y() ); - +#if JVET_AH0076_OBIC + const bool applyPdpc = m_ipaParam.applyPDPC; + initIntraPatternChType(*pu.cu, pu.Y(), true, 0, false); +#endif #if JVET_AG0146_DIMD_ITMP_IBC if (pu.cu->isBvDimd && pu.cu->ispMode == 0) { @@ -1512,16 +1519,35 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co else { #endif +#if JVET_AH0076_OBIC + { + PredictionUnit puTmp = pu; + puTmp.intraDir[0] = PLANAR_IDX; + initPredIntraParams(puTmp, pu.Y(), *(pu.cs->sps)); + const CPelBuf &srcBuf = CPelBuf(getPredictorPtr(compID), srcStride, srcHStride); +#if JVET_AC0105_DIRECTIONAL_PLANAR + xPredIntraPlanar(srcBuf, planarBuffer, 0); +#else + xPredIntraPlanar(srcBuf, planarBuffer); +#endif + if (m_ipaParam.applyPDPC) + { + xIntraPredPlanarDcPdpc( srcBuf, planarBuffer.buf, planarBuffer.stride, width, height, false ); + } + } +#else #if JVET_AC0105_DIRECTIONAL_PLANAR xPredIntraPlanar(srcBuf, planarBuffer, 0); #else xPredIntraPlanar(srcBuf, planarBuffer); #endif +#endif #if JVET_AG0146_DIMD_ITMP_IBC } #endif - +#if !JVET_AH0076_OBIC const bool applyPdpc = m_ipaParam.applyPDPC; +#endif bool blendModes[DIMD_FUSION_NUM-2] = {false}; PelBuf predAngExtra[DIMD_FUSION_NUM-2]; @@ -1538,6 +1564,9 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co PredictionUnit puTmp = pu; puTmp.intraDir[0] = pu.cu->dimdBlendMode[i]; initPredIntraParams(puTmp, pu.Y(), *(pu.cs->sps)); +#if JVET_AH0076_OBIC + const CPelBuf &srcBuf = CPelBuf(getPredictorPtr(compID), srcStride, srcHStride); +#endif #if JVET_W0123_TIMD_FUSION xPredIntraAng(srcBuf, predAngExtra[i], channelType, clpRng, false, srcBuf2nd, pu.cu->ispMode!=NOT_INTRA_SUBPARTITIONS); #else @@ -1933,7 +1962,86 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co } #endif #endif - +#if JVET_AH0076_OBIC + if (pu.cu->obicFlag && pu.cu->obicIsBlended && isLuma(compID)) + { + int width = piPred.width; + int height = piPred.height; + const UnitArea localUnitArea( pu.chromaFormat, Area( 0, 0, width, height ) ); + bool blendModes[OBIC_FUSION_NUM-1] = {false}; + PelBuf predFusion[OBIC_FUSION_NUM-1]; + const bool applyPdpc = m_ipaParam.applyPDPC; + initIntraPatternChType(*pu.cu, pu.Y(), true, 0, false); + PredictionUnit pu2 = pu; + for (int i = 0; i < OBIC_FUSION_NUM - 1; i++) + { + blendModes[i] = false; + predFusion[i] = m_tempBuffer[i].getBuf( localUnitArea.Y() ); + if (pu.cu->obicMode[i + 1] >= 0) + { + blendModes[i] = true; + pu2.intraDir[0] = pu.cu->obicMode[i + 1]; + initPredIntraParams(pu2, pu.Y(), *(pu.cs->sps)); + pu2.intraDir[0] = pu.cu->obicMode[0]; + const CPelBuf &srcBuf = CPelBuf(getPredictorPtr(compID), srcStride, srcHStride); + switch (pu.cu->obicMode[i + 1]) + { +#if JVET_AC0105_DIRECTIONAL_PLANAR + case (PLANAR_IDX): pu.cu->isBvDimd ? predUsingBv(predFusion[i].buf, predFusion[i].stride, pu.cu->bvDimd, *pu.cu) : xPredIntraPlanar(srcBuf, predFusion[i], 0); break; +#else + case (PLANAR_IDX): pu.cu->isBvDimd ? predUsingBv(predFusion[i].buf, predFusion[i].stride, pu.cu->bvDimd, *pu.cu) : xPredIntraPlanar(srcBuf, predFusion[i]); break; +#endif + case(DC_IDX): xPredIntraDc(srcBuf, predFusion[i], channelType, false); break; +#if JVET_AB0157_INTRA_FUSION + default: xPredIntraAng(srcBuf, predFusion[i], channelType, clpRng, false, srcBuf2nd, pu.cu->ispMode!=NOT_INTRA_SUBPARTITIONS); break; +#else + default: xPredIntraAng(srcBuf, predFusion[i], channelType, clpRng, bExtIntraDir); break; +#endif + } + if( (m_ipaParam.applyPDPC || pu.ciipPDPC) && (pu.cu->obicMode[i + 1] == PLANAR_IDX || pu.cu->obicMode[i + 1] == DC_IDX) ) + { + if (pu.cu->obicMode[i + 1] == PLANAR_IDX && pu.cu->isBvDimd) + { + continue; + } + xIntraPredPlanarDcPdpc( srcBuf, predFusion[i].buf, predFusion[i].stride, width, height, false ); + } + } + } + m_ipaParam.applyPDPC = applyPdpc; + const int log2WeightSum = 6; + Pel *pelPred = piPred.buf; + Pel *pelFusion[OBIC_FUSION_NUM - 1]; + int weight[OBIC_FUSION_NUM]; + weight[0] = pu.cu->obicFusionWeight[0]; + for (int i = 0; i < OBIC_FUSION_NUM - 1; i++) + { + pelFusion[i] = predFusion[i].buf; + weight[i + 1] = pu.cu->obicFusionWeight[i + 1]; + } + for( int y = 0; y < height; y++ ) + { + for( int x = 0; x < width; x++ ) + { + int blend = pelPred[x] * weight[0]; + for (int i = 0; i < OBIC_FUSION_NUM - 1; i++) + { + if (blendModes[i]) + { + blend += pelFusion[i][x] * weight[ i + 1]; + } + } + pelPred[x] = (Pel)(blend >> log2WeightSum); + } + pelPred += piPred.stride; + for (int i = 0; i < OBIC_FUSION_NUM - 1; i++) + { + pelFusion[i] += predFusion[i].stride; + } + } + return; + } +#endif #if JVET_W0123_TIMD_FUSION if (pu.cu->timd && pu.cu->timdIsBlended && isLuma(compID)) { @@ -3939,24 +4047,327 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch } } } - } + } + + // Flip the block if this is the horizontal mode + if( !bIsModeVer ) + { + for( int y = 0; y < height; y++ ) + { + Pel *dst = pDst.buf + y; + + for( int x = 0; x < width; x++ ) + { + *dst = pDstBuf[x]; + dst += pDst.stride; + } + pDstBuf += dstStride; + } + } +} +#if JVET_AH0076_OBIC +void IntraPrediction::generateObicBlending(PelBuf &piPred, const PredictionUnit &pu, PelBuf predFusion[OBIC_FUSION_NUM - 1], bool blendModes[OBIC_FUSION_NUM - 1], int planarIdx) +{ + const int height = piPred.height; + const int width = piPred.width; + const UnitArea localUnitArea( pu.chromaFormat, Area( 0, 0, width, height ) ); + PelBuf predFusionBV = m_tempBuffer[7].getBuf( localUnitArea.Y() ); + if (pu.cu->isBvDimd) + { + predUsingBv(predFusionBV.buf, predFusionBV.stride, pu.cu->bvDimd, *pu.cu); + } + const int log2WeightSum = 6; + Pel *pelPred = piPred.buf; + Pel *pelFusion[OBIC_FUSION_NUM - 1]; + Pel *pelFusionBv = predFusionBV.buf; + int weight[OBIC_FUSION_NUM]; + weight[0] = pu.cu->obicFusionWeight[0]; + for (int i = 0; i < OBIC_FUSION_NUM - 1; i++) + { + pelFusion[i] = predFusion[i].buf; + weight[i + 1] = pu.cu->obicFusionWeight[i + 1]; + } + for( int y = 0; y < height; y++ ) + { + for( int x = 0; x < width; x++ ) + { + int blend = pelPred[x] * weight[0]; + for (int i = 0; i < OBIC_FUSION_NUM - 1; i++) + { + if (blendModes[i]) + { + if (i == planarIdx && pu.cu->isBvDimd) + { + blend += pelFusionBv[x] * weight[ i + 1]; + } + else + { + blend += pelFusion[i][x] * weight[ i + 1]; + } + } + } + pelPred[x] = (Pel)(blend >> log2WeightSum); + } + pelPred += piPred.stride; + for (int i = 0; i < OBIC_FUSION_NUM - 1; i++) + { + pelFusion[i] += predFusion[i].stride; + } + pelFusionBv += predFusionBV.stride; + } + return; +} +void IntraPrediction::generateDimdBlending(PelBuf &piPred, const PredictionUnit &pu, PelBuf &piBlock0, PelBuf &piBlock1, PelBuf &piBlock2, PelBuf &piBlock3, PelBuf &plnBlock) +{ + // do blending + int width = piPred.width; + int height = piPred.height; + const UnitArea localUnitArea( pu.chromaFormat, Area( 0, 0, width, height ) ); + PelBuf planarBuffer = m_tempBuffer[0].getBuf( localUnitArea.Y() ); +#if JVET_AG0146_DIMD_ITMP_IBC + if (pu.cu->isBvDimd && pu.cu->ispMode == 0) + { + predUsingBv(planarBuffer.buf, planarBuffer.stride, pu.cu->bvDimd, *pu.cu); + } + else + { +#endif + planarBuffer.copyFrom(plnBlock); +#if JVET_AG0146_DIMD_ITMP_IBC + } +#endif + + bool blendModes[DIMD_FUSION_NUM-2] = {false}; + for( int i = 0; i < DIMD_FUSION_NUM-2; ++i) + { +#if JVET_AC0098_LOC_DEP_DIMD + blendModes[i] = (pu.cu->dimdBlendMode[i] != PLANAR_IDX); +#else + blendModes[i] = (i==0 || pu.cu->dimdBlendMode[i] != PLANAR_IDX); +#endif + + } + PelBuf predAngExtra[DIMD_FUSION_NUM-2]; + predAngExtra[0] = m_tempBuffer[1].getBuf( localUnitArea.Y() ); + predAngExtra[1] = m_tempBuffer[2].getBuf( localUnitArea.Y() ); + predAngExtra[2] = m_tempBuffer[3].getBuf( localUnitArea.Y() ); + predAngExtra[3] = m_tempBuffer[4].getBuf( localUnitArea.Y() ); + predAngExtra[0].copyFrom(piBlock0); + predAngExtra[1].copyFrom(piBlock1); + predAngExtra[2].copyFrom(piBlock2); + predAngExtra[3].copyFrom(piBlock3); + +#if JVET_AC0098_LOC_DEP_DIMD + PelBuf predAngNonLocDep = m_tempBuffer[7].getBuf( localUnitArea.Y() ); + PelBuf predAngVer = m_tempBuffer[5].getBuf( localUnitArea.Y() ); + PelBuf predAngHor = m_tempBuffer[6].getBuf( localUnitArea.Y() ); + + Pel* pelVer = predAngVer.buf; + int strideVer = predAngVer.stride; + Pel* pelHor = predAngHor.buf; + int strideHor = predAngHor.stride; + Pel *pelNonLocDep = predAngNonLocDep.buf; + int strideNonLocDep = predAngNonLocDep.stride; + + bool useLocDepBlending = false; + int weightVer = 0, weightHor = 0, weightNonLocDep = 0; + weightNonLocDep += pu.cu->dimdRelWeight[1]; + for (int i = 0; i < DIMD_FUSION_NUM-1; i++) + { + if (i == 0 || blendModes[i-1]) + { + if (pu.cu->dimdLocDep[i] == 1) + { + weightVer += (i == 0 ? pu.cu->dimdRelWeight[0] : pu.cu->dimdRelWeight[i+ 1]); + } + else if (pu.cu->dimdLocDep[i] == 2) + { + weightHor += (i == 0 ? pu.cu->dimdRelWeight[0] : pu.cu->dimdRelWeight[i+ 1]); + } + else + { + weightNonLocDep += (i == 0 ? pu.cu->dimdRelWeight[0] : pu.cu->dimdRelWeight[i+1]); + } + } + } + + if(weightHor || weightVer) + { + useLocDepBlending = true; + } + + if(!useLocDepBlending) + { + pelNonLocDep = piPred.buf; + strideNonLocDep = piPred.stride; + } + + for (int locDep = 0; locDep < 3; locDep++) + { + int totWeight = (locDep == 0 ? weightNonLocDep : (locDep == 1 ? weightVer : weightHor)); + if (totWeight == 0) + { + continue; + } + + int weights[6] = {0}; + weights[0] = (pu.cu->dimdLocDep[0] == locDep) ? pu.cu->dimdRelWeight[0] : 0; + weights[1] = (blendModes[0] && pu.cu->dimdLocDep[1] == locDep) ? pu.cu->dimdRelWeight[2] : 0; + weights[2] = (blendModes[1] && pu.cu->dimdLocDep[2] == locDep) ? pu.cu->dimdRelWeight[3] : 0; + weights[3] = (blendModes[2] && pu.cu->dimdLocDep[3] == locDep) ? pu.cu->dimdRelWeight[4] : 0; + weights[4] = (blendModes[3] && pu.cu->dimdLocDep[4] == locDep) ? pu.cu->dimdRelWeight[5] : 0; + weights[5] = (locDep == 0) ? pu.cu->dimdRelWeight[1] : 0; + + int num2blend = 0; + int blendIndexes[DIMD_FUSION_NUM] = {0}; + for (int i = 0; i < DIMD_FUSION_NUM; i++) + { + if (weights[i] != 0) + { + blendIndexes[num2blend] = i; + num2blend++; + } + } +#if JVET_W0123_TIMD_FUSION + if( (num2blend == 1 ) || (num2blend <=3 && (totWeight == (1 << (floorLog2(totWeight))) ) )) + { + int index = blendIndexes[0]; + if(locDep == 0) + { + pelNonLocDep = (index == 0 ? piPred.buf : (index == 5 ? planarBuffer.buf : predAngExtra[index-1].buf)); + strideNonLocDep = (index == 0 ? piPred.stride : (index == 5 ? planarBuffer.stride : predAngExtra[index-1].stride)); + } + else if(locDep == 1) + { + pelVer = (index == 0 ? piPred.buf : predAngExtra[index-1].buf); + strideVer = (index == 0 ? piPred.stride : predAngExtra[index-1].stride); + } + else + { + pelHor = (index == 0 ? piPred.buf : predAngExtra[index-1].buf); + strideHor = (index == 0 ? piPred.stride : predAngExtra[index-1].stride); + } + Pel* pCur = (locDep == 0 ? pelNonLocDep : (locDep == 1 ? pelVer : pelHor)); + int strideCur = (locDep == 0 ? strideNonLocDep : (locDep == 1 ? strideVer : strideHor)); + + int factor = 64 / totWeight; + if (num2blend == 2) + { + int index1 = blendIndexes[1]; + Pel* p1 = (index1 == 0 ? piPred.buf : (index1 == 5 ? planarBuffer.buf : predAngExtra[index1-1].buf)); + int stride1 = (index1 == 0 ? piPred.stride : (index1 == 5 ? planarBuffer.stride : predAngExtra[index1-1].stride)); + int w0 = (weights[index]*factor); + int w1 = 64 - w0; + m_timdBlending(pCur, strideCur, p1, stride1, w0, w1,width, height); + } + else if(num2blend == 3) + { + int index1 = blendIndexes[1]; + Pel* p1 = (index1 == 0 ? piPred.buf : (index1 == 5 ? planarBuffer.buf : predAngExtra[index1-1].buf)); + int stride1 = (index1 == 0 ? piPred.stride : (index1 == 5 ? planarBuffer.stride : predAngExtra[index1-1].stride)); + + int index2 = blendIndexes[2]; + Pel* p2 = (index2 == 0 ? piPred.buf : (index2 == 5 ? planarBuffer.buf : predAngExtra[index2-1].buf)); + int stride2 = (index2 == 0 ? piPred.stride : (index2 == 5 ? planarBuffer.stride : predAngExtra[index2-1].stride)); + int w0 = (weights[index]*factor); + int w1 = (weights[index1]*factor); + int w2 = 64 - w0 - w1; + m_dimdBlending(pCur, strideCur, p1, stride1, p2, stride2, w0, w1, w2, width, height); + } + } + else +#endif + { + Pel* pCur = (locDep == 0 ? pelNonLocDep : (locDep == 1 ? pelVer : pelHor)); + int strideCur = (locDep == 0 ? strideNonLocDep : (locDep == 1 ? strideVer : strideHor)); + Pel *pelPlanar = planarBuffer.buf; + int stridePlanar = planarBuffer.stride; + Pel *pelPredAng0 = piPred.buf; + Pel *pelPredAng1 = predAngExtra[0].buf; + Pel *pelPredAng2 = predAngExtra[1].buf; + Pel *pelPredAng3 = predAngExtra[2].buf; + Pel *pelPredAng4 = predAngExtra[3].buf; + int stride0 = piPred.stride; + int stride1 = predAngExtra[0].stride; + int stride2 = predAngExtra[1].stride; + int stride3 = predAngExtra[2].stride; + int stride4 = predAngExtra[3].stride; + for( int y = 0; y < height; y++ ) + { + for( int x = 0; x < width; x++ ) + { + int blend = pelPredAng0[x] * weights[0]; + blend += blendModes[0] ? pelPredAng1[x] * weights[1] : 0; + blend += blendModes[1] ? pelPredAng2[x] * weights[2] : 0; + blend += blendModes[2] ? pelPredAng3[x] * weights[3] : 0; + blend += blendModes[3] ? pelPredAng4[x] * weights[4] : 0; + blend += pelPlanar[x] * weights[5]; + pCur[x] = (Pel)(blend / totWeight); + } + pCur += strideCur; + pelPredAng0 += stride0; + pelPredAng1 += stride1; + pelPredAng2 += stride2; + pelPredAng3 += stride3; + pelPredAng4 += stride4; + pelPlanar += stridePlanar; + } + } + } + + if (useLocDepBlending) + { + int mode = ((weightHor > 0 && weightVer > 0) ? 0 : (weightVer > 0 ? 1 : 2)); + + Pel *pelDst = piPred.buf; + int strideDst = piPred.stride; +#if JVET_W0123_TIMD_FUSION && JVET_AG0092_ENHANCED_TIMD_FUSION + xLocationdepBlending(pelDst, strideDst, pelVer, strideVer, pelHor, strideHor, pelNonLocDep, strideNonLocDep, width, height,mode, weightVer, weightHor, weightNonLocDep); +#else + xDimdLocationdepBlending(pelDst, strideDst, pelVer, strideVer, pelHor, strideHor, pelNonLocDep, strideNonLocDep, width, height,mode, weightVer, weightHor, weightNonLocDep); +#endif + } +#else + const int log2WeightSum = 6; + Pel *pelPred = piPred.buf; + Pel *pelPlanar = planarBuffer.buf; + Pel *pelPredAng = predAngExtra[0].buf; + int w0 = pu.cu->dimdRelWeight[0], w1 = pu.cu->dimdRelWeight[1], w2 = pu.cu->dimdRelWeight[2]; + + Pel *pelPredAng2 = predAngExtra[1].buf; + Pel *pelPredAng3 = predAngExtra[2].buf; + Pel *pelPredAng4 = predAngExtra[3].buf; + int w3 = pu.cu->dimdRelWeight[3]; + int w4 = pu.cu->dimdRelWeight[4]; + int w5 = pu.cu->dimdRelWeight[5]; - // Flip the block if this is the horizontal mode - if( !bIsModeVer ) - { for( int y = 0; y < height; y++ ) { - Pel *dst = pDst.buf + y; - for( int x = 0; x < width; x++ ) { - *dst = pDstBuf[x]; - dst += pDst.stride; + int blend = pelPred[x] * w0; + blend += pelPlanar[x] * w1; +#if JVET_AC0098_LOC_DEP_DIMD + blend += blendModes[0] ? pelPredAng[x] * w2 : 0; +#else + blend += pelPredAng[x] * w2; +#endif + blend += blendModes[1] ? pelPredAng2[x] * w3 : 0; + blend += blendModes[2] ? pelPredAng3[x] * w4 : 0; + blend += blendModes[3] ? pelPredAng4[x] * w5 : 0; + pelPred[x] = (Pel)(blend >> log2WeightSum); } - pDstBuf += dstStride; + + pelPred += piPred.stride; + pelPlanar += planarBuffer.stride; + pelPredAng += predAngExtra[0].stride; + pelPredAng2 += predAngExtra[1].stride; + pelPredAng3 += predAngExtra[2].stride; + pelPredAng4 += predAngExtra[3].stride; } - } +#endif } +#endif #if JVET_Z0050_DIMD_CHROMA_FUSION #if JVET_AD0188_CCP_MERGE @@ -4680,7 +5091,12 @@ void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompAre auto mrlIndex2D = cu.firstPU->multiRefIdx; m_ipaParam.fetchRef2nd = area.compID == COMPONENT_Y; m_ipaParam.fetchRef2nd &= area.width * area.height >= SIZE_CONSTRAINT; +#if JVET_AH0076_OBIC + m_ipaParam.fetchRef2nd &= !((cu.dimd && !cu.obicFlag && cu.dimdBlending) || (cu.dimd && cu.obicFlag && cu.obicIsBlended)); +#else m_ipaParam.fetchRef2nd &= !(cu.dimd && cu.dimdBlending); +#endif + #if JVET_AH0065_RELAX_LINE_BUFFER m_ipaParam.fetchRef2nd &= !(mrlIndex2D == MULTI_REF_LINE_IDX[MRL_NUM_REF_LINES - 1] && (cu.block(COMPONENT_Y).y <= MULTI_REF_LINE_IDX[MRL_NUM_REF_LINES - 1])); #else @@ -6882,6 +7298,529 @@ int IntraPrediction::getBestNonAnglularMode(const CPelBuf& recoBuf, const CompAr return 0; } #endif + +#if JVET_AH0076_OBIC + void IntraPrediction::deriveObicMode( const CPelBuf &recoBuf, const CompArea &area, CodingUnit &cu ) + { + /* ------------------------------------------------------------------- + Step 1: Collect adjacent neighbour cands + Step 2: Collect non-adjacent neighbour cands + Step 3: Sort neighbours by distance + Step 4: Build Histogram of oCcurrence (HoC) from remaining neighbours + Step 5: Get top 6 amplitudes from the HoC + Step 6: Compute the fusion weights from amplitudes and store in CU + ---------------------------------------------------------------------- */ + + cu.obicIsBlended = false; + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + cu.obicMode[i] = -1; + cu.obicFusionWeight[i] = 0; + } + + int histogram[NUM_LUMA_MODE]; + for (int i = 0; i < NUM_LUMA_MODE; i++) + { + histogram[i] = 0; + } + const int step = 4; + const int numCUs = NUM_OBIC_CUS; + const CodingUnit* cuNeighbours[numCUs]; + + /* ----------------------------------------------------------------- + ----------- Step 1: Collect adjacent neighbour cands --------------- + ----------------------------------------------------------------- */ + + cuNeighbours[0] = cu.cs->getCURestricted(cu.lumaPos().offset(-1, 0), cu, CH_L); + cuNeighbours[1] = cu.cs->getCURestricted(cu.lumaPos().offset(0, -1), cu, CH_L); + cuNeighbours[2] = cu.cs->getCURestricted(cu.lumaPos().offset(-1, -1), cu, CH_L); + + const CodingUnit* cuTemp; + for (int i = 0; i <= cu.lheight(); i += step) + { + cuTemp = cu.cs->getCURestricted(cu.lumaPos().offset(-1, i), cu, CH_L); + if (cuTemp && CU::isIntra(*cuTemp)) + { + cuNeighbours[0] = cuTemp; + break; + } + } + for (int i = 0; i <= cu.lwidth(); i += step) + { + cuTemp = cu.cs->getCURestricted(cu.lumaPos().offset(i, -1), cu, CH_L); + if (cuTemp && CU::isIntra(*cuTemp)) + { + cuNeighbours[1] = cuTemp; + break; + } + } + + const CodingUnit* cuLeft = cu.cs->getCURestricted(cu.lumaPos().offset(-1, 0), cu, CH_L); + const CodingUnit* cuTop = cu.cs->getCURestricted(cu.lumaPos().offset(0, -1), cu, CH_L); + cuNeighbours[3] = cuLeft ? cu.cs->getCURestricted(cuLeft->lumaPos().offset(cuLeft->lwidth()-1, cuLeft->lheight()), cu, CH_L) : NULL; + cuNeighbours[4] = cuTop ? cu.cs->getCURestricted(cuTop->lumaPos().offset(cuTop->lwidth(), cuTop->lheight() - 1), cu, CH_L) : NULL; + cuNeighbours[5] = cuNeighbours[3] ? cu.cs->getCURestricted(cuNeighbours[3]->lumaPos().offset(cuNeighbours[3]->lwidth()-1, cuNeighbours[3]->lheight()), cu, CH_L) : NULL; + cuNeighbours[6] = cuNeighbours[4] ? cu.cs->getCURestricted(cuNeighbours[4]->lumaPos().offset(cuNeighbours[4]->lwidth(), cuNeighbours[4]->lheight() - 1), cu, CH_L) : NULL; + cuNeighbours[7] = cuLeft ? cu.cs->getCURestricted(cuLeft->lumaPos().offset(-1, 0), cu, CH_L) : NULL; + cuNeighbours[8] = cuTop ? cu.cs->getCURestricted(cuTop->lumaPos().offset(0, -1), cu, CH_L) : NULL; + cuNeighbours[9] = cuNeighbours[3] ? cu.cs->getCURestricted(cuNeighbours[3]->lumaPos().offset(-1, 0), cu, CH_L) : NULL; + cuNeighbours[10] = cuNeighbours[4] ? cu.cs->getCURestricted(cuNeighbours[4]->lumaPos().offset(0, -1), cu, CH_L) : NULL; + cuNeighbours[11] = cuNeighbours[5] ? cu.cs->getCURestricted(cuNeighbours[5]->lumaPos().offset(-1, 0), cu, CH_L) : NULL; + cuNeighbours[12] = cuNeighbours[6] ? cu.cs->getCURestricted(cuNeighbours[6]->lumaPos().offset(0, -1), cu, CH_L) : NULL; + + if ((!cuNeighbours[9]) && cuNeighbours[2]) + { + cuNeighbours[9] = cu.cs->getCURestricted(cuNeighbours[2]->lumaPos().offset(-1, cuNeighbours[2]->lheight()-1), cu, CH_L); + } + if ((!cuNeighbours[10]) && cuNeighbours[2]) + { + cuNeighbours[10] = cu.cs->getCURestricted(cuNeighbours[2]->lumaPos().offset(cuNeighbours[2]->lwidth()-1, -1), cu, CH_L); + } + if ((!cuNeighbours[11]) && cuLeft && cuNeighbours[7]) + { + cuNeighbours[11] = cu.cs->getCURestricted(cuNeighbours[7]->lumaPos().offset(-1, 0), cu, CH_L); + } + if ((!cuNeighbours[12]) && cuTop && cuNeighbours[8]) + { + cuNeighbours[12] = cu.cs->getCURestricted(cuNeighbours[8]->lumaPos().offset(0, -1), cu, CH_L); + } + + /* ----------------------------------------------------------------- + ---------- Step 2: Collect non-adjacent neighbour cands------------- + ----------------------------------------------------------------- */ + + const Position topLeft = area.topLeft(); + int offsetX = 0; + int offsetY = 0; + int cout = 13; + const int numNACandidate[4] = { 3, 5, 5, 5 }; + const int idxMap[4][5] = { { 0, 1, 4 }, { 0, 1, 2, 3, 4 }, { 0, 1, 2, 3, 4 }, { 0, 1, 2, 3, 4 } }; + for (int iDistanceIndex = 0; iDistanceIndex < NADISTANCE_LEVEL; iDistanceIndex++) + { + const int iNADistanceHor = cu.Y().width * (iDistanceIndex + 1); + const int iNADistanceVer = cu.Y().height * (iDistanceIndex + 1); + for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex]; iNASPIdx++) + { + switch (idxMap[iDistanceIndex][iNASPIdx]) + { + case 0: offsetX = -iNADistanceHor - 1; offsetY = cu.Y().height + iNADistanceVer - 1; break; + case 1: offsetX = cu.Y().width + iNADistanceHor - 1; offsetY = -iNADistanceVer - 1; break; + case 2: offsetX = cu.Y().width >> 1; offsetY = -iNADistanceVer - 1; break; + case 3: offsetX = -iNADistanceHor - 1; offsetY = cu.Y().height >> 1; break; + case 4: offsetX = -iNADistanceHor - 1; offsetY = -iNADistanceVer - 1; break; + default: printf("error!"); exit(0); break; + } + cuNeighbours[cout++] = cu.cs->getCURestricted(topLeft.offset(offsetX, offsetY), cu, CH_L); + } + } + + /* ----------------------------------------------------------------- + ---------------- Step 3: Sort neighbours by distance --------------- + ----------------------------------------------------------------- */ + + int limitMaxNeigh = 20; + bool useNeighbour[numCUs]; + int neighboursInDistOrder[numCUs]; + int dists[numCUs]; + for (int i = 0; i < numCUs; i++) + { + useNeighbour[i] = false; + neighboursInDistOrder[i] = 0; + dists[i] = 0; + } + for (int i = 0; i < numCUs; i++) + { + dists[i] = MAX_INT; + } + int numToMix = 0; + for (int i = 0; i < numCUs; i++) + { + useNeighbour[i] = (cuNeighbours[i] && CU::isIntra(*cuNeighbours[i])); + if (useNeighbour[i]) + { + for (int j = i-1; j >= 0; j--) + { + if (!useNeighbour[j]) + { + continue; + } + useNeighbour[i] &= (cuNeighbours[i]->lx() != cuNeighbours[j]->lx() || cuNeighbours[i]->ly() != cuNeighbours[j]->ly()); + } + } + int curNeigh = i; + int curDist = (useNeighbour[i] ? abs( (int)(cu.lx()) - (int)(cuNeighbours[i]->lx())) + abs( (int)(cu.ly()) - (int)(cuNeighbours[i]->ly())) : 0); + + for (int j = 0; j < numCUs; j++) + { + if (curDist < dists[j]) + { + for (int k = numCUs - 1; k > j; k--) + { + dists[k] = dists[k - 1]; + neighboursInDistOrder[k] = neighboursInDistOrder[k - 1]; + } + dists[j] = curDist; + neighboursInDistOrder[j] = curNeigh; + break; + } + } + } + for (int i = 0; i < numCUs; i++) + { + int j = neighboursInDistOrder[i]; + if (limitMaxNeigh > 0 && numToMix >= limitMaxNeigh) + { + useNeighbour[j] = false; + continue; + } + if (useNeighbour[j]) + { + numToMix ++; + } + } + + + /* ----------------------------------------------------------------- + --------------------------- Step 4: -------------------------------- + ---------------- Build Histogram of oCcurrence (HoC) --------------- + --------------------- from remaining neighbours -------------------- + ----------------------------------------------------------------- */ + + + for (int i = 0; i < numCUs; i++) + { + if (!useNeighbour[i]) + { + continue; + } + int numSamples = cuNeighbours[i]->lumaSize().width * cuNeighbours[i]->lumaSize().height; + if (cuNeighbours[i]->timd) + { + int m = MAP131TO67(cuNeighbours[i]->timdMode); + histogram[m] += numSamples; + if (cuNeighbours[i]->timdIsBlended && cuNeighbours[i]->timdFusionWeight[1] > 0) + { + int m = MAP131TO67(cuNeighbours[i]->timdModeSecondary); + histogram[m] += numSamples; + if (cuNeighbours[i]->timdFusionWeight[2] > 0) + { + int m = MAP131TO67(cuNeighbours[i]->timdModeNonAng); + histogram[m] += numSamples; + } + } + } + else if (cuNeighbours[i]->dimd && !cuNeighbours[i]->obicFlag) + { + int m = cuNeighbours[i]->dimdMode; + if (m >= 0 && m < NUM_LUMA_MODE) + { + histogram[m] += numSamples; + } + if (cuNeighbours[i]->dimdBlending) + { + for (int idx = 0; idx < DIMD_FUSION_NUM - 1; idx++) + { + m = cuNeighbours[i]->dimdBlendMode[idx]; + if (m >= 0 && m < NUM_LUMA_MODE && cuNeighbours[i]->dimdRelWeight[idx + 1] > 0) + { + histogram[m] += numSamples; + } + } + } + } + else if (cuNeighbours[i]->dimd && cuNeighbours[i]->obicFlag) + { + int m = cuNeighbours[i]->obicMode[0]; + histogram[m] += numSamples; + if (cuNeighbours[i]->obicIsBlended) + { + for (int idx = 1; idx < OBIC_FUSION_NUM; idx++) + { + m = cuNeighbours[i]->obicMode[idx]; + if (m >= 0 && cuNeighbours[i]->obicFusionWeight[idx] > 0) + { + histogram[m] += numSamples; + } + } + } + } + else if (cuNeighbours[i]->sgpm) + { + int m1 = cuNeighbours[i]->sgpmMode0; + int m2 = cuNeighbours[i]->sgpmMode1; + if (m1 >= 0 && m1 < NUM_LUMA_MODE) + { + histogram[m1] += numSamples; + } + if (m2 >= 0 && m2 < NUM_LUMA_MODE) + { + histogram[m2] += numSamples; + } + } + else if (cuNeighbours[i]->tmrlFlag) + { + int m = MAP131TO67(cuNeighbours[i]->firstPU->intraDir[0]); + histogram[m] += numSamples; + } +#if JVET_AG0058_EIP + else if (cuNeighbours[i]->eipFlag && cu.slice->getSliceType() != I_SLICE) + { + int m = cuNeighbours[i]->eipModel.eipDimdMode; + histogram[m] += numSamples; + } +#endif +#if JVET_AC0115_INTRA_TMP_DIMD_MTS_LFNST + else if (cuNeighbours[i]->tmpFlag && cu.slice->getSliceType() != I_SLICE) + { + int m = cuNeighbours[i]->intraTmpDimdMode; + histogram[m] += numSamples; + } +#endif +#if JVET_AB0067_MIP_DIMD_LFNST + else if (cuNeighbours[i]->mipFlag && cu.slice->getSliceType() != I_SLICE) + { + int m = cuNeighbours[i]->mipDimdMode; + histogram[m] += numSamples; + } +#endif + else if (CU::isIntra(*cuNeighbours[i]) && !cuNeighbours[i]->tmpFlag && !cuNeighbours[i]->mipFlag && !cuNeighbours[i]->eipFlag && !CU::isIBC(*cuNeighbours[i]) && !CU::isPLT(*cuNeighbours[i])) + { + int m = cuNeighbours[i]->firstPU->intraDir[0]; + histogram[m] += numSamples; + } + } + + // Penalize Dimd modes to impose diversity between OBIC and DIMD + if (cu.dimdMode >= 0 && cu.dimdMode < NUM_LUMA_MODE) + { + histogram[cu.dimdMode] >>= 1; + } + if (cu.dimdBlending && cu.dimdBlendMode[0] >= 0 && cu.dimdBlendMode[0] < NUM_LUMA_MODE && cu.dimdRelWeight[1] > 0) + { + histogram[cu.dimdBlendMode[0]] >>= 1; + } + + /* ----------------------------------------------------------------- + ------------------- Step 5: Get top 6 amplitudes ------------------- + -------------------------- from the HoC ---------------------------- + ----------------------------------------------------------------- */ + + int bestModes[OBIC_FUSION_NUM], bestAmps[OBIC_FUSION_NUM]; + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + bestModes[i] = -1; + bestAmps[i] = 0; + } + for (int i = 0; i < NUM_LUMA_MODE; i++) + { + int curMode = i; + if (curMode == PLANAR_IDX) + { + continue; + } + if (histogram[curMode] > bestAmps[0]) + { + bestAmps[5] = bestAmps[4]; + bestAmps[4] = bestAmps[3]; + bestAmps[3] = bestAmps[2]; + bestAmps[2] = bestAmps[1]; + bestAmps[1] = bestAmps[0]; + bestAmps[0] = histogram[curMode]; + bestModes[5] = bestModes[4]; + bestModes[4] = bestModes[3]; + bestModes[3] = bestModes[2]; + bestModes[2] = bestModes[1]; + bestModes[1] = bestModes[0]; + bestModes[0] = curMode; + } + else if (histogram[curMode] > bestAmps[1]) + { + bestAmps[5] = bestAmps[4]; + bestAmps[4] = bestAmps[3]; + bestAmps[3] = bestAmps[2]; + bestAmps[2] = bestAmps[1]; + bestAmps[1] = histogram[curMode]; + bestModes[5] = bestModes[4]; + bestModes[4] = bestModes[3]; + bestModes[3] = bestModes[2]; + bestModes[2] = bestModes[1]; + bestModes[1] = curMode; + } + else if (histogram[curMode] > bestAmps[2]) + { + bestAmps[5] = bestAmps[4]; + bestAmps[4] = bestAmps[3]; + bestAmps[3] = bestAmps[2]; + bestAmps[2] = histogram[curMode]; + bestModes[5] = bestModes[4]; + bestModes[4] = bestModes[3]; + bestModes[3] = bestModes[2]; + bestModes[2] = curMode; + } + else if (histogram[curMode] > bestAmps[3]) + { + bestAmps[5] = bestAmps[4]; + bestAmps[4] = bestAmps[3]; + bestAmps[3] = histogram[curMode]; + bestModes[5] = bestModes[4]; + bestModes[4] = bestModes[3]; + bestModes[3] = curMode; + } + else if (histogram[curMode] > bestAmps[4]) + { + bestAmps[5] = bestAmps[4]; + bestAmps[4] = histogram[curMode]; + bestModes[5] = bestModes[4]; + bestModes[4] = curMode; + } + else if (histogram[curMode] > bestAmps[5]) + { + bestAmps[5] = histogram[curMode]; + bestModes[5] = curMode; + } + } + if (bestModes[0] < 0) + { + return; + } + + int count = 0; + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + count += bestModes[i] >= 0 ? 1 : 0; + } + + + /* ----------------------------------------------------------------- + -------------- Step 6: Compute the fusion weights ------------------ + ---------------- from amplitudes and store in CU ------------------- + ----------------------------------------------------------------- */ + + int planarWeight = count == 1 ? 21 : 64/4; + int log2BlendWeight = 6; + int sumWeight = (1 << log2BlendWeight); + if (bestModes[1] < 0) + { + cu.obicMode[0] = bestModes[0]; + cu.obicIsBlended = false; + cu.obicFusionWeight[0] = sumWeight; + for (int i = 1; i < OBIC_FUSION_NUM; i++) + { + cu.obicMode[i] = -1; + cu.obicFusionWeight[i] = 0; + } + cu.obicIsBlended = true; + cu.obicMode[1] = PLANAR_IDX; + cu.obicFusionWeight[0] = sumWeight - planarWeight; + cu.obicFusionWeight[1] = planarWeight; + } + else + { + sumWeight = sumWeight - planarWeight; + if (count == OBIC_FUSION_NUM) + { + bestAmps[count - 1] = 0; + } + + int s1 = 0; + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + bestAmps[i] = 10 * bestAmps[i]; + } + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + s1 = s1 + bestAmps[i]; + } + int x = floorLog2(s1); + CHECK(x < 0, "floor log2 value should be no negative"); + int normS1 = (s1 << 4 >> x) & 15; + int v = g_gradDivTable[normS1] | 8; + x += (normS1 != 0); + int shift = x + 3; + int add = (1 << (shift - 1)); + int iRatio[OBIC_FUSION_NUM] = { 0 }; + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + iRatio[i] = (bestAmps[i] * v * sumWeight + add) >> shift; + if (bestAmps[i] == 0) + { + iRatio[i] = 0; + } + if( iRatio[i] > sumWeight ) + { + iRatio[i] = sumWeight; + } + CHECK( iRatio[i] > sumWeight, "Wrong ratio in OBIC" ); + } + int sumTmp = 0; + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + sumTmp += iRatio[i]; + cu.obicMode[i] = bestModes[i]; + cu.obicFusionWeight[i] = iRatio[i]; + } + if (sumTmp != sumWeight) + { + int d = sumTmp - sumWeight; + if (d > 0) + { + for (int i = OBIC_FUSION_NUM - 1; i >= 0; i--) + { + int diff = d; + for (int k = 0; k < diff; k++) + { + if (cu.obicFusionWeight[i] > 0) + { + cu.obicFusionWeight[i] -= 1; + d -= 1; + } + } + } + } + else + { + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + int diff = d; + if (cu.obicFusionWeight[i] > 0 && (cu.obicFusionWeight[i] + d) < sumWeight) + { + for (int k = 0; k < abs(diff); k++) + { + if (d == 0) + { + break; + } + if (cu.obicFusionWeight[i] > 0) + { + cu.obicFusionWeight[i] += 1; + d += 1; + } + } + } + } + } + } + sumTmp = 0; + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + sumTmp += cu.obicFusionWeight[i]; + } + CHECK( sumTmp != sumWeight, "Wrong sum!" ); + if (count == OBIC_FUSION_NUM) + { + cu.obicMode[count - 1] = PLANAR_IDX; + cu.obicFusionWeight[count - 1] = planarWeight; + } + else + { + cu.obicMode[count] = PLANAR_IDX; + cu.obicFusionWeight[count] = planarWeight; + } + cu.obicIsBlended = true; + } + } +#endif + #if JVET_AB0155_SGPM int IntraPrediction::deriveTimdMode(const CPelBuf &recoBuf, const CompArea &area, CodingUnit &cu, bool bFull, bool bHorVer) { diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index bca6799e8..eb8b6da01 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -781,6 +781,11 @@ public: #if JVET_AG0146_DIMD_ITMP_IBC int getBestNonAnglularMode(const CPelBuf& recoBuf, const CompArea& area, CodingUnit& cu, std::vector<Mv> BVs); #endif +#if JVET_AH0076_OBIC + void deriveObicMode ( const CPelBuf &recoBuf, const CompArea &area, CodingUnit &cu ); + void generateObicBlending(PelBuf &piPred, const PredictionUnit &pu, PelBuf predFusion[OBIC_FUSION_NUM - 1], bool blendModes[OBIC_FUSION_NUM - 1], int planarIdx); + void generateDimdBlending(PelBuf &piPred, const PredictionUnit &pu, PelBuf &piBlock0, PelBuf &piBlock1, PelBuf &piBlock2, PelBuf &piBlock3, PelBuf &plnBlock); +#endif #if JVET_AB0155_SGPM int deriveTimdMode ( const CPelBuf &recoBuf, const CompArea &area, CodingUnit &cu, bool bFull = true, bool bHorVer = false ); #else diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index e95c92f46..26dd739a6 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -151,6 +151,7 @@ #if ENABLE_DIMD #define JVET_AC0098_LOC_DEP_DIMD 1 // JVET-AC0098: Location-dependent Decoder-side Intra Mode Derivation +#define JVET_AH0076_OBIC 1 // JVET_AH0076: OBIC #endif #endif diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 0c38590f1..fc5d743a2 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -287,6 +287,15 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other ) plIdx = other.plIdx; #endif #if ENABLE_DIMD +#if JVET_AH0076_OBIC + obicFlag = other.obicFlag; + obicIsBlended = other.obicIsBlended; + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + obicMode[i] = other.obicMode[i]; + obicFusionWeight[i] = other.obicFusionWeight[i]; + } +#endif #if JVET_AG0146_DIMD_ITMP_IBC isBvDimd = other.isBvDimd; bvDimd = other.bvDimd; @@ -529,6 +538,15 @@ void CodingUnit::initData() plIdx = 0; #endif #if ENABLE_DIMD +#if JVET_AH0076_OBIC + obicFlag = false; + obicIsBlended = false; + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + obicMode[i] = -1; + obicFusionWeight[i] = 0; + } +#endif #if JVET_AG0146_DIMD_ITMP_IBC isBvDimd = 0; bvDimd = Mv(0, 0); diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 806a4e4c0..c761201a4 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -325,6 +325,12 @@ struct CodingUnit : public UnitArea uint8_t plIdx; #endif #if ENABLE_DIMD +#if JVET_AH0076_OBIC + bool obicFlag; + bool obicIsBlended; + int obicMode[OBIC_FUSION_NUM]; + int obicFusionWeight[OBIC_FUSION_NUM]; +#endif #if JVET_AG0146_DIMD_ITMP_IBC bool isBvDimd; Mv bvDimd; diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index e52371936..7f04e00fe 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -4574,6 +4574,211 @@ bool PU::isDMChromaSgpm(const PredictionUnit &pu) } #endif +#if JVET_AH0076_OBIC +bool PU::isObicAvail(const PredictionUnit &pu) +{ + if (!pu.lumaPos().x && !pu.lumaPos().y) + { + return false; + } + if (!pu.Y().valid() || pu.cu->predMode != MODE_INTRA || !isLuma(pu.cu->chType) || !pu.cu->slice->getSPS()->getUseDimd() || pu.Y().area() <= 32) + { + return false; + } + if (!PU::checkAvailBlocks(pu)) + { + return false; + } + return true; +} +bool PU::checkAvailBlocks(const PredictionUnit &pu) +{ + const int step = 4; + const CodingUnit& cu = *pu.cu; + const CompArea &area = cu.Y(); + const int numCUs = NUM_OBIC_CUS; + const CodingUnit* cuNeighbours[numCUs]; + cuNeighbours[0] = cu.cs->getCURestricted(cu.lumaPos().offset(-1, 0), cu, CH_L); + cuNeighbours[1] = cu.cs->getCURestricted(cu.lumaPos().offset(0, -1), cu, CH_L); + cuNeighbours[2] = cu.cs->getCURestricted(cu.lumaPos().offset(-1, -1), cu, CH_L); + + const CodingUnit* cuTemp; + for (int i = 0; i <= cu.lheight(); i += step) + { + cuTemp = cu.cs->getCURestricted(cu.lumaPos().offset(-1, i), cu, CH_L); + if (cuTemp && CU::isIntra(*cuTemp)) + { + cuNeighbours[0] = cuTemp; + break; + } + } + for (int i = 0; i <= cu.lwidth(); i += step) + { + cuTemp = cu.cs->getCURestricted(cu.lumaPos().offset(i, -1), cu, CH_L); + if (cuTemp && CU::isIntra(*cuTemp)) + { + cuNeighbours[1] = cuTemp; + break; + } + } + + const CodingUnit* cuLeft = cu.cs->getCURestricted(cu.lumaPos().offset(-1, 0), cu, CH_L); + const CodingUnit* cuTop = cu.cs->getCURestricted(cu.lumaPos().offset(0, -1), cu, CH_L); + cuNeighbours[3] = cuLeft ? cu.cs->getCURestricted(cuLeft->lumaPos().offset(cuLeft->lwidth()-1, cuLeft->lheight()), cu, CH_L) : NULL; + cuNeighbours[4] = cuTop ? cu.cs->getCURestricted(cuTop->lumaPos().offset(cuTop->lwidth(), cuTop->lheight() - 1), cu, CH_L) : NULL; + cuNeighbours[5] = cuNeighbours[3] ? cu.cs->getCURestricted(cuNeighbours[3]->lumaPos().offset(cuNeighbours[3]->lwidth()-1, cuNeighbours[3]->lheight()), cu, CH_L) : NULL; + cuNeighbours[6] = cuNeighbours[4] ? cu.cs->getCURestricted(cuNeighbours[4]->lumaPos().offset(cuNeighbours[4]->lwidth(), cuNeighbours[4]->lheight() - 1), cu, CH_L) : NULL; + cuNeighbours[7] = cuLeft ? cu.cs->getCURestricted(cuLeft->lumaPos().offset(-1, 0), cu, CH_L) : NULL; + cuNeighbours[8] = cuTop ? cu.cs->getCURestricted(cuTop->lumaPos().offset(0, -1), cu, CH_L) : NULL; + cuNeighbours[9] = cuNeighbours[3] ? cu.cs->getCURestricted(cuNeighbours[3]->lumaPos().offset(-1, 0), cu, CH_L) : NULL; + cuNeighbours[10] = cuNeighbours[4] ? cu.cs->getCURestricted(cuNeighbours[4]->lumaPos().offset(0, -1), cu, CH_L) : NULL; + cuNeighbours[11] = cuNeighbours[5] ? cu.cs->getCURestricted(cuNeighbours[5]->lumaPos().offset(-1, 0), cu, CH_L) : NULL; + cuNeighbours[12] = cuNeighbours[6] ? cu.cs->getCURestricted(cuNeighbours[6]->lumaPos().offset(0, -1), cu, CH_L) : NULL; + + if ((!cuNeighbours[9]) && cuNeighbours[2]) + { + cuNeighbours[9] = cu.cs->getCURestricted(cuNeighbours[2]->lumaPos().offset(-1, cuNeighbours[2]->lheight()-1), cu, CH_L); + } + if ((!cuNeighbours[10]) && cuNeighbours[2]) + { + cuNeighbours[10] = cu.cs->getCURestricted(cuNeighbours[2]->lumaPos().offset(cuNeighbours[2]->lwidth()-1, -1), cu, CH_L); + } + if ((!cuNeighbours[11]) && cuLeft && cuNeighbours[7]) + { + cuNeighbours[11] = cu.cs->getCURestricted(cuNeighbours[7]->lumaPos().offset(-1, 0), cu, CH_L); + } + if ((!cuNeighbours[12]) && cuTop && cuNeighbours[8]) + { + cuNeighbours[12] = cu.cs->getCURestricted(cuNeighbours[8]->lumaPos().offset(0, -1), cu, CH_L); + } + + const Position topLeft = area.topLeft(); + // non-adjacent spatial candidates + int offsetX = 0; + int offsetY = 0; + int cout = 13; + const int numNACandidate[4] = { 3, 5, 5, 5 }; + const int idxMap[4][5] = { { 0, 1, 4 }, { 0, 1, 2, 3, 4 }, { 0, 1, 2, 3, 4 }, { 0, 1, 2, 3, 4 } }; + for (int iDistanceIndex = 0; iDistanceIndex < NADISTANCE_LEVEL; iDistanceIndex++) + { + const int iNADistanceHor = cu.Y().width * (iDistanceIndex + 1); + const int iNADistanceVer = cu.Y().height * (iDistanceIndex + 1); + for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex]; iNASPIdx++) + { + switch (idxMap[iDistanceIndex][iNASPIdx]) + { + case 0: offsetX = -iNADistanceHor - 1; offsetY = cu.Y().height + iNADistanceVer - 1; break; + case 1: offsetX = cu.Y().width + iNADistanceHor - 1; offsetY = -iNADistanceVer - 1; break; + case 2: offsetX = cu.Y().width >> 1; offsetY = -iNADistanceVer - 1; break; + case 3: offsetX = -iNADistanceHor - 1; offsetY = cu.Y().height >> 1; break; + case 4: offsetX = -iNADistanceHor - 1; offsetY = -iNADistanceVer - 1; break; + default: printf("error!"); exit(0); break; + } + cuNeighbours[cout++] = cu.cs->getCURestricted(topLeft.offset(offsetX, offsetY), cu, CH_L); + } + } + int numBlocks = 0; + int limitMaxNeigh = NUM_OBIC_CUS; + bool useNeighbour[numCUs]; + int neighboursInDistOrder[numCUs]; + int dists[numCUs]; + for (int i = 0; i < numCUs; i++) + { + useNeighbour[i] = false; + neighboursInDistOrder[i] = 0; + dists[i] = 0; + } + for (int i = 0; i < numCUs; i++) + { + dists[i] = MAX_INT; + } + int numToMix = 0; + for (int i = 0; i < numCUs; i++) + { + useNeighbour[i] = (cuNeighbours[i] && CU::isIntra(*cuNeighbours[i])); + if (useNeighbour[i]) + { + for (int j = i-1; j >= 0; j--) + { + if (!useNeighbour[j]) + { + continue; + } + useNeighbour[i] &= (cuNeighbours[i]->lx() != cuNeighbours[j]->lx() || cuNeighbours[i]->ly() != cuNeighbours[j]->ly()); + } + } + int curNeigh = i; + int curDist = (useNeighbour[i] ? abs( (int)(cu.lx()) - (int)(cuNeighbours[i]->lx())) + abs( (int)(cu.ly()) - (int)(cuNeighbours[i]->ly())) : 0); + + for (int j = 0; j < numCUs; j++) + { + if (curDist < dists[j]) + { + for (int k = numCUs - 1; k > j; k--) + { + dists[k] = dists[k - 1]; + neighboursInDistOrder[k] = neighboursInDistOrder[k - 1]; + } + dists[j] = curDist; + neighboursInDistOrder[j] = curNeigh; + break; + } + } + } + for (int i = 0; i < numCUs; i++) + { + int j = neighboursInDistOrder[i]; + if (limitMaxNeigh > 0 && numToMix >= limitMaxNeigh) + { + useNeighbour[j] = false; + continue; + } + if (useNeighbour[j]) + { + numToMix ++; + } + } + for (int i = 0; i < numCUs; i++) + { + if (!useNeighbour[i]) + { + continue; + } + if (cuNeighbours[i]->timd || cuNeighbours[i]->dimd || cuNeighbours[i]->sgpm || cuNeighbours[i]->tmrlFlag) + { + numBlocks++; + } +#if JVET_AG0058_EIP + else if (cuNeighbours[i]->eipFlag && cu.slice->getSliceType() != I_SLICE) + { + numBlocks++; + } +#endif +#if JVET_AC0115_INTRA_TMP_DIMD_MTS_LFNST + else if (cuNeighbours[i]->tmpFlag && cu.slice->getSliceType() != I_SLICE) + { + numBlocks++; + } +#endif +#if JVET_AB0067_MIP_DIMD_LFNST + else if (cuNeighbours[i]->mipFlag && cu.slice->getSliceType() != I_SLICE) + { + numBlocks++; + } +#endif + else if (CU::isIntra(*cuNeighbours[i]) && !CU::isIBC(*cuNeighbours[i]) && !cuNeighbours[i]->mipFlag && !cuNeighbours[i]->tmpFlag && !cuNeighbours[i]->eipFlag && !CU::isPLT(*cuNeighbours[i])) + { + numBlocks++; + } + } + if (numBlocks < 1) + { + return false; + } + return true; +} +#endif + #if JVET_AB0155_SGPM uint32_t PU::getIntraDirLuma(const PredictionUnit &pu, const int partIdx) { diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 4e5066898..cd7a642de 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -938,6 +938,10 @@ namespace PU bool isOppositeLIC(const PredictionUnit &pu); bool hasOppositeLICFlag(const PredictionUnit &pu); #endif +#if JVET_AH0076_OBIC + bool isObicAvail(const PredictionUnit &pu); + bool checkAvailBlocks(const PredictionUnit &pu); +#endif } // TU tools @@ -1368,4 +1372,4 @@ int getAllowedCurEip(const CodingUnit& cu, const ComponentID compId, static_vect #endif #if JVET_AG0061_INTER_LFNST_NSPT int buildHistogram(const Pel *pReco, int iStride, uint32_t uiHeight, uint32_t uiWidth, int *piHistogram, int direction, int bw, int bh); -#endif \ No newline at end of file +#endif diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index d1d3735d3..fcdfcf6f0 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -1968,7 +1968,12 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) { return; } - +#if JVET_AH0076_OBIC + if (cu.obicFlag) + { + return; + } +#endif if( cu.bdpcmMode ) { cu.firstPU->intraDir[0] = cu.bdpcmMode == 2? VER_IDX : HOR_IDX; @@ -2235,10 +2240,29 @@ void CABACReader::cu_dimd_flag(CodingUnit& cu) unsigned ctxId = DeriveCtx::CtxDIMDFlag(cu); cu.dimd = m_BinDecoder.decodeBin(Ctx::DimdFlag(ctxId)); +#if JVET_AH0076_OBIC + cu_obic_flag(cu); +#endif DTRACE(g_trace_ctx, D_SYNTAX, "cu_dimd_flag() ctx=%d pos=(%d,%d) dimd=%d\n", ctxId, cu.lumaPos().x, cu.lumaPos().y, cu.dimd); } #endif +#if JVET_AH0076_OBIC +void CABACReader::cu_obic_flag(CodingUnit& cu ) +{ + cu.obicFlag = false; + if (!cu.dimd || !cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType)) + { + return; + } + if (!PU::isObicAvail(*cu.firstPU)) + { + return; + } + cu.obicFlag = m_BinDecoder.decodeBin( Ctx::obicFlag(0) ); +} +#endif + #if JVET_AG0058_EIP void CABACReader::cu_eip_flag(CodingUnit& cu) { diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 3c9513c38..76bb3c56a 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -144,6 +144,9 @@ public: #if ENABLE_DIMD void cu_dimd_flag (CodingUnit& cu); #endif +#if JVET_AH0076_OBIC + void cu_obic_flag ( CodingUnit& cu ); +#endif void cu_residual ( CodingUnit& cu, Partitioner& pm, CUCtx& cuCtx ); void rqt_root_cbf ( CodingUnit& cu ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index e6adc62f4..172098601 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -333,6 +333,13 @@ void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea ) pu->intraDir[0] = currCU.dimdMode; #if JVET_AG0146_DIMD_ITMP_IBC m_pcIntraPred->getBestNonAnglularMode(currCU.cs->picture->getRecoBuf(area), area, currCU, m_pcIntraPred->m_bvBasedMergeCandidates); +#endif +#if JVET_AH0076_OBIC + if (currCU.obicFlag) + { + m_pcIntraPred->deriveObicMode(currCU.cs->picture->getRecoBuf(area), area, currCU); + pu->intraDir[0] = currCU.obicMode[0]; + } #endif } #if JVET_W0123_TIMD_FUSION @@ -1056,7 +1063,11 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) { m_pcIntraPred->initIntraMip( pu, area ); #if JVET_AB0067_MIP_DIMD_LFNST +#if JVET_AH0076_OBIC + m_pcIntraPred->predIntraMip( compID, piPred, pu, true); +#else m_pcIntraPred->predIntraMip( compID, piPred, pu, pu.cu->lfnstIdx > 0 ? true : false); +#endif #else m_pcIntraPred->predIntraMip( compID, piPred, pu ); #endif @@ -1390,7 +1401,11 @@ void DecCu::xIntraRecACTBlk(TransformUnit& tu) { m_pcIntraPred->initIntraMip(pu, area); #if JVET_AB0067_MIP_DIMD_LFNST +#if JVET_AH0076_OBIC + m_pcIntraPred->predIntraMip(compID, piPred, pu, true); +#else m_pcIntraPred->predIntraMip(compID, piPred, pu, pu.cu->lfnstIdx > 0 ? true : false); +#endif #else m_pcIntraPred->predIntraMip(compID, piPred, pu); #endif diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 0dd19a85a..69bb99c0e 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -1508,7 +1508,12 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu ) { return; } - +#if JVET_AH0076_OBIC + if (cu.obicFlag) + { + return; + } +#endif if( cu.bdpcmMode ) { cu.firstPU->intraDir[0] = cu.bdpcmMode == 2? VER_IDX : HOR_IDX; @@ -1731,7 +1736,12 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu ) void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu ) { - +#if JVET_AH0076_OBIC + if (pu.cu->obicFlag) + { + return; + } +#endif if( pu.cu->bdpcmMode ) return; #if JVET_V0130_INTRA_TMP // check if sufficient search range is available @@ -2035,10 +2045,28 @@ void CABACWriter::cu_dimd_flag(const CodingUnit& cu) } unsigned ctxId = DeriveCtx::CtxDIMDFlag(cu); m_BinEncoder.encodeBin(cu.dimd, Ctx::DimdFlag(ctxId)); +#if JVET_AH0076_OBIC + cu_obic_flag(cu); +#endif DTRACE(g_trace_ctx, D_SYNTAX, "cu_dimd_flag() ctx=%d pos=(%d,%d) dimd=%d\n", ctxId, cu.lumaPos().x, cu.lumaPos().y, cu.dimd); } #endif +#if JVET_AH0076_OBIC +void CABACWriter::cu_obic_flag(const CodingUnit& cu ) +{ + if (!cu.dimd || !cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType)) + { + return; + } + if (!PU::isObicAvail(*cu.firstPU)) + { + return; + } + m_BinEncoder.encodeBin(cu.obicFlag ? 1 : 0, Ctx::obicFlag(0)); +} +#endif + void CABACWriter::intra_chroma_pred_modes( const CodingUnit& cu ) { #if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index d6c18e9c1..45e3b5933 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -130,6 +130,9 @@ public: #if ENABLE_DIMD void cu_dimd_flag ( const CodingUnit& cu ); #endif +#if JVET_AH0076_OBIC + void cu_obic_flag ( const CodingUnit& cu ); +#endif #if JVET_W0123_TIMD_FUSION void cu_timd_flag ( const CodingUnit& cu ); #endif diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index fdcd97c1b..c8d243a75 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -2594,7 +2594,11 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS int8_t dimdChromaMode = -1; int8_t dimdChromaModeSecond = -1; #endif - +#if JVET_AH0076_OBIC + bool obicIsBlended = false; + int obicMode[OBIC_FUSION_NUM] = { -1 }; + int obicFusionWeight[OBIC_FUSION_NUM] = { 0 }; +#endif if (isLuma(partitioner.chType)) { CodingUnit cu(tempCS->area); @@ -2703,7 +2707,9 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS m_pcIntraSearch->getMpmListSize() = PU::getIntraMPMs( pu, m_pcIntraSearch->getMPMList(), m_pcIntraSearch->getNonMPMList() ); } #endif - +#if JVET_AH0076_OBIC + bool obicModeDerived = false; +#endif #if JVET_W0123_TIMD_FUSION bool timdDerived = false; #endif @@ -2717,6 +2723,10 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS m_pcIntraSearch->m_skipTimdLfnstMtsPass = false; m_modeCtrl->resetLfnstCost(); #endif +#if JVET_AH0076_OBIC + m_pcIntraSearch->m_skipObicLfnstMtsPass = false; + m_pcIntraSearch->m_skipDimdLfnstMtsPass = false; +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING m_pcIntraSearch->m_skipCCCMSATD = false; #endif @@ -2947,7 +2957,33 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS } } #endif - +#if JVET_AH0076_OBIC + cu.obicFlag = false; + if (isLuma(partitioner.chType)) + { + if (!obicModeDerived) + { + const CompArea &area = cu.Y(); + m_pcIntraSearch->deriveObicMode(bestCS->picture->getRecoBuf(area), area, cu); + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + obicMode[i] = cu.obicMode[i]; + obicFusionWeight[i] = cu.obicFusionWeight[i]; + } + obicIsBlended = cu.obicIsBlended; + obicModeDerived = true; + } + else + { + for (int i = 0; i < OBIC_FUSION_NUM; i++) + { + cu.obicMode[i] = obicMode[i]; + cu.obicFusionWeight[i] = obicFusionWeight[i]; + } + cu.obicIsBlended = obicIsBlended; + } + } +#endif #if TMP_FAST_ENC if (isLuma(partitioner.chType) && cu.slice->getSPS()->getUseIntraTMP()) { diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index e44f95cb7..b4f9886a0 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -97,6 +97,10 @@ IntraSearch::IntraSearch() { m_eipMergePredBuf[i] = nullptr; } +#endif +#if JVET_AH0076_OBIC + m_dimdPredBuf = nullptr; + m_obicPredBuf = nullptr; #endif m_truncBinBits = nullptr; m_escapeNumBins = nullptr; @@ -276,6 +280,12 @@ void IntraSearch::destroy() delete[] m_eipMergePredBuf[i]; m_eipMergePredBuf[i] = nullptr; } +#endif +#if JVET_AH0076_OBIC + delete[] m_dimdPredBuf; + m_dimdPredBuf = nullptr; + delete[] m_obicPredBuf; + m_obicPredBuf = nullptr; #endif m_isInitialized = false; if (m_truncBinBits != nullptr) @@ -403,14 +413,18 @@ void IntraSearch::init( EncCfg* pcEncCfg, m_ddCcpFusionStorage[i].create(UnitArea(cform, Area(0, 0, maxCUWidth, maxCUHeight))); } #endif -#if JVET_AB0155_SGPM +#if JVET_AB0155_SGPM || JVET_AH0076_OBIC #if JVET_AG0152_SGPM_ITMP_IBC for (int i = 0; i < NUM_LUMA_MODE + SGPM_NUM_BVS; i++) #else for (int i = 0; i < NUM_LUMA_MODE; i++) #endif { +#if JVET_AH0076_OBIC + m_intraPredBuf[i] = new Pel[(MAX_CU_SIZE>>1) * (MAX_CU_SIZE>>1)]; +#else m_intraPredBuf[i] = new Pel[GEO_MAX_CU_SIZE_EX * GEO_MAX_CU_SIZE_EX]; +#endif } for (int i = 0; i < SGPM_NUM; i++) { @@ -426,6 +440,10 @@ void IntraSearch::init( EncCfg* pcEncCfg, { m_eipMergePredBuf[i] = new Pel[MAX_EIP_SIZE * MAX_EIP_SIZE]; } +#endif +#if JVET_AH0076_OBIC + m_dimdPredBuf = new Pel[(MAX_CU_SIZE>>1) * (MAX_CU_SIZE>>1)]; + m_obicPredBuf = new Pel[(MAX_CU_SIZE>>1) * (MAX_CU_SIZE>>1)]; #endif for( uint32_t ch = 0; ch < MAX_NUM_TBLOCKS; ch++ ) { @@ -556,6 +574,10 @@ void IntraSearch::init( EncCfg* pcEncCfg, #if INTRA_TRANS_ENC_OPT m_skipTimdLfnstMtsPass = false; #endif +#if JVET_AH0076_OBIC + m_skipObicLfnstMtsPass = false; + m_skipDimdLfnstMtsPass = false; +#endif } @@ -729,7 +751,12 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c #if JVET_AB0155_SGPM bool SGPMSaveFlag = (cu.lfnstIdx == 0 && cu.mtsFlag == 0); #endif - +#if JVET_AH0076_OBIC + bool testDimd = isLuma(partitioner.chType) && cu.slice->getSPS()->getUseDimd(); + bool testObic = testDimd && (PU::isObicAvail(*cu.firstPU) && cu.obicMode[0] >= 0); + bool obicSaveFlag = testObic && (cu.lfnstIdx == 0 && cu.mtsFlag == 0); + bool dimdSaveFlag = testDimd && (cu.lfnstIdx == 0 && cu.mtsFlag == 0); +#endif const uint32_t lfnstIdx = cu.lfnstIdx; #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS double costInterCU = findInterCUCost( cu ); @@ -830,6 +857,10 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c double regAngCost = MAX_DOUBLE; bool setSkipTimdControl = (m_pcEncCfg->getIntraPeriod() == 1) && !cu.lfnstIdx && !cu.mtsFlag; double timdAngCost = MAX_DOUBLE; +#endif +#if JVET_AH0076_OBIC + double obicAngCost = MAX_DOUBLE, dimdAngCost = MAX_DOUBLE; + bool setSkipDimdControl = (m_pcEncCfg->getIntraPeriod() == 1) && !cu.lfnstIdx && !cu.mtsFlag; #endif const bool testBDPCM = sps.getBDPCMEnabledFlag() && CU::bdpcmAllowed(cu, ComponentID(partitioner.chType)) && cu.mtsFlag == 0 && cu.lfnstIdx == 0; static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiHadModeList; @@ -873,6 +904,10 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c #if ENABLE_DIMD bool bestDimdMode = false; #endif +#if JVET_AH0076_OBIC + bool bestObicMode = false; + int bestMipDimd = 0; +#endif #if JVET_W0123_TIMD_FUSION bool bestTimdMode = false; #endif @@ -908,7 +943,11 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c if (mtsUsageFlag != 2) { #if JVET_AB0155_SGPM +#if JVET_AH0076_OBIC + if ((testSgpm && SGPMSaveFlag) || obicSaveFlag || dimdSaveFlag) +#else if (testSgpm && SGPMSaveFlag) +#endif { #if JVET_AG0152_SGPM_ITMP_IBC for (int i = 0; i < NUM_LUMA_MODE + SGPM_NUM_BVS; i++) @@ -1059,6 +1098,38 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c } #endif +#if JVET_AH0076_OBIC + int dimdNeededMode[NUM_LUMA_MODE] = {0}; + if (obicSaveFlag) + { + for (int idx = 0; idx < OBIC_FUSION_NUM; idx++) + { + int iMode = cu.obicMode[idx]; + if (iMode < 0) + { + continue; + } + dimdNeededMode[iMode] = 1; + } + } + if (dimdSaveFlag) + { + if (cu.dimdBlending) + { + for (int dimdIdx = 0; dimdIdx < DIMD_FUSION_NUM - 1; dimdIdx++) + { + int dimdMode = (dimdIdx == 0 ? cu.dimdMode : cu.dimdBlendMode[dimdIdx-1]); + if (dimdMode <= 0) + { + break; + } + dimdNeededMode[dimdMode] = 1; + } + dimdNeededMode[PLANAR_IDX] = 1; + } + } +#endif + #if JVET_AB0157_TMRL double tmrlCostList[MRL_LIST_SIZE]{ MAX_DOUBLE }; #endif @@ -1111,6 +1182,14 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c m_intraModeReady[uiMode] = 1; } #endif +#if JVET_AH0076_OBIC + if ((obicSaveFlag || dimdSaveFlag) && dimdNeededMode[uiMode] && !m_intraModeReady[uiMode]) + { + PelBuf predBuf(m_intraPredBuf[uiMode], tmpArea); + predBuf.copyFrom(piPred); + m_intraModeReady[uiMode] = 1; + } +#endif // Use the min between SAD and HAD as the cost criterion // SAD is scaled by 2 to align with the scaling of HAD @@ -1237,6 +1316,14 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c m_intraModeReady[mode] = 1; } #endif +#if JVET_AH0076_OBIC + if ((obicSaveFlag || dimdSaveFlag) && dimdNeededMode[mode] && !m_intraModeReady[mode]) + { + PelBuf predBuf(m_intraPredBuf[mode], tmpArea); + predBuf.copyFrom(piPred); + m_intraModeReady[mode] = 1; + } +#endif // Use the min between SAD and SATD as the cost criterion // SAD is scaled by 2 to align with the scaling of HAD @@ -1825,6 +1912,86 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c #endif ); } +#if JVET_AH0076_OBIC + if (obicSaveFlag || dimdSaveFlag) + { + cu.dimd = false; + cu.timd = false; + cu.mipFlag = false; + pu.multiRefIdx = 0; +#if JVET_V0130_INTRA_TMP + cu.tmpFlag = false; +#endif + cu.sgpm = false; +#if JVET_AB0157_INTRA_FUSION + initIntraPatternChType(cu, pu.Y(), true, 0, false); +#else + initIntraPatternChType(cu, pu.Y(), true); +#endif + if (obicSaveFlag) + { + for (int idx = 0; idx < OBIC_FUSION_NUM; idx++) + { + int iMode = cu.obicMode[idx]; + if (iMode < 0) + { + continue; + } + if (dimdNeededMode[iMode] && !m_intraModeReady[iMode]) + { + pu.intraDir[0] = iMode; + initPredIntraParams(pu, pu.Y(), sps); +#if JVET_AB0157_INTRA_FUSION + predIntraAng(COMPONENT_Y, piPred, pu, false); +#else + predIntraAng(COMPONENT_Y, piPred, pu); +#endif + PelBuf predBuf(m_intraPredBuf[iMode], tmpArea); + predBuf.copyFrom(piPred); + m_intraModeReady[iMode] = 1; + } + } + } + if (dimdSaveFlag) + { + if (dimdNeededMode[PLANAR_IDX] && !m_intraModeReady[PLANAR_IDX]) + { + pu.intraDir[0] = PLANAR_IDX; + initPredIntraParams(pu, pu.Y(), sps); +#if JVET_AB0157_INTRA_FUSION + predIntraAng(COMPONENT_Y, piPred, pu, false); +#else + predIntraAng(COMPONENT_Y, piPred, pu); +#endif + PelBuf predBuf(m_intraPredBuf[PLANAR_IDX], tmpArea); + predBuf.copyFrom(piPred); + m_intraModeReady[PLANAR_IDX] = 1; + } + } + for (int dimdIdx = 0; dimdIdx < DIMD_FUSION_NUM - 1; dimdIdx++) + { + int dimdMode = (dimdIdx == 0 ? cu.dimdMode : cu.dimdBlendMode[dimdIdx-1]); + if (dimdMode <= 0) + { + break; + } + + if (dimdNeededMode[dimdMode] && !m_intraModeReady[dimdMode]) + { + pu.intraDir[0] = dimdMode; + initPredIntraParams(pu, pu.Y(), sps); +#if JVET_AB0157_INTRA_FUSION + predIntraAng(COMPONENT_Y, piPred, pu, false); +#else + predIntraAng(COMPONENT_Y, piPred, pu); +#endif + PelBuf predBuf(m_intraPredBuf[dimdMode], tmpArea); + predBuf.copyFrom(piPred); + m_intraModeReady[dimdMode] = 1; + } + } + } +#endif if (sps.getUseMIP() && LFNSTSaveFlag) { // save found best modes @@ -1847,7 +2014,93 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c uiHadModeList = m_uiSavedHadModeListLFNST; CandHadList = m_dSavedHadListLFNST; } - +#if JVET_AH0076_OBIC + if (obicSaveFlag || dimdSaveFlag) + { + cu.dimd = true; + cu.obicFlag = false; + cu.timd = false; + cu.mipFlag = false; + cu.tmpFlag = false; + cu.tmrlFlag = false; + cu.firstPU->multiRefIdx = 0; + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + int iWidth = cu.lwidth(); + int iHeight = cu.lheight(); + if (obicSaveFlag) + { + cu.obicFlag = true; + int obicMode = cu.obicMode[0]; + pu.intraDir[CHANNEL_TYPE_LUMA] = obicMode; + bool blendModes[OBIC_FUSION_NUM - 1] = {false}; + PelBuf predFusion[OBIC_FUSION_NUM - 1]; + CHECK(!m_intraModeReady[obicMode], "OBIC mode is not ready!"); + const UnitArea localUnitArea( pu.chromaFormat, Area( 0, 0, iWidth, iHeight ) ); + PelBuf predBuf(m_intraPredBuf[obicMode], pu.Y()); + piPred.copyFrom(predBuf); + int planarIdx = 0; + for (int idx = 0; idx < OBIC_FUSION_NUM - 1; idx++) + { + blendModes[idx] = false; + predFusion[idx] = m_tempBuffer[idx].getBuf( localUnitArea.Y() ); + int iMode = cu.obicMode[idx + 1]; + if (iMode >= 0) + { + blendModes[idx] = true; + CHECK(!m_intraModeReady[iMode], "OBIC mode is not ready!"); + PelBuf predBufTmp(m_intraPredBuf[iMode], pu.Y()); + predFusion[idx].copyFrom(predBufTmp); + if (iMode == PLANAR_IDX) + { + planarIdx = idx; + } + } + else + { + PelBuf planarBuf(m_intraPredBuf[PLANAR_IDX], pu.Y()); + predFusion[idx].copyFrom(planarBuf); + } + } + if (cu.obicIsBlended) + { + generateObicBlending(piPred, pu, predFusion, blendModes, planarIdx); + } + else + { + initIntraPatternChType(cu, pu.Y(), false); + predIntraAng(COMPONENT_Y, piPred, pu); + } + PelBuf obicSaveBuf(m_obicPredBuf, pu.Y()); + obicSaveBuf.copyFrom(piPred); + } + if (dimdSaveFlag) + { + cu.obicFlag = false; + int dimdMode = cu.dimdMode; + pu.intraDir[CHANNEL_TYPE_LUMA] = dimdMode; + if (cu.dimdBlending) + { + PelBuf predBuf(m_intraPredBuf[dimdMode], tmpArea); + piPred.copyFrom(predBuf); + PelBuf blendBuf0((m_intraPredBuf[cu.dimdBlendMode[0] > 0 ?cu.dimdBlendMode[0] : PLANAR_IDX]), tmpArea); + PelBuf blendBuf1((m_intraPredBuf[cu.dimdBlendMode[1] > 0 ?cu.dimdBlendMode[1] : PLANAR_IDX]), tmpArea); + PelBuf blendBuf2((m_intraPredBuf[cu.dimdBlendMode[2] > 0 ?cu.dimdBlendMode[2] : PLANAR_IDX]), tmpArea); + PelBuf blendBuf3((m_intraPredBuf[cu.dimdBlendMode[3] > 0 ?cu.dimdBlendMode[3] : PLANAR_IDX]), tmpArea); + PelBuf planarBuf(m_intraPredBuf[PLANAR_IDX], tmpArea); + generateDimdBlending(piPred, pu, blendBuf0, blendBuf1, blendBuf2, blendBuf3, planarBuf); + } + else + { + initIntraPatternChType(cu, pu.Y(), false); + predIntraAng(COMPONENT_Y, piPred, pu); + } + PelBuf dimdSaveBuf(m_dimdPredBuf, pu.Y()); + dimdSaveBuf.copyFrom(piPred); + } + } + cu.dimd = false; + cu.obicFlag = false; +#endif #if JVET_AB0155_SGPM if (testSgpm) { @@ -2257,6 +2510,14 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c CHECK(numModesForFullRD != uiRdModeList.size(), "Inconsistent state!"); #endif +#if JVET_AH0076_OBIC + cu.obicFlag = false; + if (testObic) + { + ModeInfo m = ModeInfo( false, false, 0, NOT_INTRA_SUBPARTITIONS, OBIC_IDX ); + uiRdModeList.push_back(m); + } +#endif // after this point, don't use numModesForFullRD // PBINTRA fast if (m_pcEncCfg->getUsePbIntraFast() && !cs.slice->isIntra() && uiRdModeList.size() < numModesAvailable @@ -2492,7 +2753,11 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c uiOrgMode = uiRdModeList[mode]; } #if ENABLE_DIMD && INTRA_TRANS_ENC_OPT - if ((m_pcEncCfg->getIntraPeriod() == 1) && cu.slice->getSPS()->getUseDimd() && mode >= 0 && !cu.dimdBlending && uiOrgMode.ispMod == 0 && uiOrgMode.mRefId == 0 && uiOrgMode.modeId != TIMD_IDX && uiOrgMode.modeId != DIMD_IDX) + if ((m_pcEncCfg->getIntraPeriod() == 1) && cu.slice->getSPS()->getUseDimd() && mode >= 0 && !cu.dimdBlending && uiOrgMode.ispMod == 0 && uiOrgMode.mRefId == 0 && uiOrgMode.modeId != TIMD_IDX && uiOrgMode.modeId != DIMD_IDX +#if JVET_AH0076_OBIC + && uiOrgMode.modeId != OBIC_IDX +#endif + ) { bool modeDuplicated = (uiOrgMode.modeId == cu.dimdMode); if (modeDuplicated) @@ -2506,10 +2771,33 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c cu.dimd = false; if( mode >= 0 && uiOrgMode.modeId == DIMD_IDX ) /*to check*/ { +#if JVET_AH0076_OBIC + if (m_skipDimdLfnstMtsPass) + { + CHECK(!cu.lfnstIdx && !cu.mtsFlag, "invalid logic"); + continue; + } +#endif uiOrgMode.modeId = cu.dimdMode; cu.dimd = true; } #endif +#if JVET_AH0076_OBIC + cu.obicFlag = false; + if( mode >= 0 && uiOrgMode.modeId == OBIC_IDX) /*to check*/ + { + if (m_skipObicLfnstMtsPass) + { + CHECK(!cu.lfnstIdx && !cu.mtsFlag, "invalid logic"); + continue; + } + cu.obicFlag = true; + cu.dimd = true; + uiOrgMode.modeId = cu.obicMode[0]; + pu.intraDir[CHANNEL_TYPE_LUMA] = uiOrgMode.modeId; + pu.multiRefIdx = 0; + } +#endif #if JVET_AC0105_DIRECTIONAL_PLANAR cu.plIdx = 0; if (mode >= 0 && uiOrgMode.modeId == PL_HOR_IDX) @@ -2861,6 +3149,25 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c } #endif } +#endif +#if JVET_AH0076_OBIC + if (setSkipDimdControl && cu.dimd) + { + if (cu.obicFlag) + { + if (csTemp->cost < obicAngCost) + { + obicAngCost = csTemp->cost; + } + } + else + { + if (csTemp->cost < dimdAngCost) + { + dimdAngCost = csTemp->cost; + } + } + } #endif // check r-d cost if( csTemp->cost < csBest->cost ) @@ -2872,6 +3179,9 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c #if ENABLE_DIMD bestDimdMode = cu.dimd; #endif +#if JVET_AH0076_OBIC + bestObicMode = cu.obicFlag; +#endif #if JVET_W0123_TIMD_FUSION bestTimdMode = cu.timd; #endif @@ -2888,6 +3198,13 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c intraTmpDimdMode = curCu->intraTmpDimdMode; } #endif +#if JVET_AH0076_OBIC + if (cu.mipFlag) + { + CodingUnit* curCu = csBest->getCU(partitioner.currArea().lumaPos(), partitioner.chType); + bestMipDimd = curCu->mipDimdMode; + } +#endif if( sps.getUseLFNST() && mtsUsageFlag == 1 && !cu.ispMode ) { @@ -2961,6 +3278,19 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c m_skipTimdLfnstMtsPass = true; } } +#endif +#if JVET_AH0076_OBIC + if (setSkipDimdControl) + { + if (regAngCost != MAX_DOUBLE && dimdAngCost != MAX_DOUBLE && regAngCost * 1.5 < dimdAngCost) + { + m_skipDimdLfnstMtsPass = true; + } + if (regAngCost != MAX_DOUBLE && obicAngCost != MAX_DOUBLE && regAngCost * 1.5 < obicAngCost) + { + m_skipObicLfnstMtsPass = true; + } + } #endif cu.ispMode = uiBestPUMode.ispMod; cu.lfnstIdx = bestLfnstIdx; @@ -3015,6 +3345,15 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c { CHECK(pu.multiRefIdx > 0, "use of DIMD"); } +#endif +#if JVET_AH0076_OBIC + cu.obicFlag = bestObicMode; + cu.mipDimdMode = bestMipDimd; + if (cu.obicFlag) + { + pu.intraDir[ CHANNEL_TYPE_LUMA ] = cu.obicMode[0]; + cu.dimd = true; + } #endif cu.bdpcmMode = bestBDPCMMode; #if JVET_W0123_TIMD_FUSION @@ -8314,7 +8653,11 @@ void IntraSearch::xSelectAMTForFullRD(TransformUnit &tu else if (PU::isMIP(pu, chType)) { initIntraMip(pu, area); +#if JVET_AH0076_OBIC + predIntraMip(COMPONENT_Y, piPred, pu, true); +#else predIntraMip(COMPONENT_Y, piPred, pu); +#endif } #if JVET_AG0058_EIP else if (PU::isEIP(pu, chType)) @@ -8322,6 +8665,13 @@ void IntraSearch::xSelectAMTForFullRD(TransformUnit &tu const CPelBuf eipSaveBuf(pu.cu->eipMerge ? m_eipMergePredBuf[pu.intraDir[0]] : m_eipPredBuf[pu.intraDir[0]], pu.Y()); piPred.copyFrom(eipSaveBuf); } +#endif +#if JVET_AH0076_OBIC + else if (pu.cu->dimd && chType == CHANNEL_TYPE_LUMA && pu.cu->ispMode == NOT_INTRA_SUBPARTITIONS) + { + const CPelBuf dimdSaveBuf(pu.cu->obicFlag ? m_obicPredBuf : m_dimdPredBuf, pu.Y()); + piPred.copyFrom(dimdSaveBuf); + } #endif else { @@ -8632,7 +8982,11 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp { initIntraMip( pu, area ); #if JVET_AB0067_MIP_DIMD_LFNST +#if JVET_AH0076_OBIC + predIntraMip( compID, piPred, pu, true); +#else predIntraMip( compID, piPred, pu, pu.cu->lfnstIdx > 0 ? true : false); +#endif #else predIntraMip( compID, piPred, pu ); #endif @@ -8643,6 +8997,13 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp const CPelBuf eipSaveBuf(pu.cu->eipMerge ? m_eipMergePredBuf[pu.intraDir[0]] : m_eipPredBuf[pu.intraDir[0]], pu.Y()); piPred.copyFrom(eipSaveBuf); } +#endif +#if JVET_AH0076_OBIC + else if (pu.cu->dimd && compID == COMPONENT_Y && pu.cu->ispMode == NOT_INTRA_SUBPARTITIONS) + { + const CPelBuf dimdSaveBuf(pu.cu->obicFlag ? m_obicPredBuf : m_dimdPredBuf, pu.Y()); + piPred.copyFrom(dimdSaveBuf); + } #endif else { @@ -10321,7 +10682,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti { initIntraMip(pu, area); #if JVET_AB0067_MIP_DIMD_LFNST +#if JVET_AH0076_OBIC + predIntraMip(compID, piPred, pu, true); +#else predIntraMip(compID, piPred, pu, pu.cu->lfnstIdx > 0 ? true : false); +#endif #else predIntraMip(compID, piPred, pu); #endif diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index a6c47448d..f46906d58 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -609,6 +609,10 @@ private: static_vector<ModeInfo, NUM_DERIVED_EIP + MAX_MERGE_EIP> m_uiSavedHadModeListEip; static_vector<double, NUM_DERIVED_EIP + MAX_MERGE_EIP> m_dSavedModeCostEip; static_vector<double, NUM_DERIVED_EIP + MAX_MERGE_EIP> m_dSavedHadListEip; +#endif +#if JVET_AH0076_OBIC + Pel* m_dimdPredBuf; + Pel* m_obicPredBuf; #endif PelStorage m_tmpStorageLCU; PelStorage m_colorTransResiBuf; @@ -691,6 +695,10 @@ public: #if INTRA_TRANS_ENC_OPT bool m_skipTimdLfnstMtsPass; #endif +#if JVET_AH0076_OBIC + bool m_skipObicLfnstMtsPass; + bool m_skipDimdLfnstMtsPass; +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING bool m_skipCCCMSATD; int m_isCccmNoSubModeEnabledInRdo[MMLM_T_IDX + 1]; -- GitLab