diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 88235d70b7016bc4cff0a0b3c9e2ce32850465fc..5b7ec86f31eb47390807394d5329cdce29e0fa3b 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -894,6 +894,9 @@ void EncApp::xInitLibCfg() #if JVET_AD0082_TMRL_CONFIG m_cEncLib.setUseTmrl ( m_tmrl ); #endif +#if JVET_AD0085_MPM_SORTING + m_cEncLib.setUseMpmSorting ( m_mpmSorting ); +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING m_cEncLib.setUseCccm ( m_cccm ); #endif diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 039e84a72ce36d703c53e661a154df099e3a7692..0c18ef6a20716b6b56dace01a0f0ce2bb0d2145c 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1117,6 +1117,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #if JVET_AD0082_TMRL_CONFIG ("TMRL", m_tmrl, true, "Enable template based multiple reference line intra prediction\n") #endif +#if JVET_AD0085_MPM_SORTING + ( "MPMSorting", m_mpmSorting, true, "Enable template-based intra MPM list construction\n" ) +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING ( "CCCM", m_cccm, 2, "CCCM mode (0:off, 1:on, 2:on subsampling and no subsampling) [default: 2]") #endif @@ -5418,6 +5421,9 @@ void EncAppCfg::xPrintParameter() #if JVET_AD0082_TMRL_CONFIG msg(VERBOSE, "TMRL:%d ", m_tmrl); #endif +#if JVET_AD0085_MPM_SORTING + msg(VERBOSE, "MPMSorting:%d ", m_mpmSorting); +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING msg(VERBOSE, "CCCM:%d ", m_cccm); #endif diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 88bab28bee4b83642fef136aa1304a35271964c2..32ab826e4633d0749a5b650d72fae5fc48af660f 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -472,6 +472,9 @@ protected: #if JVET_AD0082_TMRL_CONFIG bool m_tmrl; #endif +#if JVET_AD0085_MPM_SORTING + bool m_mpmSorting; +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING int m_cccm; #endif diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index e7da6c891899a65ee78ac0b11273f90b263f7533..a2467e720fb1dc21903591d02c8e87c6d20f20e0 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -1400,6 +1400,23 @@ const CtxSet ContextSetCfg::IntraLumaMPMIdx = ContextSetCfg::addCtxSet { 121, 126, 119, }, { 119, 109, 121, }, }); + +#if JVET_AD0085_MPM_SORTING +const CtxSet ContextSetCfg::IntraLumaSecondMpmIdx = ContextSetCfg::addCtxSet +({ + { CNU, CNU, CNU, CNU, CNU }, + { CNU, CNU, CNU, CNU, CNU }, + { CNU, CNU, CNU, CNU, CNU }, + { DWS, DWS, DWS, DWS, DWS }, + { DWS, DWS, DWS, DWS, DWS }, + { DWS, DWS, DWS, DWS, DWS }, + { DWE, DWE, DWE, DWE, DWE }, + { DWE, DWE, DWE, DWE, DWE }, + { DWE, DWE, DWE, DWE, DWE }, + { 119, 119, 119, 119, 119 }, + { 119, 119, 119, 119, 119 }, + }); +#endif #endif const CtxSet ContextSetCfg::IntraLumaPlanarFlag = ContextSetCfg::addCtxSet @@ -3803,6 +3820,17 @@ const CtxSet ContextSetCfg::IntraLumaMPMIdx = ContextSetCfg::addCtxSet { 4, 1, 6 }, { 2, 2, 6 } }); +#if JVET_AD0085_MPM_SORTING +const CtxSet ContextSetCfg::IntraLumaSecondMpmIdx = ContextSetCfg::addCtxSet +({ + { CNU, CNU, CNU, CNU, CNU }, + { CNU, CNU, CNU, CNU, CNU }, + { CNU, CNU, CNU, CNU, CNU }, + { DWS, DWS, DWS, DWS, DWS }, + { DWS, DWS, DWS, DWS, DWS }, + { DWS, DWS, DWS, DWS, DWS }, + }); +#endif #endif const CtxSet ContextSetCfg::CclmModeFlag = ContextSetCfg::addCtxSet @@ -5350,6 +5378,15 @@ const CtxSet ContextSetCfg::IntraLumaMPMIdx = ContextSetCfg::addCtxSet { 20, 44, 35 }, { 2, 2, 6 } }); +#if JVET_AD0085_MPM_SORTING +const CtxSet ContextSetCfg::IntraLumaSecondMpmIdx = ContextSetCfg::addCtxSet +({ + { CNU, CNU, CNU, CNU, CNU }, + { CNU, CNU, CNU, CNU, CNU }, + { CNU, CNU, CNU, CNU, CNU }, + { DWS, DWS, DWS, DWS, DWS }, + }); +#endif #endif const CtxSet ContextSetCfg::CclmModeFlag = ContextSetCfg::addCtxSet diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 2f32394e4db1a7831639c20d8ce23183429f1f8c..ddeebcfa00b833b310df6dda3e245345f6ca389e 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -356,6 +356,9 @@ public: static const CtxSet IntraLumaMpmFlag; #if SECONDARY_MPM static const CtxSet IntraLumaSecondMpmFlag; +#if JVET_AD0085_MPM_SORTING + static const CtxSet IntraLumaSecondMpmIdx; +#endif #endif static const CtxSet IntraLumaPlanarFlag; #if SECONDARY_MPM diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index 354697cebc06773a61b78f8d6f2c8b3b7dc07ddd..0388bc223c6dfe1ec778ff2106495baeb31af3fe 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -1174,8 +1174,18 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co CHECK(PU::isMIP(pu, toChannelType(compId)), "We should not get here for MIP."); const uint32_t uiDirMode = isLuma( compId ) && pu.cu->bdpcmMode ? BDPCM_IDX : !isLuma(compId) && pu.cu->bdpcmModeChroma ? BDPCM_IDX : PU::getFinalIntraMode(pu, channelType); +#if JVET_AD0085_TMRL_EXTENSION + bool bExtIntraDir = false; +#if JVET_W0123_TIMD_FUSION + bExtIntraDir |= (pu.cu->timd && isLuma(compId)); +#endif +#if JVET_AD0085_TMRL_EXTENSION + bExtIntraDir |= (pu.cu->tmrlFlag && isLuma(compId)); +#endif +#else #if JVET_W0123_TIMD_FUSION bool bExtIntraDir = pu.cu->timd && isLuma( compId ); +#endif #endif CHECK( floorLog2(iWidth) < 2 && pu.cs->pcv->noChroma2x2, "Size not allowed" ); @@ -2546,8 +2556,18 @@ void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompA { const ComponentID compId = area.compID; const ChannelType chType = toChannelType(compId); +#if JVET_AD0085_TMRL_EXTENSION + bool bExtIntraDir = false; +#if JVET_W0123_TIMD_FUSION + bExtIntraDir |= (pu.cu->timd && isLuma(chType)); +#endif +#if JVET_AD0085_TMRL_EXTENSION + bExtIntraDir |= (pu.cu->tmrlFlag && isLuma(chType)); +#endif +#else #if JVET_W0123_TIMD_FUSION bool bExtIntraDir = pu.cu->timd && isLuma( chType ); +#endif #endif const bool useISP = NOT_INTRA_SUBPARTITIONS != pu.cu->ispMode && isLuma( chType ); @@ -2562,6 +2582,16 @@ void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompA #endif #if JVET_W0123_TIMD_FUSION #if JVET_AC0094_REF_SAMPLES_OPT +#if JVET_AD0085_TMRL_EXTENSION + bool checkWideAngle = !bExtIntraDir ? true : (pu.cu->timdMode != INVALID_TIMD_IDX ? pu.cu->timdModeCheckWA : pu.cu->timdModeSecondaryCheckWA); + + int predMode = checkWideAngle ? (bExtIntraDir ? getWideAngleExt(blockSize.width, blockSize.height, dirMode) : getModifiedWideAngle(blockSize.width, blockSize.height, dirMode)) + : (bExtIntraDir ? getTimdWideAngleExt(blockSize.width, blockSize.height, dirMode) : getTimdWideAngle(blockSize.width, blockSize.height, dirMode)); + if (pu.cu->tmrlFlag && isLuma(chType)) + { + predMode = getWideAngleExt(blockSize.width, blockSize.height, dirMode); + } +#else if (bExtIntraDir) { CHECK(pu.cu->timdMode != dirMode && pu.cu->timdModeSecondary != dirMode, "Unexpected dirMode"); @@ -2570,6 +2600,7 @@ void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompA const int predMode = checkWideAngle ? (bExtIntraDir ? getWideAngleExt(blockSize.width, blockSize.height, dirMode) : getModifiedWideAngle(blockSize.width, blockSize.height, dirMode)) : (bExtIntraDir ? getTimdWideAngleExt(blockSize.width, blockSize.height, dirMode) : getTimdWideAngle(blockSize.width, blockSize.height, dirMode)); CHECK(!checkWideAngle && dirMode <= DC_IDX, "Unexpected mode"); +#endif #else const int predMode = bExtIntraDir ? getWideAngleExt( blockSize.width, blockSize.height, dirMode ) : getModifiedWideAngle( blockSize.width, blockSize.height, dirMode ); #endif @@ -5599,6 +5630,119 @@ void IntraPrediction::deriveSgpmModeOrdered(const CPelBuf &recoBuf, const CompAr } #endif +#if JVET_AD0085_MPM_SORTING +void IntraPrediction::deriveMPMSorted(const PredictionUnit& pu, uint8_t* mpm, int& sortedSize, int iStartIdx) +{ + SizeType uiWidth = pu.lwidth(); + SizeType uiHeight = pu.lheight(); + const CompArea area = pu.Y(); + int channelBitDepth = pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA); + + static Pel predLuma[(MAX_CU_SIZE + DIMD_MAX_TEMP_SIZE) * (MAX_CU_SIZE + DIMD_MAX_TEMP_SIZE)]; + memset(predLuma, 0, (MAX_CU_SIZE + DIMD_MAX_TEMP_SIZE) * (MAX_CU_SIZE + DIMD_MAX_TEMP_SIZE) * sizeof(Pel)); + Pel* piPred = predLuma; + uint32_t uiPredStride = MAX_CU_SIZE + DIMD_MAX_TEMP_SIZE; + + int iCurX = pu.lx(); + int iCurY = pu.ly(); + int iRefX = -1, iRefY = -1; + uint32_t uiRefWidth = 0, uiRefHeight = 0; + int iTempWidth = 1, iTempHeight = 1; + + static_vector<uint8_t, NUM_MOST_PROBABLE_MODES> uiModeList; + static_vector<uint64_t, NUM_MOST_PROBABLE_MODES> uiCostList; + int iBestN = std::min(NUM_PRIMARY_MOST_PROBABLE_MODES - 1, sortedSize); + if (!pu.cs->pcv->isEncoder && pu.mpmFlag && pu.ipredIdx < iBestN) + { + iBestN = pu.ipredIdx; + } + + TEMPLATE_TYPE eTempType = CU::deriveTimdRefType(iCurX, iCurY, uiWidth, uiHeight, iTempWidth, iTempHeight, iRefX, + iRefY, uiRefWidth, uiRefHeight); + + if (eTempType == NO_NEIGHBOR) + { + return; + } + + const CodingStructure& cs = *pu.cs; + m_ipaParam.multiRefIndex = iTempWidth; + Pel* piOrg = cs.picture->getRecoBuf(area).buf; + int iOrgStride = cs.picture->getRecoBuf(area).stride; + piOrg += (iRefY - iCurY) * iOrgStride + (iRefX - iCurX); + DistParam distParamSad[2]; // above, left + distParamSad[0].applyWeight = false; + distParamSad[0].useMR = false; + distParamSad[1].applyWeight = false; + distParamSad[1].useMR = false; + if (eTempType == LEFT_ABOVE_NEIGHBOR) + { + m_timdSatdCost->setTimdDistParam(distParamSad[0], piOrg + iTempWidth, piPred + iTempWidth, iOrgStride, + uiPredStride, channelBitDepth, COMPONENT_Y, uiWidth, iTempHeight, 0, 1, false); // Use HAD (SATD) cost + m_timdSatdCost->setTimdDistParam(distParamSad[1], piOrg + iTempHeight * iOrgStride, + piPred + iTempHeight * uiPredStride, iOrgStride, uiPredStride, channelBitDepth, + COMPONENT_Y, iTempWidth, uiHeight, 0, 1, false); + } + else if (eTempType == LEFT_NEIGHBOR) + { + m_timdSatdCost->setTimdDistParam(distParamSad[1], piOrg, piPred, iOrgStride, uiPredStride, channelBitDepth, + COMPONENT_Y, iTempWidth, uiHeight, 0, 1, false); + } + else if (eTempType == ABOVE_NEIGHBOR) + { + m_timdSatdCost->setTimdDistParam(distParamSad[0], piOrg, piPred, iOrgStride, uiPredStride, channelBitDepth, + COMPONENT_Y, uiWidth, iTempHeight, 0, 1, false); + } + initTimdIntraPatternLuma(*pu.cu, area, eTempType != ABOVE_NEIGHBOR ? iTempWidth : 0, + eTempType != LEFT_NEIGHBOR ? iTempHeight : 0, uiRefWidth, uiRefHeight); + + uint32_t uiRealW = uiRefWidth + (eTempType == LEFT_NEIGHBOR ? iTempWidth : 0); + uint32_t uiRealH = uiRefHeight + (eTempType == ABOVE_NEIGHBOR ? iTempHeight : 0); + + for (int i = iStartIdx; i < sortedSize; i++) + { + uint64_t uiCost = 0; + int iMode = mpm[i]; + if (iMode > DC_IDX) + { + iMode = MAP67TO131(iMode); + } + initPredTimdIntraParams(pu, area, iMode); + predTimdIntraAng(COMPONENT_Y, pu, iMode, piPred, uiPredStride, uiRealW, uiRealH, eTempType, + (eTempType == ABOVE_NEIGHBOR) ? 0 : iTempWidth, + (eTempType == LEFT_NEIGHBOR) ? 0 : iTempHeight); + if (eTempType == LEFT_ABOVE_NEIGHBOR) + { + uiCost += distParamSad[0].distFunc(distParamSad[0]); + uiCost += distParamSad[1].distFunc(distParamSad[1]); + } + else if (eTempType == LEFT_NEIGHBOR) + { + uiCost = distParamSad[1].distFunc(distParamSad[1]); + } + else if (eTempType == ABOVE_NEIGHBOR) + { + uiCost += distParamSad[0].distFunc(distParamSad[0]); + } + else + { + assert(0); + } + + if (uiCostList.size() < iBestN || (uiCostList.size() >= iBestN && uiCost < uiCostList.back())) + { + updateCandList(mpm[i], uiCost, uiModeList, uiCostList, iBestN); + } + } + + sortedSize = int(uiModeList.size()) + iStartIdx; + for (int i = 0; i < uiModeList.size(); i++) + { + mpm[i + iStartIdx] = uiModeList[i]; + } +} +#endif + #if JVET_AB0155_SGPM int IntraPrediction::deriveTimdMode(const CPelBuf &recoBuf, const CompArea &area, CodingUnit &cu, bool bFull, bool bHorVer) { @@ -5701,7 +5845,11 @@ int IntraPrediction::deriveTimdMode(const CPelBuf &recoBuf, const CompArea &area if (puLeftx && CU::isIntra(*puLeftx->cu)) { uiIntraDirNeighbor[modeIdx] = PU::getIntraDirLuma(*puLeftx); - if (!puLeftx->cu->timd) + if (!puLeftx->cu->timd +#if JVET_AD0085_TMRL_EXTENSION + && !puLeftx->cu->tmrlFlag +#endif + ) { uiIntraDirNeighbor[modeIdx] = MAP67TO131(uiIntraDirNeighbor[modeIdx]); } @@ -5717,7 +5865,11 @@ int IntraPrediction::deriveTimdMode(const CPelBuf &recoBuf, const CompArea &area if (puAbovex && CU::isIntra(*puAbovex->cu) && CU::isSameCtu(*pu.cu, *puAbovex->cu)) { uiIntraDirNeighbor[modeIdx] = PU::getIntraDirLuma(*puAbovex); - if (!puAbovex->cu->timd) + if (!puAbovex->cu->timd +#if JVET_AD0085_TMRL_EXTENSION + && !puAbovex->cu->tmrlFlag +#endif + ) { uiIntraDirNeighbor[modeIdx] = MAP67TO131(uiIntraDirNeighbor[modeIdx]); } @@ -5733,7 +5885,11 @@ int IntraPrediction::deriveTimdMode(const CPelBuf &recoBuf, const CompArea &area if (puLeftBottomx && CU::isIntra(*puLeftBottomx->cu)) { uiIntraDirNeighbor[modeIdx] = PU::getIntraDirLuma(*puLeftBottomx); - if (!puLeftBottomx->cu->timd) + if (!puLeftBottomx->cu->timd +#if JVET_AD0085_TMRL_EXTENSION + && !puLeftBottomx->cu->tmrlFlag +#endif + ) { uiIntraDirNeighbor[modeIdx] = MAP67TO131(uiIntraDirNeighbor[modeIdx]); } @@ -5761,7 +5917,11 @@ int IntraPrediction::deriveTimdMode(const CPelBuf &recoBuf, const CompArea &area if (puAboveRightx && CU::isIntra(*puAboveRightx->cu)) { uiIntraDirNeighbor[modeIdx] = PU::getIntraDirLuma(*puAboveRightx); - if (!puAboveRightx->cu->timd) + if (!puAboveRightx->cu->timd +#if JVET_AD0085_TMRL_EXTENSION + && !puAboveRightx->cu->tmrlFlag +#endif + ) { uiIntraDirNeighbor[modeIdx] = MAP67TO131(uiIntraDirNeighbor[modeIdx]); } @@ -5787,7 +5947,11 @@ int IntraPrediction::deriveTimdMode(const CPelBuf &recoBuf, const CompArea &area if (puAboveLeftx && CU::isIntra(*puAboveLeftx->cu)) { uiIntraDirNeighbor[modeIdx] = PU::getIntraDirLuma(*puAboveLeftx); - if (!puAboveLeftx->cu->timd) + if (!puAboveLeftx->cu->timd +#if JVET_AD0085_TMRL_EXTENSION + && !puAboveLeftx->cu->tmrlFlag +#endif + ) { uiIntraDirNeighbor[modeIdx] = MAP67TO131(uiIntraDirNeighbor[modeIdx]); } @@ -13645,6 +13809,15 @@ void IntraPrediction::xPredTmrlIntraDc(const CPelBuf& pSrc, Pel* pDst, int iDstS Pel tmrlFiltering(Pel* pSrc, const int deltaFrac) { +#if JVET_AD0085_TMRL_EXTENSION + const TFilterCoeff* const f = InterpolationFilter::getExtIntraCubicFilter(deltaFrac); + int val = 0; + for (int i = 0; i < 4; i++) + { + val += pSrc[i] * f[i]; + } + val = (val + 128) >> 8; +#else const TFilterCoeff IntraCubicFilter[32][4] = { { 0, 64, 0, 0 }, @@ -13687,6 +13860,7 @@ Pel tmrlFiltering(Pel* pSrc, const int deltaFrac) val += pSrc[i] * IntraCubicFilter[deltaFrac][i]; } val = (val + 32) >> 6; +#endif return Pel(val); } @@ -13808,10 +13982,15 @@ void IntraPrediction::xPredTmrlIntraAng(const CPelBuf& pSrc, const ClpRng& clpRn iStartIdx = 0; iEndIdx = uiTemplateLeft; } - +#if JVET_AD0085_TMRL_EXTENSION + const int deltaInt = deltaPos >> 6; + const int deltaFract = deltaPos & 63; + if (!isIntegerSlopeExt(abs(intraPredAngle))) +#else const int deltaInt = deltaPos >> 5; const int deltaFract = deltaPos & 31; if (!isIntegerSlope(abs(intraPredAngle))) +#endif { CHECK(deltaInt + iStartIdx + lineOffset < -int(uiRefHeight), "over the prepared reference buffer."); for (int x = iStartIdx; x < iEndIdx; x++) @@ -13872,6 +14051,27 @@ void IntraPrediction::initTmrlIntraParams(const PredictionUnit& pu, const CompAr const ChannelType chType = toChannelType(compId); const Size& blockSize = Size(pu.cu->blocks[compId].width, pu.cu->blocks[compId].height); const int dirMode = PU::getFinalIntraMode(pu, chType); +#if JVET_AD0085_TMRL_EXTENSION + const int predMode = getWideAngleExt(blockSize.width, blockSize.height, dirMode); + m_ipaParam.isModeVer = predMode >= EXT_DIA_IDX; + m_ipaParam.multiRefIndex = pu.multiRefIdx; + m_ipaParam.refFilterFlag = false; + m_ipaParam.applyPDPC = false; + const int intraPredAngleMode = (m_ipaParam.isModeVer) ? predMode - EXT_VER_IDX : -(predMode - EXT_HOR_IDX); + if (dirMode > DC_IDX) + { + int absAng = 0; + static const int extAngTable[64] = { 0, 1, 2, 3, 4, 5, 6,7, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 43, 46, 49, 52, 55, 58, 61, 64, 67, 70, 74, 78, 84, 90, 96, 102, 108, 114, 121, 128, 137, 146, 159, 172, 188, 204, 230, 256, 299, 342, 427, 512, 597, 682, 853, 1024, 1536, 2048, 3072 }; + static const int extInvAngTable[64] = { 0, 32768, 16384, 10923, 8192, 6554, 5461, 4681, 4096, 3277, 2731, 2341, 2048, 1820, 1638, 1489, 1365, 1260, 1170, 1092, 1024, 964, 910, 862, 819, 762, 712, 669, 630, 596, 565, 537, 512, 489, 468, 443, 420, 390, 364, 341, 321, 303, 287, 271, 256, 239, 224, 206, 191, 174, 161, 142, 128, 110, 96, 77, 64, 55, 48, 38, 32, 21, 16, 11 }; // (512 * 64) / Angle + + const int absAngMode = abs(intraPredAngleMode); + const int signAng = intraPredAngleMode < 0 ? -1 : 1; + absAng = extAngTable[absAngMode]; + + m_ipaParam.absInvAngle = extInvAngTable[absAngMode]; + m_ipaParam.intraPredAngle = signAng * absAng; + } +#else const int predMode = getModifiedWideAngle(blockSize.width, blockSize.height, dirMode); m_ipaParam.isModeVer = predMode >= DIA_IDX; m_ipaParam.multiRefIndex = pu.multiRefIdx; @@ -13895,6 +14095,7 @@ void IntraPrediction::initTmrlIntraParams(const PredictionUnit& pu, const CompAr m_ipaParam.absInvAngle = invAngTable[absAngMode]; m_ipaParam.intraPredAngle = signAng * absAng; } +#endif } void IntraPrediction::getTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlRefList, uint8_t* tmrlIntraList, uint8_t& sizeRef, uint8_t& sizeMode) @@ -13912,6 +14113,16 @@ void IntraPrediction::getTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlR } } +#if JVET_AD0085_TMRL_EXTENSION + sizeMode = TMRL_MPM_SIZE; + int numCand = getSpatialIpm(pu, tmrlIntraList, sizeMode +#if JVET_AC0094_REF_SAMPLES_OPT + , true +#endif + , true + ); + fillMPMList(pu, tmrlIntraList, sizeMode, numCand, true); +#else // intra mode candidates sizeMode = 0; const CodingStructure& cs = *pu.cs; @@ -14141,6 +14352,7 @@ void IntraPrediction::getTmrlSearchRange(const PredictionUnit& pu, int8_t* tmrlR includedMode[tmrlIntraList[sizeMode++]] = true; } } +#endif } void IntraPrediction::getTmrlList(CodingUnit& cu) diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index afb1fe206f8607793351937c83d5d9fabad7582d..79e7254e3f5ac14e0798f175bcb5756c442f5c64 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -562,6 +562,9 @@ public: static_vector<SgpmInfo, SGPM_NUM> &candModeList, static_vector<double, SGPM_NUM> & candCostList); #endif +#if JVET_AD0085_MPM_SORTING + void deriveMPMSorted(const PredictionUnit& pu, uint8_t* mpm, int& sortedSize, int iStartIdx); +#endif #if JVET_AB0157_TMRL struct TmrlInfo { diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 4f41a1d2ae9c224bfa0548327bf9683569e37780..1c0bb5a6fd7a21482eec7cb5a7bfed62e50364ad 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -1761,6 +1761,9 @@ private: #if JVET_AD0082_TMRL_CONFIG bool m_tmrl; #endif +#if JVET_AD0085_MPM_SORTING + bool m_mpmSorting; +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING int m_cccm; #endif @@ -2369,6 +2372,10 @@ void setCCALFEnabledFlag( bool b ) void setUseTmrl (bool b) { m_tmrl = b; } bool getUseTmrl () const { return m_tmrl; } #endif +#if JVET_AD0085_MPM_SORTING + void setUseMpmSorting (bool b) { m_mpmSorting = b; } + bool getUseMpmSorting () const { return m_mpmSorting; } +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING void setUseCccm( int i ) { m_cccm = i; } int getUseCccm() const { return m_cccm; } diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp index 3daa8e6a4f28ddac9dcc968333e1d8804b402c4b..ea9a7850dd82111146302e0b8ada8950e3d95110 100644 --- a/source/Lib/CommonLib/TrQuant.cpp +++ b/source/Lib/CommonLib/TrQuant.cpp @@ -544,6 +544,12 @@ void TrQuant::xInvLfnst( const TransformUnit &tu, const ComponentID compID ) { intraMode = PLANAR_IDX; } +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (tu.cu->tmrlFlag && compID == COMPONENT_Y) + { + intraMode = MAP131TO67(intraMode); + } #endif CHECK( intraMode >= NUM_INTRA_MODE - 1, "Invalid intra mode" ); @@ -811,6 +817,12 @@ void TrQuant::xFwdLfnst( const TransformUnit &tu, const ComponentID compID, cons { intraMode = PLANAR_IDX; } +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (tu.cu->tmrlFlag && compID == COMPONENT_Y) + { + intraMode = MAP131TO67(intraMode); + } #endif CHECK( intraMode >= NUM_INTRA_MODE - 1, "Invalid intra mode" ); @@ -1236,6 +1248,12 @@ void TrQuant::getTrTypes(const TransformUnit tu, const ComponentID compID, int & { predMode = g_geoAngle2IntraAng[g_geoParams[tu.cu->sgpmSplitDir][0]]; } +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (tu.cu->tmrlFlag && compID == COMPONENT_Y) + { + predMode = MAP131TO67(predMode); + } #endif int ucMode; int nMdIdx; @@ -2655,6 +2673,12 @@ int TrQuant::getLfnstIdx(const TransformUnit &tu, ComponentID compID) intraMode = PLANAR_IDX; } #endif +#if JVET_AD0085_TMRL_EXTENSION + if (tu.cu->tmrlFlag && compID == COMPONENT_Y) + { + intraMode = MAP131TO67(intraMode); + } +#endif #if JVET_AC0105_DIRECTIONAL_PLANAR if (compID == COMPONENT_Y && intraMode == PLANAR_IDX) { diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 8acdbf3cdb0940b88f63e19f1a4f2b544355cc7d..016baa238769be147c7721b40ea0fceb854bea55 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -173,11 +173,13 @@ #define JVET_AB0157_TMRL 1 // JVET-AB0157: Template-based multiple reference line intra prediction #if JVET_AB0157_TMRL #define JVET_AD0082_TMRL_CONFIG 1 // JVET-AD0082: a configuration option for TMRL +#define JVET_AD0085_TMRL_EXTENSION 1 // JVET-AD0085: TMRL angular extension and intra candidate list modifications #endif #define JVET_AB0157_INTRA_FUSION 1 // JVET-AB0157: Intra prediction fusion #define JVET_AC0094_REF_SAMPLES_OPT 1 // JVET-AC0094: Optimizing the use of reference samples #define JVET_AC0105_DIRECTIONAL_PLANAR 1 // JVET-AC0105: Directional planar #define JVET_AD0184_REMOVAL_OF_DIVISION_OPERATIONS 1 // JVET-AD0184: Removal of division operations +#define JVET_AD0085_MPM_SORTING 1 // JVET-AD0085: Template-based intra MPM list construction //IBC #define JVET_Y0058_IBC_LIST_MODIFY 1 // JVET-Y0058: Modifications of IBC merge/AMVP list construction, ARMC-TM-IBC part is included under JVET_W0090_ARMC_TM diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 6236bf6a969f27114194503ed0782b76d6c00ec0..d91f1cd157f3a92587c53e1f81655e13df192435 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -883,13 +883,45 @@ bool CU::isIdxModeValid(const bool &areAboveRightUnavail, const bool &areBelowLe #if SECONDARY_MPM int PU::getIntraMPMs( const PredictionUnit &pu, uint8_t* mpm, uint8_t* non_mpm #if JVET_AC0094_REF_SAMPLES_OPT - , const bool& isForcedValid + , const bool& isForcedValid #endif - , const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/) +#if JVET_AD0085_MPM_SORTING + , IntraPrediction* pIntraPred/* = nullptr*/ +#endif + , const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/) #else int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/) #endif { +#if JVET_AD0085_TMRL_EXTENSION && SECONDARY_MPM + int numCand = 0; + mpm[numCand++] = PLANAR_IDX; +#if JVET_AD0085_MPM_SORTING + int maxCand = pIntraPred ? NUM_PRIMARY_MOST_PROBABLE_MODES + 1 : NUM_MOST_PROBABLE_MODES - 1; +#else + int maxCand = NUM_MOST_PROBABLE_MODES - 1; +#endif + numCand += getSpatialIpm(pu, mpm + 1, maxCand +#if JVET_AC0094_REF_SAMPLES_OPT + , isForcedValid +#endif + , false +#if JVET_AD0085_MPM_SORTING + , pIntraPred +#endif + ); + + fillMPMList(pu, mpm, NUM_MOST_PROBABLE_MODES, numCand); +#if JVET_AD0085_MPM_SORTING + if (!pu.cs->pcv->isEncoder && (pu.mpmFlag || pu.secondMpmFlag)) + { + return numCand; + } +#endif + fillNonMPMList(mpm, non_mpm); + + return numCand; +#else #if SECONDARY_MPM bool includedMode[NUM_INTRA_MODE]; memset(includedMode, false, sizeof(includedMode)); @@ -1240,6 +1272,56 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType } } #endif +#if JVET_AD0085_MPM_SORTING + if (pu.cs->sps->getUseMpmSorting()) + { +#if ENABLE_DIMD + //adding dimd modes + if (pu.cu->slice->getSPS()->getUseDimd()) + { + if (pu.cu->dimdMode != -1) + { + mpm[numValidMPM] = pu.cu->dimdMode; + if (!includedMode[mpm[numValidMPM]]) + { + includedMode[mpm[numValidMPM++]] = true; + } + + for (int i = 0; i < DIMD_FUSION_NUM - 2; i++) + { + if (pu.cu->dimdBlendMode[i] != -1) + { + mpm[numValidMPM] = pu.cu->dimdBlendMode[i]; + if (!includedMode[mpm[numValidMPM]]) + { + includedMode[mpm[numValidMPM++]] = true; + } + } + } + } + } +#endif + + numCand = numValidMPM; + + if (pIntraPred && numValidMPM > 2) + { + pIntraPred->deriveMPMSorted(pu, mpm, numValidMPM, 1); + + if (!pu.cs->pcv->isEncoder && pu.mpmFlag && pu.ipredIdx < numValidMPM) + { + return numCand; + } + + numCand = numValidMPM; + memset(includedMode, false, sizeof(includedMode)); + for (int i = 0; i < numValidMPM; i++) + { + includedMode[mpm[i]] = true; + } + } + } +#endif CHECK(2 >= numMPMs, "Invalid number of most probable modes"); @@ -1247,6 +1329,10 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType const int mod = offset + 3; { +#if JVET_AD0085_MPM_SORTING + if (!pu.cs->sps->getUseMpmSorting()) + { +#endif #if SECONDARY_MPM numCand = numValidMPM; #else @@ -1280,8 +1366,47 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType } } #endif +#if JVET_AD0085_MPM_SORTING + } +#endif #if SECONDARY_MPM +#if JVET_AD0085_MPM_SORTING + if (pu.cs->sps->getUseMpmSorting()) + { + for (int i = 0; i < numCand && numValidMPM < numMPMs; i++) + { + if (mpm[i] <= DC_IDX) + { + continue; + } + + for (int deltaAngular = 0; deltaAngular < 4 && numValidMPM < numMPMs; deltaAngular++) + { + // try to fill mode - (delta + 1) + mpm[numValidMPM] = ((mpm[i] + offset - deltaAngular) % mod) + 2; + if (!includedMode[mpm[numValidMPM]]) + { + includedMode[mpm[numValidMPM++]] = true; + } + + if (numValidMPM >= numMPMs) + { + break; + } + + // try to fill mode + delta + 1 + mpm[numValidMPM] = ((mpm[i] - 1 + deltaAngular) % mod) + 2; + if (!includedMode[mpm[numValidMPM]]) + { + includedMode[mpm[numValidMPM++]] = true; + } + } + } + } + else + { +#endif bool checkDCEnabled = false; // Derived modes of mpm[1] @@ -1292,24 +1417,24 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType for (int i = 0; i < 4 && numValidMPM < numMPMs; i++) { mpm[numValidMPM] = ((mpm[1] + offset - i) % mod) + 2; - if( !includedMode[mpm[numValidMPM]] ) + if (!includedMode[mpm[numValidMPM]]) { includedMode[mpm[numValidMPM++]] = true; } - if( numValidMPM >= numMPMs ) + if (numValidMPM >= numMPMs) { break; } mpm[numValidMPM] = ((mpm[1] - 1 + i) % mod) + 2; - if( !includedMode[mpm[numValidMPM]] ) + if (!includedMode[mpm[numValidMPM]]) { includedMode[mpm[numValidMPM++]] = true; } } } - else if( mpm[1] == DC_IDX ) + else if (mpm[1] == DC_IDX) { checkDCEnabled = true; } @@ -1324,7 +1449,7 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType for (int i = 0; i < 4 && numValidMPM < numMPMs; i++) { mpm[numValidMPM] = ((mpm[2] + offset - i) % mod) + 2; - if( !includedMode[mpm[numValidMPM]] ) + if (!includedMode[mpm[numValidMPM]]) { includedMode[mpm[numValidMPM++]] = true; } @@ -1333,13 +1458,13 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType break; mpm[numValidMPM] = ((mpm[2] - 1 + i) % mod) + 2; - if( !includedMode[mpm[numValidMPM]] ) + if (!includedMode[mpm[numValidMPM]]) { includedMode[mpm[numValidMPM++]] = true; } } } - else if( mpm[2] == DC_IDX ) + else if (mpm[2] == DC_IDX) { checkDCEnabled = true; } @@ -1352,23 +1477,26 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType for (int i = 0; i < 3 && numValidMPM < numMPMs; i++) { mpm[numValidMPM] = ((mpm[3] + offset - i) % mod) + 2; - if( !includedMode[mpm[numValidMPM]] ) + if (!includedMode[mpm[numValidMPM]]) { includedMode[mpm[numValidMPM++]] = true; } - if( numValidMPM >= numMPMs ) + if (numValidMPM >= numMPMs) { break; } mpm[numValidMPM] = ((mpm[3] - 1 + i) % mod) + 2; - if( !includedMode[mpm[numValidMPM]] ) + if (!includedMode[mpm[numValidMPM]]) { includedMode[mpm[numValidMPM++]] = true; } } } +#if JVET_AD0085_MPM_SORTING + } +#endif #else if (leftIntraDir == aboveIntraDir) { @@ -1462,6 +1590,7 @@ int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType CHECK(numCand == 0, "No candidates found"); return numCand; } +#endif } #if JVET_Y0065_GPM_INTRA @@ -1589,6 +1718,12 @@ void PU::getGeoIntraMPMs( const PredictionUnit &pu, uint8_t* mpm, uint8_t splitD mpm[numValidMPM] = puLeft->cu->timd ? MAP131TO67(PU::getIntraDirLuma(*puLeft)) : PU::getIntraDirLuma(*puLeft); #else mpm[numValidMPM] = PU::getIntraDirLuma(*puLeft); +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (puLeft->cu->tmrlFlag) + { + mpm[numValidMPM] = MAP131TO67(mpm[numValidMPM]); + } #endif if( !includedMode[mpm[numValidMPM]] ) { @@ -1610,6 +1745,12 @@ void PU::getGeoIntraMPMs( const PredictionUnit &pu, uint8_t* mpm, uint8_t splitD mpm[numValidMPM] = puAbove->cu->timd ? MAP131TO67(PU::getIntraDirLuma(*puAbove)) : PU::getIntraDirLuma(*puAbove); #else mpm[numValidMPM] = PU::getIntraDirLuma(*puAbove); +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (puAbove->cu->tmrlFlag) + { + mpm[numValidMPM] = MAP131TO67(mpm[numValidMPM]); + } #endif if( !includedMode[mpm[numValidMPM]] ) { @@ -1667,6 +1808,12 @@ void PU::getGeoIntraMPMs( const PredictionUnit &pu, uint8_t* mpm, uint8_t splitD mpm[numValidMPM] = puBelowLeft->cu->timd ? MAP131TO67(PU::getIntraDirLuma(*puBelowLeft)) : PU::getIntraDirLuma(*puBelowLeft); #else mpm[numValidMPM] = PU::getIntraDirLuma(*puBelowLeft); +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (puBelowLeft->cu->tmrlFlag) + { + mpm[numValidMPM] = MAP131TO67(mpm[numValidMPM]); + } #endif if( !includedMode[mpm[numValidMPM]] ) { @@ -1688,6 +1835,12 @@ void PU::getGeoIntraMPMs( const PredictionUnit &pu, uint8_t* mpm, uint8_t splitD mpm[numValidMPM] = puAboveRight->cu->timd ? MAP131TO67(PU::getIntraDirLuma(*puAboveRight)) : PU::getIntraDirLuma(*puAboveRight); #else mpm[numValidMPM] = PU::getIntraDirLuma(*puAboveRight); +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (puAboveRight->cu->tmrlFlag) + { + mpm[numValidMPM] = MAP131TO67(mpm[numValidMPM]); + } #endif if( !includedMode[mpm[numValidMPM]] ) { @@ -1708,6 +1861,12 @@ void PU::getGeoIntraMPMs( const PredictionUnit &pu, uint8_t* mpm, uint8_t splitD mpm[numValidMPM] = puAboveLeft->cu->timd ? MAP131TO67(PU::getIntraDirLuma(*puAboveLeft)) : PU::getIntraDirLuma(*puAboveLeft); #else mpm[numValidMPM] = PU::getIntraDirLuma(*puAboveLeft); +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (puAboveLeft->cu->tmrlFlag) + { + mpm[numValidMPM] = MAP131TO67(mpm[numValidMPM]); + } #endif if( !includedMode[mpm[numValidMPM]] ) { @@ -1877,6 +2036,12 @@ void PU::getSgpmIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t splitD mpm[numValidMPM] = puLeft->cu->timd ? MAP131TO67(PU::getIntraDirLuma(*puLeft)) : PU::getIntraDirLuma(*puLeft); #else mpm[numValidMPM] = PU::getIntraDirLuma(*puLeft); +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (puLeft->cu->tmrlFlag) + { + mpm[numValidMPM] = MAP131TO67(mpm[numValidMPM]); + } #endif if (!includedMode[mpm[numValidMPM]]) { @@ -1898,6 +2063,12 @@ void PU::getSgpmIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t splitD mpm[numValidMPM] = puAbove->cu->timd ? MAP131TO67(PU::getIntraDirLuma(*puAbove)) : PU::getIntraDirLuma(*puAbove); #else mpm[numValidMPM] = PU::getIntraDirLuma(*puAbove); +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (puAbove->cu->tmrlFlag) + { + mpm[numValidMPM] = MAP131TO67(mpm[numValidMPM]); + } #endif if (!includedMode[mpm[numValidMPM]]) { @@ -1964,6 +2135,12 @@ void PU::getSgpmIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t splitD puBelowLeft->cu->timd ? MAP131TO67(PU::getIntraDirLuma(*puBelowLeft)) : PU::getIntraDirLuma(*puBelowLeft); #else mpm[numValidMPM] = PU::getIntraDirLuma(*puBelowLeft); +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (puBelowLeft->cu->tmrlFlag) + { + mpm[numValidMPM] = MAP131TO67(mpm[numValidMPM]); + } #endif if (!includedMode[mpm[numValidMPM]]) { @@ -1986,6 +2163,12 @@ void PU::getSgpmIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t splitD puAboveRight->cu->timd ? MAP131TO67(PU::getIntraDirLuma(*puAboveRight)) : PU::getIntraDirLuma(*puAboveRight); #else mpm[numValidMPM] = PU::getIntraDirLuma(*puAboveRight); +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (puAboveRight->cu->tmrlFlag) + { + mpm[numValidMPM] = MAP131TO67(mpm[numValidMPM]); + } #endif if (!includedMode[mpm[numValidMPM]]) { @@ -2007,6 +2190,12 @@ void PU::getSgpmIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t splitD puAboveLeft->cu->timd ? MAP131TO67(PU::getIntraDirLuma(*puAboveLeft)) : PU::getIntraDirLuma(*puAboveLeft); #else mpm[numValidMPM] = PU::getIntraDirLuma(*puAboveLeft); +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (puAboveLeft->cu->tmrlFlag) + { + mpm[numValidMPM] = MAP131TO67(mpm[numValidMPM]); + } #endif if (!includedMode[mpm[numValidMPM]]) { @@ -2343,6 +2532,28 @@ bool PU::hasChromaBvFlag(const PredictionUnit &pu) } #endif +#if JVET_AD0085_MPM_SORTING +bool PU::allowMPMSorted(const PredictionUnit& pu) +{ + if (!pu.cs->sps->getUseMpmSorting()) + { + return false; + } + + const Area area = pu.Y(); + +#if JVET_AD0085_TMRL_EXTENSION + if ((pu.cs->slice->getSliceType() == I_SLICE && area.width * area.height > 128) || (area.width * area.height > 1024)) +#else + if ((pu.cs->slice->getSliceType() == I_SLICE && area.width * area.height > 32) || (area.width * area.height > 1024)) +#endif + { + return false; + } + return true; +} +#endif + #if JVET_AB0155_SGPM bool PU::isSgpm(const PredictionUnit &pu, const ChannelType &chType) { @@ -2622,6 +2833,12 @@ uint32_t PU::getCoLocatedIntraLumaMode(const PredictionUnit &pu, const int partI { return MAP131TO67(PU::getIntraDirLuma(PU::getCoLocatedLumaPU(pu), partIdx)); } +#endif +#if JVET_AD0085_TMRL_EXTENSION + if (PU::getCoLocatedLumaPU(pu).cu->tmrlFlag) + { + return MAP131TO67(PU::getIntraDirLuma(PU::getCoLocatedLumaPU(pu), partIdx)); + } #endif return PU::getIntraDirLuma(PU::getCoLocatedLumaPU(pu), partIdx); } @@ -16136,6 +16353,12 @@ void PU::spanIpmInfoIntra( PredictionUnit &pu) { ipm = MAP131TO67(ipm); } +#if JVET_AD0085_TMRL_EXTENSION + if (pu.cu->tmrlFlag) + { + ipm = MAP131TO67(ipm); + } +#endif IpmBuf ib = pu.getIpmBuf(); ib.fill(ipm); } @@ -19306,7 +19529,12 @@ uint32_t PU::getFinalIntraModeForTransform( const TransformUnit &tu, const Compo intraMode = PLANAR_IDX; } #endif - +#if JVET_AD0085_TMRL_EXTENSION + if (tu.cu->tmrlFlag && compID == COMPONENT_Y) + { + intraMode = MAP131TO67(intraMode); + } +#endif CHECK( intraMode >= NUM_INTRA_MODE - 1, "Invalid intra mode" ); intraMode = PU::getNSPTIntraMode( PU::getWideAngle( tu, intraMode, compID ) ); @@ -19355,3 +19583,274 @@ bool CU::nsptApplyCond( const TransformUnit& tu, ComponentID compID, bool allowN return cond; } #endif + +#if JVET_AD0085_TMRL_EXTENSION +int getSpatialIpm(const PredictionUnit& pu, uint8_t* spatialIpm, const int maxCands +#if JVET_AC0094_REF_SAMPLES_OPT + , const bool& isForcedValid +#endif + , bool extPrecision +#if JVET_AD0085_MPM_SORTING + , IntraPrediction* pIntraPred/* = nullptr*/ +#endif +) +{ +#if JVET_AC0094_REF_SAMPLES_OPT + uint8_t arrayReserved[NUM_LUMA_MODE]; + int nbReserved{ 0 }; +#endif + bool includedMode[EXT_VDIA_IDX + 1]{ false }; + includedMode[PLANAR_IDX] = true; + const CompArea& area = pu.block(COMPONENT_Y); + const Position topLeft = area.topLeft(); + int numCand = 0; + const ChannelType channelType = CHANNEL_TYPE_LUMA; + auto getIpm = [&](Position pos) -> void + { + if (numCand >= maxCands) + { + return; + } + const PredictionUnit* neighborPu = pu.cs->getPURestricted(pos, pu, channelType); + if (neighborPu) + { + bool found = false; + if (CU::isIntra(*neighborPu->cu)) + { + auto neighborMode = PU::getIntraDirLuma(*neighborPu); + if (neighborPu->cu->sgpm) + { + neighborMode = g_geoAngle2IntraAng[g_geoParams[neighborPu->cu->sgpmSplitDir][0]];; + } +#if JVET_AD0085_TMRL_EXTENSION + if (extPrecision) + { + spatialIpm[numCand] = (neighborPu->cu->timd || neighborPu->cu->tmrlFlag) ? neighborMode : MAP67TO131(neighborMode); + } + else + { + spatialIpm[numCand] = (neighborPu->cu->timd || neighborPu->cu->tmrlFlag) ? MAP131TO67(neighborMode) : neighborMode; + } +#else + spatialIpm[numCand] = neighborPu->cu->timd ? MAP131TO67(neighborMode) : neighborMode; +#endif + found = true; + } + if (CU::isInter(*neighborPu->cu) || CU::isIBC(*neighborPu->cu)) + { + spatialIpm[numCand] = neighborPu->getIpmInfo(pos); + if (neighborPu->cu->geoFlag) + { + spatialIpm[numCand] = g_geoAngle2IntraAng[g_geoParams[neighborPu->geoSplitDir][0]]; + } +#if JVET_AD0085_TMRL_EXTENSION + if (extPrecision) + { + spatialIpm[numCand] = MAP67TO131(spatialIpm[numCand]); + } +#endif + found = true; + } + if (found && !includedMode[spatialIpm[numCand]]) + { +#if JVET_AC0094_REF_SAMPLES_OPT + if (CU::isIdxModeValid((pu.cu)->areAboveRightUnavail, (pu.cu)->areBelowLeftUnavail, + (pu.cu)->lheight(), (pu.cu)->lwidth(), extPrecision ? MAP131TO67(spatialIpm[numCand]) : spatialIpm[numCand], isForcedValid)) + { +#endif + if (!includedMode[spatialIpm[numCand]]) + { + includedMode[spatialIpm[numCand++]] = true; + } +#if JVET_AC0094_REF_SAMPLES_OPT + } + else + { + arrayReserved[nbReserved] = spatialIpm[numCand]; + nbReserved++; + } +#endif + } + } + }; + + // add spatial positions + getIpm(topLeft.offset(-1, pu.Y().height - 1)); + getIpm(topLeft.offset(pu.Y().width - 1, -1)); + getIpm(topLeft.offset(-1, -1)); + getIpm(topLeft.offset(pu.Y().width, -1)); + getIpm(topLeft.offset(-1, pu.Y().height)); + +#if SECONDARY_MPM + //adding dimd modes + if (pu.cu->slice->getSPS()->getUseDimd()) + { + if (pu.cu->dimdMode != -1 && numCand < maxCands) + { + auto currMode = pu.cu->dimdMode; + if (extPrecision) + { + currMode = MAP67TO131(currMode); + } + spatialIpm[numCand] = currMode; + if (!includedMode[spatialIpm[numCand]]) + { + includedMode[spatialIpm[numCand++]] = true; + } + } + + if (pu.cu->dimdBlendMode[0] != -1 && numCand < maxCands) + { + auto currMode = pu.cu->dimdBlendMode[0]; + if (extPrecision) + { + currMode = MAP67TO131(currMode); + } + spatialIpm[numCand] = currMode; + if (!includedMode[spatialIpm[numCand]]) + { + includedMode[spatialIpm[numCand++]] = true; + } + } + } +#endif + + // non-adjacent spatial candidates + int offsetX = 0; + int offsetY = 0; + 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 = pu.Y().width * (iDistanceIndex + 1); + const int iNADistanceVer = pu.Y().height * (iDistanceIndex + 1); + + for (int iNASPIdx = 0; iNASPIdx < numNACandidate[iDistanceIndex]; iNASPIdx++) + { + switch (idxMap[iDistanceIndex][iNASPIdx]) + { + case 0:offsetX = -iNADistanceHor - 1; offsetY = pu.Y().height + iNADistanceVer - 1; break; + case 1:offsetX = pu.Y().width + iNADistanceHor - 1; offsetY = -iNADistanceVer - 1; break; + case 2:offsetX = pu.Y().width >> 1; offsetY = -iNADistanceVer - 1; break; + case 3:offsetX = -iNADistanceHor - 1; offsetY = pu.Y().height >> 1; break; + case 4:offsetX = -iNADistanceHor - 1; offsetY = -iNADistanceVer - 1; break; + default: printf("error!"); exit(0); break; + } + getIpm(topLeft.offset(offsetX, offsetY)); + } + } +#if JVET_AD0085_MPM_SORTING + if (pIntraPred && numCand > ((pu.cs->slice->getSliceType() == I_SLICE) ? NUM_PRIMARY_MOST_PROBABLE_MODES - 1 : 1)) + { + pIntraPred->deriveMPMSorted(pu, spatialIpm, numCand, 0); + } +#endif + +#if JVET_AC0094_REF_SAMPLES_OPT + if (!isForcedValid) + { + for (int i{ 0 }; i < nbReserved && numCand < maxCands; i++) + { + auto currMode = arrayReserved[i]; + if (!includedMode[currMode]) + { + spatialIpm[numCand] = currMode; + includedMode[currMode] = true; + numCand++; + } + } + } +#endif + + CHECK(numCand > maxCands, ""); + + return numCand; +} + +void fillMPMList(const PredictionUnit& pu, uint8_t* mpm, const int maxCands, const int numCand, bool extPrecision) +{ + if (numCand >= maxCands) + { + return; + } + + bool includedMode[EXT_VDIA_IDX + 1]{ false }; + CHECK(numCand > maxCands, ""); + int idx = 0; + for (; idx < numCand; idx++) + { + includedMode[mpm[idx]] = true; + } + + const int currNumCands = idx; + const int offset = extPrecision ? EXT_VDIA_IDX - 5 : NUM_LUMA_MODE - 6; + const int mod = offset + 3; + for (int i = 0; i < currNumCands; i++) + { + if (mpm[i] <= DC_IDX) + { + continue; + } + for (int deltaAngular = 0; deltaAngular < 4; deltaAngular++) + { + if (idx < maxCands) + { + auto mode = ((mpm[i] + offset - deltaAngular) % mod) + 2; + if (!includedMode[mode]) + { + includedMode[mode] = true; + mpm[idx++] = mode; + } + } + + if (idx < maxCands) + { + auto mode = ((mpm[i] - 1 + deltaAngular) % mod) + 2; + if (!includedMode[mode]) + { + includedMode[mode] = true; + mpm[idx++] = mode; + } + } + } + } + + uint8_t mpmDefault[] = { DC_IDX, VER_IDX, HOR_IDX, VER_IDX - 4, VER_IDX + 4, 14, 22, 42, 58, 10, 26, + 38, 62, 6, 30, 34, 66, 2, 48, 52, 16 }; + for (int i = 0; idx < maxCands; i++) + { + auto mode = mpmDefault[i]; + if (extPrecision) + { + mode = MAP67TO131(mode); + } + if (!includedMode[mode]) + { + includedMode[mode] = true; + mpm[idx++] = mode; + } + } + CHECK(idx != maxCands, ""); +} + +void fillNonMPMList(uint8_t* mpm, uint8_t* non_mpm) +{ + bool includedMode[EXT_VDIA_IDX + 1]{ false }; + for (int i = 0; i < NUM_MOST_PROBABLE_MODES; i++) + { + auto mode = mpm[i]; + includedMode[mode] = true; + CHECK(mode < PLANAR_IDX || mode >= NUM_LUMA_MODE, ""); + } + + int numNonMPM = 0; + for (int i = 0; i < NUM_LUMA_MODE; i++) + { + if (!includedMode[i] && numNonMPM < NUM_NON_MPM_MODES) + { + non_mpm[numNonMPM++] = i; + } + } + CHECK(numNonMPM != NUM_LUMA_MODE - NUM_MOST_PROBABLE_MODES, ""); +} +#endif diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 6fc19688dc8d06e8748ea1605063f1538aea9e15..12d0140ec89fa1fbbfdae32958663efbd2deab0c 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -161,9 +161,12 @@ namespace PU #if SECONDARY_MPM int getIntraMPMs(const PredictionUnit &pu, uint8_t *mpm, uint8_t* non_mpm #if JVET_AC0094_REF_SAMPLES_OPT - , const bool &isForcedValid + , const bool &isForcedValid #endif - , const ChannelType &channelType = CHANNEL_TYPE_LUMA +#if JVET_AD0085_MPM_SORTING + , IntraPrediction* pIntraPred = nullptr +#endif + , const ChannelType &channelType = CHANNEL_TYPE_LUMA ); #else int getIntraMPMs(const PredictionUnit &pu, unsigned *mpm, const ChannelType &channelType = CHANNEL_TYPE_LUMA); @@ -667,6 +670,9 @@ namespace PU #if JVET_AC0144_AFFINE_DMVR_REGRESSION void deriveAffineCandFromMvField(Position posLT, const int width, const int height, std::vector<RMVFInfo> mvInfoVec, Mv mvAffi[3]); #endif +#if JVET_AD0085_MPM_SORTING + bool allowMPMSorted(const PredictionUnit& pu); +#endif } // TU tools @@ -1065,4 +1071,17 @@ bool storeContexts( const Slice* slice, const int ctuXPosInCtus, const int ctuYP #if JVET_AC0144_AFFINE_DMVR_REGRESSION int deriveAffineSubBlkSize(const int sz, const int minSbSz, const int deltaMvX, const int deltaMvY, const int shift); #endif +#if JVET_AD0085_TMRL_EXTENSION +int getSpatialIpm(const PredictionUnit& pu, uint8_t* spatialIpm, const int maxCands +#if JVET_AC0094_REF_SAMPLES_OPT + , const bool& isForcedValid +#endif + , bool extPrecision = false +#if JVET_AD0085_MPM_SORTING + , IntraPrediction* pIntraPred = nullptr +#endif +); +void fillMPMList(const PredictionUnit& pu, uint8_t* mpm, const int numToFill, const int numCand, bool extPrecision = false); +void fillNonMPMList(uint8_t* mpm, uint8_t* non_mpm); +#endif #endif diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index d8e8dbee039d8d51b5a4e778ed3ca692ffcf58fa..9fc240c3dd6fb19f8c27b96d08c7c98818698975 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -2114,6 +2114,7 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) for( int k = 0; k < numBlocks; k++ ) { +#if !JVET_AD0085_TMRL_EXTENSION #if SECONDARY_MPM PU::getIntraMPMs( *pu, mpmPred, nonMpmPred #if JVET_AC0094_REF_SAMPLES_OPT @@ -2123,6 +2124,7 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) #else PU::getIntraMPMs(*pu, mpmPred); #endif +#endif #if ENABLE_DIMD || JVET_W0123_TIMD_FUSION pu->parseLumaMode = true; pu->mpmFlag = mpmFlag[k]; @@ -2179,7 +2181,33 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) if( m_BinDecoder.decodeBin( Ctx::IntraLumaSecondMpmFlag() ) ) { #if ENABLE_DIMD || JVET_W0123_TIMD_FUSION +#if JVET_AD0085_MPM_SORTING + int idx = 0; + if (cu.cs->sps->getUseMpmSorting()) + { + const int maxNumCtxBins = (NUM_SECONDARY_MOST_PROBABLE_MODES / 4) - 1; + int prefixIdx = 0; + int ctxId = 0; + for (int val = 0; val < maxNumCtxBins; val++) + { + unsigned int bin = m_BinDecoder.decodeBin(Ctx::IntraLumaSecondMpmIdx(ctxId++)); + prefixIdx += bin; + if (!bin) + { + break; + } + } + + idx = m_BinDecoder.decodeBinsEP(2) + prefixIdx * 4; + idx += NUM_PRIMARY_MOST_PROBABLE_MODES; + } + else + { + idx = m_BinDecoder.decodeBinsEP(4) + NUM_PRIMARY_MOST_PROBABLE_MODES; + } +#else int idx = m_BinDecoder.decodeBinsEP( 4 ) + NUM_PRIMARY_MOST_PROBABLE_MODES; +#endif ipredMode = mpmPred[idx]; pu->secondMpmFlag = true; pu->ipredIdx = idx; diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 3844cc29a47a0fbe356a4530e22127a71e1b4f82..3aeed0856a64145ace2f42ddd5af162b84d39248 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -380,11 +380,27 @@ void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea ) #if SECONDARY_MPM uint8_t* mpmPred = currCU.firstPU->intraMPM; // mpm_idx / rem_intra_luma_pred_mode uint8_t* nonMpmPred = currCU.firstPU->intraNonMPM; +#if JVET_AD0085_MPM_SORTING + if (PU::allowMPMSorted(*currCU.firstPU) && !(currCU.firstPU->mpmFlag && currCU.firstPU->ipredIdx == 0)) + { + PU::getIntraMPMs(*currCU.firstPU, mpmPred, nonMpmPred +#if JVET_AC0094_REF_SAMPLES_OPT + , true +#endif + , m_pcIntraPred + ); + } + else + { +#endif PU::getIntraMPMs( *currCU.firstPU, mpmPred, nonMpmPred #if JVET_AC0094_REF_SAMPLES_OPT , false #endif ); +#if JVET_AD0085_MPM_SORTING + } +#endif #else unsigned int mpmPred[NUM_MOST_PROBABLE_MODES]; // mpm_idx / rem_intra_luma_pred_mode PU::getIntraMPMs(*currCU.firstPU, mpmPred); diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index d5519cf55028452edd2a58b0066f85d18c3293d7..ef815682b64b74e772ff72e6a33a607ec7c70cbc 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -2544,6 +2544,9 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) #if JVET_AD0082_TMRL_CONFIG READ_FLAG(uiCode, "sps_tmrl_enabled_flag"); pcSPS->setUseTmrl(uiCode != 0); #endif +#if JVET_AD0085_MPM_SORTING + READ_FLAG(uiCode, "sps_mpm_sorting_enabled_flag"); pcSPS->setUseMpmSorting(uiCode != 0); +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING READ_UVLC(uiCode, "sps_cccm_cand"); pcSPS->setUseCccm(uiCode); #endif diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index c317b3051640f446f8ac96133c6071c9020055d5..c56e8819dec15839afe0858d6a7892228fdb875c 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -1686,7 +1686,31 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu ) if( secondaryMPMIdx < NUM_SECONDARY_MOST_PROBABLE_MODES ) { m_BinEncoder.encodeBin(1, Ctx::IntraLumaSecondMpmFlag()); +#if JVET_AD0085_MPM_SORTING + if (cu.cs->sps->getUseMpmSorting()) + { + int ctxId = 0; + const int maxNumCtxBins = (NUM_SECONDARY_MOST_PROBABLE_MODES / 4) - 1; + int prefixIdx = secondaryMPMIdx / 4; + for (int val = 0; val < maxNumCtxBins; val++) + { + unsigned int bin = (val == prefixIdx ? 0 : 1); + m_BinEncoder.encodeBin(bin, Ctx::IntraLumaSecondMpmIdx(ctxId++)); + if (!bin) + { + break; + } + } + + m_BinEncoder.encodeBinsEP(secondaryMPMIdx - prefixIdx * 4, 2); + } + else + { +#endif m_BinEncoder.encodeBinsEP( secondaryMPMIdx, 4); +#if JVET_AD0085_MPM_SORTING + } +#endif #if ENABLE_TRACING && (ENABLE_DIMD || JVET_W0123_TIMD_FUSION) pred_idx = secondaryMPMIdx + NUM_PRIMARY_MOST_PROBABLE_MODES; secondMpmFlag = true; @@ -1893,21 +1917,45 @@ void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu ) { #if SECONDARY_MPM auto secondMpmPred = mpmPred + NUM_PRIMARY_MOST_PROBABLE_MODES; - unsigned second_mpm_idx = NUM_SECONDARY_MOST_PROBABLE_MODES; + unsigned secondMpmIdx = NUM_SECONDARY_MOST_PROBABLE_MODES; for (unsigned idx = 0; idx < NUM_SECONDARY_MOST_PROBABLE_MODES; idx++) { if (ipredMode == secondMpmPred[idx]) { - second_mpm_idx = idx; + secondMpmIdx = idx; break; } } - if (second_mpm_idx < NUM_SECONDARY_MOST_PROBABLE_MODES) + if (secondMpmIdx < NUM_SECONDARY_MOST_PROBABLE_MODES) { m_BinEncoder.encodeBin(1, Ctx::IntraLumaSecondMpmFlag()); - m_BinEncoder.encodeBinsEP(second_mpm_idx, 4); +#if JVET_AD0085_MPM_SORTING + if (pu.cs->sps->getUseMpmSorting()) + { + int ctxId = 0; + const int maxNumCtxBins = (NUM_SECONDARY_MOST_PROBABLE_MODES / 4) - 1; + int prefixIdx = secondMpmIdx / 4; + for (int val = 0; val < maxNumCtxBins; val++) + { + unsigned int bin = (val == prefixIdx ? 0 : 1); + m_BinEncoder.encodeBin(bin, Ctx::IntraLumaSecondMpmIdx(ctxId++)); + if (!bin) + { + break; + } + } + + m_BinEncoder.encodeBinsEP(secondMpmIdx - prefixIdx * 4, 2); + } + else + { +#endif + m_BinEncoder.encodeBinsEP(secondMpmIdx, 4); +#if JVET_AD0085_MPM_SORTING + } +#endif } else { diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 7a3387b5c71e81a237c1d09aa983cfd08c4bbb70..71aacf2e365dcd08c58c5a397d553763cffc01b5 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -479,6 +479,9 @@ protected: #if JVET_AD0082_TMRL_CONFIG bool m_tmrl; #endif +#if JVET_AD0085_MPM_SORTING + bool m_mpmSorting; +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING int m_cccm; #endif @@ -1581,6 +1584,10 @@ public: void setUseTmrl (bool b) { m_tmrl = b; } bool getUseTmrl () const { return m_tmrl; } #endif +#if JVET_AD0085_MPM_SORTING + void setUseMpmSorting (bool b) { m_mpmSorting = b; } + bool getUseMpmSorting () const { return m_mpmSorting; } +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING void setUseCccm (int i) { m_cccm = i; } int getUseCccm () const { return m_cccm; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 4dbfdfe66d1c10abb2ceff11916bda6afb4031a2..309190015d7ed0b4c673e98e59ba711265eb4df6 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -2436,11 +2436,27 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS } #if SECONDARY_MPM +#if JVET_AD0085_MPM_SORTING + if (PU::allowMPMSorted(pu)) + { + m_pcIntraSearch->getMpmListSize() = PU::getIntraMPMs(pu, m_pcIntraSearch->getMPMList(), m_pcIntraSearch->getNonMPMList() +#if JVET_AC0094_REF_SAMPLES_OPT + , true +#endif + , m_pcIntraSearch + ); + } + else + { +#endif m_pcIntraSearch->getMpmListSize() = PU::getIntraMPMs(pu, m_pcIntraSearch->getMPMList(), m_pcIntraSearch->getNonMPMList() #if JVET_AC0094_REF_SAMPLES_OPT , false #endif -); + ); +#if JVET_AD0085_MPM_SORTING + } +#endif #endif } #if JVET_Z0050_DIMD_CHROMA_FUSION && (JVET_AC0094_REF_SAMPLES_OPT) diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index a6c3c032826874d5df8bb7e319738fd77a9fcd74..8201529c88b2baa38b7297e51c6dfc3cf0781ff8 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -1848,6 +1848,9 @@ void EncLib::xInitSPS( SPS& sps ) #if JVET_AD0082_TMRL_CONFIG sps.setUseTmrl ( m_tmrl ); #endif +#if JVET_AD0085_MPM_SORTING + sps.setUseMpmSorting ( m_mpmSorting ); +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING sps.setUseCccm ( m_cccm ); #endif diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 3801234fe3beb9b7646304a962bf8ce0108cc03e..39cb0b9d4cec3abae45cd00712f02e23225b2386 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -1605,6 +1605,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) #if JVET_AD0082_TMRL_CONFIG WRITE_FLAG(pcSPS->getUseTmrl() ? 1 : 0, "sps_tmrl_enabled_flag"); #endif +#if JVET_AD0085_MPM_SORTING + WRITE_FLAG(pcSPS->getUseMpmSorting() ? 1 : 0, "sps_mpm_sorting_enabled_flag"); +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING WRITE_UVLC(pcSPS->getUseCccm() , "sps_cccm_cand"); #endif