diff --git a/cfg/encoder_lowdelay_P_vtm.cfg b/cfg/encoder_lowdelay_P_vtm.cfg index bc59427700e7dcbeba9cb66dc684022bfc8de389..4124deae0b70f48abfe4aaa4bdbf4e2f78763d54 100644 --- a/cfg/encoder_lowdelay_P_vtm.cfg +++ b/cfg/encoder_lowdelay_P_vtm.cfg @@ -127,6 +127,7 @@ LMChroma : 1 # use CCLM only DepQuant : 1 IMV : 2 ALF : 1 +MHIntra : 1 # Fast tools PBIntraFast : 1 diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg index 9737a2854824f560bfef606585e012ef738f0307..2e9644e55279a9aa6b47d7f7869839f1435a35c2 100644 --- a/cfg/encoder_lowdelay_vtm.cfg +++ b/cfg/encoder_lowdelay_vtm.cfg @@ -129,6 +129,7 @@ IMV : 2 ALF : 1 GBi : 1 GBiFast : 1 +MHIntra : 1 # Fast tools PBIntraFast : 1 diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index 63ff58df9358f54e7567d150a6e8993a48ca04ea..bd07173bfae4208481be445f6eb35f6a1ab52e41 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -143,6 +143,7 @@ IMV : 2 ALF : 1 GBi : 1 GBiFast : 1 +MHIntra : 1 # Fast tools PBIntraFast : 1 diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 3c6efc53764d3d8d710daab9abefc93c43b8926d..73a5645b272303590a3b1aa2c59f6335dbfa67d4 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -242,6 +242,9 @@ void EncApp::xInitLibCfg() #if JVET_L0646_GBI m_cEncLib.setUseGBi ( m_GBi ); m_cEncLib.setUseGBiFast ( m_GBiFast ); +#endif +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + m_cEncLib.setUseMHIntra ( m_MHIntra ); #endif // ADD_NEW_TOOL : (encoder app) add setting of tool enabling flags and associated parameters here diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 0b7da7327be4a55d7219ebc19efa06771ef3f98a..f65ef71a760598ccb93c2b3a1a44c2d6cfe15595 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -847,6 +847,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #if JVET_L0646_GBI ("GBi", m_GBi, false, "Enable Generalized Bi-prediction(GBi)") ("GBiFast", m_GBiFast, false, "Fast methods for Generalized Bi-prediction(GBi)\n") +#endif +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + ("MHIntra", m_MHIntra, false, "Enable MHIntra mode") #endif // ADD_NEW_TOOL : (encoder app) add parsing parameters here @@ -3122,6 +3125,9 @@ void EncAppCfg::xPrintParameter() #if JVET_L0646_GBI msg( VERBOSE, "GBi:%d ", m_GBi ); msg( VERBOSE, "GBiFast:%d ", m_GBiFast ); +#endif +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + msg(VERBOSE, "MHIntra:%d ", m_MHIntra); #endif } // ADD_NEW_TOOL (add some output indicating the usage of tools) diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index a9eb00f22b16e1ccb7a754209c6b9110af5a4229..c1b61937f00af454b2e2340644c826c9167b4b05 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -225,6 +225,10 @@ protected: bool m_GBi; bool m_GBiFast; #endif + +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + bool m_MHIntra; +#endif // ADD_NEW_TOOL : (encoder app) add tool enabling flags and associated parameters here unsigned m_uiMaxCUWidth; ///< max. CU width in pixel diff --git a/source/Lib/CommonLib/CodingStatistics.h b/source/Lib/CommonLib/CodingStatistics.h index be99dbbe7dc88237915100a14a634d2dcc445f33..3c82f4abe427a601accff05b0727b5253c64edec 100644 --- a/source/Lib/CommonLib/CodingStatistics.h +++ b/source/Lib/CommonLib/CodingStatistics.h @@ -106,6 +106,9 @@ enum CodingStatisticsType STATS__CABAC_BITS__EMT_CU_FLAG, STATS__CABAC_BITS__EMT_TU_INDEX, STATS__TOOL_EMT, +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + STATS__CABAC_BITS__MH_INTRA_FLAG, +#endif STATS__TOOL_TOTAL, STATS__NUM_STATS }; @@ -178,6 +181,9 @@ static inline const char* getName(CodingStatisticsType name) #endif "CABAC_BITS__EMT_CU_FLAG", "CABAC_BITS__EMT_TU_INDX", +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + "CABAC_BITS__MH_INTRA_FLAG", +#endif "CABAC_BITS__OTHER", "CABAC_BITS__INVALID", "TOOL_FRAME", diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 434e66e89c9de59b81126a4def2fbfdc28370c46..ce7b6d551e03936a0f1f6ea4d49f50fb4da51e6c 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -777,6 +777,21 @@ const CtxSet ContextSetCfg::ctbAlfFlag = } ) }; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA +const CtxSet ContextSetCfg::MHIntraFlag = ContextSetCfg::addCtxSet +({ + { 154, }, + { 110, }, + { CNU, }, +}); + +const CtxSet ContextSetCfg::MHIntraPredMode = ContextSetCfg::addCtxSet +({ + { 183, CNU, CNU, CNU, }, + { 154, CNU, CNU, CNU, }, + { 184, CNU, CNU, CNU, }, +}); +#endif const unsigned ContextSetCfg::NumberOfContexts = (unsigned)ContextSetCfg::sm_InitTables[0].size(); diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 3e4679c06bd64c00f0f7611e8ca52e739902a135..d9f2538be3971446205a6c3a1b63123bcea2eaf0 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -195,6 +195,10 @@ public: static const CtxSet GBiIdx; #endif static const CtxSet ctbAlfFlag; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + static const CtxSet MHIntraFlag; + static const CtxSet MHIntraPredMode; +#endif static const unsigned NumberOfContexts; // combined sets for less complex copying diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index 45a66514af173d329092688d2a6d9e9691f31022..a71f12c4a7d903ae8613704ea34e3cd7330e3162 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -141,6 +141,15 @@ IntraPrediction::IntraPrediction() m_piYuvExt[ch][buf] = nullptr; } } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++) + { + for (uint32_t buf = 0; buf < 4; buf++) + { + m_yuvExt2[ch][buf] = nullptr; + } + } +#endif m_piTemp = nullptr; } @@ -160,6 +169,16 @@ void IntraPrediction::destroy() m_piYuvExt[ch][buf] = nullptr; } } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++) + { + for (uint32_t buf = 0; buf < 4; buf++) + { + delete[] m_yuvExt2[ch][buf]; + m_yuvExt2[ch][buf] = nullptr; + } + } +#endif delete[] m_piTemp; m_piTemp = nullptr; @@ -173,6 +192,13 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth destroy(); } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (m_yuvExt2[COMPONENT_Y][0] != nullptr && m_currChromaFormat != chromaFormatIDC) + { + destroy(); + } +#endif + m_currChromaFormat = chromaFormatIDC; if (m_piYuvExt[COMPONENT_Y][PRED_BUF_UNFILTERED] == nullptr) // check if first is null (in which case, nothing initialised yet) @@ -188,6 +214,21 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth } } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (m_yuvExt2[COMPONENT_Y][0] == nullptr) // check if first is null (in which case, nothing initialised yet) + { + m_yuvExtSize2 = (MAX_CU_SIZE) * (MAX_CU_SIZE); + + for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++) + { + for (uint32_t buf = 0; buf < 4; buf++) + { + m_yuvExt2[ch][buf] = new Pel[m_yuvExtSize2]; + } + } + } +#endif + int shift = bitDepthY + 4; for (int i = 32; i < 64; i++) { @@ -796,6 +837,133 @@ bool IntraPrediction::useDPCMForFirstPassIntraEstimation(const PredictionUnit &p return CU::isRDPCMEnabled(*pu.cu) && pu.cu->transQuantBypass && (uiDirMode == HOR_IDX || uiDirMode == VER_IDX); } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA +void IntraPrediction::geneWeightedPred(const ComponentID compId, PelBuf &pred, const PredictionUnit &pu, Pel *srcBuf) +{ + const int width = pred.width; + const int height = pred.height; + const int srcStride = width; + const int dstStride = pred.stride; + + const uint32_t dirMode = PU::getFinalIntraMode(pu, toChannelType(compId)); + const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compId)); + Pel* dstBuf = pred.buf; + int k, l; + + bool modeDC = (dirMode <= DC_IDX); + Pel wIntra1 = 6, wInter1 = 2, wIntra2 = 5, wInter2 = 3, wIntra3 = 3, wInter3 = 5, wIntra4 = 2, wInter4 = 6; + + if (modeDC || width < 4 || height < 4) + { + for (k = 0; k<height; k++) + { + for (l = 0; l<width; l++) + { + dstBuf[k*dstStride + l] = ClipPel((((dstBuf[k*dstStride + l] * 4) + (srcBuf[k*srcStride + l] * 4)) >> 3), clpRng); + } + } + } + else + { + if (dirMode <= DIA_IDX) + { + int interval = (width >> 2); + + for (k = 0; k<height; k++) + { + for (l = 0; l<width; l++) + { + if (l<interval) + { + dstBuf[k*dstStride + l] = ClipPel((((dstBuf[k*dstStride + l] * wInter1) + (srcBuf[k*srcStride + l] * wIntra1)) >> 3), clpRng); + } + else if (l >= interval && l < (2 * interval)) + { + dstBuf[k*dstStride + l] = ClipPel((((dstBuf[k*dstStride + l] * wInter2) + (srcBuf[k*srcStride + l] * wIntra2)) >> 3), clpRng); + } + else if (l >= (interval * 2) && l < (3 * interval)) + { + dstBuf[k*dstStride + l] = ClipPel((((dstBuf[k*dstStride + l] * wInter3) + (srcBuf[k*srcStride + l] * wIntra3)) >> 3), clpRng); + } + else + { + dstBuf[k*dstStride + l] = ClipPel((((dstBuf[k*dstStride + l] * wInter4) + (srcBuf[k*srcStride + l] * wIntra4)) >> 3), clpRng); + } + } + } + } + else + { + int interval = (height >> 2); + for (k = 0; k<height; k++) + { + for (l = 0; l<width; l++) + { + if (k<interval) + { + dstBuf[k*dstStride + l] = ClipPel((((dstBuf[k*dstStride + l] * wInter1) + (srcBuf[k*srcStride + l] * wIntra1)) >> 3), clpRng); + } + else if (k >= interval && k < (2 * interval)) + { + dstBuf[k*dstStride + l] = ClipPel((((dstBuf[k*dstStride + l] * wInter2) + (srcBuf[k*srcStride + l] * wIntra2)) >> 3), clpRng); + } + else if (k >= (interval * 2) && k < (3 * interval)) + { + dstBuf[k*dstStride + l] = ClipPel((((dstBuf[k*dstStride + l] * wInter3) + (srcBuf[k*srcStride + l] * wIntra3)) >> 3), clpRng); + } + else + { + dstBuf[k*dstStride + l] = ClipPel((((dstBuf[k*dstStride + l] * wInter4) + (srcBuf[k*srcStride + l] * wIntra4)) >> 3), clpRng); + } + } + } + } + } +} +void IntraPrediction::switchBuffer(const PredictionUnit &pu, ComponentID compID, PelBuf srcBuff, Pel *dst) +{ + Pel *src = srcBuff.bufAt(0, 0); + int compWidth = compID == COMPONENT_Y ? pu.Y().width : pu.Cb().width; + int compHeight = compID == COMPONENT_Y ? pu.Y().height : pu.Cb().height; + for (int i = 0; i < compHeight; i++) + { + for (int j = 0; j < compWidth; j++) + { + dst[j] = src[j]; + } + src += srcBuff.stride; + dst += compWidth; + } +} + +void IntraPrediction::geneIntrainterPred(const CodingUnit &cu) +{ + if (!cu.firstPU->MHIntraFlag) + { + return; + } + + const PredictionUnit* pu = cu.firstPU; + + bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, *pu, true, *pu); + initIntraPatternChType(cu, pu->Y(), isUseFilter); + predIntraAng(COMPONENT_Y, cu.cs->getPredBuf(*pu).Y(), *pu, isUseFilter); + isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cb, *pu, true, *pu); + initIntraPatternChType(cu, pu->Cb(), isUseFilter); + predIntraAng(COMPONENT_Cb, cu.cs->getPredBuf(*pu).Cb(), *pu, isUseFilter); + isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cr, *pu, true, *pu); + initIntraPatternChType(cu, pu->Cr(), isUseFilter); + predIntraAng(COMPONENT_Cr, cu.cs->getPredBuf(*pu).Cr(), *pu, isUseFilter); + + for (int currCompID = 0; currCompID < 3; currCompID++) + { + ComponentID currCompID2 = (ComponentID)currCompID; + PelBuf tmpBuf = currCompID == 0 ? cu.cs->getPredBuf(*pu).Y() : (currCompID == 1 ? cu.cs->getPredBuf(*pu).Cb() : cu.cs->getPredBuf(*pu).Cr()); + switchBuffer(*pu, currCompID2, tmpBuf, getPredictorPtr2(currCompID2, 0)); + } +} +#endif + inline bool isAboveLeftAvailable ( const CodingUnit &cu, const ChannelType &chType, const Position &posLT ); inline int isAboveAvailable ( const CodingUnit &cu, const ChannelType &chType, const Position &posLT, const uint32_t uiNumUnitsInPU, const uint32_t unitWidth, bool *validFlags ); inline int isLeftAvailable ( const CodingUnit &cu, const ChannelType &chType, const Position &posLT, const uint32_t uiNumUnitsInPU, const uint32_t unitWidth, bool *validFlags ); diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index 9d8002a8ce3d02c536ae836cb7c4fb8202fd241f..856a145bf42a37a9a1ca394d838c94211c061bbb 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -69,6 +69,10 @@ private: Pel* m_piYuvExt[MAX_NUM_COMPONENT][NUM_PRED_BUF]; int m_iYuvExtSize; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + Pel* m_yuvExt2[MAX_NUM_COMPONENT][4]; + int m_yuvExtSize2; +#endif static const uint8_t m_aucIntraFilter[MAX_NUM_CHANNEL_TYPE][MAX_INTRA_FILTER_DEPTHS]; @@ -126,6 +130,13 @@ public: static bool useFilteredIntraRefSamples( const ComponentID &compID, const PredictionUnit &pu, bool modeSpecific, const UnitArea &tuArea ); static bool useDPCMForFirstPassIntraEstimation(const PredictionUnit &pu, const uint32_t &uiDirMode); + +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + void geneWeightedPred (const ComponentID compId, PelBuf &pred, const PredictionUnit &pu, Pel *srcBuf); + Pel* getPredictorPtr2 (const ComponentID compID, uint32_t idx) { return m_yuvExt2[compID][idx]; } + void switchBuffer (const PredictionUnit &pu, ComponentID compID, PelBuf srcBuff, Pel *dst); + void geneIntrainterPred (const CodingUnit &cu); +#endif }; //! \} diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp index 8a2ac97f5aa77a099147081b89a9110d5130b39a..d85c6668b62b17c32bd8c97d9023ac71d3bbffc9 100644 --- a/source/Lib/CommonLib/Rom.cpp +++ b/source/Lib/CommonLib/Rom.cpp @@ -353,7 +353,11 @@ void initROM() // g_aucLog2[ x ]: log2(x), if x=1 -> 0, x=2 -> 1, x=4 -> 2, x=8 -> 3, x=16 -> 4, ... ::memset(g_aucLog2, 0, sizeof(g_aucLog2)); c = 0; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + for( int i = 0, n = 0; i <= (1 << (MAX_CU_DEPTH + 1)); i++ ) +#else for( int i = 0, n = 0; i <= MAX_CU_SIZE; i++ ) +#endif { g_aucNextLog2[i] = i <= 1 ? 0 : c + 1; @@ -697,9 +701,15 @@ const DecisionTreeTemplate g_mtSplitDTT = compile( // ==================================================================================================================== SizeIndexInfo* gp_sizeIdxInfo = NULL; int g_BlockSizeTrafoScale[MAX_CU_SIZE + 1][MAX_CU_SIZE + 1][2]; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA +int8_t g_aucLog2 [(1 << (MAX_CU_DEPTH + 1)) + 1]; +int8_t g_aucNextLog2[(1 << (MAX_CU_DEPTH + 1)) + 1]; +int8_t g_aucPrevLog2[(1 << (MAX_CU_DEPTH + 1)) + 1]; +#else int8_t g_aucLog2 [MAX_CU_SIZE + 1]; int8_t g_aucNextLog2[MAX_CU_SIZE + 1]; int8_t g_aucPrevLog2[MAX_CU_SIZE + 1]; +#endif UnitScale g_miScaling( MIN_CU_LOG2, MIN_CU_LOG2 ); diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h index afbb242da407759e18c6aeeb871eb063a13e4678..ff5de8fd7f0acb28ad9c69a9a37ea1bd779c47b1 100644 --- a/source/Lib/CommonLib/Rom.h +++ b/source/Lib/CommonLib/Rom.h @@ -165,9 +165,15 @@ extern const DecisionTreeTemplate g_qtbtSplitDTT; // ==================================================================================================================== extern SizeIndexInfo* gp_sizeIdxInfo; extern int g_BlockSizeTrafoScale [MAX_CU_SIZE + 1][MAX_CU_SIZE + 1][2]; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA +extern int8_t g_aucLog2 [(1 << (MAX_CU_DEPTH + 1)) + 1]; +extern int8_t g_aucNextLog2 [(1 << (MAX_CU_DEPTH + 1)) + 1]; +extern int8_t g_aucPrevLog2 [(1 << (MAX_CU_DEPTH + 1)) + 1]; +#else extern int8_t g_aucLog2 [MAX_CU_SIZE + 1]; extern int8_t g_aucNextLog2 [MAX_CU_SIZE + 1]; extern int8_t g_aucPrevLog2 [MAX_CU_SIZE + 1]; +#endif extern const int8_t i2Log2Tab[257]; inline bool is34( const SizeType& size ) diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 6023e01bc877a3e7a47d9a804bb897eb9b9e5323..f7fe9121b7231759861b20df52b4b5e35ff1293e 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1640,6 +1640,9 @@ SPSNext::SPSNext( SPS& sps ) , m_Affine ( false ) , m_AffineType ( false ) , m_MTTEnabled ( false ) +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + , m_MHIntra ( false ) +#endif #if ENABLE_WPP_PARALLELISM , m_NextDQP ( false ) #endif diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index d6ef610c7304e8361981d2524201642290e29fd9..53031e977d979db5dff1c4fbcecf7b0668977642 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -814,6 +814,9 @@ private: bool m_GBi; // #endif bool m_MTTEnabled; // +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + bool m_MHIntra; +#endif #if ENABLE_WPP_PARALLELISM bool m_NextDQP; #endif @@ -921,6 +924,11 @@ public: void setUseCompositeRef(bool b) { m_compositeRefEnabled = b; } bool getUseCompositeRef() const { return m_compositeRefEnabled; } + +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + void setUseMHIntra ( bool b ) { m_MHIntra = b; } + bool getUseMHIntra () const { return m_MHIntra; } +#endif // ADD_NEW_TOOL : (sps extension) add access functions for tool enabling flags and associated parameters here }; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 200162158bc6ef93b6edf73ce576cf2c8c19a69b..695ab7031aee892a4cc1e35f0dfe6c6c17b3271d 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,8 @@ #include <assert.h> #include <cassert> +#define JVET_L0100_MULTI_HYPOTHESIS_INTRA 1 // Combine intra mode with an extra merge indexed prediction + #define JVET_L0553_FIX_INITQP 1 #define JVET_L0147_ALF_SUBSAMPLED_LAPLACIAN 1 // Subsampled Laplacian calculation diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 6152c93f57b58f37865eb29ad338f314b8b6babd..6965bbb77f8a1f2aaddde66fab7570ac25d9cb14 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -331,6 +331,11 @@ void PredictionUnit::initData() mvdAffi[i][j].setZero(); } } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + MHIntraFlag = false; + intraDir2[0] = PLANAR_IDX; + intraDir2[1] = DM_CHROMA_IDX; +#endif } PredictionUnit& PredictionUnit::operator=(const IntraPredictionData& predData) @@ -361,6 +366,11 @@ PredictionUnit& PredictionUnit::operator=(const InterPredictionData& predData) mvdAffi[i][j] = predData.mvdAffi[i][j]; } } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + MHIntraFlag = predData.MHIntraFlag; + intraDir2[0] = predData.intraDir2[0]; + intraDir2[1] = predData.intraDir2[1]; +#endif return *this; } @@ -388,6 +398,11 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other ) mvdAffi[i][j] = other.mvdAffi[i][j]; } } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + MHIntraFlag = other.MHIntraFlag; + intraDir2[0] = other.intraDir2[0]; + intraDir2[1] = other.intraDir2[1]; +#endif return *this; } diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 93924a20065a649ddfe4e80adaf1b4553766616c..e0c850ce39c71254f141fea1bfc33217bc0c01b0 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -357,6 +357,10 @@ struct InterPredictionData int16_t refIdx [NUM_REF_PIC_LIST_01]; MergeType mergeType; Mv mvdAffi [NUM_REF_PIC_LIST_01][3]; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + bool MHIntraFlag; + uint32_t intraDir2[MAX_NUM_CHANNEL_TYPE]; +#endif }; struct PredictionUnit : public UnitArea, public IntraPredictionData, public InterPredictionData diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 065e4fe39742efeb66e7cff63714dc3909d5d84f..3a4ec7bad57529facf17b880fb14af334227d530 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -309,22 +309,42 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType // Get intra direction of left PU const PredictionUnit *puLeft = pu.cs->getPURestricted(pos.offset(-1, 0), pu, channelType); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (puLeft && (CU::isIntra(*puLeft->cu) || (channelType == CHANNEL_TYPE_LUMA && puLeft->MHIntraFlag))) +#else if (puLeft && CU::isIntra(*puLeft->cu)) +#endif { +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + leftIntraDir = puLeft->MHIntraFlag ? puLeft->intraDir2[channelType] : puLeft->intraDir[channelType]; +#else leftIntraDir = puLeft->intraDir[channelType]; +#endif if (isChroma(channelType) && leftIntraDir == DM_CHROMA_IDX) { +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + leftIntraDir = puLeft->MHIntraFlag ? puLeft->intraDir2[0] : puLeft->intraDir[0]; +#else leftIntraDir = puLeft->intraDir[0]; +#endif } } // Get intra direction of above PU const PredictionUnit *puAbove = pu.cs->getPURestricted(pos.offset(0, -1), pu, channelType); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (puAbove && (CU::isIntra(*puAbove->cu) || (channelType == CHANNEL_TYPE_LUMA && puAbove->MHIntraFlag)) && CU::isSameCtu(*pu.cu, *puAbove->cu)) +#else if (puAbove && CU::isIntra(*puAbove->cu) && CU::isSameCtu(*pu.cu, *puAbove->cu)) +#endif { +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + aboveIntraDir = puAbove->MHIntraFlag ? puAbove->intraDir2[channelType] : puAbove->intraDir[channelType]; +#else aboveIntraDir = puAbove->intraDir[channelType]; +#endif if (isChroma(channelType) && aboveIntraDir == DM_CHROMA_IDX) { @@ -478,14 +498,168 @@ bool PU::isChromaIntraModeCrossCheckMode( const PredictionUnit &pu ) return pu.intraDir[CHANNEL_TYPE_CHROMA] == DM_CHROMA_IDX; } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA +int PU::getMHIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/, const bool isChromaMDMS /*= false*/, const unsigned startIdx /*= 0*/) +{ + const unsigned numMPMs = 3; + { + int numCand = -1; + uint32_t leftIntraDir = DC_IDX, aboveIntraDir = DC_IDX; + + const CompArea& area = pu.block(getFirstComponentOfChannel(channelType)); + const Position& pos = area.pos(); + + // Get intra direction of left PU + const PredictionUnit *puLeft = pu.cs->getPURestricted(pos.offset(-1, 0), pu, channelType); + + if (puLeft && (CU::isIntra(*puLeft->cu) || puLeft->MHIntraFlag)) + { + leftIntraDir = puLeft->MHIntraFlag ? puLeft->intraDir2[channelType] : puLeft->intraDir[channelType]; + + if (isChroma(channelType) && leftIntraDir == DM_CHROMA_IDX) + { + leftIntraDir = puLeft->MHIntraFlag ? puLeft->intraDir2[0] : puLeft->intraDir[0]; + } + } + + // Get intra direction of above PU + const PredictionUnit* puAbove = pu.cs->getPURestricted(pos.offset(0, -1), pu, channelType); + + if (puAbove && (CU::isIntra(*puAbove->cu) || puAbove->MHIntraFlag) && CU::isSameCtu(*pu.cu, *puAbove->cu)) + { + aboveIntraDir = puAbove->MHIntraFlag ? puAbove->intraDir2[channelType] : puAbove->intraDir[channelType]; + + if (isChroma(channelType) && aboveIntraDir == DM_CHROMA_IDX) + { + aboveIntraDir = puAbove->MHIntraFlag ? puAbove->intraDir2[0] : puAbove->intraDir[0]; + } + } + + CHECK(2 >= numMPMs, "Invalid number of most probable modes"); + + uint32_t leftIntraDir2 = leftIntraDir; + uint32_t aboveIntraDir2 = aboveIntraDir; + + leftIntraDir2 = (leftIntraDir2 > DC_IDX) ? ((leftIntraDir2 <= DIA_IDX) ? HOR_IDX : VER_IDX) : leftIntraDir2; + aboveIntraDir2 = (aboveIntraDir2 > DC_IDX) ? ((aboveIntraDir2 <= DIA_IDX) ? HOR_IDX : VER_IDX) : aboveIntraDir2; + + if (leftIntraDir2 == aboveIntraDir2) + { + numCand = 1; + + if (leftIntraDir2 > DC_IDX) // angular modes + { + mpm[0] = leftIntraDir2; + mpm[1] = PLANAR_IDX; + mpm[2] = DC_IDX; + } + else //non-angular + { + mpm[0] = PLANAR_IDX; + mpm[1] = DC_IDX; + mpm[2] = VER_IDX; + } + } + else + { + numCand = 2; + + mpm[0] = leftIntraDir2; + mpm[1] = aboveIntraDir2; + + if (leftIntraDir2 && aboveIntraDir2) //both modes are non-planar + { + mpm[2] = PLANAR_IDX; + } + else + { + mpm[2] = (leftIntraDir2 + aboveIntraDir2) < 2 ? VER_IDX : DC_IDX; + } + } + int narrowCase = getNarrowShape(pu.lwidth(), pu.lheight()); + if (narrowCase > 0) + { + bool isMPM[NUM_LUMA_MODE]; + for (int idx = 0; idx < NUM_LUMA_MODE; idx++) + { + isMPM[idx] = false; + } + for (int idx = 0; idx < numMPMs; idx++) + { + isMPM[mpm[idx]] = true; + } + if (narrowCase == 1 && isMPM[HOR_IDX]) + { + for (int idx = 0; idx < numMPMs; idx++) + { + if (mpm[idx] == HOR_IDX) + { + if (!isMPM[PLANAR_IDX]) + mpm[idx] = PLANAR_IDX; + else if (!isMPM[DC_IDX]) + mpm[idx] = DC_IDX; + else if (!isMPM[VER_IDX]) + mpm[idx] = VER_IDX; + break; + } + } + } + if (narrowCase == 2 && isMPM[VER_IDX]) + { + for (int idx = 0; idx < numMPMs; idx++) + { + if (mpm[idx] == VER_IDX) + { + if (!isMPM[PLANAR_IDX]) + mpm[idx] = PLANAR_IDX; + else if (!isMPM[DC_IDX]) + mpm[idx] = DC_IDX; + else if (!isMPM[HOR_IDX]) + mpm[idx] = HOR_IDX; + break; + } + } + } + } + CHECK(numCand == 0, "No candidates found"); + CHECK(mpm[0] == mpm[1] || mpm[0] == mpm[2] || mpm[2] == mpm[1], "redundant MPM"); + return numCand; + } +} +int PU::getNarrowShape(const int width, const int height) +{ + int longSide = (width > height) ? width : height; + int shortSide = (width > height) ? height : width; + if (longSide > (2 * shortSide)) + { + if (longSide == width) + return 1; + else + return 2; + } + else + { + return 0; + } +} +#endif + uint32_t PU::getFinalIntraMode( const PredictionUnit &pu, const ChannelType &chType ) { +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + uint32_t uiIntraMode = pu.MHIntraFlag ? pu.intraDir2[chType] : pu.intraDir[chType]; +#else uint32_t uiIntraMode = pu.intraDir[chType]; +#endif if( uiIntraMode == DM_CHROMA_IDX && !isLuma( chType ) ) { const PredictionUnit &lumaPU = CS::isDualITree( *pu.cs ) ? *pu.cs->picture->cs->getPU( pu.blocks[chType].lumaPos(), CHANNEL_TYPE_LUMA ) : *pu.cs->getPU( pu.blocks[chType].lumaPos(), CHANNEL_TYPE_LUMA ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + uiIntraMode = pu.MHIntraFlag ? pu.intraDir2[0] : lumaPU.intraDir[0]; +#else uiIntraMode = lumaPU.intraDir[0]; +#endif } if( pu.chromaFormat == CHROMA_422 && !isLuma( chType ) ) { diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 3247170c6f357a977fdc39d16be213adee1a28ee..9a01baa46eb750e86e499c4f8a342572271c1c34 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -143,6 +143,10 @@ namespace PU bool isLMCMode ( unsigned mode); bool isLMCModeEnabled (const PredictionUnit &pu, unsigned mode); bool isChromaIntraModeCrossCheckMode(const PredictionUnit &pu); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + int getMHIntraMPMs (const PredictionUnit &pu, unsigned *mpm, const ChannelType &channelType = CHANNEL_TYPE_LUMA, const bool isChromaMDMS = false, const unsigned startIdx = 0); + int getNarrowShape (const int width, const int height); +#endif } // TU tools @@ -213,6 +217,47 @@ uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeL return 0; } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA +template<typename T, size_t N> +uint32_t updateDoubleCandList(T mode, double cost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, static_vector<T, N>& candModeList2, T mode2, size_t fastCandNum = N) +{ + CHECK(std::min(fastCandNum, candModeList.size()) != std::min(fastCandNum, candCostList.size()), "Sizes do not match!"); + CHECK(fastCandNum > candModeList.capacity(), "The vector is to small to hold all the candidates!"); + + size_t i; + size_t shift = 0; + size_t currSize = std::min(fastCandNum, candCostList.size()); + + while (shift < fastCandNum && shift < currSize && cost < candCostList[currSize - 1 - shift]) + { + shift++; + } + + if (candModeList.size() >= fastCandNum && shift != 0) + { + for (i = 1; i < shift; i++) + { + candModeList[currSize - i] = candModeList[currSize - 1 - i]; + candModeList2[currSize - i] = candModeList2[currSize - 1 - i]; + candCostList[currSize - i] = candCostList[currSize - 1 - i]; + } + candModeList[currSize - shift] = mode; + candModeList2[currSize - shift] = mode2; + candCostList[currSize - shift] = cost; + return 1; + } + else if (currSize < fastCandNum) + { + candModeList.insert(candModeList.end() - shift, mode); + candModeList2.insert(candModeList2.end() - shift, mode2); + candCostList.insert(candCostList.end() - shift, cost); + return 1; + } + + return 0; +} +#endif + #endif diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 70aae0890cdc0a0bd6a842586cf89ef874d7ad75..12d1d1bc9957d5d66cde55ce33a8cd5b31cd9c80 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -1155,6 +1155,14 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx ) if( pu.mergeFlag ) { affine_flag ( *pu.cu ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + MHIntra_flag(pu); + if (pu.MHIntraFlag) + { + MHIntra_luma_pred_modes(*pu.cu); + pu.intraDir2[1] = DM_CHROMA_IDX; + } +#endif merge_data ( pu ); } else @@ -1395,6 +1403,129 @@ void CABACReader::mvp_flag( PredictionUnit& pu, RefPicList eRefList ) } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA +void CABACReader::MHIntra_flag(PredictionUnit& pu) +{ + if (!pu.cs->sps->getSpsNext().getUseMHIntra()) + { + pu.MHIntraFlag = false; + return; + } + if (pu.cu->skip) + { + pu.MHIntraFlag = false; + return; + } + + if (pu.cu->lwidth() * pu.cu->lheight() < 64 || pu.cu->lwidth() >= MAX_CU_SIZE || pu.cu->lheight() >= MAX_CU_SIZE) + { + pu.MHIntraFlag = false; + return; + } + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET(STATS__CABAC_BITS__MH_INTRA_FLAG); + + pu.MHIntraFlag = (m_BinDecoder.decodeBin(Ctx::MHIntraFlag())); + DTRACE(g_trace_ctx, D_SYNTAX, "MHIntra_flag() MHIntra=%d pos=(%d,%d) size=%dx%d\n", pu.MHIntraFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height); +} + +void CABACReader::MHIntra_luma_pred_modes(CodingUnit &cu) +{ + if (!cu.Y().valid()) + { + return; + } + + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2(STATS__CABAC_BITS__INTRA_DIR_ANG, cu.lumaSize(), CHANNEL_TYPE_LUMA); + + const uint32_t numMPMs = 3; + + // prev_intra_luma_pred_flag + int numBlocks = CU::getNumPUs(cu); + int mpmFlag[4]; + PredictionUnit *pu = cu.firstPU; + for (int k = 0; k < numBlocks; k++) + { + if (PU::getNarrowShape(pu->lwidth(), pu->lheight()) == 0) + { + mpmFlag[k] = m_BinDecoder.decodeBin(Ctx::MHIntraPredMode()); + } + else + { + mpmFlag[k] = 1; + } + } + + // mpm_idx / rem_intra_luma_pred_mode + for (int k = 0; k < numBlocks; k++) + { + unsigned *mpm_pred = (unsigned*)alloca(numMPMs * sizeof(unsigned)); + PU::getMHIntraMPMs(*pu, mpm_pred); + + if (mpmFlag[k]) + { + unsigned pred_idx = 0; + + pred_idx = m_BinDecoder.decodeBinEP(); + if (pred_idx) + { + pred_idx += m_BinDecoder.decodeBinEP(); + } + pu->intraDir2[0] = mpm_pred[pred_idx]; + } + else + { + unsigned pred_mode = 0; + + bool isMPMCand[4]; + for (unsigned i = 0; i < 4; i++) + { + isMPMCand[i] = false; + } + for (unsigned i = 0; i < 3; i++) + { + if (mpm_pred[i] == PLANAR_IDX) + { + isMPMCand[0] = true; + } + else if (mpm_pred[i] == DC_IDX) + { + isMPMCand[1] = true; + } + else if (mpm_pred[i] == HOR_IDX) + { + isMPMCand[2] = true; + } + else if (mpm_pred[i] == VER_IDX) + { + isMPMCand[3] = true; + } + } + if (!isMPMCand[0]) + { + pred_mode = PLANAR_IDX; + } + if (!isMPMCand[1]) + { + pred_mode = DC_IDX; + } + if (!isMPMCand[2]) + { + pred_mode = HOR_IDX; + } + if (!isMPMCand[3]) + { + pred_mode = VER_IDX; + } + pu->intraDir2[0] = pred_mode; + } + + DTRACE(g_trace_ctx, D_SYNTAX, "intra_luma_pred_modes() idx=%d pos=(%d,%d) mode=%d\n", k, pu->lumaPos().x, pu->lumaPos().y, pu->intraDir2[0]); + pu = pu->next; + } +} +#endif + + //================================================================================ // clause 7.3.8.7 //-------------------------------------------------------------------------------- diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index fd194650c2275ac547e9cff453b7c7f04d167b64..aabf26f8246ea9ad231bf14c7c1265d6225c2589 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -101,6 +101,10 @@ public: void inter_pred_idc ( PredictionUnit& pu ); void ref_idx ( PredictionUnit& pu, RefPicList eRefList ); void mvp_flag ( PredictionUnit& pu, RefPicList eRefList ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + void MHIntra_flag ( PredictionUnit& pu ); + void MHIntra_luma_pred_modes ( CodingUnit& cu ); +#endif // pcm samples (clause 7.3.8.7) void pcm_samples ( TransformUnit& tu ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 8fb1c75ba89f278c1a621440ce9e8fd16f45bade..aa112c2b56212d7c96a40a4f126aa3047cf901ca 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -314,9 +314,22 @@ void DecCu::xFillPCMBuffer(CodingUnit &cu) void DecCu::xReconInter(CodingUnit &cu) { +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + m_pcIntraPred->geneIntrainterPred(cu); +#endif + // inter prediction m_pcInterPred->motionCompensation( cu ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (cu.firstPU->MHIntraFlag) + { + m_pcIntraPred->geneWeightedPred(COMPONENT_Y, cu.cs->getPredBuf(*cu.firstPU).Y(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Y, 0)); + m_pcIntraPred->geneWeightedPred(COMPONENT_Cb, cu.cs->getPredBuf(*cu.firstPU).Cb(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Cb, 0)); + m_pcIntraPred->geneWeightedPred(COMPONENT_Cr, cu.cs->getPredBuf(*cu.firstPU).Cr(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Cr, 0)); + } +#endif + DTRACE ( g_trace_ctx, D_TMP, "pred " ); DTRACE_CRC( g_trace_ctx, D_TMP, *cu.cs, cu.cs->getPredBuf( cu ), &cu.Y() ); diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 6411f40925591b25135a41bca89c1ade35e90d73..90b1f4379fa99b2493a614cf16c1d5c6af6d6514 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -812,6 +812,9 @@ void HLSyntaxReader::parseSPSNext( SPSNext& spsNext, const bool usePCM ) READ_FLAG( symbol, "reserved_flag" ); if( symbol != 0 ) EXIT("Incompatible version: SPSNext reserved flag not equal to zero (bitstream was probably created with newer software version)" ); } READ_FLAG( symbol, "mtt_enabled_flag" ); spsNext.setMTTMode ( symbol ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + READ_FLAG( symbol, "MHIntra_flag" ); spsNext.setUseMHIntra ( symbol != 0 ); +#endif #if ENABLE_WPP_PARALLELISM READ_FLAG( symbol, "next_dqp_enabled_flag" ); spsNext.setUseNextDQP ( symbol != 0 ); #else diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 6eb95048a8d34be9fdb4d2bd1d56368420e34b0e..b94bf2712b0e320a8118f2dde1eb740491498e37 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -1114,6 +1114,13 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu ) if( pu.mergeFlag ) { affine_flag ( *pu.cu ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + MHIntra_flag( pu ); + if ( pu.MHIntraFlag ) + { + MHIntra_luma_pred_modes( *pu.cu ); + } +#endif merge_idx ( pu ); } else @@ -1347,7 +1354,90 @@ void CABACWriter::mvp_flag( const PredictionUnit& pu, RefPicList eRefList ) DTRACE( g_trace_ctx, D_SYNTAX, "mvpIdx(refList:%d)=%d\n", eRefList, pu.mvpIdx[eRefList] ); } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA +void CABACWriter::MHIntra_flag(const PredictionUnit& pu) +{ + if (!pu.cs->sps->getSpsNext().getUseMHIntra()) + { + CHECK(pu.MHIntraFlag == true, "invalid MHIntra SPS"); + return; + } + if (pu.cu->skip) + { + CHECK(pu.MHIntraFlag == true, "invalid MHIntra and skip"); + return; + } + if (pu.cu->lwidth() * pu.cu->lheight() < 64 || pu.cu->lwidth() >= MAX_CU_SIZE || pu.cu->lheight() >= MAX_CU_SIZE) + { + CHECK(pu.MHIntraFlag == true, "invalid MHIntra and blk"); + return; + } + m_BinEncoder.encodeBin(pu.MHIntraFlag, Ctx::MHIntraFlag()); + DTRACE(g_trace_ctx, D_SYNTAX, "MHIntra_flag() intrainter=%d pos=(%d,%d) size=%dx%d\n", pu.MHIntraFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height); +} + +void CABACWriter::MHIntra_luma_pred_modes(const CodingUnit& cu) +{ + if (!cu.Y().valid()) + { + return; + } + + unsigned numMPMs = 3; + int numBlocks = CU::getNumPUs(cu); + unsigned *mpm_preds[4]; + unsigned mpm_idxs[4]; + unsigned pred_modes[4]; + + const PredictionUnit* pu = cu.firstPU; + + for (int k = 0; k < numBlocks; k++) + { + unsigned*& mpm_pred = mpm_preds[k]; + unsigned& mpm_idx = mpm_idxs[k]; + unsigned& pred_mode = pred_modes[k]; + + mpm_pred = (unsigned*)alloca(numMPMs * sizeof(unsigned)); + PU::getMHIntraMPMs(*pu, mpm_pred); + + pred_mode = pu->intraDir2[0]; + mpm_idx = numMPMs; + + for (unsigned idx = 0; idx < numMPMs; idx++) + { + if (pred_mode == mpm_pred[idx]) + { + mpm_idx = idx; + break; + } + } + if (PU::getNarrowShape(pu->lwidth(), pu->lheight()) == 0) + { + m_BinEncoder.encodeBin(mpm_idx < numMPMs, Ctx::MHIntraPredMode()); + } + pu = pu->next; + } + + pu = cu.firstPU; + + // mpm_idx / rem_intra_luma_pred_mode + for (int k = 0; k < numBlocks; k++) + { + const unsigned& mpm_idx = mpm_idxs[k]; + if (mpm_idx < numMPMs) + { + m_BinEncoder.encodeBinEP(mpm_idx > 0); + if (mpm_idx) + { + m_BinEncoder.encodeBinEP(mpm_idx > 1); + } + } + DTRACE(g_trace_ctx, D_SYNTAX, "intra_luma_pred_modes() idx=%d pos=(%d,%d) mode=%d\n", k, pu->lumaPos().x, pu->lumaPos().y, pu->intraDir2[0]); + pu = pu->next; + } +} +#endif //================================================================================ // clause 7.3.8.7 diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index b17bfadeef0a8c6034921de77b5838e451e51257..9b76813fad28fc16d6dc869e0c38c7d84ed84b3f 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -115,6 +115,10 @@ public: void ref_idx ( const PredictionUnit& pu, RefPicList eRefList ); void mvp_flag ( const PredictionUnit& pu, RefPicList eRefList ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + void MHIntra_flag ( const PredictionUnit& pu ); + void MHIntra_luma_pred_modes ( const CodingUnit& cu ); +#endif // pcm samples (clause 7.3.8.7) void pcm_samples ( const TransformUnit& tu ); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 71f50a481222dc17cdb80a41932e80d642a51ef8..7ffd5475d782ba1c4a453c606460863c02271d93 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -208,6 +208,10 @@ protected: bool m_GBi; bool m_GBiFast; #endif + +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + bool m_MHIntra; +#endif // ADD_NEW_TOOL : (encoder lib) add tool enabling flags and associated parameters here bool m_useFastLCTU; @@ -651,6 +655,12 @@ public: void setUseGBiFast ( uint32_t b ) { m_GBiFast = b; } bool getUseGBiFast () const { return m_GBiFast; } #endif + +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + void setUseMHIntra ( bool b ) { m_MHIntra = b; } + bool getUseMHIntra () const { return m_MHIntra; } +#endif + // ADD_NEW_TOOL : (encoder lib) add access functions here void setMaxCUWidth ( uint32_t u ) { m_maxCUWidth = u; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 926841c1057fb2740c447752eab355c7ab3f2bc3..4bb7573714e5c545067379c5ed3565b569fe0eb3 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1439,9 +1439,33 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& RdModeList.push_back( i ); } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + static_vector<unsigned, MRG_MAX_NUM_CANDS> RdModeList2; // store the Intra mode for Intrainter + RdModeList2.clear(); + bool isIntrainterEnabled = sps.getSpsNext().getUseMHIntra(); + if (bestCS->area.lwidth() * bestCS->area.lheight() < 64 || bestCS->area.lwidth() >= MAX_CU_SIZE || bestCS->area.lheight() >= MAX_CU_SIZE) + { + isIntrainterEnabled = false; + } + bool isTestSkipMerge[MRG_MAX_NUM_CANDS]; // record if the merge candidate has tried skip mode + for (uint32_t uiMerge = 0; uiMerge < MRG_MAX_NUM_CANDS; uiMerge++) + { + isTestSkipMerge[uiMerge] = false; + } +#endif +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if( m_pcEncCfg->getUseFastMerge() || isIntrainterEnabled) +#else if( m_pcEncCfg->getUseFastMerge() ) +#endif { uiNumMrgSATDCand = NUM_MRG_SATD_CAND; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (isIntrainterEnabled) + { + uiNumMrgSATDCand += 1; + } +#endif bestIsSkip = false; if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) ) @@ -1449,8 +1473,21 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& bestIsSkip = blkCache->isSkip( tempCS->area ); } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (isIntrainterEnabled) // always perform low complexity check + { + bestIsSkip = false; + } +#endif + static_vector<double, MRG_MAX_NUM_CANDS> candCostList; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + for (uint32_t idx = 0; idx < MRG_MAX_NUM_CANDS; idx++) + { + candCostList[idx] = MAX_DOUBLE; + } +#endif // 1. Pass: get SATD-cost for selected candidates and reduce their count if( !bestIsSkip ) { @@ -1459,6 +1496,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda( encTestMode.lossless ); CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + const double sqrtLambdaForFirstPassIntra = m_pcRdCost->getMotionLambda(cu.transQuantBypass) / double(1 << SCALE_BITS); +#endif partitioner.setCUData( cu ); cu.slice = tempCS->slice; @@ -1511,9 +1551,21 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& } double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand); +#else updateCandList( uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand ); +#endif CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" ); } + +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (isIntrainterEnabled) + { + getMHIntraLCCand(pu, RdModeList, candCostList, RdModeList2, uiNumMrgSATDCand, sqrtLambdaForFirstPass, sqrtLambdaForFirstPassIntra, distParam, localUnitArea); + } +#endif + // Try to limit number of candidates using SATD-costs for( uint32_t i = 1; i < uiNumMrgSATDCand; i++ ) { @@ -1524,6 +1576,31 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& } } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (isIntrainterEnabled) + { + pu.MHIntraFlag = true; + for (uint32_t mergeCnt = 0; mergeCnt < uiNumMrgSATDCand; mergeCnt++) + { + if (RdModeList[mergeCnt] >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS)) + { + pu.intraDir2[0] = RdModeList2[mergeCnt]; + pu.intraDir2[1] = DM_CHROMA_IDX; + uint32_t bufIdx = (pu.intraDir2[0] > 1) ? (pu.intraDir2[0] == HOR_IDX ? 2 : 3) : pu.intraDir2[0]; + bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cb, pu, true, pu); + m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cb(), isUseFilter); + m_pcIntraSearch->predIntraAng(COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), pu, isUseFilter); + m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx)); + isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cr, pu, true, pu); + m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cr(), isUseFilter); + m_pcIntraSearch->predIntraAng(COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), pu, isUseFilter); + m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx)); + } + } + pu.MHIntraFlag = false; + } +#endif + tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); } else @@ -1540,6 +1617,18 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ ) { uint32_t uiMergeCand = RdModeList[uiMrgHADIdx]; + +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS)) // intrainter does not support skip mode + { + uiMergeCand -= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS); // for skip, map back to normal merge candidate idx and try RDO + if (isTestSkipMerge[uiMergeCand]) // avoid redundancy + { + continue; + } + } +#endif + if( ( (uiNoResidualPass != 0) && candHasNoResidual[uiMergeCand] ) || ( (uiNoResidualPass == 0) && bestIsSkip ) ) { @@ -1564,6 +1653,17 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& cu.qp = encTestMode.qp; PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (uiNoResidualPass == 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS)) + { + uiMergeCand -= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS); + pu.MHIntraFlag = true; + pu.intraDir2[0] = RdModeList2[uiMrgHADIdx]; + CHECK(pu.intraDir2[0]<0 || pu.intraDir2[0]>(NUM_LUMA_MODE - 1), "out of intra mode"); + pu.intraDir2[1] = DM_CHROMA_IDX; + } +#endif + mergeCtx.setMergeInfo( pu, uiMergeCand ); PU::spanMotionInfo( pu, mergeCtx ); @@ -1572,7 +1672,27 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& #if DMVR_JVET_LOW_LATENCY_K0217 pu.mvd[0] = refinedMvdL0[uiMergeCand]; #endif +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (pu.MHIntraFlag) + { + uint32_t bufIdx = (pu.intraDir2[0] > 1) ? (pu.intraDir2[0] == HOR_IDX ? 2 : 3) : pu.intraDir2[0]; + PelBuf tmpBuf = tempCS->getPredBuf(pu).Y(); + tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Y()); + m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, bufIdx)); + tmpBuf = tempCS->getPredBuf(pu).Cb(); + tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cb()); + m_pcIntraSearch->geneWeightedPred(COMPONENT_Cb, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx)); + tmpBuf = tempCS->getPredBuf(pu).Cr(); + tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cr()); + m_pcIntraSearch->geneWeightedPred(COMPONENT_Cr, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx)); + } + else + { + tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]); + } +#else tempCS->getPredBuf().copyFrom( acMergeBuffer[ uiMergeCand ]); +#endif } else { @@ -1580,12 +1700,23 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (!pu.MHIntraFlag && uiNoResidualPass != 0) + { + isTestSkipMerge[uiMergeCand] = true; + } +#endif + xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass , NULL , 1 , uiNoResidualPass == 0 ? &candHasNoResidual[uiMergeCand] : NULL ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.MHIntraFlag) +#else if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip ) +#endif { bestIsSkip = bestCS->getCU( partitioner.chType )->rootCbf == 0; } @@ -2171,9 +2302,23 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be if( NULL != bestHasNonResi && (bestCostInternal > tempCS->cost) ) { bestCostInternal = tempCS->cost; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (!(tempCS->getPU(partitioner.chType)->MHIntraFlag)) +#endif *bestHasNonResi = !cu->rootCbf; } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (cu->rootCbf == false) + { + if (tempCS->getPU(partitioner.chType)->MHIntraFlag) + { + tempCS->cost = MAX_DOUBLE; + return; + } + } +#endif + #if WCG_EXT DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) ); #else @@ -2292,5 +2437,96 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best #endif +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA +template<typename T, size_t N> +void EncCu::getMHIntraLCCand(PredictionUnit &pu, static_vector<T, N>& RdModeList, static_vector<double, N>& candCostList, static_vector<T, N>& RdModeList2, uint32_t uiNumMrgSATDCand, const double sqrtLambdaForFirstPass, const double sqrtLambdaForFirstPassIntra, DistParam distParam, const UnitArea localUnitArea) +{ + PelUnitBuf acMergeBuffer[MRG_MAX_NUM_CANDS]; // acquire normal merge pred buffer + + int numTestIntraMode = 4; + // prepare for Intra bits calculation + const TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx()); + const TempCtx ctxStartIntraMode(m_CtxCache, SubCtx(Ctx::MHIntraPredMode, m_CABACEstimator->getCtx())); + + // for Intrainter fast, recored the best intra mode during the first round for mrege 0 + int bestMHIntraMode = -1; + double bestMHIntraCost = MAX_DOUBLE; + + pu.MHIntraFlag = true; + + // save the to-be-tested merge candidates + uint32_t MHIntraMergeCand[NUM_MRG_SATD_CAND]; + + for (uint32_t mergeCnt = 0; mergeCnt < NUM_MRG_SATD_CAND; mergeCnt++) + { + MHIntraMergeCand[mergeCnt] = RdModeList[mergeCnt]; + } + + for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, 4); mergeCnt++) + { + uint32_t mergeCand = MHIntraMergeCand[mergeCnt]; + acMergeBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea); + + // estimate merge bits + uint32_t bitsCand = mergeCand + 1; + if (mergeCand == pu.cs->slice->getMaxNumMergeCand() - 1) + { + bitsCand--; + } + + // first round + for (uint32_t intraCnt = 0; intraCnt < numTestIntraMode; intraCnt++) + { + pu.intraDir2[0] = (intraCnt < 2) ? intraCnt : ((intraCnt == 2) ? HOR_IDX : VER_IDX); + + // fast 2 + if (mergeCnt > 0 && bestMHIntraMode != pu.intraDir2[0]) + { + continue; + } + int narrowCase = PU::getNarrowShape(pu.lwidth(), pu.lheight()); + if (narrowCase == 1 && pu.intraDir2[0] == HOR_IDX) + { + continue; + } + if (narrowCase == 2 && pu.intraDir2[0] == VER_IDX) + { + continue; + } + // generate intrainter Y prediction + if (mergeCnt == 0) + { + bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, pu, true, pu); + m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Y(), isUseFilter); + m_pcIntraSearch->predIntraAng(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, isUseFilter); + m_pcIntraSearch->switchBuffer(pu, COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt)); + } + + pu.cs->getPredBuf(pu).copyFrom(acMergeBuffer[mergeCand]); + m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt)); + + // calculate cost + distParam.cur = pu.cs->getPredBuf(pu).Y(); + Distortion sadValue = distParam.distFunc(distParam); + m_CABACEstimator->getCtx() = SubCtx(Ctx::MHIntraPredMode, ctxStartIntraMode); + uint64_t fracModeBits = m_pcIntraSearch->xFracModeBitsIntra(pu, pu.intraDir2[0], CHANNEL_TYPE_LUMA); + double cost = (double)sadValue + (double)(bitsCand + 1) * sqrtLambdaForFirstPass + (double)fracModeBits * sqrtLambdaForFirstPassIntra; + + updateDoubleCandList(mergeCand + MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS, cost, RdModeList, candCostList, RdModeList2, pu.intraDir2[0], uiNumMrgSATDCand); + + // fast 2 + if (mergeCnt == 0 && cost < bestMHIntraCost) + { + bestMHIntraMode = pu.intraDir2[0]; + bestMHIntraCost = cost; + } + } + } + pu.MHIntraFlag = false; + m_CABACEstimator->getCtx() = ctxStart; + return; +} +#endif + //! \} diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index d8131f4532a7f5b5e278e8284af1d8cf9275b42c..e75d96b3381b6761ce78519aaf22c2f8e26df4fc 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -212,6 +212,10 @@ protected: || abs(cu.slice->getPOC() - cu.slice->getRefPOC(REF_PIC_LIST_1, cu.refIdxBi[1])) == 1)))); } #endif +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + template<typename T, size_t N> + void getMHIntraLCCand (PredictionUnit &pu, static_vector<T, N>& RdModeList, static_vector<double, N>& candCostList, static_vector<T, N>& RdModeList2, uint32_t uiNumMrgSATDCand, const double sqrtLambdaForFirstPass, const double sqrtLambdaForFirstPassIntra, DistParam distParam, const UnitArea localUnitArea); +#endif }; //! \} diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 43573b1ab2c70f9b90ba700d5c50ae660e4a65ec..1fd74956212c5c23442bcde04b571cea7b3fed75 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -855,6 +855,10 @@ void EncLib::xInitSPS(SPS &sps) #if JVET_L0646_GBI sps.getSpsNext().setUseGBi ( m_GBi ); #endif +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + sps.getSpsNext().setUseMHIntra ( m_MHIntra ); +#endif + // ADD_NEW_TOOL : (encoder lib) set tool enabling flags and associated parameters here int minCUSize = ( /*sps.getSpsNext().getUseQTBT() ? 1 << MIN_CU_LOG2 :*/ sps.getMaxCUWidth() >> sps.getLog2DiffMaxMinCodingBlockSize() ); diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 0dffa353696d65086cb5c22f0d5f165770d5489a..17f5e5b9beb774fb1a49befa3baab9f47f45d6ac 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -1786,19 +1786,34 @@ uint64_t IntraSearch::xFracModeBitsIntra(PredictionUnit &pu, const uint32_t &uiM { uint32_t orgMode = uiMode; +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if (!pu.MHIntraFlag) +#endif std::swap(orgMode, pu.intraDir[chType]); m_CABACEstimator->resetBits(); if( isLuma( chType ) ) { +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if ( pu.MHIntraFlag ) + m_CABACEstimator->MHIntra_luma_pred_modes(*pu.cu); + else + { + m_CABACEstimator->intra_luma_pred_mode(pu); + } +#else m_CABACEstimator->intra_luma_pred_mode( pu ); +#endif } else { m_CABACEstimator->intra_chroma_pred_mode( pu ); } +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + if ( !pu.MHIntraFlag ) +#endif std::swap(orgMode, pu.intraDir[chType]); return m_CABACEstimator->getEstFracBits(); diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index e71c42a8dad89e1525ac39eea946c49dc64cc0d3..424f78da79fb42c1554a766a6494ae446f8d175d 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -119,6 +119,9 @@ public: void estIntraPredLumaQT ( CodingUnit &cu, Partitioner& pm ); void estIntraPredChromaQT (CodingUnit &cu, Partitioner& pm); void IPCMSearch (CodingStructure &cs, Partitioner& partitioner); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + uint64_t xFracModeBitsIntra (PredictionUnit &pu, const uint32_t &uiMode, const ChannelType &compID); +#endif protected: @@ -139,7 +142,9 @@ protected: uint64_t xGetIntraFracBitsQTChroma(TransformUnit& tu, const ComponentID &compID); void xEncCoeffQT (CodingStructure &cs, Partitioner& pm, const ComponentID &compID); +#if !JVET_L0100_MULTI_HYPOTHESIS_INTRA uint64_t xFracModeBitsIntra (PredictionUnit &pu, const uint32_t &uiMode, const ChannelType &compID); +#endif void xIntraCodingTUBlock (TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2 = 0, uint32_t* numSig = nullptr ); diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 29f4b427fe6f4718638c486259f4b19778f63dd5..27d000978040bb22afb39b4508133785e42e37cb 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -553,6 +553,9 @@ void HLSWriter::codeSPSNext( const SPSNext& spsNext, const bool usePCM ) } WRITE_FLAG( spsNext.getMTTEnabled() ? 1 : 0, "mtt_enabled_flag" ); +#if JVET_L0100_MULTI_HYPOTHESIS_INTRA + WRITE_FLAG( spsNext.getUseMHIntra() ? 1 : 0, "MHIntra_flag" ); +#endif #if ENABLE_WPP_PARALLELISM WRITE_FLAG( spsNext.getUseNextDQP(), "next_dqp_enabled_flag" ); #else