From e621c4a43f6e5ccce5486c5957b1933f6fbe7460 Mon Sep 17 00:00:00 2001 From: deluxan <santiago.de.luxan@hhi.fraunhofer.de> Date: Fri, 2 Aug 2019 20:02:06 +0200 Subject: [PATCH] Integration of JVET-0502 --- cfg/encoder_lowdelay_P_vtm.cfg | 2 +- cfg/encoder_lowdelay_vtm.cfg | 2 +- cfg/encoder_randomaccess_vtm.cfg | 2 +- source/Lib/CommonLib/IntraPrediction.cpp | 145 ++++++- source/Lib/CommonLib/IntraPrediction.h | 11 + source/Lib/CommonLib/TrQuant.cpp | 14 + source/Lib/CommonLib/TrQuant.h | 6 +- source/Lib/CommonLib/TypeDef.h | 6 + source/Lib/CommonLib/UnitTools.cpp | 27 ++ source/Lib/CommonLib/UnitTools.h | 5 + source/Lib/DecoderLib/CABACReader.cpp | 4 + source/Lib/DecoderLib/DecCu.cpp | 34 ++ source/Lib/EncoderLib/CABACWriter.cpp | 8 + source/Lib/EncoderLib/EncCu.cpp | 34 ++ source/Lib/EncoderLib/EncCu.h | 4 + source/Lib/EncoderLib/EncModeCtrl.h | 3 + source/Lib/EncoderLib/IntraSearch.cpp | 523 ++++++++++++++++++++++- source/Lib/EncoderLib/IntraSearch.h | 133 +++++- 18 files changed, 956 insertions(+), 7 deletions(-) diff --git a/cfg/encoder_lowdelay_P_vtm.cfg b/cfg/encoder_lowdelay_P_vtm.cfg index 2d24145ce..be04c02b9 100644 --- a/cfg/encoder_lowdelay_P_vtm.cfg +++ b/cfg/encoder_lowdelay_P_vtm.cfg @@ -133,7 +133,7 @@ MIP : 1 # Fast tools PBIntraFast : 1 -ISPFast : 1 +ISPFast : 0 FastMrg : 1 AMaxBT : 1 FastMIP : 0 diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg index 148f03230..15864d6a3 100644 --- a/cfg/encoder_lowdelay_vtm.cfg +++ b/cfg/encoder_lowdelay_vtm.cfg @@ -138,7 +138,7 @@ PROF : 1 # Fast tools PBIntraFast : 1 -ISPFast : 1 +ISPFast : 0 FastMrg : 1 AMaxBT : 1 FastMIP : 0 diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index 2e4c7a033..58a9f20fd 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -156,7 +156,7 @@ PROF : 1 # Fast tools PBIntraFast : 1 -ISPFast : 1 +ISPFast : 0 FastMrg : 1 AMaxBT : 1 FastMIP : 0 diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index f9a5914b3..ebd48f18f 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -328,8 +328,12 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co const int srcStride = m_topRefLength + 1 + (whRatio + 1) * multiRefIdx; const int srcHStride = m_leftRefLength + 1 + (hwRatio + 1) * multiRefIdx; #endif - + +#if JVET_O0502_ISP_CLEANUP + const CPelBuf& srcBuf = pu.cu->ispMode && isLuma(compID) ? getISPBuffer() : CPelBuf(getPredictorPtr(compID), srcStride, srcHStride); +#else const CPelBuf & srcBuf = CPelBuf(getPredictorPtr(compID), srcStride, srcHStride); +#endif const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compID)); switch (uiDirMode) @@ -519,7 +523,11 @@ void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompA m_ipaParam.multiRefIndex = isLuma (chType) ? pu.multiRefIdx : 0 ; m_ipaParam.refFilterFlag = false; m_ipaParam.interpolationFlag = false; +#if JVET_O0502_ISP_CLEANUP + m_ipaParam.applyPDPC = ((puSize.width >= MIN_TB_SIZEY && puSize.height >= MIN_TB_SIZEY) || !isLuma(compId)) && m_ipaParam.multiRefIndex == 0; +#else m_ipaParam.applyPDPC = !useISP && m_ipaParam.multiRefIndex == 0; +#endif const int intraPredAngleMode = (m_ipaParam.isModeVer) ? predMode - VER_IDX : -(predMode - HOR_IDX); @@ -573,10 +581,12 @@ void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompA || DC_IDX == dirMode ) { +#if !JVET_O0502_ISP_CLEANUP if (useISP) { m_ipaParam.interpolationFlag = (m_ipaParam.isModeVer ? puSize.width : puSize.height) > 8 ? true : false ; } +#endif } else if (isLuma( chType ) && pu.cu->bdpcmMode) // BDPCM { @@ -1065,6 +1075,132 @@ void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompAre } } +#if JVET_O0502_ISP_CLEANUP +void IntraPrediction::initIntraPatternChTypeISP(const CodingUnit& cu, const CompArea& area, PelBuf& recBuf, const bool forceRefFilterFlag) +{ + const CodingStructure& cs = *cu.cs; + + if (!forceRefFilterFlag) + { + initPredIntraParams(*cu.firstPU, area, *cs.sps); + } + + const Position posLT = area; + bool isLeftAvail = cs.isDecomp(posLT.offset(-1, 0), CHANNEL_TYPE_LUMA); + bool isAboveAvail = cs.isDecomp(posLT.offset(0, -1), CHANNEL_TYPE_LUMA); + // ----- Step 1: unfiltered reference samples ----- +#if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN + if (cu.blocks[area.compID].x == area.x && cu.blocks[area.compID].y == area.y) +#else + if (CU::isISPFirst(cu, area, area.compID)) +#endif + { + Pel* refBufUnfiltered = m_piYuvExt[area.compID][PRED_BUF_UNFILTERED]; + // With the first subpartition all the CU reference samples are fetched at once in a single call to xFillReferenceSamples + if (cu.ispMode == HOR_INTRA_SUBPARTITIONS) + { + m_leftRefLength = cu.Y().height << 1; + m_topRefLength = cu.Y().width + area.width; + } + else //if (cu.ispMode == VER_INTRA_SUBPARTITIONS) + { + m_leftRefLength = cu.Y().height + area.height; + m_topRefLength = cu.Y().width << 1; + } + + const int multiRefIdx = m_ipaParam.multiRefIndex; + const int whRatio = m_ipaParam.whRatio; + const int hwRatio = m_ipaParam.hwRatio; + const int srcStride = m_topRefLength + 1 + (whRatio + 1) * multiRefIdx; + const int srcHStride = m_leftRefLength + 1 + (hwRatio + 1) * multiRefIdx; + m_pelBufISP[0] = m_pelBufISPBase[0] = PelBuf(m_piYuvExt[area.compID][PRED_BUF_UNFILTERED], srcStride, srcHStride); + m_pelBufISP[1] = m_pelBufISPBase[1] = PelBuf(m_piYuvExt[area.compID][PRED_BUF_FILTERED], srcStride, srcHStride); + + xFillReferenceSamples(cs.picture->getRecoBuf(cu.Y()), refBufUnfiltered, cu.Y(), cu); + + // After having retrieved all the CU reference samples, the number of reference samples is now adjusted for the current subpartition + m_topRefLength = cu.blocks[area.compID].width + area.width; + m_leftRefLength = cu.blocks[area.compID].height + area.height; + } + else + { + //Now we only need to fetch the newly available reconstructed samples from the previously coded TU + Position tuPos = area; + tuPos.relativeTo(cu.Y()); + m_pelBufISP[0] = m_pelBufISPBase[0].subBuf(tuPos, area.size()); + m_pelBufISP[1] = m_pelBufISPBase[1].subBuf(tuPos, area.size()); + + PelBuf& dstBuf = m_pelBufISP[0]; + + m_topRefLength = cu.blocks[area.compID].width + area.width; + m_leftRefLength = cu.blocks[area.compID].height + area.height; + + const int predSizeHor = m_topRefLength; + const int predSizeVer = m_leftRefLength; + if (cu.ispMode == HOR_INTRA_SUBPARTITIONS) + { + Pel* src = recBuf.bufAt(0, -1); + Pel* dst = dstBuf.bufAt(1, 0); + for (int i = 0; i < area.width; i++) + { + dst[i] = src[i]; + } + Pel sample = src[area.width - 1]; + dst += area.width; + for (int i = 0; i < predSizeHor - area.width; i++) + { + dst[i] = sample; + } + if (!isLeftAvail) //if left is not avaible, then it is necessary to fetch these samples for each subpartition + { + Pel* dst = dstBuf.bufAt(0, 0); + Pel sample = src[0]; + for (int i = 0; i < predSizeVer + 1; i++) + { + *dst = sample; + dst += dstBuf.stride; + } + } + } + else + { + Pel* src = recBuf.bufAt(-1, 0); + Pel* dst = dstBuf.bufAt(0, 1); + for (int i = 0; i < area.height; i++) + { + *dst = *src; + src += recBuf.stride; + dst += dstBuf.stride; + } + Pel sample = src[-recBuf.stride]; + for (int i = 0; i < predSizeVer - area.height; i++) + { + *dst = sample; + dst += dstBuf.stride; + } + + if (!isAboveAvail) //if above is not avaible, then it is necessary to fetch these samples for each subpartition + { + Pel* dst = dstBuf.bufAt(0, 0); + Pel sample = recBuf.at(-1, 0); + for (int i = 0; i < predSizeHor + 1; i++) + { + dst[i] = sample; + } + } + } + } + // ----- Step 2: filtered reference samples ----- + if (m_ipaParam.refFilterFlag || forceRefFilterFlag) + { + Pel* refBufUnfiltered = m_pelBufISP[0].buf; + Pel* refBufFiltered = m_pelBufISP[1].buf; + xFilterReferenceSamples(refBufUnfiltered, refBufFiltered, area, *cs.sps, cu.firstPU->multiRefIdx, m_pelBufISP[0].stride); + } +} +#endif + + void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu ) { const ChannelType chType = toChannelType( area.compID ); @@ -1322,6 +1458,9 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps , int multiRefIdx +#if JVET_O0502_ISP_CLEANUP + , int stride +#endif ) { if (area.compID != COMPONENT_Y) @@ -1337,7 +1476,11 @@ void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* const int predSize = m_topRefLength + (whRatio + 1) * multiRefIdx; const int predHSize = m_leftRefLength + (hwRatio + 1) * multiRefIdx; #endif +#if JVET_O0502_ISP_CLEANUP + const int predStride = stride == 0 ? predSize + 1 : stride; +#else const int predStride = predSize + 1; +#endif diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index 901eff095..157283e03 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -68,6 +68,10 @@ class IntraPrediction private: Pel* m_piYuvExt[MAX_NUM_COMPONENT][NUM_PRED_BUF]; +#if JVET_O0502_ISP_CLEANUP + PelBuf m_pelBufISPBase[2]; + PelBuf m_pelBufISP[2]; +#endif int m_iYuvExtSize; Pel* m_yuvExt2[MAX_NUM_COMPONENT][4]; @@ -129,6 +133,9 @@ protected: void xFillReferenceSamples ( const CPelBuf &recoBuf, Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu ); void xFilterReferenceSamples ( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps , int multiRefIdx +#if JVET_O0502_ISP_CLEANUP + , int predStride = 0 +#endif ); static int getWideAngle ( int width, int height, int predMode ); @@ -152,6 +159,10 @@ public: void xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea); /// set parameters from CU data for accessing intra data void initIntraPatternChType (const CodingUnit &cu, const CompArea &area, const bool forceRefFilterFlag = false); // use forceRefFilterFlag to get both filtered and unfiltered buffers +#if JVET_O0502_ISP_CLEANUP + void initIntraPatternChTypeISP (const CodingUnit& cu, const CompArea& area, PelBuf& piReco, const bool forceRefFilterFlag = false); // use forceRefFilterFlag to get both filtered and unfiltered buffers + const PelBuf& getISPBuffer () { return m_pelBufISP[m_ipaParam.refFilterFlag ? PRED_BUF_FILTERED : PRED_BUF_UNFILTERED]; } +#endif // Matrix-based intra prediction void initIntraMip (const PredictionUnit &pu); diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp index d45791d5d..ddf049944 100644 --- a/source/Lib/CommonLib/TrQuant.cpp +++ b/source/Lib/CommonLib/TrQuant.cpp @@ -1056,7 +1056,11 @@ void TrQuant::xQuant(TransformUnit &tu, const ComponentID &compID, const CCoeffB m_quant->quant( tu, compID, pSrc, uiAbsSum, cQP, ctx ); } +#if JVET_O0502_ISP_CLEANUP +void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const QpParam& cQP, std::vector<TrMode>* trModes, const int maxCand ) +#else void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand, double* diagRatio, double* horVerRatio ) +#endif { CodingStructure &cs = *tu.cs; const CompArea &rect = tu.blocks[compID]; @@ -1111,9 +1115,11 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const it++; } +#if !JVET_O0502_ISP_CLEANUP // it gets the distribution of the DCT-II coefficients energy, which will be useful to discard ISP tests CoeffBuf coeffsDCT( m_mtsCoeffs[0], rect ); xGetCoeffEnergy( tu, compID, coeffsDCT, diagRatio, horVerRatio ); +#endif int numTests = 0; std::vector<TrCost>::iterator itC = trCosts.begin(); const double fac = facBB[g_aucLog2[std::max(width, height)]-2]; @@ -1128,7 +1134,11 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const } } +#if JVET_O0502_ISP_CLEANUP +void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const QpParam& cQP, TCoeff& uiAbsSum, const Ctx& ctx, const bool loadTr ) +#else void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr, double* diagRatio, double* horVerRatio ) +#endif { CodingStructure &cs = *tu.cs; const SPS &sps = *cs.sps; @@ -1207,6 +1217,7 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const } } +#if !JVET_O0502_ISP_CLEANUP //we do this only with the DCT-II coefficients if( isLuma(compID) && !loadTr && tu.mtsIdx == MTS_DCT2_DCT2 @@ -1215,6 +1226,7 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const //it gets the distribution of the coefficients energy, which will be useful to discard ISP tests xGetCoeffEnergy( tu, compID, tempCoeff, diagRatio, horVerRatio ); } +#endif if( sps.getUseLFNST() ) { @@ -1233,6 +1245,7 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const TU::setCbfAtDepth (tu, compID, tu.depth, uiAbsSum > 0); } +#if !JVET_O0502_ISP_CLEANUP void TrQuant::xGetCoeffEnergy( TransformUnit &tu, const ComponentID &compID, const CoeffBuf& coeffs, double* diagRatio, double* horVerRatio ) { if( nullptr == diagRatio || nullptr == horVerRatio ) return; @@ -1266,6 +1279,7 @@ void TrQuant::xGetCoeffEnergy( TransformUnit &tu, const ComponentID &compID, con *diagRatio = 0 == wdtE && 0 == hgtE && 0 == diaE ? 1 : double( diaE ) / double( wdtE + hgtE ); } } +#endif void TrQuant::applyForwardRDPCM(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const RDPCMMode &mode) { diff --git a/source/Lib/CommonLib/TrQuant.h b/source/Lib/CommonLib/TrQuant.h index f762386ac..ba4e30823 100644 --- a/source/Lib/CommonLib/TrQuant.h +++ b/source/Lib/CommonLib/TrQuant.h @@ -94,9 +94,13 @@ protected: public: void invTransformNxN (TransformUnit &tu, const ComponentID &compID, PelBuf &pResi, const QpParam &cQPs); - +#if JVET_O0502_ISP_CLEANUP + void transformNxN ( TransformUnit& tu, const ComponentID& compID, const QpParam& cQP, std::vector<TrMode>* trModes, const int maxCand ); + void transformNxN ( TransformUnit& tu, const ComponentID& compID, const QpParam& cQP, TCoeff& uiAbsSum, const Ctx& ctx, const bool loadTr = false ); +#else void transformNxN ( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand, double* diagRatio = nullptr, double* horVerRatio = nullptr ); void transformNxN ( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr = false, double* diagRatio = nullptr, double* horVerRatio = nullptr ); +#endif void rdpcmNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, RDPCMMode &rdpcmMode); void applyForwardRDPCM(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const RDPCMMode &rdpcmMode); diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 2e3d38e17..2990155da 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,7 @@ #include <assert.h> #include <cassert> +#define JVET_O0502_ISP_CLEANUP 1 // JVET-O0502: Enable PDPC and all 67 intra modes and apply the cubic filter always (also included in JVET-O0341) for ISP #define JVET_O0070_PROF 1 // JVET-O0070 method 4-2.1a: Prediction refinement with optical flow for affine mode @@ -484,7 +485,12 @@ enum ISPType NOT_INTRA_SUBPARTITIONS = 0, HOR_INTRA_SUBPARTITIONS = 1, VER_INTRA_SUBPARTITIONS = 2, +#if JVET_O0502_ISP_CLEANUP + NUM_INTRA_SUBPARTITIONS_MODES = 3, + INTRA_SUBPARTITIONS_RESERVED = 4 +#else NUM_INTRA_SUBPARTITIONS_MODES = 3 +#endif }; enum SbtIdx diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 413d6dacd..1bf6e46ab 100755 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -282,6 +282,7 @@ bool CU::divideTuInRows( const CodingUnit &cu ) return cu.ispMode == HOR_INTRA_SUBPARTITIONS ? true : false; } +#if !JVET_O0502_ISP_CLEANUP bool CU::firstTestISPHorSplit( const int width, const int height, const ComponentID compID, const CodingUnit *cuLeft, const CodingUnit *cuAbove ) { //this function decides which split mode (horizontal or vertical) is tested first (encoder only) @@ -351,6 +352,7 @@ bool CU::firstTestISPHorSplit( const int width, const int height, const Componen return true; } } +#endif PartSplit CU::getISPType( const CodingUnit &cu, const ComponentID compID ) { @@ -432,6 +434,31 @@ uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit return partitionSize; } +#if JVET_O0502_ISP_CLEANUP +bool CU::allLumaCBfsAreZero(const CodingUnit& cu) +{ + if (!cu.ispMode) + { + return TU::getCbf(*cu.firstTU, COMPONENT_Y) == false; + } + else + { + int numTotalTUs = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> g_aucLog2[cu.firstTU->lheight()] : cu.lwidth() >> g_aucLog2[cu.firstTU->lwidth()]; + //bool allZeroCbfs = false; + TransformUnit* tuPtr = cu.firstTU; + for (int tuIdx = 0; tuIdx < numTotalTUs; tuIdx++) + { + if (TU::getCbf(*tuPtr, COMPONENT_Y) == true) + { + return false; + } + tuPtr = tuPtr->next; + } + return true; + } +} +#endif + PUTraverser CU::traversePUs( CodingUnit& cu ) { diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 0e8f46b1a..05b03ea61 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -96,13 +96,18 @@ namespace CU bool divideTuInRows ( const CodingUnit &cu ); +#if !JVET_O0502_ISP_CLEANUP bool firstTestISPHorSplit ( const int width, const int height, const ComponentID compID, const CodingUnit *cuLeft = nullptr, const CodingUnit *cuAbove = nullptr ); +#endif PartSplit getISPType ( const CodingUnit &cu, const ComponentID compID ); bool isISPLast ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ); bool isISPFirst ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ); bool canUseISP ( const CodingUnit &cu, const ComponentID compID ); bool canUseISP ( const int width, const int height, const int maxTrSize = MAX_TB_SIZEY ); uint32_t getISPSplitDim ( const int width, const int height, const PartSplit ispType ); +#if JVET_O0502_ISP_CLEANUP + bool allLumaCBfsAreZero ( const CodingUnit& cu ); +#endif PUTraverser traversePUs ( CodingUnit& cu); TUTraverser traverseTUs ( CodingUnit& cu); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 296ecdf77..64f2393ff 100755 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -1269,7 +1269,11 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) for( int k = 0; k < numBlocks; k++ ) { CHECK(numBlocks != 1, "not supported yet"); +#if JVET_O0502_ISP_CLEANUP + if ( cu.firstPU->multiRefIdx ) +#else if( cu.firstPU->multiRefIdx || ( cu.ispMode && isLuma( cu.chType ) ) ) +#endif { mpmFlag[0] = true; } diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index ba1571a52..998eb3394 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -204,8 +204,39 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) const PredictionUnit &pu = *tu.cs->getPU( area.pos(), chType ); const uint32_t uiChFinalMode = PU::getFinalIntraMode( pu, chType ); +#if JVET_O0502_ISP_CLEANUP + PelBuf pReco = cs.getRecoBuf(area); +#endif //===== init availability pattern ===== +#if JVET_O0502_ISP_CLEANUP +#if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN + bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID); + bool firstTBInPredReg = CU::isFirstTBInPredReg(*tu.cu, compID, area); + CompArea areaPredReg(COMPONENT_Y, tu.chromaFormat, area); +#endif + if (tu.cu->ispMode && isLuma(compID)) + { +#if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN + if (predRegDiffFromTB) + { + if (firstTBInPredReg) + { + CU::adjustPredArea(areaPredReg); + m_pcIntraPred->initIntraPatternChTypeISP(*tu.cu, areaPredReg, pReco); + } + } + else +#endif + { + m_pcIntraPred->initIntraPatternChTypeISP(*tu.cu, area, pReco); + } + } + else + { + m_pcIntraPred->initIntraPatternChType(*tu.cu, area); + } +#else #if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID); bool firstTBInPredReg = CU::isFirstTBInPredReg (*tu.cu, compID, area); @@ -221,6 +252,7 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) else #endif m_pcIntraPred->initIntraPatternChType(*tu.cu, area); +#endif //===== get prediction signal ===== if( compID != COMPONENT_Y && PU::isLMCMode( uiChFinalMode ) ) @@ -323,7 +355,9 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) CrossComponentPrediction::crossComponentPrediction( tu, compID, cs.getResiBuf( tu.Y() ), piResi, piResi, true ); } +#if !JVET_O0502_ISP_CLEANUP PelBuf pReco = cs.getRecoBuf( area ); +#endif if( !tu.cu->ispMode || !isLuma( compID ) ) { diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 188e7d6c3..0b14b65cc 100755 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -1054,7 +1054,11 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu ) break; } } +#if JVET_O0502_ISP_CLEANUP + if ( pu->multiRefIdx ) +#else if( pu->multiRefIdx || ( cu.ispMode && isLuma( cu.chType ) ) ) +#endif { CHECK(mpm_idx >= numMPMs, "use of non-MPM"); } @@ -1154,7 +1158,11 @@ void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu ) break; } } +#if JVET_O0502_ISP_CLEANUP + if ( pu.multiRefIdx ) +#else if( pu.multiRefIdx || ( pu.cu->ispMode && isLuma( pu.cu->chType ) ) ) +#endif { CHECK(mpm_idx >= numMPMs, "use of non-MPM"); } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index fe5b1633d..140adf9fc 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -572,8 +572,15 @@ bool EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS, } +#if JVET_O0502_ISP_CLEANUP +void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& partitioner, double maxCostAllowed ) +#else void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner ) +#endif { +#if JVET_O0502_ISP_CLEANUP + CHECK(maxCostAllowed < 0, "Wrong value of maxCostAllowed!"); +#endif if (m_shareState == NO_SHARE) { tempCS->sharedBndPos = tempCS->area.Y().lumaPos(); @@ -660,6 +667,9 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par do { EncTestMode currTestMode = m_modeCtrl->currTestMode(); +#if JVET_O0502_ISP_CLEANUP + currTestMode.maxCostAllowed = maxCostAllowed; +#endif if (pps.getUseDQP() && CS::isDualITree(*tempCS) && isChroma(partitioner.chType)) { @@ -1246,7 +1256,13 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, #if JVET_O0070_PROF tempSubCS->bestParent = bestSubCS->bestParent = bestCS; #endif +#if JVET_O0502_ISP_CLEANUP + double newMaxCostAllowed = isLuma(partitioner.chType) ? std::min(encTestMode.maxCostAllowed, bestCS->cost - m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist)) : MAX_DOUBLE; + newMaxCostAllowed = std::max(0.0, newMaxCostAllowed); + xCompressCU(tempSubCS, bestSubCS, partitioner, newMaxCostAllowed); +#else xCompressCU( tempSubCS, bestSubCS, partitioner ); +#endif #if JVET_O0070_PROF tempSubCS->bestParent = bestSubCS->bestParent = nullptr; #endif @@ -1464,8 +1480,17 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC bool validCandRet = false; if( isLuma( partitioner.chType ) ) { +#if JVET_O0502_ISP_CLEANUP + //ISP uses the value of the best cost so far (luma if it is the fast version) to avoid test non-necessary subpartitions + double bestCostSoFar = CS::isDualITree(*tempCS) ? m_modeCtrl->getBestCostWithoutSplitFlags() : bestCU && bestCU->predMode == MODE_INTRA ? bestCS->lumaCost : bestCS->cost; + if (CS::isDualITree(*tempCS) && encTestMode.maxCostAllowed < bestCostSoFar) + { + bestCostSoFar = encTestMode.maxCostAllowed; + } +#else //the Intra SubPartitions mode uses the value of the best cost so far (luma if it is the fast version) to avoid test non-necessary lines const double bestCostSoFar = CS::isDualITree( *tempCS ) ? m_modeCtrl->getBestCostWithoutSplitFlags() : bestCU && bestCU->predMode == MODE_INTRA ? bestCS->lumaCost : bestCS->cost; +#endif validCandRet = m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner, bestCostSoFar, mtsFlag, startMTSIdx[ trGrpIdx ], endMTSIdx[ trGrpIdx ], ( trGrpIdx > 0 ) ); if( sps.getUseLFNST() && ( !validCandRet || ( cu.ispMode && cu.firstTU->cbf[ COMPONENT_Y ] == 0 ) ) ) { @@ -1626,13 +1651,22 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC } } +#if JVET_O0502_ISP_CLEANUP + //we decide to skip the non-DCT-II transforms and LFNST according to the ISP results + if ((endMtsFlag > 0 || endLfnstIdx > 0) && cu.ispMode && !mtsFlag && !lfnstIdx && tempCS->slice->isIntra() && m_pcEncCfg->getUseFastISP()) +#else //we decide to skip the second emt pass or not according to the ISP results if( considerMtsSecondPass && cu.ispMode && !mtsFlag && tempCS->slice->isIntra() ) +#endif { double bestCostDct2NoIsp = m_modeCtrl->getMtsFirstPassNoIspCost(); CHECKD( bestCostDct2NoIsp <= bestIspCost, "wrong cost!" ); +#if JVET_O0502_ISP_CLEANUP + double threshold = 1.4; +#else double nSamples = ( double ) ( cu.lwidth() << g_aucLog2[ cu.lheight() ] ); double threshold = 1 + 1.4 / sqrt( nSamples ); +#endif double lfnstThreshold = 1.01 * threshold; if( bestCostDct2NoIsp > bestIspCost*lfnstThreshold ) diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index 994992656..9ea4376c5 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -175,7 +175,11 @@ protected: void xCalDebCost ( CodingStructure &cs, Partitioner &partitioner, bool calDist = false ); Distortion getDistortionDb ( CodingStructure &cs, CPelBuf org, CPelBuf reco, ComponentID compID, const CompArea& compArea, bool afterDb ); +#if JVET_O0502_ISP_CLEANUP + void xCompressCU ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm, double maxCostAllowed = MAX_DOUBLE ); +#else void xCompressCU ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm ); +#endif #if ENABLE_SPLIT_PARALLELISM void xCompressCUParallel ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm ); void copyState ( EncCu* other, Partitioner& pm, const UnitArea& currArea, const bool isDist ); diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h index d29d095c4..a690dc538 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.h +++ b/source/Lib/EncoderLib/EncModeCtrl.h @@ -112,6 +112,9 @@ struct EncTestMode EncTestModeOpts opts; int qp; bool lossless; +#if JVET_O0502_ISP_CLEANUP + double maxCostAllowed; +#endif }; diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 31956e602..e90c5e545 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -323,6 +323,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, #else bool testISP = sps.getUseISP() && cu.mtsFlag == 0 && cu.lfnstIdx == 0 && CU::canUseISP( width, height, MAX_TB_SIZEY ); #endif +#if !JVET_O0502_ISP_CLEANUP bool ispHorIsFirstTest = testISP ? CU::firstTestISPHorSplit( width, height, COMPONENT_Y, nullptr, nullptr ) : true; int ispOptions[] = { NOT_INTRA_SUBPARTITIONS, HOR_INTRA_SUBPARTITIONS, VER_INTRA_SUBPARTITIONS }; if ( !ispHorIsFirstTest ) @@ -330,8 +331,19 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, ispOptions[1] = VER_INTRA_SUBPARTITIONS; ispOptions[2] = HOR_INTRA_SUBPARTITIONS; } +#endif if( testISP ) { +#if JVET_O0502_ISP_CLEANUP + //reset the variables used for the tests + m_ispCandListHor.clear(); + m_ispCandListVer.clear(); + m_regIntraRDListWithCosts.clear(); + m_ispTestedModes.clear(); + //save the number of subpartitions + m_ispTestedModes.numTotalParts[0] = (int)height >> g_aucLog2[CU::getISPSplitDim(width, height, TU_1D_HORZ_SPLIT)]; + m_ispTestedModes.numTotalParts[1] = (int)width >> g_aucLog2[CU::getISPSplitDim(width, height, TU_1D_VERT_SPLIT)]; +#else //variables for the full RD list without MRL modes m_rdModeListWithoutMrl .clear(); m_rdModeListWithoutMrlHor .clear(); @@ -340,6 +352,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, m_intraModeDiagRatio .clear(); m_intraModeHorVerRatio .clear(); m_intraModeTestedNormalIntra.clear(); +#endif } #if JVET_O1136_TS_BDPCM_SIGNALLING @@ -557,8 +570,13 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } if ( testISP ) { +#if JVET_O0502_ISP_CLEANUP + // we save the regular intra modes list + m_ispCandListHor = uiRdModeList; +#else //we save the list with no mrl modes to keep only the Hadamard selected modes (no mpms) m_rdModeListWithoutMrl = uiRdModeList; +#endif } #if ENABLE_JVET_L0283_MRL pu.multiRefIdx = 1; @@ -671,6 +689,23 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } if ( testISP ) { +#if JVET_O0502_ISP_CLEANUP + // we add the MPMs to list that contains only regular intra modes + for (int j = 0; j < numCand; j++) + { + bool mostProbableModeIncluded = false; + ModeInfo mostProbableMode(false, 0, NOT_INTRA_SUBPARTITIONS, uiPreds[j]); + + for (int i = 0; i < m_ispCandListHor.size(); i++) + { + mostProbableModeIncluded |= (mostProbableMode == m_ispCandListHor[i]); + } + if (!mostProbableModeIncluded) + { + m_ispCandListHor.push_back(mostProbableMode); + } + } +#else //we add the ISP MPMs to the list without mrl modes m_rdModeListWithoutMrlHor = m_rdModeListWithoutMrl; m_rdModeListWithoutMrlVer = m_rdModeListWithoutMrl; @@ -701,6 +736,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } } cu.ispMode = NOT_INTRA_SUBPARTITIONS; +#endif } } //*** Add MPMs for MIP to candidate list @@ -765,6 +801,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } } +#if !JVET_O0502_ISP_CLEANUP if( testISP ) // we remove the non-MPMs from the ISP lists { static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeListCopyHor = m_rdModeListWithoutMrlHor; @@ -800,6 +837,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } cu.ispMode = NOT_INTRA_SUBPARTITIONS; } +#endif CHECK( numModesForFullRD != uiRdModeList.size(), "Inconsistent state!" ); @@ -821,8 +859,12 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, uiRdModeList.resize(std::min<size_t>(uiRdModeList.size(), maxSize)); if ( testISP ) { +#if JVET_O0502_ISP_CLEANUP + m_ispCandListHor.resize(std::min<size_t>(m_ispCandListHor.size(), maxSize)); +#else m_rdModeListWithoutMrlHor.resize(std::min<size_t>(m_rdModeListWithoutMrlHor.size(), maxSize)); m_rdModeListWithoutMrlVer.resize(std::min<size_t>(m_rdModeListWithoutMrlVer.size(), maxSize)); +#endif } } if (maxSize == 0) @@ -842,8 +884,18 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } } +#if JVET_O0502_ISP_CLEANUP + int numNonISPModes = (int)uiRdModeList.size(); +#endif + if ( testISP ) { +#if JVET_O0502_ISP_CLEANUP + // we reserve positions for ISP in the common full RD list + const int maxNumRDModesISP = 16; + for (int i = 0; i < maxNumRDModesISP; i++) + uiRdModeList.push_back(ModeInfo(false, 0, INTRA_SUBPARTITIONS_RESERVED, 0)); +#else //we create a single full RD list that includes all intra modes using regular intra, MRL and ISP auto* firstIspList = ispOptions[1] == HOR_INTRA_SUBPARTITIONS ? &m_rdModeListWithoutMrlHor : &m_rdModeListWithoutMrlVer; auto* secondIspList = ispOptions[1] == HOR_INTRA_SUBPARTITIONS ? &m_rdModeListWithoutMrlVer : &m_rdModeListWithoutMrlHor; @@ -877,6 +929,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, uiRdModeList.insert( uiRdModeList.end(), secondIspList->begin(), secondIspList->end() ); uiRdModeList.insert( uiRdModeList.end(), firstIspList->begin() , firstIspList->end() ); } +#endif } //===== check modes (using r-d costs) ===== @@ -920,14 +973,18 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } // just to be sure numModesForFullRD = ( int ) uiRdModeList.size(); +#if !JVET_O0502_ISP_CLEANUP PartSplit intraSubPartitionsProcOrder = TU_NO_ISP; int bestNormalIntraModeIndex = -1; +#endif TUIntraSubPartitioner subTuPartitioner( partitioner ); if( !cu.ispMode && !cu.mtsFlag ) { m_modeCtrl->setMtsFirstPassNoIspCost( MAX_DOUBLE ); } +#if !JVET_O0502_ISP_CLEANUP bool ispHorAllZeroCbfs = false, ispVerAllZeroCbfs = false; +#endif for (int mode = -2 * int(testBDPCM); mode < (int)uiRdModeList.size(); mode++) { @@ -952,6 +1009,18 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, else { cu.bdpcmMode = 0; +#if JVET_O0502_ISP_CLEANUP + if (uiRdModeList[mode].ispMod == INTRA_SUBPARTITIONS_RESERVED) + { + if (mode == numNonISPModes) // the list needs to be sorted only once + { + xSortISPCandList(bestCurrentCost, csBest->cost); + } + xGetNextISPMode(uiRdModeList[mode], (mode > 0 ? &uiRdModeList[mode - 1] : nullptr), Size(width, height)); + if (uiRdModeList[mode].ispMod == INTRA_SUBPARTITIONS_RESERVED) + continue; + } +#endif uiOrgMode = uiRdModeList[mode]; cu.mipFlag = uiOrgMode.mipFlg; cu.ispMode = uiOrgMode.ispMod; @@ -962,6 +1031,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, CHECK(pu.multiRefIdx && (pu.intraDir[0] == PLANAR_IDX), "Error: combination of MRL and Planar mode not supported"); CHECK(cu.ispMode && cu.mipFlag, "Error: combination of ISP and MIP not supported"); CHECK(cu.ispMode && pu.multiRefIdx, "Error: combination of ISP and MRL not supported"); +#if !JVET_O0502_ISP_CLEANUP if( cu.ispMode ) { intraSubPartitionsProcOrder = CU::getISPType( cu, COMPONENT_Y ); @@ -979,6 +1049,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, continue; } } +#endif } // set context models @@ -990,8 +1061,23 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, bool tmpValidReturn = false; if( cu.ispMode ) { +#if JVET_O0502_ISP_CLEANUP + tmpValidReturn = xIntraCodingLumaISP(*csTemp, subTuPartitioner, bestCurrentCost); + if (csTemp->tus.size() == 0) + { + // no TUs were coded + csTemp->cost = MAX_DOUBLE; + continue; + } + if (!cu.mtsFlag && !cu.lfnstIdx) + { + // we save the data for future tests + m_ispTestedModes.setModeResults((ISPType)cu.ispMode, (int)uiOrgMode.modeId, (int)csTemp->tus.size(), csTemp->cus[0]->firstTU->cbf[COMPONENT_Y] ? csTemp->cost : MAX_DOUBLE, csBest->cost); + } +#else tmpValidReturn = xRecurIntraCodingLumaQT( *csTemp, subTuPartitioner, bestCurrentCost, 0, intraSubPartitionsProcOrder, false, mtsCheckRangeFlag, mtsFirstCheckId, mtsLastCheckId, moreProbMTSIdxFirst ); +#endif } else { @@ -1003,8 +1089,16 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, mtsCheckRangeFlag, mtsFirstCheckId, mtsLastCheckId, moreProbMTSIdxFirst ); } +#if JVET_O0502_ISP_CLEANUP + if (!cu.ispMode && !cu.mtsFlag && !cu.lfnstIdx && !cu.bdpcmMode && !pu.multiRefIdx && !cu.mipFlag && testISP) + { + m_regIntraRDListWithCosts.push_back(ModeInfoWithCost(cu.mipFlag, pu.multiRefIdx, cu.ispMode, uiOrgMode.modeId, csTemp->cost)); + } +#endif + if( cu.ispMode && !csTemp->cus[0]->firstTU->cbf[COMPONENT_Y] ) { +#if !JVET_O0502_ISP_CLEANUP if( !sps.getUseLFNST() ) { if ( cu.ispMode == HOR_INTRA_SUBPARTITIONS ) @@ -1016,6 +1110,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, ispVerAllZeroCbfs |= ( m_pcEncCfg->getUseFastISP() && csTemp->tus[0]->lwidth() > 2 && csTemp->cost >= bestCurrentCost ); } } +#endif csTemp->cost = MAX_DOUBLE; csTemp->costDbOffset = 0; tmpValidReturn = false; @@ -1027,8 +1122,13 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, m_modeCostStore[ lfnstIdx ][ testMip ? rdModeIdxList[ mode ] : mode ] = tmpValidReturn ? csTemp->cost : ( MAX_DOUBLE / 2.0 ); //(MAX_DOUBLE / 2.0) ?? } - +#if JVET_O0502_ISP_CLEANUP + DTRACE(g_trace_ctx, D_INTRA_COST, "IntraCost T [x=%d,y=%d,w=%d,h=%d] %f (%d,%d,%d,%d,%d,%d) \n", cu.blocks[0].x, + cu.blocks[0].y, (int)width, (int)height, csTemp->cost, uiOrgMode.modeId, uiOrgMode.ispMod, + pu.multiRefIdx, cu.mipFlag, cu.lfnstIdx, cu.mtsFlag); +#else DTRACE( g_trace_ctx, D_INTRA_COST, "IntraCost T %f (%d) \n", csTemp->cost, uiOrgMode.modeId ); +#endif if( tmpValidReturn ) @@ -1056,7 +1156,9 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, if( !cu.ispMode && !cu.bdpcmMode && csBest->cost < bestCostNonBDPCM ) { bestCostNonBDPCM = csBest->cost; +#if !JVET_O0502_ISP_CLEANUP bestNormalIntraModeIndex = mode; +#endif } } @@ -1802,7 +1904,9 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp const bool bUseCrossCPrediction = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isChroma( compID ) && PU::isChromaIntraModeCrossCheckMode( pu ) && checkCrossCPrediction; const bool ccUseRecoResi = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate(); +#if !JVET_O0502_ISP_CLEANUP const bool ispSplitIsAllowed = sps.getUseISP() && CU::canUseISP( *tu.cu, compID ); +#endif //===== init availability pattern ===== @@ -1816,6 +1920,32 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp PelBuf sharedPredTS( m_pSharedPredTransformSkip[compID], area ); if( default0Save1Load2 != 2 ) { +#if JVET_O0502_ISP_CLEANUP +#if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN + bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID); + bool firstTBInPredReg = CU::isFirstTBInPredReg(*tu.cu, compID, area); + CompArea areaPredReg(COMPONENT_Y, tu.chromaFormat, area); +#endif + if (tu.cu->ispMode && isLuma(compID)) + { +#if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN + if (predRegDiffFromTB) + { + if (firstTBInPredReg) + { + CU::adjustPredArea(areaPredReg); + initIntraPatternChTypeISP(*tu.cu, areaPredReg, piReco); + } + } + else +#endif + initIntraPatternChTypeISP(*tu.cu, area, piReco); + } + else + { + initIntraPatternChType(*tu.cu, area); + } +#else #if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID); bool firstTBInPredReg = CU::isFirstTBInPredReg(*tu.cu, compID, area); @@ -1831,6 +1961,7 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp else #endif initIntraPatternChType(*tu.cu, area); +#endif //===== get prediction signal ===== if( compID != COMPONENT_Y && PU::isLMCMode( uiChFinalMode ) ) @@ -2001,6 +2132,14 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp if( isLuma(compID) ) { #endif +#if JVET_O0502_ISP_CLEANUP + if (trModes) + { + m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, CU::isIntra(*tu.cu) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand()); + tu.mtsIdx = trModes->at(0).first; + } + m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); +#else double diagRatio = 0, horVerRatio = 0; if( trModes ) @@ -2015,10 +2154,20 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp m_intraModeHorVerRatio .push_back(horVerRatio); m_intraModeTestedNormalIntra.push_back((int)uiChFinalMode); } +#endif DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), compID, uiAbsSum ); +#if JVET_O0502_ISP_CLEANUP + if (tu.cu->ispMode && isLuma(compID) && CU::isISPLast(*tu.cu, area, area.compID) && CU::allLumaCBfsAreZero(*tu.cu)) + { + // ISP has to have at least one non-zero CBF + ruiDist = MAX_INT; + return; + } +#endif + //--- inverse transform --- if (uiAbsSum > 0) @@ -2189,6 +2338,118 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } } +#if JVET_O0502_ISP_CLEANUP +bool IntraSearch::xIntraCodingLumaISP(CodingStructure& cs, Partitioner& partitioner, const double bestCostSoFar) +{ + int subTuCounter = 0; + const CodingUnit& cu = *cs.getCU(partitioner.currArea().lumaPos(), partitioner.chType); + bool earlySkipISP = false; + bool uiSplitCbfLuma = false; + const PartSplit ispType = CU::getISPType(cu, COMPONENT_Y); + + cs.cost = 0; + + partitioner.splitCurrArea(ispType, cs); + + do // subpartitions loop + { + uint32_t numSig = 0; + Distortion singleDistTmpLuma = 0; + uint64_t singleTmpFracBits = 0; + double singleCostTmp = 0; + + TransformUnit& tu = cs.addTU(CS::getArea(cs, partitioner.currArea(), partitioner.chType), partitioner.chType); + tu.depth = partitioner.currTrDepth; + + // Encode TU + xIntraCodingTUBlock(tu, COMPONENT_Y, false, singleDistTmpLuma, 0, &numSig); + + if (singleDistTmpLuma == MAX_INT) // all zero CBF skip + { + earlySkipISP = true; + partitioner.exitCurrSplit(); + cs.cost = MAX_DOUBLE; + return false; + } + + { + if (m_pcRdCost->calcRdCost(cs.fracBits, cs.dist + singleDistTmpLuma) > bestCostSoFar) + { + // The accumulated cost + distortion is already larger than the best cost so far, so it is not necessary to calculate the rate + earlySkipISP = true; + } + else + { + singleTmpFracBits = xGetIntraFracBitsQT(cs, partitioner, true, false, subTuCounter, ispType); + } + singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma); + } + + cs.cost += singleCostTmp; + cs.dist += singleDistTmpLuma; + cs.fracBits += singleTmpFracBits; + + subTuCounter++; + + uiSplitCbfLuma |= TU::getCbfAtDepth(*cs.getTU(partitioner.currArea().lumaPos(), partitioner.chType, subTuCounter - 1), COMPONENT_Y, partitioner.currTrDepth); + int nSubPartitions = m_ispTestedModes.numTotalParts[cu.ispMode - 1]; + if (subTuCounter < nSubPartitions) + { + // exit condition if the accumulated cost is already larger than the best cost so far (no impact in RD performance) + if (cs.cost > bestCostSoFar) + { + earlySkipISP = true; + break; + } + else if (subTuCounter < nSubPartitions) + { + // more restrictive exit condition + double threshold = nSubPartitions == 2 ? 0.95 : subTuCounter == 1 ? 0.83 : 0.91; + if (subTuCounter < nSubPartitions && cs.cost > bestCostSoFar * threshold) + { + earlySkipISP = true; + break; + } + } + } + } while (partitioner.nextPart(cs)); // subpartitions loop + + partitioner.exitCurrSplit(); + const UnitArea& currArea = partitioner.currArea(); + const uint32_t currDepth = partitioner.currTrDepth; + + if (earlySkipISP) + { + cs.cost = MAX_DOUBLE; + } + else + { + cs.cost = m_pcRdCost->calcRdCost(cs.fracBits, cs.dist); + // The cost check is necessary here again to avoid superfluous operations if the maximum number of coded subpartitions was reached and yet ISP did not win + if (cs.cost < bestCostSoFar) + { + cs.setDecomp(cu.Y()); + cs.picture->getRecoBuf(currArea.Y()).copyFrom(cs.getRecoBuf(currArea.Y())); + + for (auto& ptu : cs.tus) + { + if (currArea.Y().contains(ptu->Y())) + { + TU::setCbfAtDepth(*ptu, COMPONENT_Y, currDepth, uiSplitCbfLuma ? 1 : 0); + } + } + } + else + { + cs.cost = MAX_DOUBLE; + earlySkipISP = true; + } + } + return !earlySkipISP; +} +#endif + + bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &partitioner, const double bestCostSoFar, const int subTuIdx, const PartSplit ispType, const bool ispIsCurrentWinner, bool mtsCheckRangeFlag, int mtsFirstCheckId, int mtsLastCheckId, bool moreProbMTSIdxFirst ) { int subTuCounter = subTuIdx; @@ -3276,3 +3537,263 @@ void IntraSearch::reduceHadCandList(static_vector<T, N>& candModeList, static_ve candCostList = tempCandCostList; numModesForFullRD = int(candModeList.size()); } + +#if JVET_O0502_ISP_CLEANUP +// It decides which modes from the ISP lists can be full RD tested +void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode, const Size cuSize) +{ + static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM>* rdModeLists[2] = { &m_ispCandListHor, &m_ispCandListVer }; + + ISPType nextISPcandSplitType; + if (!m_ispTestedModes.stopTestingHorSplit && !m_ispTestedModes.stopTestingVerSplit) + { + nextISPcandSplitType = !lastMode ? HOR_INTRA_SUBPARTITIONS : lastMode->ispMod == HOR_INTRA_SUBPARTITIONS ? VER_INTRA_SUBPARTITIONS : HOR_INTRA_SUBPARTITIONS; + } + else if (!m_ispTestedModes.stopTestingHorSplit && m_ispTestedModes.stopTestingVerSplit) + { + nextISPcandSplitType = HOR_INTRA_SUBPARTITIONS; + } + else if (m_ispTestedModes.stopTestingHorSplit && !m_ispTestedModes.stopTestingVerSplit) + { + nextISPcandSplitType = VER_INTRA_SUBPARTITIONS; + } + else + { + return; // no more modes will be tested + } + + int maxNumSubPartitions = m_ispTestedModes.numTotalParts[nextISPcandSplitType - 1]; + + if (m_ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2) + { + // Split stop criteria after checking the performance of previously tested intra modes + const int thresholdSplit1 = maxNumSubPartitions; + + int mode1 = m_ispTestedModes.getTestedIntraMode((ISPType)nextISPcandSplitType, 0); + mode1 = mode1 == DC_IDX ? -1 : mode1; + int numSubPartsBestMode1 = mode1 != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)nextISPcandSplitType, mode1) : -1; + int mode2 = m_ispTestedModes.getTestedIntraMode((ISPType)nextISPcandSplitType, 1); + mode2 = mode2 == DC_IDX ? -1 : mode2; + int numSubPartsBestMode2 = mode2 != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)nextISPcandSplitType, mode2) : -1; + + // 1) The 2 most promising modes do not reach a certain number of sub-partitions + if (numSubPartsBestMode1 != -1 && numSubPartsBestMode2 != -1) + { + if (numSubPartsBestMode1 < thresholdSplit1 && numSubPartsBestMode2 < thresholdSplit1) + { + m_ispTestedModes.stopTestingVerSplit = nextISPcandSplitType == VER_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingVerSplit; + m_ispTestedModes.stopTestingHorSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingHorSplit; + return; + } + } + + // 2) One split is better than the other after PLANAR and one angle have been tested + ISPType otherSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? VER_INTRA_SUBPARTITIONS : HOR_INTRA_SUBPARTITIONS; + int numSubPartsBestAngleOtherSplit = mode2 != -1 ? m_ispTestedModes.getNumCompletedSubParts(otherSplit, mode2) : -1; + bool stopThisSplit = false; + if (numSubPartsBestAngleOtherSplit != -1 && numSubPartsBestMode2 != -1) + { + if (numSubPartsBestAngleOtherSplit > numSubPartsBestMode2) + { + stopThisSplit = true; + } + else if (numSubPartsBestAngleOtherSplit == numSubPartsBestMode2 && numSubPartsBestAngleOtherSplit == maxNumSubPartitions) + { + double rdCostBestAngleThisSplit = m_ispTestedModes.getRDCost(nextISPcandSplitType, mode2, maxNumSubPartitions); + double rdCostBestAngleOtherSplit = m_ispTestedModes.getRDCost(otherSplit, mode2, maxNumSubPartitions); + + if (rdCostBestAngleThisSplit == MAX_DOUBLE || rdCostBestAngleOtherSplit < rdCostBestAngleThisSplit * 1.3) + { + stopThisSplit = true; + } + } + } + if (stopThisSplit) + { + m_ispTestedModes.stopTestingVerSplit = nextISPcandSplitType == VER_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingVerSplit; + m_ispTestedModes.stopTestingHorSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingHorSplit; + return; + } + } + + // Now a new mode is retrieved from the list and it has to be decided whether it should be tested or not + if (m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1] < rdModeLists[nextISPcandSplitType - 1]->size()) + { + ModeInfo candidate = rdModeLists[nextISPcandSplitType - 1]->at(m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1]); + m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1]++; + + // extra modes are only tested if ISP has won so far + if (m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1] > m_ispTestedModes.numOrigModesToTest) + { + if (m_ispTestedModes.bestSplitSoFar != candidate.ispMod || m_ispTestedModes.bestModeSoFar == PLANAR_IDX) + { + return; + } + } + + bool testCandidate = true; + + // we look for a reference mode that has already been tested within the window and decide to test the new one according to the reference mode costs + if (candidate.modeId >= DC_IDX && maxNumSubPartitions > 2 && m_ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2) + { + const int angWindowSize = 5; + int numSubPartsLeftMode, numSubPartsRightMode, numSubPartsRefMode, leftIntraMode = -1, rightIntraMode = -1; + int windowSize = candidate.modeId > DC_IDX ? angWindowSize : 1; + int numSamples = cuSize.width << g_aucLog2[cuSize.height]; + int numSubPartsLimit = numSamples >= 256 ? maxNumSubPartitions - 1 : 2; + + xFindAlreadyTestedNearbyIntraModes((int)candidate.modeId, &leftIntraMode, &rightIntraMode, (ISPType)candidate.ispMod, windowSize); + + numSubPartsLeftMode = leftIntraMode != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, leftIntraMode) : -1; + numSubPartsRightMode = rightIntraMode != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, rightIntraMode) : -1; + + numSubPartsRefMode = std::max(numSubPartsLeftMode, numSubPartsRightMode); + + if (numSubPartsRefMode > 0) + { + // The mode was found. Now we check the condition + testCandidate = numSubPartsRefMode > numSubPartsLimit; + } + } + + if (testCandidate) + { + modeInfo = candidate; + } + } +} + +void IntraSearch::xFindAlreadyTestedNearbyIntraModes(int currentIntraMode, int* leftIntraMode, int* rightIntraMode, ISPType ispOption, int windowSize) +{ + bool leftModeFound = false, rightModeFound = false; + *leftIntraMode = -1; + *rightIntraMode = -1; + const unsigned st = ispOption - 1; + + for (int k = 1; k <= windowSize; k++) + { + int off = currentIntraMode - 2 - k; + int leftMode = (off < 0) ? NUM_LUMA_MODE + off : currentIntraMode - k; + int rightMode = currentIntraMode > DC_IDX ? (((int)currentIntraMode - 2 + k) % 65) + 2 : PLANAR_IDX; + + leftModeFound = leftMode != (int)currentIntraMode ? m_ispTestedModes.modeHasBeenTested[leftMode][st] : false; + rightModeFound = rightMode != (int)currentIntraMode ? m_ispTestedModes.modeHasBeenTested[rightMode][st] : false; + if (leftModeFound || rightModeFound) + { + *leftIntraMode = leftModeFound ? leftMode : -1; + *rightIntraMode = rightModeFound ? rightMode : -1; + break; + } + } +} + +void IntraSearch::xSortISPCandList(double bestCostSoFar, double bestNonISPCost) +{ + if (m_pcEncCfg->getUseFastISP()) + { + double thSkipISP = 1.4; + if (bestNonISPCost > bestCostSoFar * thSkipISP) + { + m_ispTestedModes.stopTestingHorSplit = true; + m_ispTestedModes.stopTestingVerSplit = true; + return; + } + } + + for (int k = 0; k < m_ispCandListHor.size(); k++) + { + m_ispCandListHor.at(k).ispMod = HOR_INTRA_SUBPARTITIONS; //we set the correct ISP split type value + } + + auto origHadList = m_ispCandListHor; // save the original hadamard list of regular intra + bool modeIsInList[NUM_LUMA_MODE] = { false }; + + m_ispCandListHor.clear(); + m_ispCandListVer.clear(); + + // we sort the normal intra modes according to their full RD costs + std::sort(m_regIntraRDListWithCosts.begin(), m_regIntraRDListWithCosts.end(), ModeInfoWithCost::compareModeInfoWithCost); + + // we get the best angle from the regular intra list + int bestNormalIntraAngle = -1; + for (int modeIdx = 0; modeIdx < m_regIntraRDListWithCosts.size(); modeIdx++) + { + if (bestNormalIntraAngle == -1 && m_regIntraRDListWithCosts.at(modeIdx).modeId > DC_IDX) + { + bestNormalIntraAngle = m_regIntraRDListWithCosts.at(modeIdx).modeId; + break; + } + } + + int mode1 = PLANAR_IDX; + int mode2 = bestNormalIntraAngle; + + ModeInfo refMode = origHadList.at(0); + auto* destListPtr = &m_ispCandListHor; + // 1) Planar + destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, mode1)); + modeIsInList[mode1] = true; + // 2) Best angle in regular intra + if (mode2 != -1) + { + destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, mode2)); + modeIsInList[mode2] = true; + } + // 3) Remaining regular intra modes that were full RD tested (except DC, which is added after the angles from regular intra) + int dcModeIndex = -1; + for (int remModeIdx = 0; remModeIdx < m_regIntraRDListWithCosts.size(); remModeIdx++) + { + int currentMode = m_regIntraRDListWithCosts.at(remModeIdx).modeId; + if (currentMode != mode1 && currentMode != mode2) + { + if (currentMode > DC_IDX) + { + destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, currentMode)); + modeIsInList[currentMode] = true; + } + else if (currentMode == DC_IDX) + { + dcModeIndex = remModeIdx; + } + } + } + // 4) DC is added after the angles from regular intra + if (dcModeIndex != -1) + { + destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, DC_IDX)); + modeIsInList[DC_IDX] = true; + } + + // 5) We add extra candidates to the list that will only be tested is likely to win + m_ispTestedModes.numOrigModesToTest = (int)destListPtr->size(); + const int addedModesFromHadList = 3; + int newModesAdded = 0; + + for (int k = 0; k < origHadList.size(); k++) + { + if (newModesAdded == addedModesFromHadList) + { + break; + } + if (!modeIsInList[origHadList.at(k).modeId]) + { + destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, origHadList.at(k).modeId)); + newModesAdded++; + } + } + + // Copy modes to other split-type list + m_ispCandListVer = m_ispCandListHor; + for (int i = 0; i < m_ispCandListVer.size(); i++) + { + m_ispCandListVer[i].ispMod = VER_INTRA_SUBPARTITIONS; + } + + // Reset the tested modes information to 0 + for (int i = 0; i < m_ispCandListHor.size(); i++) + { + m_ispTestedModes.clearISPModeInfo(m_ispCandListHor[i].modeId); + } +} + +#endif diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index fd005a552..d038d7310 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -87,10 +87,131 @@ private: ModeInfo(const bool mipf, const int mrid, const uint8_t ispm, const uint32_t mode) : mipFlg(mipf), mRefId(mrid), ispMod(ispm), modeId(mode) {} bool operator==(const ModeInfo cmp) const { return (mipFlg == cmp.mipFlg && mRefId == cmp.mRefId && ispMod == cmp.ispMod && modeId == cmp.modeId); } }; +#if JVET_O0502_ISP_CLEANUP + struct ModeInfoWithCost : public ModeInfo + { + double rdCost; + ModeInfoWithCost() : ModeInfo(), rdCost(MAX_DOUBLE) {} + ModeInfoWithCost(const bool mipf, const int mrid, const uint8_t ispm, const uint32_t mode, double cost) : ModeInfo(mipf, mrid, ispm, mode), rdCost(cost) {} + bool operator==(const ModeInfoWithCost cmp) const { return (mipFlg == cmp.mipFlg && mRefId == cmp.mRefId && ispMod == cmp.ispMod && modeId == cmp.modeId && rdCost == cmp.rdCost); } + static bool compareModeInfoWithCost(ModeInfoWithCost a, ModeInfoWithCost b) { return a.rdCost < b.rdCost; } + }; + + struct ISPTestedModeInfo + { + int numCompSubParts; + double rdCost; + + ISPTestedModeInfo() {} + + void setMode(int numParts, double cost) + { + numCompSubParts = numParts; + rdCost = cost; + } + void clear() + { + numCompSubParts = -1; + rdCost = MAX_DOUBLE; + } + }; + struct ISPTestedModesInfo + { + ISPTestedModeInfo intraMode[NUM_LUMA_MODE][2]; + bool modeHasBeenTested[NUM_LUMA_MODE][2]; + int numTotalParts[2]; + static_vector<int, FAST_UDI_MAX_RDMODE_NUM> testedModes[2]; + int bestModeSoFar; + ISPType bestSplitSoFar; + int bestMode[2]; + double bestCost[2]; + int numTestedModes[2]; + int candIndexInList[2]; + bool stopTestingHorSplit; + bool stopTestingVerSplit; + int numOrigModesToTest; + + // set a tested mode results + void setModeResults(ISPType splitType, int iModeIdx, int numCompletedParts, double rdCost, double currentBestCost) + { + const unsigned st = splitType - 1; + CHECKD(st > 1, "The split type is invalid!"); + const int maxNumParts = numTotalParts[st]; + intraMode[iModeIdx][st].setMode(numCompletedParts, numCompletedParts == maxNumParts ? rdCost : MAX_DOUBLE); + testedModes[st].push_back(iModeIdx); + numTestedModes[st]++; + modeHasBeenTested[iModeIdx][st] = true; + if (numCompletedParts == maxNumParts && rdCost < bestCost[st]) // best mode update + { + bestMode[st] = iModeIdx; + bestCost[st] = rdCost; + } + if (numCompletedParts == maxNumParts && rdCost < currentBestCost) // best mode update + { + bestModeSoFar = iModeIdx; + bestSplitSoFar = splitType; + } + } + + int getNumCompletedSubParts(ISPType splitType, int iModeIdx) + { + const unsigned st = splitType - 1; + CHECK(st < 0 || st > 1, "The split type is invalid!"); + CHECK(iModeIdx < 0 || iModeIdx >(NUM_LUMA_MODE - 1), "The modeIdx is invalid"); + return modeHasBeenTested[iModeIdx][st] ? intraMode[iModeIdx][st].numCompSubParts : -1; + } + + double getRDCost(ISPType splitType, int iModeIdx, int maxNumSubParts) + { + const unsigned st = splitType - 1; + CHECKD(st > 1, "The split type is invalid!"); + return modeHasBeenTested[iModeIdx][st] && intraMode[iModeIdx][st].numCompSubParts == maxNumSubParts + ? intraMode[iModeIdx][st].rdCost + : -1; + } + + // get a tested intra mode index + int getTestedIntraMode(ISPType splitType, int pos) + { + const unsigned st = splitType - 1; + CHECKD(st > 1, "The split type is invalid!"); + return pos < testedModes[st].size() ? testedModes[st].at(pos) : -1; + } + + // set everything to default values + void clear() + { + numTestedModes[0] = numTestedModes[1] = 0; + candIndexInList[0] = candIndexInList[1] = 0; + stopTestingHorSplit = false; + stopTestingVerSplit = false; + testedModes[0].clear(); + testedModes[1].clear(); + bestCost[0] = MAX_DOUBLE; + bestCost[1] = MAX_DOUBLE; + bestMode[0] = -1; + bestMode[1] = -1; + bestModeSoFar = -1; + bestSplitSoFar = NOT_INTRA_SUBPARTITIONS; + numOrigModesToTest = -1; + memset(modeHasBeenTested, 0, sizeof(modeHasBeenTested)); + } + void clearISPModeInfo(int idx) + { + intraMode[idx][0].clear(); + intraMode[idx][1].clear(); + } + }; + + static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_ispCandListHor, m_ispCandListVer; + static_vector<ModeInfoWithCost, FAST_UDI_MAX_RDMODE_NUM> m_regIntraRDListWithCosts; + ISPTestedModesInfo m_ispTestedModes; +#else static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrl; static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrlHor; static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrlVer; +#endif //cost variables for the EMT algorithm and new modes list double m_bestModeCostStore[ NUM_LFNST_NUM_PER_SET ]; // RD cost of the best mode for each PU using DCT2 @@ -98,9 +219,11 @@ private: ModeInfo m_savedRdModeList[ NUM_LFNST_NUM_PER_SET ][ NUM_LUMA_MODE ]; int32_t m_savedNumRdModes[ NUM_LFNST_NUM_PER_SET ]; +#if !JVET_O0502_ISP_CLEANUP static_vector<double, FAST_UDI_MAX_RDMODE_NUM> m_intraModeDiagRatio; static_vector<double, FAST_UDI_MAX_RDMODE_NUM> m_intraModeHorVerRatio; static_vector<int, FAST_UDI_MAX_RDMODE_NUM> m_intraModeTestedNormalIntra; +#endif static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_uiSavedRdModeListLFNST; static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_uiSavedHadModeListLFNST; @@ -180,7 +303,9 @@ protected: ChromaCbfs xRecurIntraChromaCodingQT( CodingStructure &cs, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE, const PartSplit ispType = TU_NO_ISP ); bool xRecurIntraCodingLumaQT ( CodingStructure &cs, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP, const bool ispIsCurrentWinner = false, bool mtsCheckRangeFlag = false, int mtsFirstCheckId = 0, int mtsLastCheckId = 0, bool moreProbMTSIdxFirst = false ); - +#if JVET_O0502_ISP_CLEANUP + bool xIntraCodingLumaISP ( CodingStructure& cs, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE ); +#endif void encPredIntraDPCM( const ComponentID &compID, PelBuf &pOrg, PelBuf &pDst, const uint32_t &uiDirMode ); static bool useDPCMForFirstPassIntraEstimation( const PredictionUnit &pu, const uint32_t &uiDirMode ); @@ -189,6 +314,12 @@ protected: void reduceHadCandList(static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, int& numModesForFullRD, const double thresholdHadCost, const double thresholdHadCostConv); double m_bestCostNonMip; + +#if JVET_O0502_ISP_CLEANUP + void xGetNextISPMode ( ModeInfo& modeInfo, const ModeInfo* lastMode, const Size cuSize ); + void xFindAlreadyTestedNearbyIntraModes ( int currentIntraMode, int* leftIntraMode, int* rightIntraMode, ISPType ispOption, int windowSize ); + void xSortISPCandList ( double bestCostSoFar, double bestNonISPCost ); +#endif };// END CLASS DEFINITION EncSearch //! \} -- GitLab