diff --git a/cfg/encoder_intra_vtm.cfg b/cfg/encoder_intra_vtm.cfg index 7711642cff8b42a48ad62190aaeb7323d2cd696c..751f31896c08ddb813b730434d8749a2ca9a135a 100644 --- a/cfg/encoder_intra_vtm.cfg +++ b/cfg/encoder_intra_vtm.cfg @@ -51,6 +51,7 @@ SAO : 1 # Sample adaptive offset (0: OFF, 1 AMP : 1 # Asymmetric motion partitions (0: OFF, 1: ON) TransformSkip : 1 # Transform skipping (0: OFF, 1: ON) TransformSkipFast : 1 # Fast Transform skipping (0: OFF, 1: ON) +TransformSkipLog2MaxSize : 5 SAOLcuBoundary : 0 # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON) #============ Slices ================ @@ -101,8 +102,9 @@ MaxBTDepthISliceL : 3 MaxBTDepthISliceC : 3 MTT : 1 -EMT : 1 -EMTFast : 1 +MTS : 1 +MTSIntraMaxCand : 3 +MTSInterMaxCand : 4 Affine : 1 SubPuMvp : 1 MaxNumMergeCand : 6 diff --git a/cfg/encoder_lowdelay_P_vtm.cfg b/cfg/encoder_lowdelay_P_vtm.cfg index 98c635a6f6ec04f52cd2cdb6da88036f9e144113..e6bb635cb071123a713b8f4fa6824d701bbaee9f 100644 --- a/cfg/encoder_lowdelay_P_vtm.cfg +++ b/cfg/encoder_lowdelay_P_vtm.cfg @@ -59,6 +59,7 @@ SAO : 1 # Sample adaptive offset (0: OFF, 1 AMP : 1 # Asymmetric motion partitions (0: OFF, 1: ON) TransformSkip : 1 # Transform skipping (0: OFF, 1: ON) TransformSkipFast : 1 # Fast Transform skipping (0: OFF, 1: ON) +TransformSkipLog2MaxSize : 5 SAOLcuBoundary : 0 # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON) #============ Slices ================ @@ -117,8 +118,9 @@ MaxBTDepthISliceL : 3 MaxBTDepthISliceC : 3 MTT : 1 -EMT : 1 -EMTFast : 1 +MTS : 1 +MTSIntraMaxCand : 3 +MTSInterMaxCand : 4 Affine : 1 SubPuMvp : 1 MaxNumMergeCand : 6 diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg index dd9b1ab7bf9c1625e19859946f9dfec9fcffbfa4..4748271faa75f06cd2cf7efc32824ece1c7283d9 100644 --- a/cfg/encoder_lowdelay_vtm.cfg +++ b/cfg/encoder_lowdelay_vtm.cfg @@ -59,6 +59,7 @@ SAO : 1 # Sample adaptive offset (0: OFF, 1 AMP : 1 # Asymmetric motion partitions (0: OFF, 1: ON) TransformSkip : 1 # Transform skipping (0: OFF, 1: ON) TransformSkipFast : 1 # Fast Transform skipping (0: OFF, 1: ON) +TransformSkipLog2MaxSize : 5 SAOLcuBoundary : 0 # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON) #============ Slices ================ @@ -117,8 +118,9 @@ MaxBTDepthISliceL : 3 MaxBTDepthISliceC : 3 MTT : 1 -EMT : 1 -EMTFast : 1 +MTS : 1 +MTSIntraMaxCand : 3 +MTSInterMaxCand : 4 Affine : 1 SubPuMvp : 1 MaxNumMergeCand : 6 diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index 5054f69fdc656d74ad0d89076de0641124e7d9a2..f2c8530daf30e801ce1d107f7b93ff12cba3534d 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -73,6 +73,7 @@ SAO : 1 # Sample adaptive offset (0: OFF, 1 AMP : 1 # Asymmetric motion partitions (0: OFF, 1: ON) TransformSkip : 1 # Transform skipping (0: OFF, 1: ON) TransformSkipFast : 1 # Fast Transform skipping (0: OFF, 1: ON) +TransformSkipLog2MaxSize : 5 SAOLcuBoundary : 0 # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON) #============ Slices ================ @@ -131,8 +132,9 @@ MaxBTDepthISliceL : 3 MaxBTDepthISliceC : 3 MTT : 1 -EMT : 1 -EMTFast : 1 +MTS : 1 +MTSIntraMaxCand : 3 +MTSInterMaxCand : 4 Affine : 1 SubPuMvp : 1 MaxNumMergeCand : 6 diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 4e47a75dfb014ebec6739b5edf17f62e7ff91491..42a467a345c88079922cf494e8f0b1c5afe91d08 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -227,10 +227,17 @@ void EncApp::xInitLibCfg() #if ENABLE_WPP_PARALLELISM m_cEncLib.setUseAltDQPCoding ( m_AltDQPCoding ); #endif +#if JVET_M0464_UNI_MTS + m_cEncLib.setIntraMTS ( m_MTS & 1 ); + m_cEncLib.setIntraMTSMaxCand ( m_MTSIntraMaxCand ); + m_cEncLib.setInterMTS ( ( m_MTS >> 1 ) & 1 ); + m_cEncLib.setInterMTSMaxCand ( m_MTSInterMaxCand ); +#else m_cEncLib.setIntraEMT ( m_EMT & 1 ); m_cEncLib.setFastIntraEMT ( m_FastEMT & m_EMT & 1 ); m_cEncLib.setInterEMT ( ( m_EMT >> 1 ) & 1 ); m_cEncLib.setFastInterEMT ( ( m_FastEMT >> 1 ) & ( m_EMT >> 1 ) & 1 ); +#endif m_cEncLib.setUseCompositeRef ( m_compositeRefEnabled ); m_cEncLib.setUseGBi ( m_GBi ); m_cEncLib.setUseGBiFast ( m_GBiFast ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 5a98da21bc335cd8df0140af4d909595080668bc..77d82dd18d8799c17f4e7073e1464af99fe93c32 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -828,6 +828,15 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("LMChroma", m_LMChroma, 1, " LMChroma prediction " "\t0: Disable LMChroma\n" "\t1: Enable LMChroma\n") +#if JVET_M0464_UNI_MTS + ("MTS", m_MTS, 0, "Multiple Transform Set (MTS)\n" + "\t0: Disable MTS\n" + "\t1: Enable only Intra MTS\n" + "\t2: Enable only Inter MTS\n" + "\t3: Enable both Intra & Inter MTS\n") + ("MTSIntraMaxCand", m_MTSIntraMaxCand, 3, "Number of additional candidates to test in encoder search for MTS in intra slices\n") + ("MTSInterMaxCand", m_MTSInterMaxCand, 4, "Number of additional candidates to test in encoder search for MTS in inter slices\n") +#else ("EMT,-emt", m_EMT, 0, "Enhanced Multiple Transform (EMT)\n" "\t0: Disable EMT\n" "\t1: Enable only Intra EMT\n" @@ -838,6 +847,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) "\t1: Enable fast methods only for Intra EMT\n" "\t2: Enable fast methods only for Inter EMT\n" "\t3: Enable fast methods for both Intra & Inter EMT\n") +#endif ("CompositeLTReference", m_compositeRefEnabled, false, "Enable Composite Long Term Reference Frame") ("GBi", m_GBi, false, "Enable Generalized Bi-prediction(GBi)") ("GBiFast", m_GBiFast, false, "Fast methods for Generalized Bi-prediction(GBi)\n") @@ -989,8 +999,13 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("SaoLumaOffsetBitShift", saoOffsetBitShift[CHANNEL_TYPE_LUMA], 0, "Specify the luma SAO bit-shift. If negative, automatically calculate a suitable value based upon bit depth and initial QP") ("SaoChromaOffsetBitShift", saoOffsetBitShift[CHANNEL_TYPE_CHROMA], 0, "Specify the chroma SAO bit-shift. If negative, automatically calculate a suitable value based upon bit depth and initial QP") ("TransformSkip", m_useTransformSkip, false, "Intra transform skipping") +#if JVET_M0464_UNI_MTS + ("TransformSkipFast", m_useTransformSkipFast, false, "Fast encoder search for transform skipping, winner takes it all mode.") + ("TransformSkipLog2MaxSize", m_log2MaxTransformSkipBlockSize, 5U, "Specify transform-skip maximum size. Minimum 2, Maximum 5. (not valid in V1 profiles)") +#else ("TransformSkipFast", m_useTransformSkipFast, false, "Fast intra transform skipping") ("TransformSkipLog2MaxSize", m_log2MaxTransformSkipBlockSize, 2U, "Specify transform-skip maximum size. Minimum 2. (not valid in V1 profiles)") +#endif ("ImplicitResidualDPCM", m_rdpcmEnabledFlag[RDPCM_SIGNAL_IMPLICIT], false, "Enable implicitly signalled residual DPCM for intra (also known as sample-adaptive intra predict) (not valid in V1 profiles)") ("ExplicitResidualDPCM", m_rdpcmEnabledFlag[RDPCM_SIGNAL_EXPLICIT], false, "Enable explicitly signalled residual DPCM for inter (not valid in V1 profiles)") ("ResidualRotation", m_transformSkipRotationEnabledFlag, false, "Enable rotation of transform-skipped and transquant-bypassed TUs through 180 degrees prior to entropy coding (not valid in V1 profiles)") @@ -1919,8 +1934,14 @@ bool EncAppCfg::xCheckParameter() xConfirmPara( m_ImvMode, "IMV is only allowed with NEXT profile" ); xConfirmPara(m_CPRMode, "CPR Mode only allowed with NEXT profile"); xConfirmPara( m_useFastLCTU, "Fast large CTU can only be applied when encoding with NEXT profile" ); +#if JVET_M0464_UNI_MTS + xConfirmPara( m_MTS, "MTS only allowed with NEXT profile" ); + xConfirmPara( m_MTSIntraMaxCand, "MTS only allowed with NEXT profile" ); + xConfirmPara( m_MTSInterMaxCand, "MTS only allowed with NEXT profile" ); +#else xConfirmPara( m_EMT, "EMT only allowed with NEXT profile" ); xConfirmPara( m_FastEMT, "EMT only allowed with NEXT profile" ); +#endif xConfirmPara( m_compositeRefEnabled, "Composite Reference Frame is only allowed with NEXT profile" ); xConfirmPara( m_GBi, "GBi is only allowed with NEXT profile" ); xConfirmPara( m_GBiFast, "GBiFast is only allowed with NEXT profile" ); @@ -2049,7 +2070,11 @@ bool EncAppCfg::xCheckParameter() xConfirmPara(m_profile == Profile::MAINSTILLPICTURE && m_framesToBeEncoded > 1, "Number of frames to be encoded must be 1 when main still picture profile is used."); xConfirmPara(m_crossComponentPredictionEnabledFlag==true, "CrossComponentPrediction must not be used for non main-RExt profiles."); +#if JVET_M0464_UNI_MTS + xConfirmPara(m_log2MaxTransformSkipBlockSize>=6, "Transform Skip Log2 Max Size must be less or equal to 5."); +#else xConfirmPara(m_log2MaxTransformSkipBlockSize!=2, "Transform Skip Log2 Max Size must be 2 for V1 profiles."); +#endif xConfirmPara(m_transformSkipRotationEnabledFlag==true, "UseResidualRotation must not be enabled for non main-RExt profiles."); xConfirmPara(m_transformSkipContextEnabledFlag==true, "UseSingleSignificanceMapContext must not be enabled for non main-RExt profiles."); xConfirmPara(m_rdpcmEnabledFlag[RDPCM_SIGNAL_IMPLICIT]==true, "ImplicitResidualDPCM must not be enabled for non main-RExt profiles."); @@ -2138,6 +2163,7 @@ bool EncAppCfg::xCheckParameter() xConfirmPara (m_log2MaxTransformSkipBlockSize < 2, "Transform Skip Log2 Max Size must be at least 2 (4x4)"); +#if !JVET_M0464_UNI_MTS if (m_log2MaxTransformSkipBlockSize!=2 && m_useTransformSkipFast) { msg( WARNING, "***************************************************************************\n"); @@ -2146,6 +2172,7 @@ bool EncAppCfg::xCheckParameter() msg( WARNING, "** It may be better to disable transform skip fast mode **\n"); msg( WARNING, "***************************************************************************\n"); } +#endif xConfirmPara( m_quadtreeTULog2MaxSize * m_tuLog2MaxSize >= 0, "Setting of TULog2MaxSize and QuadtreeTULog2MaxSize is mutually exclusive - use only one of the parameters" ); @@ -2258,8 +2285,14 @@ bool EncAppCfg::xCheckParameter() m_maxNumAffineMergeCand = m_SubPuMvpMode; } +#if JVET_M0464_UNI_MTS + xConfirmPara( m_MTS < 0 || m_MTS > 3, "MTS must be greater than 0 smaller than 4" ); + xConfirmPara( m_MTSIntraMaxCand < 0 || m_MTSIntraMaxCand > 5, "m_MTSIntraMaxCand must be greater than 0 and smaller than 6" ); + xConfirmPara( m_MTSInterMaxCand < 0 || m_MTSInterMaxCand > 5, "m_MTSInterMaxCand must be greater than 0 and smaller than 6" ); +#else xConfirmPara( m_EMT < 0 || m_EMT >3, "EMT must be 0, 1, 2 or 3" ); xConfirmPara( m_FastEMT < 0 || m_FastEMT >3, "FEMT must be 0, 1, 2 or 3" ); +#endif if( m_usePCM) { for (uint32_t channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++) @@ -3091,8 +3124,12 @@ void EncAppCfg::xPrintParameter() msg( VERBOSE, "AltDQPCoding:%d ", m_AltDQPCoding ); #endif msg( VERBOSE, "LMChroma:%d ", m_LMChroma ); +#if JVET_M0464_UNI_MTS + msg( VERBOSE, "MTS: %1d(intra) %1d(inter) ", m_MTS & 1, ( m_MTS >> 1 ) & 1 ); +#else msg( VERBOSE, "EMT: %1d(intra) %1d(inter) ", m_EMT & 1, ( m_EMT >> 1 ) & 1 ); - msg(VERBOSE, "CompositeLTReference:%d ", m_compositeRefEnabled); +#endif + msg( VERBOSE, "CompositeLTReference:%d ", m_compositeRefEnabled); msg( VERBOSE, "GBi:%d ", m_GBi ); msg( VERBOSE, "GBiFast:%d ", m_GBiFast ); #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET @@ -3117,7 +3154,11 @@ void EncAppCfg::xPrintParameter() msg( VERBOSE, "FastMrg:%d ", m_useFastMrg ); msg( VERBOSE, "PBIntraFast:%d ", m_usePbIntraFast ); if( m_ImvMode == 2 ) msg( VERBOSE, "IMV4PelFast:%d ", m_Imv4PelFast ); +#if JVET_M0464_UNI_MTS + if( m_MTS ) msg( VERBOSE, "MTSMaxCand: %1d(intra) %1d(inter) ", m_MTSIntraMaxCand, m_MTSInterMaxCand ); +#else if( m_EMT ) msg( VERBOSE, "EMTFast: %1d(intra) %1d(inter) ", ( m_FastEMT & m_EMT & 1 ), ( m_FastEMT >> 1 ) & ( m_EMT >> 1 ) & 1 ); +#endif msg( VERBOSE, "AMaxBT:%d ", m_useAMaxBT ); msg( VERBOSE, "E0023FastEnc:%d ", m_e0023FastEnc ); msg( VERBOSE, "ContentBasedFastQtbt:%d ", m_contentBasedFastQtbt ); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 94bedb0c472ea8232629567dcc2dd166985bae70..3e56906da77dfe36a39089b3faef90b2883d83ba 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -214,8 +214,14 @@ protected: bool m_AltDQPCoding; #endif int m_LMChroma; +#if JVET_M0464_UNI_MTS + int m_MTS; ///< XZ: Multiple Transform Set + int m_MTSIntraMaxCand; ///< XZ: Number of additional candidates to test + int m_MTSInterMaxCand; ///< XZ: Number of additional candidates to test +#else int m_EMT; ///< XZ: Enhanced Multiple Transform int m_FastEMT; ///< XZ: Fast Methods of Enhanced Multiple Transform +#endif bool m_compositeRefEnabled; bool m_GBi; diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 986b0cd35278cd112addd6da1da2a08e8e8aa241..75c8659612b68a09bc88ece2402087ca227b2884 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -211,8 +211,14 @@ static const int DM_CHROMA_IDX = NUM_INTRA_MODE; ///< chro static const uint8_t INTER_MODE_IDX = 255; ///< index for inter modes +#if JVET_M0464_UNI_MTS +static const uint32_t NUM_TRAFO_MODES_MTS = 6; ///< Max Intra CU size applying EMT, supported values: 8, 16, 32, 64, 128 +static const uint32_t MTS_INTRA_MAX_CU_SIZE = 32; ///< Max Intra CU size applying EMT, supported values: 8, 16, 32, 64, 128 +static const uint32_t MTS_INTER_MAX_CU_SIZE = 32; ///< Max Inter CU size applying EMT, supported values: 8, 16, 32, 64, 128 +#else static const uint32_t EMT_INTRA_MAX_CU_WITH_QTBT = 32; ///< Max Intra CU size applying EMT, supported values: 8, 16, 32, 64, 128 static const uint32_t EMT_INTER_MAX_CU_WITH_QTBT = 32; ///< Max Inter CU size applying EMT, supported values: 8, 16, 32, 64, 128 +#endif static const int NUM_MOST_PROBABLE_MODES = 6; static const int LM_SYMBOL_NUM = (1 + NUM_LMC_MODE); @@ -321,7 +327,9 @@ static const int MAX_ENCODER_DEBLOCKING_QUALITY_LAYERS = 8 ; static const uint32_t LUMA_LEVEL_TO_DQP_LUT_MAXSIZE = 1024; ///< max LUT size for QP offset based on luma #endif +#if !JVET_M0464_UNI_MTS static const int NUM_EMT_CU_FLAG_CTX = 6; ///< number of context models for EMT CU-level flag +#endif //QTBT high level parameters //for I slice luma CTB configuration para. diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index b9ae70afdc92f8605985fec1f1eec82ead25356e..178cd6ffd736e1bc52179557384207acf1268005 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -81,7 +81,11 @@ CoeffCodingContext::CoeffCodingContext(const TransformUnit& tu, ComponentID comp , m_lastOffsetY (0) , m_lastShiftX (0) , m_lastShiftY (0) +#if JVET_M0464_UNI_MTS + , m_TrafoBypass (tu.cs->sps->getSpsRangeExtension().getTransformSkipContextEnabledFlag() && (tu.cu->transQuantBypass || tu.mtsIdx==1)) +#else , m_TrafoBypass (tu.cs->sps->getSpsRangeExtension().getTransformSkipContextEnabledFlag() && (tu.cu->transQuantBypass || tu.transformSkip[m_compID])) +#endif , m_scanPosLast (-1) , m_subSetId (-1) , m_subSetPos (-1) @@ -96,7 +100,9 @@ CoeffCodingContext::CoeffCodingContext(const TransformUnit& tu, ComponentID comp , m_parFlagCtxSet ( Ctx::ParFlag[m_chType] ) , m_gtxFlagCtxSet { Ctx::GtxFlag[m_chType], Ctx::GtxFlag[m_chType+2] } , m_sigCoeffGroupFlag () +#if !JVET_M0464_UNI_MTS , m_emtNumSigCoeff (0) +#endif { // LOGTODO unsigned log2sizeX = m_log2BlockWidth; diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index f0856345a28839190472acbad4baf48aa5623cc7..c2e6d7899d721684782f1306adb4e4e2c8439a38 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -183,8 +183,10 @@ public: return std::min(sum, 31); } +#if !JVET_M0464_UNI_MTS unsigned emtNumSigCoeff() const { return m_emtNumSigCoeff; } void setEmtNumSigCoeff( unsigned val ) { m_emtNumSigCoeff = val; } +#endif private: // constant @@ -235,7 +237,9 @@ private: CtxSet m_parFlagCtxSet; CtxSet m_gtxFlagCtxSet[2]; std::bitset<MLS_GRP_NUM> m_sigCoeffGroupFlag; +#if !JVET_M0464_UNI_MTS unsigned m_emtNumSigCoeff; +#endif }; diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index cb190a39075d343d6e18f55e3224e63d6a2c3f2e..6555d5d76529d296f17adb4312ef14160d97cd68 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -1080,6 +1080,7 @@ const CtxSet ContextSetCfg::SaoTypeIdx = ContextSetCfg::addCtxSet #endif }); +#if !JVET_M0464_UNI_MTS const CtxSet ContextSetCfg::TransformSkipFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE @@ -1093,6 +1094,7 @@ const CtxSet ContextSetCfg::TransformSkipFlag = ContextSetCfg::addCtxSet { 109, 42, }, #endif }); +#endif const CtxSet ContextSetCfg::TransquantBypassFlag = ContextSetCfg::addCtxSet ({ @@ -1124,6 +1126,21 @@ const CtxSet ContextSetCfg::RdpcmDir = ContextSetCfg::addCtxSet #endif }); +#if JVET_M0464_UNI_MTS +const CtxSet ContextSetCfg::MTSIndex = ContextSetCfg::addCtxSet +({ +#if JVET_M0453_CABAC_ENGINE + { CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, + { CNU, CNU, CNU, CNU, CNU, CNU, CNU, 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, }, +#else + { CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, + { CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, + { CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, CNU, }, +#endif +}); +#else const CtxSet ContextSetCfg::EMTTuIndex = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE @@ -1151,6 +1168,7 @@ const CtxSet ContextSetCfg::EMTCuFlag = ContextSetCfg::addCtxSet { CNU, CNU, 140, 155, 155, CNU, }, #endif }); +#endif const CtxSet ContextSetCfg::CrossCompPred = ContextSetCfg::addCtxSet ({ diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 336bf5453a3fff8c5455363f9d53f7260b3b6841..457764898b46a84ec984b2fc4255005471badd8e 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -282,12 +282,18 @@ public: static const CtxSet MVPIdx; static const CtxSet SaoMergeFlag; static const CtxSet SaoTypeIdx; +#if JVET_M0464_UNI_MTS + static const CtxSet MTSIndex; +#else static const CtxSet TransformSkipFlag; +#endif static const CtxSet TransquantBypassFlag; static const CtxSet RdpcmFlag; static const CtxSet RdpcmDir; +#if !JVET_M0464_UNI_MTS static const CtxSet EMTTuIndex; static const CtxSet EMTCuFlag; +#endif static const CtxSet CrossCompPred; static const CtxSet ChromaQpAdjFlag; static const CtxSet ChromaQpAdjIdc; diff --git a/source/Lib/CommonLib/DepQuant.cpp b/source/Lib/CommonLib/DepQuant.cpp index 267f168f0f060c558bb5b4df476be8b218aa5aa3..5bebbf03f73532dcbf9cb95ff72bc93d40d3f455 100644 --- a/source/Lib/CommonLib/DepQuant.cpp +++ b/source/Lib/CommonLib/DepQuant.cpp @@ -642,7 +642,11 @@ namespace DQIntern const int channelBitDepth = sps.getBitDepth( chType ); const int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange( chType ); const int nomTransformShift = getTransformShift( channelBitDepth, area.size(), maxLog2TrDynamicRange ); +#if JVET_M0464_UNI_MTS + const bool clipTransformShift = ( tu.mtsIdx==1 && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag() ); +#else const bool clipTransformShift = ( tu.transformSkip[ compID ] && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag() ); +#endif const int transformShift = ( clipTransformShift ? std::max<int>( 0, nomTransformShift ) : nomTransformShift ); // quant parameters @@ -726,7 +730,11 @@ namespace DQIntern const TCoeff minTCoeff = -( 1 << maxLog2TrDynamicRange ); const TCoeff maxTCoeff = ( 1 << maxLog2TrDynamicRange ) - 1; const int nomTransformShift = getTransformShift( channelBitDepth, area.size(), maxLog2TrDynamicRange ); +#if JVET_M0464_UNI_MTS + const bool clipTransformShift = ( tu.mtsIdx==1 && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag() ); +#else const bool clipTransformShift = ( tu.transformSkip[ compID ] && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag() ); +#endif const int transformShift = ( clipTransformShift ? std::max<int>( 0, nomTransformShift ) : nomTransformShift ); #if HM_QTBT_AS_IN_JEM_QUANT Intermediate_Int shift = IQUANT_SHIFT + 1 - qpPer - transformShift + ( TU::needsBlockSizeTrafoScale( area ) ? ADJ_DEQUANT_SHIFT : 0 ); diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp index bed8fd5d85d0e325b213b748d921275be5672e63..ca477139b28c97e7342b3cae0b7c14d1494355ac 100644 --- a/source/Lib/CommonLib/Quant.cpp +++ b/source/Lib/CommonLib/Quant.cpp @@ -301,7 +301,11 @@ void Quant::dequant(const TransformUnit &tu, CHECK(uiWidth > m_uiMaxTrSize, "Unsupported transformation size"); // Represents scaling through forward transform +#if JVET_M0464_UNI_MTS + const bool bClipTransformShiftTo0 = tu.mtsIdx!=1 && sps->getSpsRangeExtension().getExtendedPrecisionProcessingFlag(); +#else const bool bClipTransformShiftTo0 = (tu.transformSkip[compID] != 0) && sps->getSpsRangeExtension().getExtendedPrecisionProcessingFlag(); +#endif const int originalTransformShift = getTransformShift(channelBitDepth, area.size(), maxLog2TrDynamicRange); const int iTransformShift = bClipTransformShiftTo0 ? std::max<int>(0, originalTransformShift) : originalTransformShift; @@ -717,7 +721,11 @@ void Quant::quant(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf const CCoeffBuf &piCoef = pSrc; CoeffBuf piQCoef = tu.getCoeffs(compID); +#if JVET_M0464_UNI_MTS + const bool useTransformSkip = tu.mtsIdx==1; +#else const bool useTransformSkip = tu.transformSkip[compID]; +#endif const int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange(toChannelType(compID)); { @@ -820,7 +828,11 @@ bool Quant::xNeedRDOQ(TransformUnit &tu, const ComponentID &compID, const CCoeff const CCoeffBuf piCoef = pSrc; +#if JVET_M0464_UNI_MTS + const bool useTransformSkip = tu.mtsIdx==1; +#else const bool useTransformSkip = tu.transformSkip[compID]; +#endif const int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange(toChannelType(compID)); #if HEVC_USE_SCALING_LISTS diff --git a/source/Lib/CommonLib/QuantRDOQ.cpp b/source/Lib/CommonLib/QuantRDOQ.cpp index 8204a8c7f3959988ac7bff07cb74a9c81afb980b..ff034e11b1faffd033879f16420ad8e7f09905b7 100644 --- a/source/Lib/CommonLib/QuantRDOQ.cpp +++ b/source/Lib/CommonLib/QuantRDOQ.cpp @@ -542,7 +542,11 @@ void QuantRDOQ::quant(TransformUnit &tu, const ComponentID &compID, const CCoeff const CCoeffBuf &piCoef = pSrc; CoeffBuf piQCoef = tu.getCoeffs(compID); +#if JVET_M0464_UNI_MTS + const bool useTransformSkip = tu.mtsIdx==1; +#else const bool useTransformSkip = tu.transformSkip[compID]; +#endif bool useRDOQ = useTransformSkip ? m_useRDOQTS : m_useRDOQ; @@ -598,7 +602,11 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, // Represents scaling through forward transform int iTransformShift = getTransformShift(channelBitDepth, rect.size(), maxLog2TrDynamicRange); +#if JVET_M0464_UNI_MTS + if (tu.mtsIdx==1 && extendedPrecision) +#else if (tu.transformSkip[compID] && extendedPrecision) +#endif { iTransformShift = std::max<int>(0, iTransformShift); } diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h index 93494b89493c8a3dc8a2c90281a1e77d7b6c3fda..b29861de01a6162cf3ac85a3ec8e6ec6c206a434 100644 --- a/source/Lib/CommonLib/Rom.h +++ b/source/Lib/CommonLib/Rom.h @@ -113,7 +113,9 @@ extern const uint8_t g_chroma422IntraAngleMappingTable[NUM_INTRA_MODE]; extern const TMatrixCoeff g_as_DST_MAT_4 [TRANSFORM_NUMBER_OF_DIRECTIONS][4][4]; #endif +#if !JVET_M0464_UNI_MTS extern const uint32_t g_EmtSigNumThr; +#endif extern const TMatrixCoeff g_trCoreDCT2P2 [TRANSFORM_NUMBER_OF_DIRECTIONS][ 2][ 2]; extern const TMatrixCoeff g_trCoreDCT2P4 [TRANSFORM_NUMBER_OF_DIRECTIONS][ 4][ 4]; diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index fa7f7a33b712149641546842dc329cd17775e176..5fb5831f2492c34db02d932e72ccb172df3167ae 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1738,8 +1738,13 @@ SPSNext::SPSNext( SPS& sps ) , m_BIO ( false ) , m_DisableMotionCompression ( false ) , m_LMChroma ( false ) +#if JVET_M0464_UNI_MTS + , m_IntraMTS ( false ) + , m_InterMTS ( false ) +#else , m_IntraEMT ( false ) , m_InterEMT ( false ) +#endif , m_Affine ( false ) , m_AffineType ( false ) , m_MTTEnabled ( false ) diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 60b4d5a27c78a5a582e08aa593d92b6992993f68..6b71c04aa0c7ad7e9408cb0967411a96c57f6875 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -804,8 +804,13 @@ private: bool m_BIO; bool m_DisableMotionCompression; // 13 bool m_LMChroma; // 17 +#if JVET_M0464_UNI_MTS + bool m_IntraMTS; // 18 + bool m_InterMTS; // 19 +#else bool m_IntraEMT; // 18 bool m_InterEMT; // 19 +#endif bool m_Affine; bool m_AffineType; bool m_GBi; // @@ -872,10 +877,17 @@ public: #endif void setUseLMChroma ( bool b ) { m_LMChroma = b; } bool getUseLMChroma () const { return m_LMChroma; } +#if JVET_M0464_UNI_MTS + void setUseIntraMTS ( bool b ) { m_IntraMTS = b; } + bool getUseIntraMTS () const { return m_IntraMTS; } + void setUseInterMTS ( bool b ) { m_InterMTS = b; } + bool getUseInterMTS () const { return m_InterMTS; } +#else void setUseIntraEMT ( bool b ) { m_IntraEMT = b; } bool getUseIntraEMT () const { return m_IntraEMT; } void setUseInterEMT ( bool b ) { m_InterEMT = b; } bool getUseInterEMT () const { return m_InterEMT; } +#endif void setUseGBi ( bool b ) { m_GBi = b; } bool getUseGBi () const { return m_GBi; } #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp index 92276925911e26cfe517cc9f236c50e32c3fc62b..f2afd109dbc34b8db435b25fb24882642c21634b 100644 --- a/source/Lib/CommonLib/TrQuant.cpp +++ b/source/Lib/CommonLib/TrQuant.cpp @@ -91,7 +91,13 @@ TrQuant::TrQuant() : m_quant( nullptr ) { // allocate temporary buffers m_plTempCoeff = (TCoeff*) xMalloc( TCoeff, MAX_CU_SIZE * MAX_CU_SIZE ); - +#if JVET_M0464_UNI_MTS + m_mtsCoeffs = new TCoeff*[ NUM_TRAFO_MODES_MTS ]; + for( int i = 0; i < NUM_TRAFO_MODES_MTS; i++ ) + { + m_mtsCoeffs[i] = (TCoeff*) xMalloc( TCoeff, MAX_CU_SIZE * MAX_CU_SIZE ); + } +#endif } TrQuant::~TrQuant() @@ -108,6 +114,17 @@ TrQuant::~TrQuant() xFree( m_plTempCoeff ); m_plTempCoeff = nullptr; } +#if JVET_M0464_UNI_MTS + if( m_mtsCoeffs ) + { + for( int i = 0; i < NUM_TRAFO_MODES_MTS; i++ ) + { + xFree( m_mtsCoeffs[i] ); + m_mtsCoeffs[i] = nullptr; + } + m_mtsCoeffs = nullptr; + } +#endif } #if ENABLE_SPLIT_PARALLELISM @@ -187,8 +204,11 @@ void TrQuant::invTransformNxN( TransformUnit &tu, const ComponentID &compID, Pel DTRACE_COEFF_BUF( D_TCOEFF, tempCoeff, tu, tu.cu->predMode, compID ); - +#if JVET_M0464_UNI_MTS + if( tu.mtsIdx == 1 ) +#else if( tu.transformSkip[compID] ) +#endif { xITransformSkip( tempCoeff, pResi, tu, compID ); } @@ -207,7 +227,11 @@ void TrQuant::invRdpcmNxN(TransformUnit& tu, const ComponentID &compID, PelBuf & { const CompArea &area = tu.blocks[compID]; +#if JVET_M0464_UNI_MTS + if (CU::isRDPCMEnabled(*tu.cu) && (tu.mtsIdx==1 || tu.cu->transQuantBypass)) +#else if (CU::isRDPCMEnabled(*tu.cu) && ((tu.transformSkip[compID] != 0) || tu.cu->transQuantBypass)) +#endif { const uint32_t uiWidth = area.width; const uint32_t uiHeight = area.height; @@ -267,19 +291,34 @@ void TrQuant::invRdpcmNxN(TransformUnit& tu, const ComponentID &compID, PelBuf & void TrQuant::getTrTypes ( TransformUnit tu, const ComponentID compID, int &trTypeHor, int &trTypeVer ) { +#if JVET_M0464_UNI_MTS + bool mtsActivated = CU::isIntra( *tu.cu ) ? tu.cs->sps->getSpsNext().getUseIntraMTS() : tu.cs->sps->getSpsNext().getUseInterMTS(); +#else bool emtActivated = CU::isIntra( *tu.cu ) ? tu.cs->sps->getSpsNext().getUseIntraEMT() : tu.cs->sps->getSpsNext().getUseInterEMT(); +#endif trTypeHor = DCT2; trTypeVer = DCT2; +#if JVET_M0464_UNI_MTS + if ( mtsActivated ) +#else if ( emtActivated ) +#endif { if( compID == COMPONENT_Y ) { +#if JVET_M0464_UNI_MTS + if ( tu.mtsIdx > 1 ) + { + int indHor = ( tu.mtsIdx - 2 ) & 1; + int indVer = ( tu.mtsIdx - 2 ) >> 1; +#else if ( tu.cu->emtFlag ) { int indHor = tu.emtIdx & 1; int indVer = tu.emtIdx >> 1; +#endif trTypeHor = indHor ? DCT8 : DST7; trTypeVer = indVer ? DCT8 : DST7; @@ -437,7 +476,67 @@ void TrQuant::xQuant(TransformUnit &tu, const ComponentID &compID, const CCoeffB m_quant->quant( tu, compID, pSrc, uiAbsSum, cQP, ctx ); } +#if JVET_M0464_UNI_MTS +void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand) +{ + CodingStructure &cs = *tu.cs; + const SPS &sps = *cs.sps; + const CompArea &rect = tu.blocks[compID]; + const uint32_t width = rect.width; + const uint32_t height = rect.height; + + const CPelBuf resiBuf = cs.getResiBuf(rect); + + CHECK( sps.getMaxTrSize() < width, "Unsupported transformation size" ); + + int pos = 0; + std::vector<TrCost> trCosts; + std::vector<TrMode>::iterator it = trModes->begin(); + const double facBB[] = { 1.2, 1.3, 1.3, 1.4, 1.5 }; + while( it != trModes->end() ) + { + tu.mtsIdx = it->first; + CoeffBuf tempCoeff( m_mtsCoeffs[tu.mtsIdx], rect ); + + if( tu.mtsIdx == 1 ) + { + xTransformSkip( tu, compID, resiBuf, tempCoeff.buf ); + } + else + { + xT( tu, compID, resiBuf, tempCoeff, width, height ); + } + + int sumAbs = 0; + for( int pos = 0; pos < width*height; pos++ ) + { + sumAbs += abs( tempCoeff.buf[pos] ); + } + + trCosts.push_back( TrCost( sumAbs, pos++ ) ); + it++; + } + + int numTests = 0; + std::vector<TrCost>::iterator itC = trCosts.begin(); + const double fac = facBB[g_aucLog2[std::max(width, height)]-2]; + const double thr = fac * trCosts.begin()->first; + const double thrTS = trCosts.begin()->first; + while( itC != trCosts.end() ) + { + const bool testTr = itC->first <= ( itC->second == 1 ? thrTS : thr ) && numTests <= maxCand; + trModes->at( itC->second ).second = testTr; + numTests += testTr; + itC++; + } +} +#endif + +#if JVET_M0464_UNI_MTS +void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr) +#else void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx) +#endif { CodingStructure &cs = *tu.cs; const SPS &sps = *cs.sps; @@ -483,11 +582,21 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q { CHECK( sps.getMaxTrSize() < uiWidth, "Unsupported transformation size" ); +#if JVET_M0464_UNI_MTS + CoeffBuf tempCoeff( loadTr ? m_mtsCoeffs[tu.mtsIdx] : m_plTempCoeff, rect ); +#else CoeffBuf tempCoeff( m_plTempCoeff, rect ); +#endif DTRACE_PEL_BUF( D_RESIDUALS, resiBuf, tu, tu.cu->predMode, compID ); +#if JVET_M0464_UNI_MTS + if( !loadTr ) + { + if( tu.mtsIdx == 1 ) +#else if( tu.transformSkip[compID] ) +#endif { xTransformSkip( tu, compID, resiBuf, tempCoeff.buf ); } @@ -495,6 +604,9 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q { xT( tu, compID, resiBuf, tempCoeff, uiWidth, uiHeight ); } +#if JVET_M0464_UNI_MTS + } +#endif DTRACE_COEFF_BUF( D_TCOEFF, tempCoeff, tu, tu.cu->predMode, compID ); @@ -567,7 +679,11 @@ void TrQuant::applyForwardRDPCM(TransformUnit &tu, const ComponentID &compID, co void TrQuant::rdpcmNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, RDPCMMode &rdpcmMode) { +#if JVET_M0464_UNI_MTS + if (!CU::isRDPCMEnabled(*tu.cu) || (tu.mtsIdx!=1 && !tu.cu->transQuantBypass)) +#else if (!CU::isRDPCMEnabled(*tu.cu) || (!tu.transformSkip[compID] && !tu.cu->transQuantBypass)) +#endif { rdpcmMode = RDPCM_OFF; } diff --git a/source/Lib/CommonLib/TrQuant.h b/source/Lib/CommonLib/TrQuant.h index c663f9e76ab738e0139daf5024b520fa9843cd3f..aa58a29981b7f6a8ac09601972a487a8811cc6f5 100644 --- a/source/Lib/CommonLib/TrQuant.h +++ b/source/Lib/CommonLib/TrQuant.h @@ -87,7 +87,12 @@ public: void invTransformNxN (TransformUnit &tu, const ComponentID &compID, PelBuf &pResi, const QpParam &cQPs); +#if JVET_M0464_UNI_MTS + void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand); + void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr=false); +#else void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx); +#endif void rdpcmNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, RDPCMMode &rdpcmMode); void applyForwardRDPCM(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const RDPCMMode &rdpcmMode); @@ -122,6 +127,9 @@ protected: private: Quant *m_quant; //!< Quantizer +#if JVET_M0464_UNI_MTS + TCoeff** m_mtsCoeffs; +#endif // forward Transform diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 02dd93e301a1c421a0387e8542426ef642670584..e1a5da86a21c4a72d2eda4fcfd056ab103c5d074 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,13 @@ #include <assert.h> #include <cassert> +#define JVET_M0464_UNI_MTS 1 + +#if JVET_M0464_UNI_MTS +typedef std::pair<int, bool> TrMode; +typedef std::pair<int, int> TrCost; +#endif + #define JVET_M0421_SPLIT_SIG 1 #define REMOVE_BIN_DECISION_TREE 1 diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 30286edd9bf4c88dd17cf26614ed33172eb188f3..eca98e81345541f2838616aa1d715e7ed54af207 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -261,7 +261,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other ) qp = other.qp; chromaQpAdj = other.chromaQpAdj; rootCbf = other.rootCbf; +#if !JVET_M0464_UNI_MTS emtFlag = other.emtFlag; +#endif #if HEVC_TILES_WPP tileIdx = other.tileIdx; #endif @@ -292,7 +294,9 @@ void CodingUnit::initData() qp = 0; chromaQpAdj = 0; rootCbf = true; +#if !JVET_M0464_UNI_MTS emtFlag = 0; +#endif #if HEVC_TILES_WPP tileIdx = 0; #endif @@ -493,12 +497,17 @@ void TransformUnit::initData() { cbf[i] = 0; rdpcm[i] = NUMBER_OF_RDPCM_MODES; +#if !JVET_M0464_UNI_MTS transformSkip[i] = false; +#endif compAlpha[i] = 0; } depth = 0; +#if JVET_M0464_UNI_MTS + mtsIdx = 0; +#else emtIdx = 0; - +#endif } void TransformUnit::init(TCoeff **coeffs, Pel **pcmbuf) @@ -528,11 +537,17 @@ TransformUnit& TransformUnit::operator=(const TransformUnit& other) cbf[i] = other.cbf[i]; rdpcm[i] = other.rdpcm[i]; +#if !JVET_M0464_UNI_MTS transformSkip[i] = other.transformSkip[i]; +#endif compAlpha[i] = other.compAlpha[i]; } depth = other.depth; +#if JVET_M0464_UNI_MTS + mtsIdx = other.mtsIdx; +#else emtIdx = other.emtIdx; +#endif return *this; } @@ -549,15 +564,20 @@ void TransformUnit::copyComponentFrom(const TransformUnit& other, const Componen cbf[i] = other.cbf[i]; rdpcm[i] = other.rdpcm[i]; +#if !JVET_M0464_UNI_MTS transformSkip[i] = other.transformSkip[i]; +#endif compAlpha[i] = other.compAlpha[i]; depth = other.depth; - +#if JVET_M0464_UNI_MTS + mtsIdx = isLuma( i ) ? other.mtsIdx : mtsIdx; +#else if( isLuma( i ) ) { emtIdx = other.emtIdx; } +#endif } CoeffBuf TransformUnit::getCoeffs(const ComponentID id) { return CoeffBuf(m_coeffs[id], blocks[id]); } diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 761da4cfe37a7b803d5d0a10aab70013849da36f..81e85c9c0ec9db09a0ddd1a096e4bcb160e50c57 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -305,7 +305,9 @@ struct CodingUnit : public UnitArea #if HEVC_TILES_WPP uint32_t tileIdx; #endif +#if !JVET_M0464_UNI_MTS uint8_t emtFlag; +#endif uint8_t GBiIdx; int refIdxBi[2]; // needed for fast imv mode decisions @@ -410,11 +412,17 @@ struct TransformUnit : public UnitArea ChannelType chType; uint8_t depth; +#if JVET_M0464_UNI_MTS + uint8_t mtsIdx; +#else uint8_t emtIdx; - uint8_t cbf [ MAX_NUM_TBLOCKS ]; +#endif + uint8_t cbf [ MAX_NUM_TBLOCKS ]; RDPCMMode rdpcm [ MAX_NUM_TBLOCKS ]; +#if !JVET_M0464_UNI_MTS bool transformSkip[ MAX_NUM_TBLOCKS ]; - int8_t compAlpha [ MAX_NUM_TBLOCKS ]; +#endif + int8_t compAlpha [ MAX_NUM_TBLOCKS ]; TransformUnit() : chType( CH_L ) { } TransformUnit(const UnitArea& unit); diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index ee952d0c99bd5a5fabb49abf9d8c7a445f5d5e86..0e9cab6aa120678e8937ff1c4e9d0d8475733f2d 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -236,7 +236,11 @@ bool CU::hasNonTsCodedBlock( const CodingUnit& cu ) { for( uint32_t i = 0; i < ::getNumberValidTBlocks( *cu.cs->pcv ); i++ ) { +#if JVET_M0464_UNI_MTS + hasAnyNonTSCoded |= ( currTU.blocks[i].valid() && ( isLuma(ComponentID(i)) ? currTU.mtsIdx != 1 : true ) && TU::getCbf( currTU, ComponentID( i ) ) ); +#else hasAnyNonTSCoded |= ( currTU.blocks[i].valid() && !currTU.transformSkip[i] && TU::getCbf( currTU, ComponentID( i ) ) ); +#endif } } @@ -4248,6 +4252,31 @@ void TU::setCbfAtDepth(TransformUnit &tu, const ComponentID &compID, const unsig tu.cbf[compID] |= ((cbf ? 1 : 0) << depth); } +#if JVET_M0464_UNI_MTS +bool TU::isTSAllowed(const TransformUnit &tu, const ComponentID compID) +{ + bool tsAllowed = compID == COMPONENT_Y; + const int maxSize = tu.cs->pps->getPpsRangeExtension().getLog2MaxTransformSkipBlockSize(); + + tsAllowed &= tu.cs->pps->getUseTransformSkip(); + tsAllowed &= !tu.cu->transQuantBypass; + + SizeType transformSkipMaxSize = 1 << maxSize; + tsAllowed &= tu.lwidth() <= transformSkipMaxSize && tu.lheight() <= transformSkipMaxSize; + + return tsAllowed; +} + +bool TU::isMTSAllowed(const TransformUnit &tu, const ComponentID compID) +{ + bool mtsAllowed = compID == COMPONENT_Y; + const int maxSize = CU::isIntra( *tu.cu ) ? MTS_INTRA_MAX_CU_SIZE : MTS_INTER_MAX_CU_SIZE; + + mtsAllowed &= CU::isIntra( *tu.cu ) ? tu.cs->sps->getSpsNext().getUseIntraMTS() : tu.cs->sps->getSpsNext().getUseInterMTS(); + mtsAllowed &= ( tu.lwidth() <= maxSize && tu.lheight() <= maxSize ); + return mtsAllowed; +} +#else bool TU::hasTransformSkipFlag(const CodingStructure& cs, const CompArea& area) { uint32_t transformSkipLog2MaxSize = cs.pps->getPpsRangeExtension().getLog2MaxTransformSkipBlockSize(); @@ -4255,10 +4284,15 @@ bool TU::hasTransformSkipFlag(const CodingStructure& cs, const CompArea& area) SizeType transformSkipMaxSize = 1 << transformSkipLog2MaxSize; return area.width <= transformSkipMaxSize && area.height <= transformSkipMaxSize; } +#endif uint32_t TU::getGolombRiceStatisticsIndex(const TransformUnit &tu, const ComponentID &compID) { +#if JVET_M0464_UNI_MTS + const bool transformSkip = tu.mtsIdx==1; +#else const bool transformSkip = tu.transformSkip[compID]; +#endif const bool transquantBypass = tu.cu->transQuantBypass; //-------- @@ -4340,7 +4374,11 @@ uint32_t TU::getNumNonZeroCoeffsNonTS( const TransformUnit& tu, const bool bLuma uint32_t count = 0; for( uint32_t i = 0; i < ::getNumberValidTBlocks( *tu.cs->pcv ); i++ ) { +#if JVET_M0464_UNI_MTS + if( tu.blocks[i].valid() && ( isLuma(ComponentID(i)) ? tu.mtsIdx !=1 : true ) && TU::getCbf( tu, ComponentID( i ) ) ) +#else if( tu.blocks[i].valid() && !tu.transformSkip[i] && TU::getCbf( tu, ComponentID( i ) ) ) +#endif { if( isLuma ( tu.blocks[i].compID ) && !bLuma ) continue; if( isChroma( tu.blocks[i].compID ) && !bChroma ) continue; diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index b844652e5da8d9ebdce9fa509b2aff051053152b..b735cdb37a2d9d45ffc7ebaab5f380ea5572737b 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -171,7 +171,12 @@ namespace TU bool getCbf (const TransformUnit &tu, const ComponentID &compID); bool getCbfAtDepth (const TransformUnit &tu, const ComponentID &compID, const unsigned &depth); void setCbfAtDepth ( TransformUnit &tu, const ComponentID &compID, const unsigned &depth, const bool &cbf); +#if JVET_M0464_UNI_MTS + bool isTSAllowed (const TransformUnit &tu, const ComponentID compID); + bool isMTSAllowed (const TransformUnit &tu, const ComponentID compID); +#else bool hasTransformSkipFlag (const CodingStructure& cs, const CompArea& area); +#endif uint32_t getGolombRiceStatisticsIndex (const TransformUnit &tu, const ComponentID &compID); #if HEVC_USE_MDCS uint32_t getCoefScanIdx (const TransformUnit &tu, const ComponentID &compID); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index f1ee3346719c94067dd120609768cca768705de0..1d201b375c97ce5b5c41fa1d8442756dd98bda52 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -1905,7 +1905,9 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, if( split ) { { +#if !JVET_M0464_UNI_MTS if( trDepth == 0 ) emt_cu_flag( cu ); +#endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) { @@ -1989,7 +1991,9 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, TU::setCbfAtDepth( tu, COMPONENT_Cr, trDepth, ( chromaCbfs.Cr ? 1 : 0 ) ); } +#if !JVET_M0464_UNI_MTS if( trDepth == 0 && TU::getCbfAtDepth( tu, COMPONENT_Y, 0 ) ) emt_cu_flag( cu ); +#endif transform_unit( tu, cuCtx, chromaCbfs ); } @@ -2186,14 +2190,22 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) DTRACE( g_trace_ctx, D_SYNTAX, "residual_coding() etype=%d pos=(%d,%d) size=%dx%d predMode=%d\n", tu.blocks[compID].compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.blocks[compID].width, tu.blocks[compID].height, cu.predMode ); // parse transform skip and explicit rdpcm mode +#if JVET_M0464_UNI_MTS + mts_coding ( tu, compID ); +#else transform_skip_flag( tu, compID ); +#endif explicit_rdpcm_mode( tu, compID ); #if HEVC_USE_SIGN_HIDING // determine sign hiding bool signHiding = ( cu.cs->slice->getSignDataHidingEnabledFlag() && !cu.transQuantBypass && tu.rdpcm[compID] == RDPCM_OFF ); +#if JVET_M0464_UNI_MTS + if( signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.mtsIdx==1 ) +#else if( signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.transformSkip[compID] ) +#endif { const ChannelType chType = toChannelType( compID ); const unsigned intraMode = PU::getFinalIntraMode( *cu.cs->getPU( tu.blocks[compID].pos(), chType ), chType ); @@ -2211,7 +2223,9 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) CoeffCodingContext cctx ( tu, compID ); #endif TCoeff* coeff = tu.getCoeffs( compID ).buf; +#if !JVET_M0464_UNI_MTS unsigned numSig = 0; +#endif // parse last coeff position cctx.setScanPosLast( last_sig_coeff( cctx ) ); @@ -2220,21 +2234,25 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) const int stateTransTab = ( tu.cs->slice->getDepQuantEnabledFlag() ? 32040 : 0 ); int state = 0; +#if !JVET_M0464_UNI_MTS bool useEmt = ( cu.cs->sps->getSpsNext().getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getSpsNext().getUseInterEMT() && cu.predMode != MODE_INTRA ); useEmt = useEmt && isLuma(compID); +#endif for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--) { cctx.initSubblock ( subSetId ); residual_coding_subblock( cctx, coeff, stateTransTab, state ); +#if !JVET_M0464_UNI_MTS if (useEmt) { numSig += cctx.emtNumSigCoeff(); cctx.setEmtNumSigCoeff( 0 ); } +#endif } - +#if !JVET_M0464_UNI_MTS if( useEmt && !tu.transformSkip[compID] && compID == COMPONENT_Y && tu.cu->emtFlag ) { if( CU::isIntra( *tu.cu ) ) @@ -2246,9 +2264,55 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) emt_tu_index( tu ); } } +#endif } +#if JVET_M0464_UNI_MTS +void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) +{ + const CodingUnit &cu = *tu.cu; + const bool tsAllowed = TU::isTSAllowed ( tu, compID ); + const bool mtsAllowed = TU::isMTSAllowed( tu, compID ); + + if( !mtsAllowed && !tsAllowed ) return; + int symbol = 0; + int ctxIdx = 0; + + if( tsAllowed ) + { + ctxIdx = 6; + symbol = m_BinDecoder.decodeBin( Ctx::MTSIndex( ctxIdx ) ); + tu.mtsIdx = 1-symbol; // 1 = TS + } + + if( tu.mtsIdx != 1 ) + { + if( mtsAllowed ) + { + ctxIdx = std::min( (int)cu.qtDepth, 5 ); + symbol = m_BinDecoder.decodeBin( Ctx::MTSIndex( ctxIdx ) ); + + if( symbol ) + { + ctxIdx = 7; + tu.mtsIdx = 2; // mtsIdx = 2 -- 4 + for( int i = 0; i < 3; i++, ctxIdx++ ) + { + symbol = m_BinDecoder.decodeBin( Ctx::MTSIndex( ctxIdx ) ); + tu.mtsIdx += symbol; + + if( !symbol ) + { + break; + } + } + } + } + } + DTRACE( g_trace_ctx, D_SYNTAX, "mts_coding() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, cu.lx(), cu.ly(), tu.mtsIdx ); +} +#else void CABACReader::transform_skip_flag( TransformUnit& tu, ComponentID compID ) { @@ -2327,7 +2391,7 @@ void CABACReader::emt_cu_flag( CodingUnit& cu ) DTRACE( g_trace_ctx, D_SYNTAX, "emt_cu_flag() etype=%d pos=(%d,%d) emtCuFlag=%d\n", COMPONENT_Y, cu.lx(), cu.ly(), ( int ) cu.emtFlag ); } } - +#endif void CABACReader::explicit_rdpcm_mode( TransformUnit& tu, ComponentID compID ) { @@ -2335,7 +2399,11 @@ void CABACReader::explicit_rdpcm_mode( TransformUnit& tu, ComponentID compID ) tu.rdpcm[compID] = RDPCM_OFF; +#if JVET_M0464_UNI_MTS + if( !CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && ( tu.mtsIdx==1 || cu.transQuantBypass ) ) +#else if( !CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && ( tu.transformSkip[compID] || cu.transQuantBypass ) ) +#endif { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE( STATS__EXPLICIT_RDPCM_BITS, tu.blocks[tu.chType].lumaSize() ); @@ -2618,7 +2686,9 @@ void CABACReader::residual_coding_subblock( CoeffCodingContext& cctx, TCoeff* co coeff[ sigBlkPos[k] ] = ( sumAbs & 1 ? -AbsCoeff : AbsCoeff ); } #endif +#if !JVET_M0464_UNI_MTS cctx.setEmtNumSigCoeff( numNonZero ); +#endif } diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 1fb95d7fbb27f828ea7573285652a003d5e55c2d..a9c9ec4040b87900333934967455990a482b5cec 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -127,9 +127,13 @@ public: // residual coding (clause 7.3.8.11) void residual_coding ( TransformUnit& tu, ComponentID compID ); +#if JVET_M0464_UNI_MTS + void mts_coding ( TransformUnit& tu, ComponentID compID ); +#else void transform_skip_flag ( TransformUnit& tu, ComponentID compID ); void emt_tu_index ( TransformUnit& tu ); void emt_cu_flag ( CodingUnit& cu ); +#endif void explicit_rdpcm_mode ( TransformUnit& tu, ComponentID compID ); int last_sig_coeff ( CoeffCodingContext& cctx ); void residual_coding_subblock ( CoeffCodingContext& cctx, TCoeff* coeff, const int stateTransTable, int& state ); diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index e6813e513f4fe3a4eb1dea8065235b1051c7b69c..0f0bbc947ae077f23ce3ce2e1221c1d5d0181bcd 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -794,8 +794,13 @@ void HLSyntaxReader::parseSPSNext( SPSNext& spsNext, const bool usePCM ) READ_FLAG( symbol, "bio_enable_flag" ); spsNext.setUseBIO ( symbol != 0 ); READ_FLAG( symbol, "disable_motion_compression_flag" ); spsNext.setDisableMotCompress ( symbol != 0 ); READ_FLAG( symbol, "lm_chroma_enabled_flag" ); spsNext.setUseLMChroma ( symbol != 0 ); +#if JVET_M0464_UNI_MTS + READ_FLAG( symbol, "mts_intra_enabled_flag" ); spsNext.setUseIntraMTS ( symbol != 0 ); + READ_FLAG( symbol, "mts_inter_enabled_flag" ); spsNext.setUseInterMTS ( symbol != 0 ); +#else READ_FLAG( symbol, "emt_intra_enabled_flag" ); spsNext.setUseIntraEMT ( symbol != 0 ); READ_FLAG( symbol, "emt_inter_enabled_flag" ); spsNext.setUseInterEMT ( symbol != 0 ); +#endif READ_FLAG( symbol, "affine_flag" ); spsNext.setUseAffine ( symbol != 0 ); if ( spsNext.getUseAffine() ) { diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 453fc371fb5d35fb70bdcdc0502c5b96992351a2..eb391f4dcb261abf64549ffec038f63413269d9d 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -1843,7 +1843,9 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth ); chromaCbfs.Cr = TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth ); } +#if !JVET_M0464_UNI_MTS if( trDepth == 0 ) emt_cu_flag( cu ); +#endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) { @@ -1881,7 +1883,9 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit } } +#if !JVET_M0464_UNI_MTS if( trDepth == 0 && TU::getCbfAtDepth( tu, COMPONENT_Y, 0 ) ) emt_cu_flag( cu ); +#endif transform_unit( tu, cuCtx, chromaCbfs ); } @@ -2086,13 +2090,21 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID ) DTRACE( g_trace_ctx, D_SYNTAX, "residual_coding() etype=%d pos=(%d,%d) size=%dx%d predMode=%d\n", tu.blocks[compID].compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.blocks[compID].width, tu.blocks[compID].height, cu.predMode ); // code transform skip and explicit rdpcm mode +#if JVET_M0464_UNI_MTS + mts_coding ( tu, compID ); +#else transform_skip_flag( tu, compID ); +#endif explicit_rdpcm_mode( tu, compID ); #if HEVC_USE_SIGN_HIDING // determine sign hiding bool signHiding = ( cu.cs->slice->getSignDataHidingEnabledFlag() && !cu.transQuantBypass && tu.rdpcm[compID] == RDPCM_OFF ); +#if JVET_M0464_UNI_MTS + if( signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.mtsIdx==1 ) +#else if( signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.transformSkip[compID] ) +#endif { const ChannelType chType = toChannelType( compID ); const unsigned intraMode = PU::getFinalIntraMode( *cu.cs->getPU( tu.blocks[compID].pos(), chType ), chType ); @@ -2110,7 +2122,9 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID ) CoeffCodingContext cctx ( tu, compID ); #endif const TCoeff* coeff = tu.getCoeffs( compID ).buf; +#if !JVET_M0464_UNI_MTS unsigned numSig = 0; +#endif // determine and set last coeff position and sig group flags int scanPosLast = -1; @@ -2133,22 +2147,27 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID ) // code subblocks const int stateTab = ( tu.cs->slice->getDepQuantEnabledFlag() ? 32040 : 0 ); int state = 0; +#if !JVET_M0464_UNI_MTS bool useEmt = ( cu.cs->sps->getSpsNext().getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getSpsNext().getUseInterEMT() && cu.predMode != MODE_INTRA ); useEmt = useEmt && isLuma(compID); +#endif for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--) { cctx.initSubblock ( subSetId, sigGroupFlags[subSetId] ); residual_coding_subblock( cctx, coeff, stateTab, state ); +#if !JVET_M0464_UNI_MTS if (useEmt) { numSig += cctx.emtNumSigCoeff(); cctx.setEmtNumSigCoeff( 0 ); } +#endif } +#if !JVET_M0464_UNI_MTS if( useEmt && !tu.transformSkip[compID] && compID == COMPONENT_Y && tu.cu->emtFlag ) { if( CU::isIntra( *tu.cu ) ) @@ -2160,9 +2179,56 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID ) emt_tu_index( tu ); } } +#endif } +#if JVET_M0464_UNI_MTS +void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID ) +{ + const CodingUnit &cu = *tu.cu; + const bool tsAllowed = TU::isTSAllowed ( tu, compID ); + const bool mtsAllowed = TU::isMTSAllowed( tu, compID ); + + if( !mtsAllowed && !tsAllowed ) return; + + int symbol = 0; + int ctxIdx = 0; + + if( tsAllowed ) + { + symbol = 1 - ( tu.mtsIdx == 1 ? 1 : 0 ); + ctxIdx = 6; + m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) ); + } + + if( tu.mtsIdx != 1 ) + { + if( mtsAllowed ) + { + symbol = tu.mtsIdx != 0 ? 1 : 0; + ctxIdx = std::min( (int)cu.qtDepth, 5 ); + m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) ); + if( symbol ) + { + ctxIdx = 7; + for( int i = 0; i < 3; i++, ctxIdx++ ) + { + symbol = tu.mtsIdx > i + 2 ? 1 : 0; + m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) ); + + if( !symbol ) + { + break; + } + } + } + } + } + + DTRACE( g_trace_ctx, D_SYNTAX, "mts_coding() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, cu.lx(), cu.ly(), tu.mtsIdx ); +} +#else void CABACWriter::transform_skip_flag( const TransformUnit& tu, ComponentID compID ) { if( !tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag( *tu.cs, tu.blocks[compID] ) || ( isLuma( compID ) && tu.cu->emtFlag ) ) @@ -2224,13 +2290,17 @@ void CABACWriter::emt_cu_flag( const CodingUnit& cu ) DTRACE( g_trace_ctx, D_SYNTAX, "emt_cu_flag() etype=%d pos=(%d,%d) emtCuFlag=%d\n", COMPONENT_Y, cu.lx(), cu.ly(), ( int ) cu.emtFlag ); } } - +#endif void CABACWriter::explicit_rdpcm_mode( const TransformUnit& tu, ComponentID compID ) { const CodingUnit& cu = *tu.cu; +#if JVET_M0464_UNI_MTS + if( !CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && ( tu.mtsIdx==1 || cu.transQuantBypass ) ) +#else if( !CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && ( tu.transformSkip[compID] || cu.transQuantBypass ) ) +#endif { ChannelType chType = toChannelType( compID ); switch( tu.rdpcm[compID] ) @@ -2477,7 +2547,9 @@ void CABACWriter::residual_coding_subblock( CoeffCodingContext& cctx, const TCoe #else m_BinEncoder.encodeBinsEP( signPattern, numNonZero ); #endif +#if !JVET_M0464_UNI_MTS cctx.setEmtNumSigCoeff(numNonZero); +#endif } diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index a43066e4ceca15eee0c89154e355a8deb016cd38..f2c07551ffa2369a95c367d24c350b0e611d804b 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -142,9 +142,13 @@ public: // residual coding (clause 7.3.8.11) void residual_coding ( const TransformUnit& tu, ComponentID compID ); +#if JVET_M0464_UNI_MTS + void mts_coding ( const TransformUnit& tu, ComponentID compID ); +#else void transform_skip_flag ( const TransformUnit& tu, ComponentID compID ); void emt_tu_index ( const TransformUnit& tu ); void emt_cu_flag ( const CodingUnit& cu ); +#endif void explicit_rdpcm_mode ( const TransformUnit& tu, ComponentID compID ); void last_sig_coeff ( CoeffCodingContext& cctx ); void residual_coding_subblock ( CoeffCodingContext& cctx, const TCoeff* coeff, const int stateTransTable, int& state ); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 9655f0e97dc5096985ce064e5efe0c37bf4a0fca..a0020e5a4700be90c14bc5d39bb6e7ac4edfbda4 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -202,10 +202,17 @@ protected: unsigned m_log2DiffMaxMinCodingBlockSize; int m_LMChroma; +#if JVET_M0464_UNI_MTS + int m_IntraMTS; + int m_InterMTS; + int m_IntraMTSMaxCand; + int m_InterMTSMaxCand; +#else int m_IntraEMT; int m_InterEMT; int m_FastIntraEMT; int m_FastInterEMT; +#endif bool m_LargeCTU; int m_SubPuMvpMode; bool m_Affine; @@ -695,6 +702,16 @@ public: bool getUseAltDQPCoding () const { return m_AltDQPCoding; } #endif +#if JVET_M0464_UNI_MTS + void setIntraMTSMaxCand ( unsigned u ) { m_IntraMTSMaxCand = u; } + unsigned getIntraMTSMaxCand () const { return m_IntraMTSMaxCand; } + void setInterMTSMaxCand ( unsigned u ) { m_InterMTSMaxCand = u; } + unsigned getInterMTSMaxCand () const { return m_InterMTSMaxCand; } + void setIntraMTS ( bool b ) { m_IntraMTS = b; } + bool getIntraMTS () const { return m_IntraMTS; } + void setInterMTS ( bool b ) { m_InterMTS = b; } + bool getInterMTS () const { return m_InterMTS; } +#else void setFastIntraEMT ( bool b ) { m_FastIntraEMT = b; } bool getFastIntraEMT () const { return m_FastIntraEMT; } void setFastInterEMT ( bool b ) { m_FastInterEMT = b; } @@ -703,6 +720,7 @@ public: bool getIntraEMT () const { return m_IntraEMT; } void setInterEMT ( bool b ) { m_InterEMT = b; } bool getInterEMT () const { return m_InterEMT; } +#endif @@ -878,7 +896,6 @@ public: #if X0038_LAMBDA_FROM_QP_CAPABILITY int getIntraQPOffset () const { return m_intraQPOffset; } int getLambdaFromQPEnable () const { return m_lambdaFromQPEnable; } - public: int getBaseQP () const { return m_iQP; } // public should use getQPForPicture. int getQPForPicture (const uint32_t gopIndex, const Slice *pSlice) const; // Function actually defined in EncLib.cpp diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 0c1987e0c8337e19f6737473b1c54fac4085cc67..7bbda75b3a1b97071c1306e4eafbbf7c5a96c2b0 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1262,19 +1262,25 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) { +#if !JVET_M0464_UNI_MTS double bestInterCost = m_modeCtrl->getBestInterCost(); double costSize2Nx2NemtFirstPass = m_modeCtrl->getEmtSize2Nx2NFirstPassCost(); bool skipSecondEmtPass = m_modeCtrl->getSkipSecondEMTPass(); const SPS &sps = *tempCS->sps; - const PPS &pps = *tempCS->pps; +#endif + const PPS &pps = *tempCS->pps; +#if !JVET_M0464_UNI_MTS const CodingUnit *bestCU = bestCS->getCU( partitioner.chType ); const int maxSizeEMT = EMT_INTRA_MAX_CU_WITH_QTBT; uint8_t considerEmtSecondPass = ( sps.getSpsNext().getUseIntraEMT() && isLuma( partitioner.chType ) && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT ) ? 1 : 0; +#endif Distortion interHad = m_modeCtrl->getInterHad(); - +#if JVET_M0464_UNI_MTS + { +#else for( uint8_t emtCuFlag = 0; emtCuFlag <= considerEmtSecondPass; emtCuFlag++ ) { //Possible early EMT tests interruptions @@ -1288,6 +1294,7 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC { continue; } +#endif tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); @@ -1305,7 +1312,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1; cu.qp = encTestMode.qp; //cu.ipcm = false; +#if !JVET_M0464_UNI_MTS cu.emtFlag = emtCuFlag; +#endif CU::addPUs( cu ); @@ -1321,7 +1330,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC interHad = 0; // JEM assumes only perfect reconstructions can from now on beat the inter mode m_modeCtrl->enforceInterHad( 0 ); +#if JVET_M0464_UNI_MTS + return; +#else continue; +#endif } if( !CS::isDualITree( *tempCS ) ) @@ -1374,9 +1387,10 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC xCheckDQP( *tempCS, partitioner ); - +#if !JVET_M0464_UNI_MTS // we save the cost of the modes for the first EMT pass if( !emtCuFlag ) static_cast< double& >( costSize2Nx2NemtFirstPass ) = tempCS->cost; +#endif #if WCG_EXT DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) ); @@ -1385,7 +1399,7 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC #endif xCheckBestMode( tempCS, bestCS, partitioner, encTestMode ); - +#if !JVET_M0464_UNI_MTS //now we check whether the second pass of SIZE_2Nx2N and the whole Intra SIZE_NxN should be skipped or not if( !emtCuFlag && !tempCS->slice->isIntra() && bestCU && bestCU->predMode != MODE_INTRA && m_pcEncCfg->getFastInterEMT() ) { @@ -1397,7 +1411,7 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC break; } } - +#endif } //for emtCuFlag } @@ -2074,10 +2088,14 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& isTestSkipMerge[uiMergeCand] = true; } +#if JVET_M0464_UNI_MTS + xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, NULL, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL ); +#else xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass , NULL , 1 , uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL); +#endif if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.mhIntraFlag) { @@ -2334,7 +2352,11 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, triangleBuffer[candIdx0], triangleBuffer[candIdx1] ); } +#if JVET_M0464_UNI_MTS + xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, noResidualPass, NULL, ( noResidualPass == 0 ? &trianglecandHasNoResidual[mergeCand] : NULL ) ); +#else xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, noResidualPass, NULL, true, ( (noResidualPass == 0 ) ? &trianglecandHasNoResidual[mergeCand] : NULL ) ); +#endif if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip) { @@ -2581,7 +2603,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct m_pcInterSearch->motionCompensation( pu ); } +#if JVET_M0464_UNI_MTS + xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, NULL, ( uiNoResidualPass == 0 ? &candHasNoResidual[uiMergeCand] : NULL ) ); +#else xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, NULL, true, ((uiNoResidualPass == 0) ? &candHasNoResidual[uiMergeCand] : NULL) ); +#endif if ( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip ) { @@ -2804,6 +2830,9 @@ void EncCu::xCheckRDCostCPRModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct { if (!(bestIsSkip && (numResidualPass == 0))) { +#if JVET_M0464_UNI_MTS + { +#else unsigned char considerEmtSecondPass = 0; bool skipSecondEmtPass = true; bool hasResidual[2] = { false, false }; @@ -2816,6 +2845,7 @@ void EncCu::xCheckRDCostCPRModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct { continue; } +#endif // first get merge candidates CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, (const ChannelType)partitioner.chType), (const ChannelType)partitioner.chType); @@ -2831,8 +2861,9 @@ void EncCu::xCheckRDCostCPRModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct cu.transQuantBypass = encTestMode.lossless; cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1; cu.qp = encTestMode.qp; - +#if !JVET_M0464_UNI_MTS cu.emtFlag = false; +#endif PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType);// tempCS->addPU(cu); pu.intraDir[0] = DC_IDX; // set intra pred for cpr block @@ -2858,20 +2889,24 @@ void EncCu::xCheckRDCostCPRModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct xCheckDQP(*tempCS, partitioner); } +#if !JVET_M0464_UNI_MTS hasResidual[emtCuFlag] = cu.rootCbf; emtCost[emtCuFlag] = tempCS->cost; +#endif DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda()); xCheckBestMode(tempCS, bestCS, partitioner, encTestMode); tempCS->initStructData(encTestMode.qp, encTestMode.lossless); } +#if !JVET_M0464_UNI_MTS if (numResidualPass == 0 && (emtCost[0] <= emtCost[1] ? !hasResidual[0] : !hasResidual[1])) { // If no residual when allowing for one, then set mark to not try case where residual is forced to 0 candHasNoResidual[mergeCand] = 1; } +#endif if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip) { @@ -2930,6 +2965,9 @@ void EncCu::xCheckRDCostCPRMode(CodingStructure *&tempCS, CodingStructure *&best // MC m_pcInterSearch->motionCompensation(pu, REF_PIC_LIST_0, true, chroma); +#if JVET_M0464_UNI_MTS + { +#else double bestCost = bestCS->cost; unsigned char considerEmtSecondPass = 0; bool skipSecondEmtPass = true; @@ -2945,13 +2983,16 @@ void EncCu::xCheckRDCostCPRMode(CodingStructure *&tempCS, CodingStructure *&best } tempCS->getCU(tempCS->chType)->emtFlag = emtCuFlag; +#endif m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, false, true, chroma); +#if !JVET_M0464_UNI_MTS if (m_pcEncCfg->getFastInterEMT()) { emtFirstPassCost = (!emtCuFlag) ? tempCS->cost : emtFirstPassCost; } +#endif xEncodeDontSplit(*tempCS, partitioner); if (tempCS->pps->getUseDQP() && (partitioner.currDepth) <= tempCS->pps->getMaxCuDQPDepth()) @@ -2962,6 +3003,7 @@ void EncCu::xCheckRDCostCPRMode(CodingStructure *&tempCS, CodingStructure *&best DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda()); xCheckBestMode(tempCS, bestCS, partitioner, encTestMode); +#if !JVET_M0464_UNI_MTS //now we check whether the second pass should be skipped or not if (!emtCuFlag && considerEmtSecondPass) { @@ -2990,6 +3032,7 @@ void EncCu::xCheckRDCostCPRMode(CodingStructure *&tempCS, CodingStructure *&best tempCS->cost = MAX_DOUBLE; } } +#endif } } // bValid @@ -3155,11 +3198,18 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC } } +#if JVET_M0464_UNI_MTS + xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, 0 + , m_pImvTempCS ? m_pImvTempCS[wIdx] : NULL + , 0 + , &equGBiCost +#else xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, 0 , m_pImvTempCS ? m_pImvTempCS[wIdx] : NULL , 1 , 0 , &equGBiCost +#endif ); if( g_GbiSearchOrder[gbiLoopIdx] == GBI_DEFAULT ) @@ -3282,7 +3332,9 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be } cu.imv = iIMV > 1 ? 2 : 1; +#if !JVET_M0464_UNI_MTS cu.emtFlag = false; +#endif bool testGbi; uint8_t gbiIdx; @@ -3349,11 +3401,18 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be return false; } +#if JVET_M0464_UNI_MTS + xEncodeInterResidual( tempCS, bestCS, partitioner, encTestModeBase, 0 + , NULL + , 0 + , &equGBiCost +#else xEncodeInterResidual( tempCS, bestCS, partitioner, encTestModeBase, 0 , NULL , true , 0 , &equGBiCost +#endif ); tempCS->initStructData(encTestMode.qp, encTestMode.lossless); @@ -3381,11 +3440,22 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be return true; } +#if JVET_M0464_UNI_MTS +void EncCu::xEncodeInterResidual( CodingStructure *&tempCS + , CodingStructure *&bestCS + , Partitioner &partitioner + , const EncTestMode& encTestMode + , int residualPass + , CodingStructure* imvCS + , bool* bestHasNonResi + , double* equGBiCost +#else void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode, int residualPass , CodingStructure* imvCS , int emtMode , bool* bestHasNonResi , double* equGBiCost +#endif ) { if( residualPass == 1 && encTestMode.lossless ) @@ -3396,14 +3466,18 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be CodingUnit* cu = tempCS->getCU( partitioner.chType ); double bestCostInternal = MAX_DOUBLE; double bestCost = bestCS->cost; +#if !JVET_M0464_UNI_MTS const SPS& sps = *tempCS->sps; const int maxSizeEMT = EMT_INTER_MAX_CU_WITH_QTBT; +#endif bool swapped = false; // avoid unwanted data copy bool reloadCU = false; +#if !JVET_M0464_UNI_MTS const bool considerEmtSecondPass = emtMode && sps.getSpsNext().getUseInterEMT() && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT; int minEMTMode = 0; int maxEMTMode = (considerEmtSecondPass?1:0); +#endif // Not allow very big |MVd| to avoid CABAC crash caused by too large MVd. Normally no impact on coding performance. const int maxMvd = 1 << 15; @@ -3433,12 +3507,14 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be } } +#if !JVET_M0464_UNI_MTS if( emtMode == 2 ) { minEMTMode = maxEMTMode = (cu->emtFlag?1:0); } for( int curEmtMode = minEMTMode; curEmtMode <= maxEMTMode; curEmtMode++ ) +#endif { if( reloadCU ) { @@ -3470,7 +3546,9 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be reloadCU = true; // enable cu reloading cu->skip = false; +#if !JVET_M0464_UNI_MTS cu->emtFlag = curEmtMode; +#endif const bool skipResidual = residualPass == 1; m_pcInterSearch->encodeResAndCalcRdInterCU( *tempCS, partitioner, skipResidual ); @@ -3509,7 +3587,9 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be } } +#if !JVET_M0464_UNI_MTS double emtFirstPassCost = tempCS->cost; +#endif if( imvCS && (tempCS->cost < imvCS->cost) ) { if( imvCS->cost != MAX_DOUBLE ) @@ -3541,6 +3621,7 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be #endif xCheckBestMode( tempCS, bestCS, partitioner, encTestMode ); +#if !JVET_M0464_UNI_MTS //now we check whether the second pass should be skipped or not if( !curEmtMode && maxEMTMode ) { @@ -3554,6 +3635,7 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS, CodingStructure *&be maxEMTMode = 0; // do not test EMT } } +#endif } //end emt loop } diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index 4adbc26dce805e3710a1d1673de0025bd1f97415..eadb9e445cf2dd738f566d96652d2109473e05c7 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -190,12 +190,24 @@ protected: void xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode ); +#if JVET_M0464_UNI_MTS + void xEncodeInterResidual( CodingStructure *&tempCS + , CodingStructure *&bestCS + , Partitioner &partitioner + , const EncTestMode& encTestMode + , int residualPass = 0 + , CodingStructure* imvCS = NULL + , bool* bestHasNonResi = NULL + , double* equGBiCost = NULL + ); +#else void xEncodeInterResidual ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode, int residualPass = 0 , CodingStructure* imvCS = NULL , int emtMode = 1 , bool* bestHasNonResi = NULL , double* equGBiCost = NULL ); +#endif #if REUSE_CU_RESULTS void xReuseCachedResult ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &Partitioner ); #endif diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 68fdd2caf1ed82d37dcca64fd22a19d19fb1b3a1..c996912c6790415770232bff81fa2883dd77e73d 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -797,7 +797,11 @@ void EncLib::xInitSPS(SPS &sps) sps.setNoSbtmvpConstraintFlag(m_SubPuMvpMode ? false : true); sps.setNoAmvrConstraintFlag(!m_bNoAmvrConstraintFlag); sps.setNoAffineMotionConstraintFlag(!m_Affine); +#if JVET_M0464_UNI_MTS + sps.setNoMtsConstraintFlag((m_IntraMTS || m_InterMTS) ? false : true); +#else sps.setNoMtsConstraintFlag((m_IntraEMT || m_InterEMT) ? false : true); +#endif sps.setNoLadfConstraintFlag(!m_LadfEnabled); sps.setNoDepQuantConstraintFlag(!m_DepQuantEnabledFlag); sps.setNoSignDataHidingConstraintFlag(!m_SignDataHidingEnabledFlag); @@ -859,8 +863,13 @@ void EncLib::xInitSPS(SPS &sps) #if ENABLE_WPP_PARALLELISM sps.getSpsNext().setUseNextDQP ( m_AltDQPCoding ); #endif +#if JVET_M0464_UNI_MTS + sps.getSpsNext().setUseIntraMTS ( m_IntraMTS ); + sps.getSpsNext().setUseInterMTS ( m_InterMTS ); +#else sps.getSpsNext().setUseIntraEMT ( m_IntraEMT ); sps.getSpsNext().setUseInterEMT ( m_InterEMT ); +#endif sps.getSpsNext().setUseCompositeRef ( m_compositeRefEnabled ); sps.getSpsNext().setUseGBi ( m_GBi ); #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index eeee01f51e3c8c2262e37cb09b968b09afba6ebc..a1a47b7c1ed77f3e56ef886f2a77a9685b0fd255 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -1606,6 +1606,7 @@ bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingSt { cuECtx.set( BEST_TRIV_SPLIT_COST, tempCS->cost ); } +#if !JVET_M0464_UNI_MTS else if( encTestmode.type == ETM_INTRA ) { const CodingUnit cu = *tempCS->getCU( partitioner.chType ); @@ -1615,6 +1616,7 @@ bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingSt cuECtx.bestEmtSize2Nx2N1stPass = tempCS->cost; } } +#endif if( m_pcEncCfg->getIMV4PelFast() && m_pcEncCfg->getIMV() && encTestmode.type == ETM_INTER_ME ) { diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h index b320d6e036a179418c9edd12ca62ee28e30d78a7..e4e1410c1780532cfe9a7d77aae34b027a1f51bd 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.h +++ b/source/Lib/EncoderLib/EncModeCtrl.h @@ -184,10 +184,12 @@ struct ComprCUCtx , extraFeatures ( ) , extraFeaturesd( ) , bestInterCost ( MAX_DOUBLE ) +#if !JVET_M0464_UNI_MTS , bestEmtSize2Nx2N1stPass ( MAX_DOUBLE ) , skipSecondEMTPass ( false ) +#endif , interHad (std::numeric_limits<Distortion>::max()) #if ENABLE_SPLIT_PARALLELISM , isLevelSplitParallel @@ -216,8 +218,10 @@ struct ComprCUCtx static_vector<int64_t, 30> extraFeatures; static_vector<double, 30> extraFeaturesd; double bestInterCost; +#if !JVET_M0464_UNI_MTS double bestEmtSize2Nx2N1stPass; bool skipSecondEMTPass; +#endif Distortion interHad; #if ENABLE_SPLIT_PARALLELISM bool isLevelSplitParallel; @@ -298,9 +302,11 @@ public: double getBestInterCost () const { return m_ComprCUCtxList.back().bestInterCost; } Distortion getInterHad () const { return m_ComprCUCtxList.back().interHad; } void enforceInterHad ( Distortion had ) { m_ComprCUCtxList.back().interHad = had; } +#if !JVET_M0464_UNI_MTS double getEmtSize2Nx2NFirstPassCost () const { return m_ComprCUCtxList.back().bestEmtSize2Nx2N1stPass; } bool getSkipSecondEMTPass () const { return m_ComprCUCtxList.back().skipSecondEMTPass; } void setSkipSecondEMTPass ( bool b ) { m_ComprCUCtxList.back().skipSecondEMTPass = b; } +#endif protected: void xExtractFeatures ( const EncTestMode encTestmode, CodingStructure& cs ); diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 1a30af140b175a9f84bc6b4f6db7eed7976b3e51..3026b1d2d16eeb0cb965eda040d89bc97dec04ff 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -4721,7 +4721,9 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { const UnitArea& currArea = partitioner.currArea(); const SPS &sps = *cs.sps; +#if !JVET_M0464_UNI_MTS const PPS &pps = *cs.pps; +#endif const uint32_t numValidComp = getNumberValidComponents( sps.getChromaFormatIdc() ); const uint32_t numTBlocks = getNumberValidTBlocks ( *cs.pcv ); const CodingUnit &cu = *cs.getCU(partitioner.chType); @@ -4753,10 +4755,16 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { TransformUnit &tu = csFull->addTU(CS::isDualITree(cs) ? cu : currArea, partitioner.chType); tu.depth = currDepth; +#if JVET_M0464_UNI_MTS + tu.mtsIdx = 0; +#else tu.emtIdx = 0; +#endif double minCost [MAX_NUM_TBLOCKS]; +#if !JVET_M0464_UNI_MTS bool checkTransformSkip [MAX_NUM_TBLOCKS]; +#endif m_CABACEstimator->resetBits(); @@ -4783,19 +4791,22 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par continue; const CompArea& compArea = tu.blocks[compID]; const int channelBitDepth = sps.getBitDepth(toChannelType(compID)); - +#if !JVET_M0464_UNI_MTS checkTransformSkip[compID] = false; +#endif if( !tu.blocks[compID].valid() ) { continue; } +#if !JVET_M0464_UNI_MTS checkTransformSkip[compID] = pps.getUseTransformSkip() && TU::hasTransformSkipFlag( *tu.cs, tu.blocks[compID] ) && !cs.isLossless; if( isLuma(compID) ) { checkTransformSkip[compID] &= !tu.cu->emtFlag; } +#endif const bool isCrossCPredictionAvailable = TU::hasCrossCompPredInfo( tu, compID ); @@ -4808,10 +4819,32 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par preCalcAlpha = xCalcCrossComponentPredictionAlpha( tu, compID, m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate() ); } +#if JVET_M0464_UNI_MTS + const bool tsAllowed = TU::isTSAllowed ( tu, compID ); + const bool mtsAllowed = TU::isMTSAllowed( tu, compID ); + uint8_t nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests + std::vector<TrMode> trModes; + trModes.push_back( TrMode( 0, true ) ); //DCT2 + if( tsAllowed ) + { + trModes.push_back( TrMode( 1, true ) ); + } + if( mtsAllowed ) + { + for( int i = 2; i < 6; i++ ) + { + trModes.push_back( TrMode( i, true ) ); + } + } +#endif const int crossCPredictionModesToTest = preCalcAlpha != 0 ? 2 : 1; +#if JVET_M0464_UNI_MTS + const int numTransformCandidates = nNumTransformCands; +#else const int numEmtTransformCandidates = isLuma(compID) && tu.cu->emtFlag && sps.getSpsNext().getUseInterEMT() ? 4 : 1; const int numTransformCandidates = checkTransformSkip[compID] ? ( numEmtTransformCandidates + 1 ) : numEmtTransformCandidates; int lastTransformModeIndex = numTransformCandidates - 1; //lastTransformModeIndex is the mode for transformSkip (if transformSkip is active) +#endif const bool isOneMode = crossCPredictionModesToTest == 1 && numTransformCandidates == 1; bool isLastBest = isOneMode; @@ -4829,8 +4862,23 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par m_CABACEstimator->getCtx() = ctxStart; m_CABACEstimator->resetBits(); +#if JVET_M0464_UNI_MTS + if( isLuma( compID ) ) + { + if( bestTU.mtsIdx == 1 && m_pcEncCfg->getUseTransformSkipFast() ) + { + continue; + } + if( !trModes[transformMode].second ) + { + continue; + } + tu.mtsIdx = trModes[transformMode].first; + } +#else if( isLuma( compID ) ) tu.emtIdx = transformMode; tu.transformSkip[compID] = checkTransformSkip[compID] && transformMode == lastTransformModeIndex; +#endif tu.compAlpha[compID] = bUseCrossCPrediction ? preCalcAlpha : 0; const QpParam cQP(tu, compID); // note: uses tu.transformSkip[compID] @@ -4853,7 +4901,23 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par crossComponentPrediction( tu, compID, lumaResi, resiBuf, resiBuf, false ); } +#if JVET_M0464_UNI_MTS + if( nNumTransformCands > 1 ) + { + if( transformMode == 0 ) + { + m_pcTrQuant->transformNxN( tu, compID, cQP, &trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand() ); + tu.mtsIdx = trModes[0].first; + } + m_pcTrQuant->transformNxN( tu, compID, cQP, currAbsSum, m_CABACEstimator->getCtx(), true ); + } + else + { + m_pcTrQuant->transformNxN( tu, compID, cQP, currAbsSum, m_CABACEstimator->getCtx() ); + } +#else m_pcTrQuant->transformNxN(tu, compID, cQP, currAbsSum, m_CABACEstimator->getCtx()); +#endif if (isFirstMode || (currAbsSum == 0)) { @@ -4937,7 +5001,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par nonCoeffCost = MAX_DOUBLE; } } +#if JVET_M0464_UNI_MTS + else if( transformMode > 0 && !bUseCrossCPrediction ) +#else else if( ( transformMode == lastTransformModeIndex ) && checkTransformSkip[compID] && !bUseCrossCPrediction ) +#endif { currCompCost = MAX_DOUBLE; } @@ -4951,7 +5019,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par } // evaluate +#if JVET_M0464_UNI_MTS + if( ( currCompCost < minCost[compID] ) || ( transformMode == 1 && currCompCost == minCost[compID] ) ) +#else if( ( currCompCost < minCost[compID] ) || ( transformMode == lastTransformModeIndex && checkTransformSkip[compID] && currCompCost == minCost[compID] ) ) +#endif { // copy component if (isFirstMode && ((nonCoeffCost < currCompCost) || (currAbsSum == 0))) // check for forced null @@ -5073,10 +5145,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par ); csSplit->cost = m_pcRdCost->calcRdCost( csSplit->fracBits, csSplit->dist ); +#if !JVET_M0464_UNI_MTS if( csFull && csSplit->cost >= csFull->cost && m_pcEncCfg->getFastInterEMT() ) { break; } +#endif } while( partitioner.nextPart( *csSplit ) ); partitioner.exitCurrSplit(); @@ -5084,8 +5158,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par unsigned anyCbfSet = 0; unsigned compCbf[3] = { 0, 0, 0 }; +#if JVET_M0464_UNI_MTS + if( !bCheckFull ) +#else bool isSplit = bCheckFull ? false : true; if( !bCheckFull || ( csSplit->cost < csFull->cost && m_pcEncCfg->getFastInterEMT() ) || !m_pcEncCfg->getFastInterEMT() ) +#endif { for( auto &currTU : csSplit->traverseTUs( currArea, partitioner.chType ) ) { @@ -5137,10 +5215,13 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { cs.useSubStructure( *csSplit, partitioner.chType, currArea, false, false, false, true ); cs.cost = csSplit->cost; +#if !JVET_M0464_UNI_MTS isSplit = true; +#endif } } +#if !JVET_M0464_UNI_MTS if( ( !isSplit && m_pcEncCfg->getFastInterEMT() ) || ( !m_pcEncCfg->getFastInterEMT() && !( !bCheckFull || ( anyCbfSet && csSplit->cost < csFull->cost ) ) ) ) { CHECK( !bCheckFull, "Error!" ); @@ -5148,6 +5229,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par cs.cost = csFull->cost; m_CABACEstimator->getCtx() = ctxBest; } +#endif if( csSplit && csFull ) { diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index d8ebcd96c05cd8dd54bd97ac443144e0f9d48752..ac23b0a313c1459a5601ecc27059bbc6c00ab1d0 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -285,7 +285,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) uint32_t extraModes = 0; // add two extra modes, which would be used after uiMode <= DC_IDX is removed for cu.nsstIdx == 3 - +#if !JVET_M0464_UNI_MTS const int width = partitioner.currArea().lwidth(); const int height = partitioner.currArea().lheight(); @@ -306,6 +306,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) { emtUsageFlag = 0; //this forces the recalculation of the candidates list. Why is this necessary? (to be checked) } +#endif static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> uiHadModeList; static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandCostList; @@ -315,7 +316,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) static_vector<int, FAST_UDI_MAX_RDMODE_NUM>* nullList = NULL; auto &pu = *cu.firstPU; +#if !JVET_M0464_UNI_MTS int puIndex = 0; +#endif { CandHadList.clear(); CandCostList.clear(); @@ -335,8 +338,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) numModesForFullRD = numModesAvailable; #endif - +#if !JVET_M0464_UNI_MTS if( emtUsageFlag != 2 ) +#endif { // this should always be true CHECK( !pu.Y().valid(), "PU is not valid" ); @@ -547,6 +551,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) uiRdModeList.push_back( i ); } } +#if !JVET_M0464_UNI_MTS if( emtUsageFlag == 1 ) { // Store the modes to be checked with RD @@ -554,7 +559,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) std::copy_n( uiRdModeList.begin(), numModesForFullRD, m_savedRdModeList[puIndex] ); std::copy_n(extendRefList.begin(), numModesForFullRD, m_savedExtendRefList[puIndex]); } +#endif } +#if !JVET_M0464_UNI_MTS else //emtUsage = 2 (here we potentially reduce the number of modes that will be full-RD checked) { if( isAllIntra && m_pcEncCfg->getFastIntraEMT() ) @@ -585,6 +592,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) std::copy_n(m_savedExtendRefList[puIndex], m_savedNumRdModes[puIndex], extendRefList.begin()); } } +#endif CHECK( numModesForFullRD != uiRdModeList.size(), "Inconsistent state!" ); @@ -592,7 +600,11 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) // after this point, don't use numModesForFullRD // PBINTRA fast +#if JVET_M0464_UNI_MTS + if( m_pcEncCfg->getUsePbIntraFast() && !cs.slice->isIntra() && uiRdModeList.size() < numModesAvailable ) +#else if( m_pcEncCfg->getUsePbIntraFast() && !cs.slice->isIntra() && uiRdModeList.size() < numModesAvailable && emtUsageFlag != 2 ) +#endif { if( CandHadList.size() < 3 || CandHadList[2] > cs.interHad * PBINTRA_RATIO ) { @@ -649,11 +661,12 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) xRecurIntraCodingLumaQT( *csTemp, partitioner ); +#if !JVET_M0464_UNI_MTS if( emtUsageFlag == 1 && m_pcEncCfg->getFastIntraEMT() ) { m_modeCostStore[puIndex][uiMode] = csTemp->cost; //cs.cost; } - +#endif DTRACE( g_trace_ctx, D_INTRA_COST, "IntraCost T %f (%d) \n", csTemp->cost, uiOrgMode ); @@ -664,11 +677,12 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) uiBestPUMode = uiOrgMode; bestExtendRef = multiRefIdx; - +#if !JVET_M0464_UNI_MTS if( ( emtUsageFlag == 1 ) && m_pcEncCfg->getFastIntraEMT() ) { m_bestModeCostStore[puIndex] = csBest->cost; //cs.cost; } +#endif } csTemp->releaseIntermediateData(); @@ -1048,7 +1062,9 @@ void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, { const UnitArea &currArea = partitioner.currArea(); TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType ); +#if !JVET_M0464_UNI_MTS CodingUnit &currCU = *currTU.cu; +#endif uint32_t currDepth = partitioner.currTrDepth; const bool subdiv = currTU.depth > currDepth; @@ -1081,7 +1097,9 @@ void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, if (subdiv) { +#if !JVET_M0464_UNI_MTS if( currDepth == 0 && bLuma ) m_CABACEstimator->emt_cu_flag( currCU ); +#endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) { @@ -1099,8 +1117,9 @@ void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, } else { +#if !JVET_M0464_UNI_MTS if( currDepth == 0 && bLuma && TU::getCbfAtDepth( currTU, COMPONENT_Y, 0 ) ) m_CABACEstimator->emt_cu_flag( currCU ); - +#endif //===== Cbfs ===== if (bLuma) { @@ -1185,7 +1204,11 @@ uint64_t IntraSearch::xGetIntraFracBitsQTChroma(TransformUnit& currTU, const Com return fracBits; } +#if JVET_M0464_UNI_MTS +void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2, uint32_t* numSig, std::vector<TrMode>* trModes, const bool loadTr) +#else void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2, uint32_t* numSig ) +#endif { if (!tu.blocks[compID].valid()) { @@ -1280,8 +1303,16 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp m_pcTrQuant->selectLambda(compID); #endif - +#if JVET_M0464_UNI_MTS + if( trModes ) + { + m_pcTrQuant->transformNxN( tu, compID, cQP, trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand() ); + tu.mtsIdx = trModes->at(0).first; + } + m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); +#else m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx()); +#endif DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), compID, uiAbsSum ); @@ -1322,8 +1353,10 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &partitioner ) { const UnitArea &currArea = partitioner.currArea(); +#if !JVET_M0464_UNI_MTS const CodingUnit &cu = *cs.getCU(currArea.lumaPos(), partitioner.chType); - uint32_t currDepth = partitioner.currTrDepth; +#endif + uint32_t currDepth = partitioner.currTrDepth; const PPS &pps = *cs.pps; const bool keepResi = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() || KEEP_PRED_AND_RESI_SIGNALS; bool bCheckFull = true; @@ -1333,6 +1366,12 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par uint32_t numSig = 0; +#if JVET_M0464_UNI_MTS + double dSingleCost = MAX_DOUBLE; + Distortion uiSingleDistLuma = 0; + uint64_t singleFracBits = 0; + int bestModeId[MAX_NUM_COMPONENT] = { 0, 0, 0 }; +#else bool checkInitTrDepth = false, checkInitTrDepthTransformSkipWinner = false; double dSingleCost = MAX_DOUBLE; @@ -1344,6 +1383,7 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par bool isAllIntra = m_pcEncCfg->getIntraPeriod() == 1; uint8_t numTransformIndexCands = nNumTransformCands; +#endif const TempCtx ctxStart ( m_CtxCache, m_CABACEstimator->getCtx() ); TempCtx ctxBest ( m_CtxCache ); @@ -1367,6 +1407,26 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par TransformUnit &tu = csFull->addTU( CS::getArea( *csFull, currArea, partitioner.chType ), partitioner.chType ); tu.depth = currDepth; +#if JVET_M0464_UNI_MTS + const bool tsAllowed = TU::isTSAllowed ( tu, COMPONENT_Y ); + const bool mtsAllowed = TU::isMTSAllowed( tu, COMPONENT_Y ); + uint8_t nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests + std::vector<TrMode> trModes; + trModes.push_back( TrMode( 0, true ) ); //DCT2 + if( tsAllowed ) + { + trModes.push_back( TrMode( 1, true ) ); + } + if( mtsAllowed ) + { + for( int i = 2; i < 6; i++ ) + { + trModes.push_back( TrMode( i, true) ); + } + } + + CHECK( !tu.Y().valid(), "Invalid TU" ); +#else checkTransformSkip &= TU::hasTransformSkipFlag( *tu.cs, tu.Y() ); checkTransformSkip &= !cu.transQuantBypass; checkTransformSkip &= !cu.emtFlag; @@ -1378,6 +1438,7 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par CHECK( checkInitTrDepthTransformSkipWinner && !checkTransformSkip, "Transform Skip must be enabled if it was the winner in the previous call of xRecurIntraCodingLumaQT!" ); +#endif CodingStructure &saveCS = *m_pSaveCS[0]; @@ -1388,9 +1449,14 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par double singleCostTmp = 0; int firstCheckId = 0; +#if JVET_M0464_UNI_MTS + int lastCheckId = trModes[nNumTransformCands-1].first; + bool isNotOnlyOneMode = nNumTransformCands != 1; +#else //we add the EMT candidates to the loop. TransformSkip will still be the last one to be checked (when modeId == lastCheckId) as long as checkTransformSkip is true int lastCheckId = numTransformIndexCands - ( firstCheckId + 1 ) + ( int ) checkTransformSkip; bool isNotOnlyOneMode = lastCheckId != firstCheckId && !checkInitTrDepthTransformSkipWinner; +#endif if( isNotOnlyOneMode ) { @@ -1401,9 +1467,25 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par tmpTU = &saveCS.addTU(currArea, partitioner.chType); } +#if JVET_M0464_UNI_MTS + bool cbfDCT2 = true; +#else bool cbfBestMode = false; +#endif - +#if JVET_M0464_UNI_MTS + for( int modeId = firstCheckId; modeId < nNumTransformCands; modeId++ ) + { + if( !cbfDCT2 || ( m_pcEncCfg->getUseTransformSkipFast() && bestModeId[COMPONENT_Y] == 1 ) ) + { + break; + } + if( !trModes[modeId].second ) + { + continue; + } + tu.mtsIdx = trModes[modeId].first; +#else for( int modeId = firstCheckId; modeId <= lastCheckId; modeId++ ) { if( checkInitTrDepthTransformSkipWinner ) @@ -1426,6 +1508,7 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par continue; } } +#endif if ((modeId != firstCheckId) && isNotOnlyOneMode) { @@ -1435,7 +1518,11 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par int default0Save1Load2 = 0; singleDistTmpLuma = 0; +#if JVET_M0464_UNI_MTS + if( modeId == firstCheckId && nNumTransformCands > 1 ) +#else if (modeId == firstCheckId && modeId != lastCheckId && !checkInitTrDepthTransformSkipWinner ) +#endif { default0Save1Load2 = 1; } @@ -1443,7 +1530,26 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par { default0Save1Load2 = 2; } - +#if JVET_M0464_UNI_MTS + if( nNumTransformCands > 1 ) + { + xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig, modeId == 0 ? &trModes : nullptr, true ); + if( modeId == 0 ) + { + for( int i = 0; i < nNumTransformCands; i++ ) + { + if( trModes[i].second ) + { + lastCheckId = trModes[i].first; + } + } + } + } + else + { + xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig ); + } +#else if (cu.emtFlag) { tu.emtIdx = transformIndex; @@ -1458,10 +1564,15 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par } xIntraCodingTUBlock( tu, COMPONENT_Y, false, singleDistTmpLuma, default0Save1Load2, &numSig ); +#endif //----- determine rate and r-d cost ----- +#if JVET_M0464_UNI_MTS + if( ( trModes[modeId].first != 0 && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) ) ) +#else //the condition (transformIndex != DCT2_EMT) seems to be irrelevant, since DCT2_EMT=7 and the highest value of transformIndex is 4 if( ( modeId == lastCheckId && checkTransformSkip && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) ) ) +#endif { //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. singleCostTmp = MAX_DOUBLE; @@ -1478,9 +1589,16 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par uiSingleDistLuma = singleDistTmpLuma; singleFracBits = singleTmpFracBits; +#if JVET_M0464_UNI_MTS + bestModeId[COMPONENT_Y] = trModes[modeId].first; + if( trModes[modeId].first == 0 ) + { + cbfDCT2 = TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ); + } +#else bestModeId[COMPONENT_Y] = modeId; cbfBestMode = TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ); - +#endif if( bestModeId[COMPONENT_Y] != lastCheckId ) { @@ -1604,7 +1722,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition TransformUnit &currTU = *cs.getTU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA ); const PredictionUnit &pu = *cs.getPU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA ); +#if !JVET_M0464_UNI_MTS const TransformUnit &currTULuma = CS::isDualITree( cs ) ? *cs.picture->cs->getTU( currArea.lumaPos(), CHANNEL_TYPE_LUMA ) : currTU; +#endif uint32_t currDepth = partitioner.currTrDepth; const PPS &pps = *cs.pps; @@ -1617,6 +1737,7 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition return cbfs; } +#if !JVET_M0464_UNI_MTS bool checkTransformSkip = pps.getUseTransformSkip(); checkTransformSkip &= TU::hasTransformSkipFlag( *currTU.cs, partitioner.currArea().Cb() ); @@ -1638,6 +1759,7 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition checkTransformSkip &= ( nbLumaSkip > 0 ); } } +#endif CodingStructure &saveCS = *m_pSaveCS[1]; saveCS.pcv = cs.pcv; @@ -1666,8 +1788,12 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition const bool checkCrossComponentPrediction = PU::isChromaIntraModeCrossCheckMode( pu ) && pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && TU::getCbf( currTU, COMPONENT_Y ); const int crossCPredictionModesToTest = checkCrossComponentPrediction ? 2 : 1; +#if JVET_M0464_UNI_MTS + const int totalModesToTest = crossCPredictionModesToTest; +#else const int transformSkipModesToTest = checkTransformSkip ? 2 : 1; const int totalModesToTest = crossCPredictionModesToTest * transformSkipModesToTest; +#endif const bool isOneMode = (totalModesToTest == 1); int currModeId = 0; @@ -1681,12 +1807,16 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition ctxStart = m_CABACEstimator->getCtx(); } +#if !JVET_M0464_UNI_MTS for (int transformSkipModeId = 0; transformSkipModeId < transformSkipModesToTest; transformSkipModeId++) +#endif { for (int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++) { currTU.compAlpha [compID] = 0; +#if !JVET_M0464_UNI_MTS currTU.transformSkip[compID] = transformSkipModeId; +#endif currModeId++; @@ -1697,7 +1827,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition { default0Save1Load2 = 0; } +#if JVET_M0464_UNI_MTS + else if (!isOneMode && (crossCPredictionModeId == 0)) +#else else if (!isOneMode && (transformSkipModeId == 0) && (crossCPredictionModeId == 0)) +#endif { default0Save1Load2 = 1; //save prediction on first mode } @@ -1715,7 +1849,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition xIntraCodingTUBlock( currTU, compID, crossCPredictionModeId != 0, singleDistCTmp, default0Save1Load2 ); +#if JVET_M0464_UNI_MTS + if( ( ( crossCPredictionModeId == 1 ) && ( currTU.compAlpha[compID] == 0 ) ) ) //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. +#else if( ( ( crossCPredictionModeId == 1 ) && ( currTU.compAlpha[compID] == 0 ) ) || ( ( transformSkipModeId == 1 ) && !TU::getCbf( currTU, compID ) ) ) //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. +#endif { singleCostTmp = MAX_DOUBLE; } diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 92448ab87457a0f0ef76183f100679f7adef3e60..3c1ce2b8137592b7a868bf67ed1d2ee70c9b9003 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -75,10 +75,12 @@ private: CodingStructure **m_pSaveCS; //cost variables for the EMT algorithm and new modes list +#if !JVET_M0464_UNI_MTS double m_bestModeCostStore[4]; // RD cost of the best mode for each PU using DCT2 double m_modeCostStore [4][NUM_LUMA_MODE]; // RD cost of each mode for each PU using DCT2 uint32_t m_savedRdModeList [4][NUM_LUMA_MODE], m_savedNumRdModes[4]; int m_savedExtendRefList[4][NUM_LUMA_MODE]; +#endif protected: // interface to option @@ -142,7 +144,11 @@ protected: void xEncCoeffQT (CodingStructure &cs, Partitioner& pm, const ComponentID &compID); +#if JVET_M0464_UNI_MTS + void xIntraCodingTUBlock (TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2 = 0, uint32_t* numSig = nullptr, std::vector<TrMode>* trModes=nullptr, const bool loadTr=false ); +#else void xIntraCodingTUBlock (TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2 = 0, uint32_t* numSig = nullptr ); +#endif ChromaCbfs xRecurIntraChromaCodingQT (CodingStructure &cs, Partitioner& pm); diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index cbb7bbdc2b005623228053b7ad74defad7fa7256..410a9dededdc5e40821cbb26e07a9a5bc63b84e3 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -534,8 +534,13 @@ void HLSWriter::codeSPSNext( const SPSNext& spsNext, const bool usePCM ) WRITE_FLAG( spsNext.getUseBIO() ? 1 : 0, "bio_enable_flag" ); WRITE_FLAG( spsNext.getDisableMotCompress() ? 1 : 0, "disable_motion_compression_flag" ); WRITE_FLAG( spsNext.getUseLMChroma() ? 1 : 0, "lm_chroma_enabled_flag" ); +#if JVET_M0464_UNI_MTS + WRITE_FLAG( spsNext.getUseIntraMTS() ? 1 : 0, "mts_intra_enabled_flag" ); + WRITE_FLAG( spsNext.getUseInterMTS() ? 1 : 0, "mts_inter_enabled_flag" ); +#else WRITE_FLAG( spsNext.getUseIntraEMT() ? 1 : 0, "emt_intra_enabled_flag" ); WRITE_FLAG( spsNext.getUseInterEMT() ? 1 : 0, "emt_inter_enabled_flag" ); +#endif WRITE_FLAG( spsNext.getUseAffine() ? 1 : 0, "affine_flag" ); if ( spsNext.getUseAffine() ) {