diff --git a/cfg/encoder_intra_vtm.cfg b/cfg/encoder_intra_vtm.cfg index 63f1575885fcb22d75a55a17d30f43f5bb6f7de9..3e8c0359aaca510e07a7ac40ffcc935c2b1ff8c3 100644 --- a/cfg/encoder_intra_vtm.cfg +++ b/cfg/encoder_intra_vtm.cfg @@ -111,6 +111,7 @@ LMCSSignalType : 0 # Input signal type: 0:SDR, 1:HDR-PQ, 2:HD LMCSUpdateCtrl : 1 # LMCS model update control: 0:RA, 1:AI, 2:LDB/LDP MIP : 1 JointCbCr : 1 # joint coding of chroma residuals (if available): 0: disable, 1: enable +ChromaTS : 1 # Fast tools PBIntraFast : 1 diff --git a/cfg/encoder_lowdelay_P_vtm.cfg b/cfg/encoder_lowdelay_P_vtm.cfg index 9ec4a5d13cf00e9d8e1da1bfc47971a6f37dc64c..b869fd5292eef9b34290351c5eb17f5be4323942 100644 --- a/cfg/encoder_lowdelay_P_vtm.cfg +++ b/cfg/encoder_lowdelay_P_vtm.cfg @@ -133,6 +133,7 @@ MIP : 1 JointCbCr : 1 # joint coding of chroma residuals (if available): 0: disable, 1: enable PROF : 1 PPSorSliceMode : 3 +ChromaTS : 1 # Fast tools PBIntraFast : 1 diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg index c8899e2e74339001db4bce7515fd2c23997dd3a0..932df208e69b4adaf221b49d621ee10eb93e45cd 100644 --- a/cfg/encoder_lowdelay_vtm.cfg +++ b/cfg/encoder_lowdelay_vtm.cfg @@ -137,6 +137,7 @@ MIP : 1 JointCbCr : 1 # joint coding of chroma residuals (if available): 0: disable, 1: enable PROF : 1 PPSorSliceMode : 2 +ChromaTS : 1 # Fast tools PBIntraFast : 1 diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index e11813ba3f1e9f7352d753f5ff48ca0db0e1bfe4..c3b70fe2b03a4e986411e633b68e2f7adb0a8c2a 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -165,6 +165,7 @@ AMaxBT : 1 FastMIP : 0 FastLFNST : 0 FastLocalDualTreeMode : 1 +ChromaTS : 1 # Encoder optimization tools AffineAmvrEncOpt : 1 diff --git a/doc/software-manual.tex b/doc/software-manual.tex index a1b8bafe51948657d19759eedcce6c6a7d3297c1..b98ab091cd0955c1333b1086d09cddee49ef2c64 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -2220,6 +2220,16 @@ luma TUs are also skipped. This option has no effect if TransformSkip is disabled. \\ +\Option{ChromaTS} & +%\ShortOption{\None} & +\Default{false} & +Enables or disables reduced testing of the transform-skipping mode +decision for chroma TUs. When disabled, no RDO search is performed for +chroma TUs. +\par +This option has no effect if TransformSkip is disabled. +\\ + \Option{UseNonLinearAlfLuma} & %\ShortOption{\None} & \Default{true} & diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index a7ebf95d8e3f941f8fd694102fe2773f4e4624e0..2a971fe45f8bb9c86016d18d287d3671aabd898d 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -370,6 +370,9 @@ void EncApp::xInitLibCfg() m_cEncLib.setLog2SaoOffsetScale ( CHANNEL_TYPE_CHROMA, m_log2SaoOffsetScale[CHANNEL_TYPE_CHROMA] ); m_cEncLib.setUseTransformSkip ( m_useTransformSkip ); m_cEncLib.setUseTransformSkipFast ( m_useTransformSkipFast ); +#if JVET_P0058_CHROMA_TS + m_cEncLib.setUseChromaTS ( m_useChromaTS && m_useTransformSkip); +#endif m_cEncLib.setUseBDPCM ( m_useBDPCM ); m_cEncLib.setTransformSkipRotationEnabledFlag ( m_transformSkipRotationEnabledFlag ); m_cEncLib.setTransformSkipContextEnabledFlag ( m_transformSkipContextEnabledFlag ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index ba71af2acfa0904126166a5db36fb3a5cfc9b36a..4ac5792b0078a18320d3234d1fdf0ee194fb647b 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1134,6 +1134,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("TransformSkip", m_useTransformSkip, false, "Intra transform skipping") ("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)") +#if JVET_P0058_CHROMA_TS + ("ChromaTS", m_useChromaTS, false, "Enable encoder search of chromaTS") +#endif ("BDPCM", m_useBDPCM, false, "BDPCM") ("ISPFast", m_useFastISP, false, "Fast encoder search for ISP") ("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)") @@ -3586,6 +3589,9 @@ void EncAppCfg::xPrintParameter() msg( VERBOSE, "TransformSkip:%d ", m_useTransformSkip ); msg( VERBOSE, "TransformSkipFast:%d ", m_useTransformSkipFast ); msg( VERBOSE, "TransformSkipLog2MaxSize:%d ", m_log2MaxTransformSkipBlockSize); +#if JVET_P0058_CHROMA_TS + msg(VERBOSE, "ChromaTS:%d ", m_useChromaTS); +#endif msg( VERBOSE, "BDPCM:%d ", m_useBDPCM ); msg( VERBOSE, "Slice: M=%d ", int(m_sliceMode)); if (m_sliceMode!=NO_SLICES) diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 267c895f257277da34cec92bcbc2407e70f70038..7ae720a425c416bf519505bc42eb4228a4d18a1e 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -305,6 +305,9 @@ protected: int m_MmvdDisNum; unsigned m_PLTMode; bool m_JointCbCrMode; +#if JVET_P0058_CHROMA_TS + bool m_useChromaTS; +#endif unsigned m_IBCMode; unsigned m_IBCLocalSearchRangeX; unsigned m_IBCLocalSearchRangeY; diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index 217bf1b732cb5b6f70043c81bbca77ab566859f4..f1c33e0b2cf920f8d0dac44cdfee23ecdc66892c 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -68,7 +68,11 @@ CoeffCodingContext::CoeffCodingContext( const TransformUnit& tu, ComponentID com , m_lastOffsetY (0) , m_lastShiftX (0) , m_lastShiftY (0) +#if JVET_P0058_CHROMA_TS + , m_TrafoBypass (tu.cs->sps->getSpsRangeExtension().getTransformSkipContextEnabledFlag() && (tu.cu->transQuantBypass || tu.mtsIdx[m_compID] == MTS_SKIP)) +#else , m_TrafoBypass (tu.cs->sps->getSpsRangeExtension().getTransformSkipContextEnabledFlag() && (tu.cu->transQuantBypass || tu.mtsIdx==MTS_SKIP)) +#endif , m_scanPosLast (-1) , m_subSetId (-1) , m_subSetPos (-1) diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index a1037dbdc891af452afd4086058d72bc4780632d..b8a593afdc0659e1d7c983f608ddea9004dec4d5 100755 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -735,10 +735,17 @@ const CtxSet ContextSetCfg::RdpcmDir = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::MTSIndex = ContextSetCfg::addCtxSet ({ +#if JVET_P0058_CHROMA_TS + { 29, CNU, CNU, CNU, CNU, CNU, 33, 18, 27, 0, CNU, CNU }, + { 29, CNU, CNU, CNU, CNU, CNU, 18, 33, 27, 0, CNU, CNU }, + { 20, CNU, CNU, CNU, CNU, CNU, 33, 0, 42, 0, CNU, CNU }, + { 8, DWS, DWS, DWS, DWS, DWS, 1, 0, 9, 0, DWS, 1 }, +#else { 29, CNU, CNU, CNU, CNU, CNU, 33, 18, 27, 0, CNU, }, { 29, CNU, CNU, CNU, CNU, CNU, 18, 33, 27, 0, CNU, }, { 20, CNU, CNU, CNU, CNU, CNU, 33, 0, 42, 0, CNU, }, { 8, DWS, DWS, DWS, DWS, DWS, 1, 0, 9, 0, DWS, }, +#endif }); const CtxSet ContextSetCfg::ISPMode = ContextSetCfg::addCtxSet diff --git a/source/Lib/CommonLib/DepQuant.cpp b/source/Lib/CommonLib/DepQuant.cpp index ce6484410b4b14e5f97b64e00fcdffa3aa1b1769..8cb1c93d6eff6abe774888f2c6cd9c8fd9610ae6 100644 --- a/source/Lib/CommonLib/DepQuant.cpp +++ b/source/Lib/CommonLib/DepQuant.cpp @@ -667,7 +667,12 @@ namespace DQIntern { CHECKD( lambda <= 0.0, "Lambda must be greater than 0" ); +#if JVET_P0058_CHROMA_TS + const int qpDQ = cQP.Qp(tu.mtsIdx[compID] == MTS_SKIP) + 1; +#else const int qpDQ = cQP.Qp(tu.mtsIdx==MTS_SKIP && isLuma(compID)) + 1; + +#endif const int qpPer = qpDQ / 6; const int qpRem = qpDQ - 6 * qpPer; const SPS& sps = *tu.cs->sps; @@ -676,7 +681,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_P0058_CHROMA_TS + const bool clipTransformShift = ( tu.mtsIdx[compID] == MTS_SKIP && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag()); +#else const bool clipTransformShift = ( tu.mtsIdx==MTS_SKIP && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag() ); +#endif const bool needsSqrt2ScaleAdjustment = TU::needsSqrt2Scale(tu, compID); const int transformShift = ( clipTransformShift ? std::max<int>( 0, nomTransformShift ) : nomTransformShift ) + (needsSqrt2ScaleAdjustment?-1:0); // quant parameters @@ -732,7 +741,11 @@ namespace DQIntern } //----- set dequant parameters ----- +#if JVET_P0058_CHROMA_TS + const int qpDQ = cQP.Qp(tu.mtsIdx[compID] == MTS_SKIP) + 1; +#else const int qpDQ = cQP.Qp(tu.mtsIdx==MTS_SKIP && isLuma(compID)) + 1; +#endif const int qpPer = qpDQ / 6; const int qpRem = qpDQ - 6 * qpPer; const SPS& sps = *tu.cs->sps; @@ -742,7 +755,11 @@ namespace DQIntern const TCoeff minTCoeff = -( 1 << maxLog2TrDynamicRange ); const TCoeff maxTCoeff = ( 1 << maxLog2TrDynamicRange ) - 1; const int nomTransformShift = getTransformShift( channelBitDepth, area.size(), maxLog2TrDynamicRange ); +#if JVET_P0058_CHROMA_TS + const bool clipTransformShift = ( tu.mtsIdx[compID] == MTS_SKIP && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag()); +#else const bool clipTransformShift = ( tu.mtsIdx==MTS_SKIP && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag() ); +#endif const bool needsSqrt2ScaleAdjustment = TU::needsSqrt2Scale(tu, compID); const int transformShift = ( clipTransformShift ? std::max<int>( 0, nomTransformShift ) : nomTransformShift ) + (needsSqrt2ScaleAdjustment?-1:0); Intermediate_Int shift = IQUANT_SHIFT + 1 - qpPer - transformShift + (enableScalingLists ? LOG2_SCALING_LIST_NEUTRAL_VALUE : 0); @@ -1469,7 +1486,11 @@ namespace DQIntern bool zeroOut = false; bool zeroOutforThres = false; int effWidth = tuPars.m_width, effHeight = tuPars.m_height; +#if JVET_P0058_CHROMA_TS + if( ( tu.mtsIdx[compID] > MTS_SKIP || (tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tuPars.m_height <= 32 && tuPars.m_width <= 32)) && !tu.cu->transQuantBypass && compID == COMPONENT_Y) +#else if( ( tu.mtsIdx > MTS_SKIP || ( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tuPars.m_height <= 32 && tuPars.m_width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif { effHeight = (tuPars.m_height == 32) ? 16 : tuPars.m_height; effWidth = (tuPars.m_width == 32) ? 16 : tuPars.m_width; @@ -1478,7 +1499,11 @@ namespace DQIntern zeroOutforThres = zeroOut || (32 < tuPars.m_height || 32 < tuPars.m_width); //===== find first test position ===== int firstTestPos = numCoeff - 1; +#if JVET_P0058_CHROMA_TS + if (lfnstIdx > 0 && tu.mtsIdx[compID] != MTS_SKIP && width >= 4 && height >= 4) +#else if( lfnstIdx > 0 && tu.mtsIdx != MTS_SKIP && width >= 4 && height >= 4 ) +#endif { firstTestPos = ( ( width == 4 && height == 4 ) || ( width == 8 && height == 8 ) ) ? 7 : 15 ; } @@ -1583,10 +1608,18 @@ DepQuant::~DepQuant() void DepQuant::quant( TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pSrc, TCoeff &uiAbsSum, const QpParam &cQP, const Ctx& ctx ) { - if( tu.cs->slice->getDepQuantEnabledFlag() && (tu.mtsIdx != MTS_SKIP || !isLuma(compID)) ) +#if JVET_P0058_CHROMA_TS + if ( tu.cs->slice->getDepQuantEnabledFlag() && (tu.mtsIdx[compID] != MTS_SKIP) ) +#else + if ( tu.cs->slice->getDepQuantEnabledFlag() && (tu.mtsIdx != MTS_SKIP || !isLuma(compID)) ) +#endif { //===== scaling matrix ==== +#if JVET_P0058_CHROMA_TS + const int qpDQ = cQP.Qp(tu.mtsIdx[compID] == MTS_SKIP) + 1; +#else const int qpDQ = cQP.Qp(tu.mtsIdx==MTS_SKIP && isLuma(compID)) + 1; +#endif const int qpPer = qpDQ / 6; const int qpRem = qpDQ - 6 * qpPer; const CompArea &rect = tu.blocks[compID]; @@ -1596,7 +1629,11 @@ void DepQuant::quant( TransformUnit &tu, const ComponentID &compID, const CCoeff CHECK(scalingListType >= SCALING_LIST_NUM, "Invalid scaling list"); const uint32_t log2TrWidth = floorLog2(width); const uint32_t log2TrHeight = floorLog2(height); +#if JVET_P0058_CHROMA_TS + const bool enableScalingLists = getUseScalingList(width, height, (tu.mtsIdx[compID] == MTS_SKIP)); +#else const bool enableScalingLists = getUseScalingList(width, height, (tu.mtsIdx == MTS_SKIP && isLuma(compID))); +#endif static_cast<DQIntern::DepQuant*>(p)->quant( tu, pSrc, compID, cQP, Quant::m_dLambda, ctx, uiAbsSum, enableScalingLists, Quant::getQuantCoeff(scalingListType, qpRem, log2TrWidth, log2TrHeight) ); } else @@ -1607,9 +1644,17 @@ void DepQuant::quant( TransformUnit &tu, const ComponentID &compID, const CCoeff void DepQuant::dequant( const TransformUnit &tu, CoeffBuf &dstCoeff, const ComponentID &compID, const QpParam &cQP ) { +#if JVET_P0058_CHROMA_TS + if( tu.cs->slice->getDepQuantEnabledFlag() && (tu.mtsIdx[compID] != MTS_SKIP)) +#else if( tu.cs->slice->getDepQuantEnabledFlag() && (tu.mtsIdx != MTS_SKIP || !isLuma(compID)) ) +#endif { +#if JVET_P0058_CHROMA_TS + const int qpDQ = cQP.Qp(tu.mtsIdx[compID] == MTS_SKIP) + 1; +#else const int qpDQ = cQP.Qp(tu.mtsIdx==MTS_SKIP && isLuma(compID)) + 1; +#endif const int qpPer = qpDQ / 6; const int qpRem = qpDQ - 6 * qpPer; const CompArea &rect = tu.blocks[compID]; @@ -1619,8 +1664,11 @@ void DepQuant::dequant( const TransformUnit &tu, CoeffBuf &dstCoeff, const Compo CHECK(scalingListType >= SCALING_LIST_NUM, "Invalid scaling list"); const uint32_t log2TrWidth = floorLog2(width); const uint32_t log2TrHeight = floorLog2(height); - +#if JVET_P0058_CHROMA_TS + const bool enableScalingLists = getUseScalingList(width, height, (tu.mtsIdx[compID] == MTS_SKIP)); +#else const bool enableScalingLists = getUseScalingList(width, height, (tu.mtsIdx == MTS_SKIP && isLuma(compID))); +#endif static_cast<DQIntern::DepQuant*>(p)->dequant( tu, dstCoeff, compID, cQP, enableScalingLists, Quant::getDequantCoeff(scalingListType, qpRem, log2TrWidth, log2TrHeight) ); } else diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp index 0264a6055aaf2657ba4853f4865a5bef7c5debbd..45b2dcee4f243ea864d63a23935cc7eb89ef7a31 100644 --- a/source/Lib/CommonLib/Quant.cpp +++ b/source/Lib/CommonLib/Quant.cpp @@ -369,7 +369,11 @@ void Quant::dequant(const TransformUnit &tu, const int maxLog2TrDynamicRange = sps->getMaxLog2TrDynamicRange(toChannelType(compID)); const TCoeff transformMinimum = -(1 << maxLog2TrDynamicRange); const TCoeff transformMaximum = (1 << maxLog2TrDynamicRange) - 1; +#if JVET_P0058_CHROMA_TS + const bool isTransformSkip = (tu.mtsIdx[compID] == MTS_SKIP); +#else const bool isTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID); +#endif const bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, isTransformSkip); const int scalingListType = getScalingListType(tu.cu->predMode, compID); const int channelBitDepth = sps->getBitDepth(toChannelType(compID)); @@ -389,7 +393,11 @@ void Quant::dequant(const TransformUnit &tu, CHECK(uiWidth > m_uiMaxTrSize, "Unsupported transformation size"); // Represents scaling through forward transform +#if JVET_P0058_CHROMA_TS + const bool bClipTransformShiftTo0 = tu.mtsIdx[compID] != MTS_SKIP && sps->getSpsRangeExtension().getExtendedPrecisionProcessingFlag(); +#else const bool bClipTransformShiftTo0 = tu.mtsIdx!=MTS_SKIP && sps->getSpsRangeExtension().getExtendedPrecisionProcessingFlag(); +#endif const int originalTransformShift = getTransformShift(channelBitDepth, area.size(), maxLog2TrDynamicRange); const bool needSqrtAdjustment = TU::needsBlockSizeTrafoScale( tu, compID ); const int iTransformShift = (bClipTransformShiftTo0 ? std::max<int>(0, originalTransformShift) : originalTransformShift) + (needSqrtAdjustment?-1:0); @@ -932,7 +940,11 @@ void Quant::quant(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf const CCoeffBuf &piCoef = pSrc; CoeffBuf piQCoef = tu.getCoeffs(compID); +#if JVET_P0058_CHROMA_TS + const bool useTransformSkip = (tu.mtsIdx[compID] == MTS_SKIP); +#else const bool useTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID); +#endif const int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange(toChannelType(compID)); { @@ -1012,7 +1024,11 @@ bool Quant::xNeedRDOQ(TransformUnit &tu, const ComponentID &compID, const CCoeff const CCoeffBuf piCoef = pSrc; +#if JVET_P0058_CHROMA_TS + const bool useTransformSkip = (tu.mtsIdx[compID] == MTS_SKIP); +#else const bool useTransformSkip = tu.mtsIdx == MTS_SKIP && isLuma(compID); +#endif const int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange(toChannelType(compID)); int scalingListType = getScalingListType(tu.cu->predMode, compID); @@ -1072,7 +1088,11 @@ void Quant::transformSkipQuantOneSample(TransformUnit &tu, const ComponentID &co const int iTransformShift = getTransformShift(channelBitDepth, rect.size(), maxLog2TrDynamicRange); const int scalingListType = getScalingListType(tu.cu->predMode, compID); const bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, true); +#if JVET_P0058_CHROMA_TS + const bool useTransformSkip = (tu.mtsIdx[compID] == MTS_SKIP); +#else const bool useTransformSkip = tu.mtsIdx == MTS_SKIP && isLuma(compID); +#endif const int defaultQuantisationCoefficient = g_quantScales[0][cQP.rem(useTransformSkip)]; CHECK( scalingListType >= SCALING_LIST_NUM, "Invalid scaling list" ); @@ -1124,8 +1144,13 @@ void Quant::invTrSkipDeQuantOneSample(TransformUnit &tu, const ComponentID &comp const CompArea &rect = tu.blocks[compID]; const uint32_t uiWidth = rect.width; const uint32_t uiHeight = rect.height; +#if JVET_P0058_CHROMA_TS + const int QP_per = cQP.per(tu.mtsIdx[compID] == MTS_SKIP); + const int QP_rem = cQP.rem(tu.mtsIdx[compID] == MTS_SKIP); +#else const int QP_per = cQP.per(tu.mtsIdx==MTS_SKIP && isLuma(compID)); const int QP_rem = cQP.rem(tu.mtsIdx==MTS_SKIP && isLuma(compID)); +#endif const int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange(toChannelType(compID)); const int channelBitDepth = sps.getBitDepth(toChannelType(compID)); const int iTransformShift = getTransformShift(channelBitDepth, rect.size(), maxLog2TrDynamicRange); diff --git a/source/Lib/CommonLib/QuantRDOQ.cpp b/source/Lib/CommonLib/QuantRDOQ.cpp index e72c83a866e6d92351b9580d06fac4d1a3877894..ff150c610b2aa4ba2c3a4b61c00dc9701a9f51c1 100644 --- a/source/Lib/CommonLib/QuantRDOQ.cpp +++ b/source/Lib/CommonLib/QuantRDOQ.cpp @@ -520,7 +520,11 @@ void QuantRDOQ::quant(TransformUnit &tu, const ComponentID &compID, const CCoeff const CCoeffBuf &piCoef = pSrc; CoeffBuf piQCoef = tu.getCoeffs(compID); +#if JVET_P0058_CHROMA_TS + const bool useTransformSkip = (tu.mtsIdx[compID] == MTS_SKIP); +#else const bool useTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID); +#endif bool useRDOQ = useTransformSkip ? m_useRDOQTS : m_useRDOQ; @@ -536,7 +540,11 @@ void QuantRDOQ::quant(TransformUnit &tu, const ComponentID &compID, const CCoeff if (!m_useSelectiveRDOQ || xNeedRDOQ(tu, compID, piCoef, cQP)) { #endif +#if JVET_P0058_CHROMA_TS + if( useTransformSkip ) +#else if( isLuma( compID ) && useTransformSkip ) +#endif { if( tu.cu->bdpcmMode && isLuma(compID) ) { @@ -592,7 +600,11 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, // Represents scaling through forward transform int iTransformShift = getTransformShift(channelBitDepth, rect.size(), maxLog2TrDynamicRange); +#if JVET_P0058_CHROMA_TS + if (tu.mtsIdx[compID] == MTS_SKIP && extendedPrecision) +#else if (tu.mtsIdx==MTS_SKIP && extendedPrecision) +#endif { iTransformShift = std::max<int>(0, iTransformShift); } @@ -629,7 +641,11 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, const bool needSqrtAdjustment= TU::needsBlockSizeTrafoScale( tu, compID ); +#if JVET_P0058_CHROMA_TS + const bool isTransformSkip = (tu.mtsIdx[compID] == MTS_SKIP); +#else const bool isTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID); +#endif const double *const pdErrScale = xGetErrScaleCoeffSL(scalingListType, uiLog2BlockWidth, uiLog2BlockHeight, cQP.rem(isTransformSkip)); const int *const piQCoef = getQuantCoeff(scalingListType, cQP.rem(isTransformSkip), uiLog2BlockWidth, uiLog2BlockHeight); const bool enableScalingLists = getUseScalingList(uiWidth, uiHeight, isTransformSkip); @@ -1220,7 +1236,11 @@ void QuantRDOQ::xRateDistOptQuantTS( TransformUnit &tu, const ComponentID &compI m_bdpcm = 0; const bool needsSqrt2Scale = TU::needsSqrt2Scale( tu, compID ); // should always be false - transform-skipped blocks don't require sqrt(2) compensation. +#if JVET_P0058_CHROMA_TS + const bool isTransformSkip = (tu.mtsIdx[compID] == MTS_SKIP); +#else const bool isTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID); +#endif const int qBits = QUANT_SHIFT + qp.per(isTransformSkip) + transformShift + ( needsSqrt2Scale ? -1 : 0 ); // Right shift of non-RDOQ quantizer; level = (coeff*uiQ + offset)>>q_bits const int quantisationCoefficient = g_quantScales[needsSqrt2Scale?1:0][qp.rem(isTransformSkip)]; const double errorScale = xGetErrScaleCoeff( TU::needsSqrt2Scale( tu, compID ), width, height, qp.rem(isTransformSkip), maxLog2TrDynamicRange, channelBitDepth ); @@ -1456,7 +1476,11 @@ void QuantRDOQ::forwardRDPCM( TransformUnit &tu, const ComponentID &compID, cons m_bdpcm = dirMode; const bool needsSqrt2Scale = TU::needsSqrt2Scale(tu, compID); // should always be false - transform-skipped blocks don't require sqrt(2) compensation. +#if JVET_P0058_CHROMA_TS + const bool isTransformSkip = (tu.mtsIdx[compID] == MTS_SKIP); +#else const bool isTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID); +#endif const int qBits = QUANT_SHIFT + qp.per(isTransformSkip) + transformShift + ( needsSqrt2Scale ? -1 : 0 ); // Right shift of non-RDOQ quantizer; level = (coeff*uiQ + offset)>>q_bits const int quantisationCoefficient = g_quantScales[needsSqrt2Scale ? 1 : 0][qp.rem(isTransformSkip)]; const double errorScale = xGetErrScaleCoeff(TU::needsSqrt2Scale(tu, compID), width, height, qp.rem(isTransformSkip), maxLog2TrDynamicRange, channelBitDepth); diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp index 11ecdde1833448b1756b3609ba55a0592e4680f7..51ba7016fdafa50ffca741cd3bb9e74922721e1c 100644 --- a/source/Lib/CommonLib/TrQuant.cpp +++ b/source/Lib/CommonLib/TrQuant.cpp @@ -314,7 +314,11 @@ void TrQuant::xInvLfnst( const TransformUnit &tu, const ComponentID compID ) const uint32_t height = area.height; const uint32_t lfnstIdx = tu.cu->lfnstIdx; +#if JVET_P0058_CHROMA_TS + if (lfnstIdx && tu.mtsIdx[compID] != MTS_SKIP && width >= 4 && height >= 4) +#else if( lfnstIdx && tu.mtsIdx != MTS_SKIP && width >= 4 && height >= 4 ) +#endif { const bool whge3 = width >= 8 && height >= 8; const ScanElement * scan = whge3 ? g_coefTopLeftDiagScan8x8[ gp_sizeIdxInfo->idxFrom( width ) ] : g_scanOrder[ SCAN_GROUPED_4x4 ][ SCAN_DIAG ][ gp_sizeIdxInfo->idxFrom( width ) ][ gp_sizeIdxInfo->idxFrom( height ) ]; @@ -406,7 +410,11 @@ void TrQuant::xFwdLfnst( const TransformUnit &tu, const ComponentID compID, cons const uint32_t height = area.height; const uint32_t lfnstIdx = tu.cu->lfnstIdx; +#if JVET_P0058_CHROMA_TS + if( lfnstIdx && tu.mtsIdx[compID] != MTS_SKIP && width >= 4 && height >= 4) +#else if( lfnstIdx && tu.mtsIdx != MTS_SKIP && width >= 4 && height >= 4 ) +#endif { const bool whge3 = width >= 8 && height >= 8; const ScanElement * scan = whge3 ? g_coefTopLeftDiagScan8x8[ gp_sizeIdxInfo->idxFrom( width ) ] : g_scanOrder[ SCAN_GROUPED_4x4 ][ SCAN_DIAG ][ gp_sizeIdxInfo->idxFrom( width ) ][ gp_sizeIdxInfo->idxFrom( height ) ]; @@ -432,7 +440,11 @@ void TrQuant::xFwdLfnst( const TransformUnit &tu, const ComponentID compID, cons bool tu8x8Flag = ( width == 8 && height == 8 ); TCoeff* lfnstTemp; TCoeff* coeffTemp; +#if JVET_P0058_CHROMA_TS + TCoeff * tempCoeff = loadTr ? m_mtsCoeffs[tu.mtsIdx[compID]] : m_tempCoeff; +#else TCoeff * tempCoeff = loadTr ? m_mtsCoeffs[tu.mtsIdx] : m_tempCoeff; +#endif int y; lfnstTemp = m_tempInMatrix; // forward low frequency non-separable transform @@ -526,7 +538,11 @@ void TrQuant::invTransformNxN( TransformUnit &tu, const ComponentID &compID, Pel xInvLfnst( tu, compID ); } +#if JVET_P0058_CHROMA_TS + if( tu.mtsIdx[compID] == MTS_SKIP ) +#else if( isLuma(compID) && tu.mtsIdx == MTS_SKIP ) +#endif { xITransformSkip( tempCoeff, pResi, tu, compID ); } @@ -545,7 +561,11 @@ void TrQuant::invRdpcmNxN(TransformUnit& tu, const ComponentID &compID, PelBuf & { const CompArea &area = tu.blocks[compID]; +#if JVET_P0058_CHROMA_TS + if (CU::isRDPCMEnabled(*tu.cu) && (tu.mtsIdx[compID] == MTS_SKIP || tu.cu->transQuantBypass)) +#else if (CU::isRDPCMEnabled(*tu.cu) && (tu.mtsIdx==MTS_SKIP || tu.cu->transQuantBypass)) +#endif { const uint32_t uiWidth = area.width; const uint32_t uiHeight = area.height; @@ -740,11 +760,19 @@ void TrQuant::getTrTypes(const TransformUnit tu, const ComponentID compID, int & if (isExplicitMTS) { +#if JVET_P0058_CHROMA_TS + if (tu.mtsIdx[compID] > MTS_SKIP) +#else if (tu.mtsIdx > MTS_SKIP) +#endif { +#if JVET_P0058_CHROMA_TS + int indHor = (tu.mtsIdx[compID] - MTS_DST7_DST7) & 1; + int indVer = (tu.mtsIdx[compID] - MTS_DST7_DST7) >> 1; +#else int indHor = (tu.mtsIdx - MTS_DST7_DST7) & 1; int indVer = (tu.mtsIdx - MTS_DST7_DST7) >> 1; - +#endif trTypeHor = indHor ? DCT8 : DST7; trTypeVer = indVer ? DCT8 : DST7; } @@ -915,6 +943,10 @@ void TrQuant::xITransformSkip(const CCoeffBuf &pCoeff, const int maxLog2TrDynamicRange = tu.cs->sps->getMaxLog2TrDynamicRange(toChannelType(compID)); const int channelBitDepth = tu.cs->sps->getBitDepth(toChannelType(compID)); +#if JVET_P0058_CHROMA_TS && RExt__DECODER_DEBUG_TOOL_STATISTICS + CodingStatistics::IncrementStatisticTool(CodingStatisticsClassType{ STATS__TOOL_EMT, uint32_t(width), uint32_t(height), compID }); +#endif + int iTransformShift = getTransformShift(channelBitDepth, area.size(), maxLog2TrDynamicRange); if( tu.cs->sps->getSpsRangeExtension().getExtendedPrecisionProcessingFlag() ) { @@ -973,8 +1005,16 @@ void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const const double facBB[] = { 1.2, 1.3, 1.3, 1.4, 1.5 }; while( it != trModes->end() ) { +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[compID] = it->first; +#else tu.mtsIdx = it->first; +#endif +#if JVET_P0058_CHROMA_TS + CoeffBuf tempCoeff( m_mtsCoeffs[tu.mtsIdx[compID]], rect); +#else CoeffBuf tempCoeff( m_mtsCoeffs[tu.mtsIdx], rect ); +#endif if( tu.noResidual ) { int sumAbs = 0; @@ -983,7 +1023,11 @@ void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const continue; } +#if JVET_P0058_CHROMA_TS + if ( tu.mtsIdx[compID] == MTS_SKIP ) +#else if( isLuma(compID) && tu.mtsIdx == MTS_SKIP ) +#endif { xTransformSkip( tu, compID, resiBuf, tempCoeff.buf ); } @@ -999,7 +1043,11 @@ void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const } double scaleSAD=1.0; +#if JVET_P0058_CHROMA_TS + if ( tu.mtsIdx[compID] == MTS_SKIP && ((floorLog2(width) + floorLog2(height)) & 1) == 1) +#else if (isLuma(compID) && tu.mtsIdx==MTS_SKIP && ((floorLog2(width) + floorLog2(height)) & 1) == 1 ) +#endif { scaleSAD=1.0/1.414213562; // compensate for not scaling transform skip coefficients by 1/sqrt(2) } @@ -1009,7 +1057,11 @@ void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const int numTests = 0; std::vector<TrCost>::iterator itC = trCosts.begin(); +#if JVET_P0058_CHROMA_TS + const double fac = facBB[std::max(0, floorLog2(std::max(width, height)) - 2)]; +#else const double fac = facBB[floorLog2(std::max(width, height))-2]; +#endif const double thr = fac * trCosts.begin()->first; const double thrTS = trCosts.begin()->first; while( itC != trCosts.end() ) @@ -1044,7 +1096,11 @@ void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const if( tu.cu->bdpcmMode && isLuma(compID) ) { +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[compID] = MTS_SKIP; +#else tu.mtsIdx = MTS_SKIP; +#endif } if (rdpcmMode == RDPCM_OFF) @@ -1080,13 +1136,21 @@ void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const CHECK( cs.sps->getMaxTbSize() < uiWidth, "Unsupported transformation size" ); +#if JVET_P0058_CHROMA_TS + CoeffBuf tempCoeff(loadTr ? m_mtsCoeffs[tu.mtsIdx[compID]] : m_tempCoeff, rect); +#else CoeffBuf tempCoeff(loadTr ? m_mtsCoeffs[tu.mtsIdx] : m_tempCoeff, rect); +#endif DTRACE_PEL_BUF( D_RESIDUALS, resiBuf, tu, tu.cu->predMode, compID ); if( !loadTr ) { +#if JVET_P0058_CHROMA_TS + if ( tu.mtsIdx[compID] == MTS_SKIP ) +#else if( isLuma(compID) && tu.mtsIdx == MTS_SKIP ) +#endif { xTransformSkip( tu, compID, resiBuf, tempCoeff.buf ); } @@ -1174,7 +1238,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_P0058_CHROMA_TS + if (!CU::isRDPCMEnabled(*tu.cu) || (tu.mtsIdx[compID] != MTS_SKIP && !tu.cu->transQuantBypass)) +#else if (!CU::isRDPCMEnabled(*tu.cu) || (tu.mtsIdx!=MTS_SKIP && !tu.cu->transQuantBypass)) +#endif { rdpcmMode = RDPCM_OFF; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index cb17fd390981a6f10d030cbb53a5408ac47e5fe1..93e22e5485d6123ab3ef622bddfa8dbb5fb875a9 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -91,6 +91,11 @@ #define JVET_P0170_ZERO_POS_SIMPLIFICATION 1 // JVET-P0170: Simplification of deriving ZeroPos +#define JVET_P0058_CHROMA_TS 1 // JVET-P0058: Enable Transform skip for chroma +#if JVET_P0058_CHROMA_TS +#define JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD 1 // Modified cost criterion for chroma intra encoder search +#endif + #define JVET_P0436_CQP_OFFSET_SIGNALLING 1 // JVET_P0436: CU chroma QP offset signalling consistent with VPDU and bugfix #define JVET_P0505_ALF_CLIP_VALUE 1 // JVET-P0505: Modified non-linear ALF clipping value derivations diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 05d0035b99eca17823259cdf3571fd9c078c83d0..4b2874848c1270845768df01e0d40798469ca896 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -734,9 +734,14 @@ void TransformUnit::initData() cbf[i] = 0; rdpcm[i] = NUMBER_OF_RDPCM_MODES; compAlpha[i] = 0; +#if JVET_P0058_CHROMA_TS + mtsIdx[i] = MTS_DCT2_DCT2; +#endif } depth = 0; +#if !JVET_P0058_CHROMA_TS mtsIdx = MTS_DCT2_DCT2; +#endif noResidual = false; jointCbCr = 0; m_chromaResScaleInv = 0; @@ -774,9 +779,14 @@ TransformUnit& TransformUnit::operator=(const TransformUnit& other) cbf[i] = other.cbf[i]; rdpcm[i] = other.rdpcm[i]; compAlpha[i] = other.compAlpha[i]; +#if JVET_P0058_CHROMA_TS + mtsIdx[i] = other.mtsIdx[i]; +#endif } depth = other.depth; +#if !JVET_P0058_CHROMA_TS mtsIdx = other.mtsIdx; +#endif noResidual = other.noResidual; jointCbCr = other.jointCbCr; return *this; @@ -800,7 +810,11 @@ void TransformUnit::copyComponentFrom(const TransformUnit& other, const Componen compAlpha[i] = other.compAlpha[i]; depth = other.depth; +#if JVET_P0058_CHROMA_TS + mtsIdx[i] = other.mtsIdx[i]; +#else mtsIdx = isLuma( i ) ? other.mtsIdx : mtsIdx; +#endif noResidual = other.noResidual; jointCbCr = isChroma( i ) ? other.jointCbCr : jointCbCr; } @@ -845,7 +859,11 @@ int TransformUnit::getTbAreaAfterCoefZeroOut(ComponentID compID) const int tbArea = blocks[compID].width * blocks[compID].height; int tbZeroOutWidth = blocks[compID].width; int tbZeroOutHeight = blocks[compID].height; +#if JVET_P0058_CHROMA_TS + if ((mtsIdx[compID] > MTS_SKIP || (cs->sps->getUseMTS() && cu->sbtInfo != 0 && blocks[compID].width <= 32 && blocks[compID].height <= 32)) && !cu->transQuantBypass && compID == COMPONENT_Y) +#else if ((mtsIdx > MTS_SKIP || (cs->sps->getUseMTS() && cu->sbtInfo != 0 && blocks[compID].width <= 32 && blocks[compID].height <= 32)) && !cu->transQuantBypass && compID == COMPONENT_Y) +#endif { tbZeroOutWidth = (blocks[compID].width == 32) ? 16 : tbZeroOutWidth; tbZeroOutHeight = (blocks[compID].height == 32) ? 16 : tbZeroOutHeight; diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 305aa0ac860c465bb0774dee06546cffc3818a2f..1cfc5a798da2558b05a0e82cebc72ba4eff53507 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -463,7 +463,11 @@ struct TransformUnit : public UnitArea int m_chromaResScaleInv; uint8_t depth; +#if JVET_P0058_CHROMA_TS + uint8_t mtsIdx [ MAX_NUM_TBLOCKS ]; +#else uint8_t mtsIdx; +#endif bool noResidual; uint8_t jointCbCr; uint8_t cbf [ MAX_NUM_TBLOCKS ]; diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 2ca98de92fde125f01a050cdd88d5fc8b6488a95..dd49aed52a395140fc5d90784cec7693ebfb7cc8 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -3794,15 +3794,29 @@ void TU::setCbfAtDepth(TransformUnit &tu, const ComponentID &compID, const unsig bool TU::isTSAllowed(const TransformUnit &tu, const ComponentID compID) { +#if !JVET_P0058_CHROMA_TS bool tsAllowed = compID == COMPONENT_Y; +#endif const int maxSize = tu.cs->pps->getLog2MaxTransformSkipBlockSize(); +#if JVET_P0058_CHROMA_TS + bool tsAllowed = tu.cs->sps->getTransformSkipEnabledFlag(); +#else tsAllowed &= tu.cs->sps->getTransformSkipEnabledFlag(); +#endif tsAllowed &= !tu.cu->transQuantBypass; tsAllowed &= ( !tu.cu->ispMode || !isLuma(compID) ); SizeType transformSkipMaxSize = 1 << maxSize; +#if JVET_P0058_CHROMA_TS + tsAllowed &= !(tu.cu->bdpcmMode && isLuma(compID)); +#else tsAllowed &= !(tu.cu->bdpcmMode && tu.lwidth() <= transformSkipMaxSize && tu.lheight() <= transformSkipMaxSize); +#endif +#if JVET_P0058_CHROMA_TS + tsAllowed &= tu.blocks[compID].width <= transformSkipMaxSize && tu.blocks[compID].height <= transformSkipMaxSize; +#else tsAllowed &= tu.lwidth() <= transformSkipMaxSize && tu.lheight() <= transformSkipMaxSize; +#endif tsAllowed &= !tu.cu->sbtInfo; return tsAllowed; @@ -3841,7 +3855,11 @@ bool TU::hasCrossCompPredInfo( const TransformUnit &tu, const ComponentID &compI bool TU::needsSqrt2Scale( const TransformUnit &tu, const ComponentID &compID ) { const Size &size=tu.blocks[compID]; +#if JVET_P0058_CHROMA_TS + const bool isTransformSkip = (tu.mtsIdx[compID] == MTS_SKIP); +#else const bool isTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID); +#endif return (!isTransformSkip) && (((floorLog2(size.width) + floorLog2(size.height)) & 1) == 1); } diff --git a/source/Lib/CommonLib/dtrace_blockstatistics.cpp b/source/Lib/CommonLib/dtrace_blockstatistics.cpp index 350af8f22b00d2070b3859ebb7053c71ae34b9ab..8b4bdab1027a14e1b4f3b0ecfd6276e01940c7bc 100644 --- a/source/Lib/CommonLib/dtrace_blockstatistics.cpp +++ b/source/Lib/CommonLib/dtrace_blockstatistics.cpp @@ -712,13 +712,18 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea) if (tu.Y().valid()) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::Cbf_Y), tu.cbf[COMPONENT_Y]); +#if JVET_P0058_CHROMA_TS + DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::MTSIdx_Y), tu.mtsIdx[COMPONENT_Y]); +#else DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::MTSIdx), tu.mtsIdx); +#endif } if ( tu.Cb().valid() ) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::JointCbCr), tu.jointCbCr); } +#if !JVET_P0058_CHROMA_TS if( !CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && ( tu.mtsIdx==MTS_SKIP || cu.transQuantBypass ) ) { if (tu.Y().valid()) @@ -734,7 +739,7 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea) DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::RDPCM_Cr), tu.rdpcm[COMPONENT_Cr]); } } - +#endif bool lumaOnly = ( cu.chromaFormat == CHROMA_400 || !tu.blocks[COMPONENT_Cb].valid() ); if( !lumaOnly ) { @@ -752,6 +757,10 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea) { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cb), tu.cbf[COMPONENT_Cb]); DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cr), tu.cbf[COMPONENT_Cr]); +#if JVET_P0058_CHROMA_TS + DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::MTSIdx_Cb), tu.mtsIdx[COMPONENT_Cb]); + DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::MTSIdx_Cr), tu.mtsIdx[COMPONENT_Cr]); +#endif } } } @@ -1009,12 +1018,20 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) if (tu.Y().valid()) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::Cbf_Y), tu.cbf[COMPONENT_Y]); +#if JVET_P0058_CHROMA_TS + DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::MTSIdx_Y), tu.mtsIdx[COMPONENT_Y]); +#else DTRACE_BLOCK_SCALAR( g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName( BlockStatistic::MTSIdx ), tu.mtsIdx ); +#endif } if (!(cu.chromaFormat == CHROMA_400 || (cu.isSepTree() && cu.chType == CHANNEL_TYPE_LUMA))) { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cb), tu.cbf[COMPONENT_Cb]); DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cr), tu.cbf[COMPONENT_Cr]); +#if JVET_P0058_CHROMA_TS + DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::MTSIdx_Cb), tu.mtsIdx[COMPONENT_Cb]); + DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::MTSIdx_Cr), tu.mtsIdx[COMPONENT_Cr]); +#endif } } } diff --git a/source/Lib/CommonLib/dtrace_blockstatistics.h b/source/Lib/CommonLib/dtrace_blockstatistics.h index b802f1183fd303c02e654cf27dc3ea139f8600db..18e7a4ba4bc548e61b7b91b6e12082f65f0a2a2d 100644 --- a/source/Lib/CommonLib/dtrace_blockstatistics.h +++ b/source/Lib/CommonLib/dtrace_blockstatistics.h @@ -64,7 +64,13 @@ enum class BlockStatistic { QP, SplitSeries, TransQuantBypassFlag, +#if JVET_P0058_CHROMA_TS + MTSIdx_Y, + MTSIdx_Cb, + MTSIdx_Cr, +#else MTSIdx, +#endif BDPCM, TileIdx, IndependentSliceIdx, @@ -159,7 +165,13 @@ static const std::map<BlockStatistic, std::tuple<std::string, BlockStatisticType { BlockStatistic::Luma_IntraMode, std::tuple<std::string, BlockStatisticType, std::string>{"Luma_IntraMode", BlockStatisticType::Integer, "[0, " + std::to_string(NUM_INTRA_MODE) + "]"}}, { BlockStatistic::Chroma_IntraMode, std::tuple<std::string, BlockStatisticType, std::string>{"Chroma_IntraMode", BlockStatisticType::Integer, "[0, " + std::to_string(NUM_INTRA_MODE) + "]"}}, { BlockStatistic::SkipFlag, std::tuple<std::string, BlockStatisticType, std::string>{"SkipFlag", BlockStatisticType::Flag, ""}}, +#if JVET_P0058_CHROMA_TS + { BlockStatistic::MTSIdx_Y, std::tuple<std::string, BlockStatisticType, std::string> {"MTS_Y", BlockStatisticType::Integer, ""} }, + { BlockStatistic::MTSIdx_Cb, std::tuple<std::string, BlockStatisticType, std::string>{"MTS_Cb", BlockStatisticType::Integer, ""} }, + { BlockStatistic::MTSIdx_Cr, std::tuple<std::string, BlockStatisticType, std::string>{"MTS_Cr", BlockStatisticType::Integer, ""} }, +#else { BlockStatistic::MTSIdx, std::tuple<std::string, BlockStatisticType, std::string>{"TransformSkipFlag_Y", BlockStatisticType::Integer, ""}}, +#endif { BlockStatistic::BDPCM, std::tuple<std::string, BlockStatisticType, std::string>{"BDPCM", BlockStatisticType::Flag, ""}}, // called bdpcmMode, but used like a flag in the software? related to intra, but signalled always? { BlockStatistic::TileIdx, std::tuple<std::string, BlockStatisticType, std::string>{"TileIdx", BlockStatisticType::Integer, ""}}, { BlockStatistic::IndependentSliceIdx, std::tuple<std::string, BlockStatisticType, std::string>{"IndependentSliceIdx", BlockStatisticType::Integer, ""}}, diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index db62d52ddc215410ca27e6470c60f7e4862b373c..71321b20de47fecd3c0253ec760061f3cfde903a 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -2914,7 +2914,11 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID, CUCtx& mts_coding ( tu, compID ); explicit_rdpcm_mode( tu, compID ); +#if JVET_P0058_CHROMA_TS + if( tu.mtsIdx[compID] == MTS_SKIP || (tu.cu->bdpcmMode && isLuma(compID) ) ) +#else if( isLuma( compID ) && ( tu.mtsIdx == MTS_SKIP || tu.cu->bdpcmMode ) ) +#endif { residual_codingTS( tu, compID ); return; @@ -2922,7 +2926,11 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID, CUCtx& // determine sign hiding bool signHiding = ( cu.cs->slice->getSignDataHidingEnabledFlag() && !cu.transQuantBypass && tu.rdpcm[compID] == RDPCM_OFF ); +#if JVET_P0058_CHROMA_TS + if( signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.mtsIdx[compID] == MTS_SKIP ) +#else if( signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.mtsIdx==MTS_SKIP ) +#endif { const ChannelType chType = toChannelType( compID ); const unsigned intraMode = PU::getFinalIntraMode( *cu.cs->getPU( tu.blocks[compID].pos(), chType ), chType ); @@ -2938,12 +2946,20 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID, CUCtx& // parse last coeff position cctx.setScanPosLast( last_sig_coeff( cctx, tu, compID ) ); +#if JVET_P0058_CHROMA_TS + if (tu.mtsIdx[compID] != MTS_SKIP && tu.blocks[compID].height >= 4 && tu.blocks[compID].width >= 4 ) +#else if( tu.mtsIdx != MTS_SKIP && tu.blocks[ compID ].height >= 4 && tu.blocks[ compID ].width >= 4 ) +#endif { const int maxLfnstPos = ((tu.blocks[compID].height == 4 && tu.blocks[compID].width == 4) || (tu.blocks[compID].height == 8 && tu.blocks[compID].width == 8)) ? 7 : 15; cuCtx.violatesLfnstConstrained[ toChannelType(compID) ] |= cctx.scanPosLast() > maxLfnstPos; } +#if JVET_P0058_CHROMA_TS + if( tu.mtsIdx[compID] != MTS_SKIP && tu.blocks[compID].height >= 4 && tu.blocks[compID].width >= 4 ) +#else if( tu.mtsIdx != MTS_SKIP && tu.blocks[ compID ].height >= 4 && tu.blocks[ compID ].width >= 4 ) +#endif { const int lfnstLastScanPosTh = isLuma( compID ) ? LFNST_LAST_SIG_LUMA : LFNST_LAST_SIG_CHROMA; cuCtx.lfnstLastScanPos |= cctx.scanPosLast() >= lfnstLastScanPosTh; @@ -2958,7 +2974,11 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID, CUCtx& for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--) { cctx.initSubblock ( subSetId ); +#if JVET_P0058_CHROMA_TS + if( ( tu.mtsIdx[compID] > MTS_SKIP || (tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[compID].height <= 32 && tu.blocks[compID].width <= 32)) && !tu.cu->transQuantBypass && compID == COMPONENT_Y) +#else if( ( tu.mtsIdx > MTS_SKIP || ( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif { if( ( tu.blocks[ compID ].height == 32 && cctx.cgPosY() >= ( 16 >> cctx.log2CGHeight() ) ) || ( tu.blocks[ compID ].width == 32 && cctx.cgPosX() >= ( 16 >> cctx.log2CGWidth() ) ) ) { @@ -2975,7 +2995,11 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) const bool tsAllowed = TU::isTSAllowed ( tu, compID ); const bool mtsAllowed = TU::isMTSAllowed( tu, compID ); +#if JVET_P0058_CHROMA_TS + if ( tu.cu->bdpcmMode && isLuma(compID)) tu.mtsIdx[compID] = MTS_SKIP; +#else if( tu.cu->bdpcmMode ) tu.mtsIdx = MTS_SKIP; +#endif if( !mtsAllowed && !tsAllowed ) return; RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__MTS_FLAGS, tu.blocks[compID], compID ); @@ -2985,12 +3009,24 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) if( tsAllowed ) { +#if JVET_P0058_CHROMA_TS + ctxIdx = isLuma(compID) ? 6 : 11; +#else ctxIdx = 6; +#endif symbol = m_BinDecoder.decodeBin( Ctx::MTSIndex( ctxIdx ) ); +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[compID] = symbol ? MTS_SKIP : MTS_DCT2_DCT2; +#else tu.mtsIdx = symbol ? MTS_SKIP : MTS_DCT2_DCT2; +#endif } +#if JVET_P0058_CHROMA_TS + if (tu.mtsIdx[compID] != MTS_SKIP ) +#else if( tu.mtsIdx != MTS_SKIP ) +#endif { if( mtsAllowed ) { @@ -3000,12 +3036,19 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) if( symbol ) { ctxIdx = 7; +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[compID] = MTS_DST7_DST7; // mtsIdx = 2 -- 4 +#else tu.mtsIdx = MTS_DST7_DST7; // mtsIdx = 2 -- 4 +#endif for( int i = 0; i < 3; i++, ctxIdx++ ) { symbol = m_BinDecoder.decodeBin( Ctx::MTSIndex( ctxIdx ) ); +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[compID] += symbol; +#else tu.mtsIdx += symbol; - +#endif if( !symbol ) { break; @@ -3014,7 +3057,11 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) } } } +#if JVET_P0058_CHROMA_TS + DTRACE( g_trace_ctx, D_SYNTAX, "mts_coding() etype=%d pos=(%d,%d) mtsIdx=%d\n", compID, tu.cu->lx(), tu.cu->ly(), tu.mtsIdx[compID]); +#else DTRACE(g_trace_ctx, D_SYNTAX, "mts_coding() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, tu.cu->lx(), tu.cu->ly(), tu.mtsIdx); +#endif } void CABACReader::isp_mode( CodingUnit& cu ) @@ -3043,7 +3090,11 @@ void CABACReader::explicit_rdpcm_mode( TransformUnit& tu, ComponentID compID ) tu.rdpcm[compID] = RDPCM_OFF; +#if JVET_P0058_CHROMA_TS + if (!CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && ( tu.mtsIdx[compID] == MTS_SKIP || cu.transQuantBypass)) +#else if( !CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && ( tu.mtsIdx==MTS_SKIP || cu.transQuantBypass ) ) +#endif { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE( STATS__EXPLICIT_RDPCM_BITS, tu.blocks[tu.chType].lumaSize() ); @@ -3081,7 +3132,11 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu, CUCtx& cuCtx ) const bool lumaFlag = cu.isSepTree() ? ( isLuma( cu.chType ) ? true : false ) : true; const bool chromaFlag = cu.isSepTree() ? ( isChroma( cu.chType ) ? true : false ) : true; bool nonZeroCoeffNonTsCorner8x8 = ( lumaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] ) || (chromaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] ); +#if JVET_P0058_CHROMA_TS + const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx[COMPONENT_Y] != MTS_DCT2_DCT2); +#else const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2); +#endif if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 ) { cu.lfnstIdx = 0; @@ -3116,7 +3171,11 @@ int CABACReader::last_sig_coeff( CoeffCodingContext& cctx, TransformUnit& tu, Co unsigned maxLastPosX = cctx.maxLastPosX(); unsigned maxLastPosY = cctx.maxLastPosY(); +#if JVET_P0058_CHROMA_TS + if( ( tu.mtsIdx[compID] > MTS_SKIP || (tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[compID].width <= 32 && tu.blocks[compID].height <= 32)) && !tu.cu->transQuantBypass && compID == COMPONENT_Y) +#else if( ( tu.mtsIdx > MTS_SKIP || ( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif { maxLastPosX = ( tu.blocks[ compID ].width == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosX; maxLastPosY = ( tu.blocks[ compID ].height == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosY; diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index d45a177a094ccd0c45566204ef486cc12eb8c5fe..bcaf7e21c3430334cd2022b9122aee7fcb02271b 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -2684,7 +2684,11 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID, mts_coding ( tu, compID ); explicit_rdpcm_mode( tu, compID ); +#if JVET_P0058_CHROMA_TS + if (tu.mtsIdx[compID] == MTS_SKIP || (tu.cu->bdpcmMode && isLuma(compID))) +#else if( isLuma( compID ) && ( tu.mtsIdx == MTS_SKIP || tu.cu->bdpcmMode ) ) +#endif { residual_codingTS( tu, compID ); return; @@ -2692,7 +2696,11 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID, // determine sign hiding bool signHiding = ( cu.cs->slice->getSignDataHidingEnabledFlag() && !cu.transQuantBypass && tu.rdpcm[compID] == RDPCM_OFF ); +#if JVET_P0058_CHROMA_TS + if( signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.mtsIdx[compID] == MTS_SKIP) +#else if( signHiding && CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && tu.mtsIdx==MTS_SKIP ) +#endif { const ChannelType chType = toChannelType( compID ); const unsigned intraMode = PU::getFinalIntraMode( *cu.cs->getPU( tu.blocks[compID].pos(), chType ), chType ); @@ -2721,12 +2729,20 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID, CHECK( scanPosLast < 0, "Coefficient coding called for empty TU" ); cctx.setScanPosLast(scanPosLast); +#if JVET_P0058_CHROMA_TS + if (cuCtx && tu.mtsIdx[compID] != MTS_SKIP && tu.blocks[compID].height >= 4 && tu.blocks[compID].width >= 4) +#else if( cuCtx && tu.mtsIdx != MTS_SKIP && tu.blocks[ compID ].height >= 4 && tu.blocks[ compID ].width >= 4 ) +#endif { const int maxLfnstPos = ((tu.blocks[compID].height == 4 && tu.blocks[compID].width == 4) || (tu.blocks[compID].height == 8 && tu.blocks[compID].width == 8)) ? 7 : 15; cuCtx->violatesLfnstConstrained[ toChannelType(compID) ] |= cctx.scanPosLast() > maxLfnstPos; } +#if JVET_P0058_CHROMA_TS + if (cuCtx && tu.mtsIdx[compID] != MTS_SKIP && tu.blocks[compID].height >= 4 && tu.blocks[compID].width >= 4) +#else if( cuCtx && tu.mtsIdx != MTS_SKIP && tu.blocks[ compID ].height >= 4 && tu.blocks[ compID ].width >= 4 ) +#endif { const int lfnstLastScanPosTh = isLuma( compID ) ? LFNST_LAST_SIG_LUMA : LFNST_LAST_SIG_CHROMA; cuCtx->lfnstLastScanPos |= cctx.scanPosLast() >= lfnstLastScanPosTh; @@ -2744,7 +2760,11 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID, for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--) { cctx.initSubblock ( subSetId, sigGroupFlags[subSetId] ); +#if JVET_P0058_CHROMA_TS + if( ( tu.mtsIdx[compID] > MTS_SKIP || (tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[compID].height <= 32 && tu.blocks[compID].width <= 32)) && !tu.cu->transQuantBypass && compID == COMPONENT_Y) +#else if( ( tu.mtsIdx > MTS_SKIP || ( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].height <= 32 && tu.blocks[ compID ].width <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif { if( ( tu.blocks[ compID ].height == 32 && cctx.cgPosY() >= ( 16 >> cctx.log2CGHeight() ) ) || ( tu.blocks[ compID ].width == 32 && cctx.cgPosX() >= ( 16 >> cctx.log2CGWidth() ) ) ) @@ -2753,10 +2773,7 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID, } } residual_coding_subblock( cctx, coeff, stateTab, state ); - } - - } void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID ) @@ -2771,16 +2788,33 @@ void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID ) if( tsAllowed ) { +#if JVET_P0058_CHROMA_TS + symbol = (tu.mtsIdx[compID] == MTS_SKIP) ? 1 : 0; +#else symbol = (tu.mtsIdx == MTS_SKIP) ? 1 : 0; +#endif + +#if JVET_P0058_CHROMA_TS + ctxIdx = isLuma(compID) ? 6 : 11; +#else ctxIdx = 6; +#endif m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) ); } +#if JVET_P0058_CHROMA_TS + if( tu.mtsIdx[compID] != MTS_SKIP ) +#else if( tu.mtsIdx != MTS_SKIP ) +#endif { if( mtsAllowed ) { +#if JVET_P0058_CHROMA_TS + symbol = tu.mtsIdx[compID] != MTS_DCT2_DCT2 ? 1 : 0; +#else symbol = tu.mtsIdx != MTS_DCT2_DCT2 ? 1 : 0; +#endif ctxIdx = 0; m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) ); @@ -2789,7 +2823,11 @@ void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID ) ctxIdx = 7; for( int i = 0; i < 3; i++, ctxIdx++ ) { +#if JVET_P0058_CHROMA_TS + symbol = tu.mtsIdx[compID] > i + MTS_DST7_DST7 ? 1 : 0; +#else symbol = tu.mtsIdx > i + MTS_DST7_DST7 ? 1 : 0; +#endif m_BinEncoder.encodeBin( symbol, Ctx::MTSIndex( ctxIdx ) ); if( !symbol ) @@ -2800,7 +2838,11 @@ void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID ) } } } +#if JVET_P0058_CHROMA_TS + DTRACE( g_trace_ctx, D_SYNTAX, "mts_coding() etype=%d pos=(%d,%d) mtsIdx=%d\n", compID, tu.cu->lx(), tu.cu->ly(), tu.mtsIdx[compID]); +#else DTRACE( g_trace_ctx, D_SYNTAX, "mts_coding() etype=%d pos=(%d,%d) mtsIdx=%d\n", COMPONENT_Y, tu.cu->lx(), tu.cu->ly(), tu.mtsIdx); +#endif } void CABACWriter::isp_mode( const CodingUnit& cu ) @@ -2825,7 +2867,11 @@ void CABACWriter::isp_mode( const CodingUnit& cu ) void CABACWriter::explicit_rdpcm_mode( const TransformUnit& tu, ComponentID compID ) { const CodingUnit& cu = *tu.cu; +#if JVET_P0058_CHROMA_TS + if (!CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && (tu.mtsIdx[compID] == MTS_SKIP || cu.transQuantBypass)) +#else if( !CU::isIntra(cu) && CU::isRDPCMEnabled(cu) && ( tu.mtsIdx==MTS_SKIP || cu.transQuantBypass ) ) +#endif { ChannelType chType = toChannelType( compID ); switch( tu.rdpcm[compID] ) @@ -2861,7 +2907,11 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx ) const bool lumaFlag = cu.isSepTree() ? ( isLuma( cu.chType ) ? true : false ) : true; const bool chromaFlag = cu.isSepTree() ? ( isChroma( cu.chType ) ? true : false ) : true; bool nonZeroCoeffNonTsCorner8x8 = ( lumaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] ) || (chromaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] ); +#if JVET_P0058_CHROMA_TS + const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx[COMPONENT_Y] != MTS_DCT2_DCT2); +#else const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2); +#endif if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 ) { return; @@ -2904,7 +2954,11 @@ void CABACWriter::last_sig_coeff( CoeffCodingContext& cctx, const TransformUnit& unsigned maxLastPosX = cctx.maxLastPosX(); unsigned maxLastPosY = cctx.maxLastPosY(); +#if JVET_P0058_CHROMA_TS + if ((tu.mtsIdx[compID] > MTS_SKIP || (tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[compID].width <= 32 && tu.blocks[compID].height <= 32)) && !tu.cu->transQuantBypass && compID == COMPONENT_Y) +#else if( ( tu.mtsIdx > MTS_SKIP || ( tu.cs->sps->getUseMTS() && tu.cu->sbtInfo != 0 && tu.blocks[ compID ].width <= 32 && tu.blocks[ compID ].height <= 32 ) ) && !tu.cu->transQuantBypass && compID == COMPONENT_Y ) +#endif { maxLastPosX = ( tu.blocks[compID].width == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosX; maxLastPosY = ( tu.blocks[compID].height == 32 ) ? g_uiGroupIdx[ 15 ] : maxLastPosY; diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 7d899ae5b632e6f928de9759ee4e9e6b20fc5903..40b26e02a855c9768b3accc6ac0916936248efb6 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -434,6 +434,9 @@ protected: uint32_t m_log2SaoOffsetScale[MAX_NUM_CHANNEL_TYPE]; bool m_useTransformSkip; bool m_useTransformSkipFast; +#if JVET_P0058_CHROMA_TS + bool m_useChromaTS; +#endif bool m_useBDPCM; uint32_t m_log2MaxTransformSkipBlockSize; bool m_transformSkipRotationEnabledFlag; @@ -1221,6 +1224,10 @@ public: void setTransformSkipRotationEnabledFlag (const bool value) { m_transformSkipRotationEnabledFlag = value; } bool getTransformSkipContextEnabledFlag () const { return m_transformSkipContextEnabledFlag; } void setTransformSkipContextEnabledFlag (const bool value) { m_transformSkipContextEnabledFlag = value; } +#if JVET_P0058_CHROMA_TS + bool getUseChromaTS () { return m_useChromaTS; } + void setUseChromaTS (bool b) { m_useChromaTS = b; } +#endif bool getUseBDPCM () { return m_useBDPCM; } void setUseBDPCM ( bool b ) { m_useBDPCM = b; } bool getUseJointCbCr () { return m_JointCbCrMode; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 39f28c445a19896b1fe384c73737bd837c4f53b6..5788126d7cb38d387640999f02417e23b7daed78 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1923,7 +1923,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC if( bestCS->cus.size() == 1 ) { CodingUnit &cu = *bestCS->cus.front(); +#if JVET_P0058_CHROMA_TS + if (cu.firstTU->mtsIdx[COMPONENT_Y] == MTS_SKIP) +#else if( cu.firstTU->mtsIdx == MTS_SKIP ) +#endif { if( ( floorLog2( cu.firstTU->blocks[ COMPONENT_Y ].width ) + floorLog2( cu.firstTU->blocks[ COMPONENT_Y ].height ) ) >= 6 ) { @@ -4345,8 +4349,13 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS sbtOffCost = tempCS->cost; sbtOffDist = tempCS->dist; sbtOffRootCbf = cu->rootCbf; +#if JVET_P0058_CHROMA_TS + currBestSbt = CU::getSbtInfo(cu->firstTU->mtsIdx[COMPONENT_Y] > MTS_SKIP ? SBT_OFF_MTS : SBT_OFF_DCT, 0); + currBestTrs = cu->firstTU->mtsIdx[COMPONENT_Y]; +#else currBestSbt = CU::getSbtInfo( cu->firstTU->mtsIdx > MTS_SKIP ? SBT_OFF_MTS : SBT_OFF_DCT, 0 ); currBestTrs = cu->firstTU->mtsIdx; +#endif #if WCG_EXT DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) ); @@ -4477,7 +4486,11 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS if( tempCS->cost < currBestCost ) { currBestSbt = cu->sbtInfo; +#if JVET_P0058_CHROMA_TS + currBestTrs = tempCS->tus[cu->sbtInfo ? cu->getSbtPos() : 0]->mtsIdx[COMPONENT_Y]; +#else currBestTrs = tempCS->tus[cu->sbtInfo ? cu->getSbtPos() : 0]->mtsIdx; +#endif assert( currBestTrs == 0 || currBestTrs == 1 ); currBestCost = tempCS->cost; } diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index e5f6ec1e8eb5dfecac51c2848163c243a533219b..d676186951573d7be8a93f6ba38d258e7c39a4d4 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -6504,7 +6504,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { TransformUnit &tu = csFull->addTU(CS::getArea(cs, currArea, partitioner.chType), partitioner.chType); tu.depth = currDepth; +#if JVET_P0058_CHROMA_TS + for (int i = 0; i<MAX_NUM_TBLOCKS; i++) tu.mtsIdx[i] = MTS_DCT2_DCT2; +#else tu.mtsIdx = MTS_DCT2_DCT2; +#endif tu.checkTuNoResidual( partitioner.currPartIdx() ); const Slice &slice = *cs.slice; @@ -6560,7 +6564,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par preCalcAlpha = xCalcCrossComponentPredictionAlpha( tu, compID, m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate() ); } +#if JVET_P0058_CHROMA_TS + const bool tsAllowed = TU::isTSAllowed(tu, compID) && (isLuma(compID) || (isChroma(compID) && m_pcEncCfg->getUseChromaTS())); +#else const bool tsAllowed = TU::isTSAllowed ( tu, compID ); +#endif 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; @@ -6613,9 +6621,16 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par m_CABACEstimator->getCtx() = ctxStart; m_CABACEstimator->resetBits(); +#if JVET_P0058_CHROMA_TS +#else if( isLuma( compID ) ) +#endif { +#if JVET_P0058_CHROMA_TS + if (bestTU.mtsIdx[compID] == MTS_SKIP && m_pcEncCfg->getUseTransformSkipFast()) +#else if( bestTU.mtsIdx == MTS_SKIP && m_pcEncCfg->getUseTransformSkipFast() ) +#endif { continue; } @@ -6623,7 +6638,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { continue; } +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[compID] = trModes[transformMode].first; +#else tu.mtsIdx = trModes[transformMode].first; +#endif } tu.compAlpha[compID] = bUseCrossCPrediction ? preCalcAlpha : 0; @@ -6669,7 +6688,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par #else m_pcTrQuant->transformNxN( tu, compID, cQP, &trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand() ); #endif +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[compID] = trModes[0].first; +#else tu.mtsIdx = trModes[0].first; +#endif } m_pcTrQuant->transformNxN( tu, compID, cQP, currAbsSum, m_CABACEstimator->getCtx(), true ); } @@ -6876,7 +6899,10 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par tu.jointCbCr = (uint8_t) cbfMask; tu.compAlpha[COMPONENT_Cb] = tu.compAlpha[COMPONENT_Cr] = 0; - +#if JVET_P0058_CHROMA_TS + // encoder bugfix: initialize mtsIdx for chroma under JointCbCrMode. + tu.mtsIdx[COMPONENT_Cb] = tu.mtsIdx[COMPONENT_Cr] = MTS_DCT2_DCT2; +#endif const QpParam cQP(tu, COMPONENT_Cb); // note: uses tu.transformSkip[compID] #if RDOQ_CHROMA_LAMBDA diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index d93c8f81d79d326affd17c4b8bde0cba90713cb6..0dacb9e318ef0b15453b60749656f021d0e168a2 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -1156,9 +1156,16 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner { modeIsEnable[i] = 1; } - +#if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD + DistParam distParamSad; + DistParam distParamSatd; +#else DistParam distParam; +#endif +#if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD +#else const bool useHadamard = !cu.transQuantBypass; +#endif pu.intraDir[1] = MDLM_L_IDX; // temporary assigned, just to indicate this is a MDLM mode. for luma down-sampling operation. initIntraPatternChType(cu, pu.Cb()); @@ -1179,16 +1186,32 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner } pu.intraDir[1] = mode; // temporary assigned, for SATD checking. +#if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD + int64_t sad = 0; + int64_t sadCb = 0; + int64_t satdCb = 0; + int64_t sadCr = 0; + int64_t satdCr = 0; +#else int64_t sad = 0; +#endif CodingStructure& cs = *(pu.cs); CompArea areaCb = pu.Cb(); PelBuf orgCb = cs.getOrgBuf(areaCb); PelBuf predCb = cs.getPredBuf(areaCb); - +#if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD + m_pcRdCost->setDistParam(distParamSad, orgCb, predCb, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, false); + m_pcRdCost->setDistParam(distParamSatd, orgCb, predCb, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, true); +#else m_pcRdCost->setDistParam(distParam, orgCb, predCb, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, useHadamard); +#endif +#if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD + distParamSad.applyWeight = false; + distParamSatd.applyWeight = false; +#else distParam.applyWeight = false; - +#endif if (PU::isLMCMode(mode)) { predIntraChromaLM(COMPONENT_Cb, predCb, pu, areaCb, mode); @@ -1198,16 +1221,28 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner initPredIntraParams(pu, pu.Cb(), *pu.cs->sps); predIntraAng(COMPONENT_Cb, predCb, pu); } - +#if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD + sadCb = distParamSad.distFunc(distParamSad) * 2; + satdCb = distParamSatd.distFunc(distParamSatd); + sad += std::min(sadCb, satdCb); +#else sad += distParam.distFunc(distParam); - +#endif CompArea areaCr = pu.Cr(); PelBuf orgCr = cs.getOrgBuf(areaCr); PelBuf predCr = cs.getPredBuf(areaCr); - +#if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD + m_pcRdCost->setDistParam(distParamSad, orgCr, predCr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, false); + m_pcRdCost->setDistParam(distParamSatd, orgCr, predCr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, true); +#else m_pcRdCost->setDistParam(distParam, orgCr, predCr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, useHadamard); +#endif +#if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD + distParamSad.applyWeight = false; + distParamSatd.applyWeight = false; +#else distParam.applyWeight = false; - +#endif if (PU::isLMCMode(mode)) { predIntraChromaLM(COMPONENT_Cr, predCr, pu, areaCr, mode); @@ -1217,7 +1252,13 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner initPredIntraParams(pu, pu.Cr(), *pu.cs->sps); predIntraAng(COMPONENT_Cr, predCr, pu); } +#if JVET_P0058_CHROMA_TS_ENCODER_INTRA_SAD_MOD + sadCr = distParamSad.distFunc(distParamSad) * 2; + satdCr = distParamSatd.distFunc(distParamSatd); + sad += std::min(sadCr, satdCr); +#else sad += distParam.distFunc(distParam); +#endif satdSortedCost[idx] = sad; } // sort the mode based on the cost from small to large. @@ -2427,7 +2468,11 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp #else m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, CU::isIntra(*tu.cu) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand()); #endif +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[compID] = trModes->at(0).first; +#else tu.mtsIdx = trModes->at(0).first; +#endif } m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); @@ -2466,7 +2511,24 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } PelBuf& codeResi = ( codeCompId == COMPONENT_Cr ? crResi : piResi ); uiAbsSum = 0; + +#if JVET_P0058_CHROMA_TS + if (trModes) + { +#if JVET_P0273_MTSIntraMaxCand + m_pcTrQuant->transformNxN(tu, compID, qpCbCr, trModes, m_pcEncCfg->getMTSIntraMaxCand()); +#else + m_pcTrQuant->transformNxN(tu, compID, qpCbCr, trModes, CU::isIntra(*tu.cu) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand()); +#endif + tu.mtsIdx[compID] = trModes->at(0).first; + } +#endif +#if JVET_P0058_CHROMA_TS + // encoder bugfix: Set loadTr to aovid redundant transform process + m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); +#else m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, 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 ), codeCompId, uiAbsSum ); if( uiAbsSum > 0 ) { @@ -2810,7 +2872,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par } else { +#if JVET_P0058_CHROMA_TS + if( !cbfDCT2 || ( m_pcEncCfg->getUseTransformSkipFast() && bestModeId[ COMPONENT_Y ] == MTS_SKIP)) +#else if( !cbfDCT2 || ( m_pcEncCfg->getUseTransformSkipFast() && bestModeId[ COMPONENT_Y ] == 1 ) ) +#endif { break; } @@ -2819,11 +2885,19 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par continue; } //we compare the DCT-II cost against the best ISP cost so far (except for TS) +#if JVET_P0058_CHROMA_TS + if (m_pcEncCfg->getUseFastISP() && !cu.ispMode && ispIsCurrentWinner && trModes[modeId].first != MTS_DCT2_DCT2 && (trModes[modeId].first != MTS_SKIP || !tsAllowed) && bestDCT2cost > bestCostSoFar * threshold) +#else if( m_pcEncCfg->getUseFastISP() && !cu.ispMode && ispIsCurrentWinner && trModes[ modeId ].first != 0 && ( trModes[ modeId ].first != 1 || !tsAllowed ) && bestDCT2cost > bestCostSoFar * threshold ) +#endif { continue; } +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[COMPONENT_Y] = trModes[modeId].first; +#else tu.mtsIdx = trModes[ modeId ].first; +#endif } @@ -2867,25 +2941,45 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par if( transformIndex == 1 ) { +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[COMPONENT_Y] = (uiIntraMode < 34) ? MTS_DST7_DCT8 : MTS_DCT8_DST7; +#else tu.mtsIdx = ( uiIntraMode < 34 ) ? MTS_DST7_DCT8 : MTS_DCT8_DST7; +#endif } else if( transformIndex == 2 ) { +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[COMPONENT_Y] = (uiIntraMode < 34) ? MTS_DCT8_DST7 : MTS_DST7_DCT8; +#else tu.mtsIdx = ( uiIntraMode < 34 ) ? MTS_DCT8_DST7 : MTS_DST7_DCT8; +#endif } else { +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[COMPONENT_Y] = MTS_DST7_DST7 + transformIndex; +#else tu.mtsIdx = MTS_DST7_DST7 + transformIndex; +#endif } } else { +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[COMPONENT_Y] = MTS_DST7_DST7 + transformIndex; +#else tu.mtsIdx = MTS_DST7_DST7 + transformIndex; +#endif } } else { +#if JVET_P0058_CHROMA_TS + tu.mtsIdx[COMPONENT_Y] = transformIndex; +#else tu.mtsIdx = transformIndex; +#endif } if( !cu.mtsFlag && checkTransformSkip ) @@ -3299,9 +3393,26 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio int bestModeId = 0; Distortion singleDistCTmp = 0; double singleCostTmp = 0; - const int crossCPredictionModesToTest = checkCrossComponentPrediction ? 2 : 1; +#if JVET_P0058_CHROMA_TS + const bool tsAllowed = TU::isTSAllowed(currTU, compID) && (m_pcEncCfg->getUseChromaTS()); + uint8_t nNumTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests + std::vector<TrMode> trModes; + trModes.push_back(TrMode(0, true)); // DCT2 + + if (tsAllowed) + { + trModes.push_back(TrMode(1, true));//TS + } + CHECK(!currTU.Cb().valid(), "Invalid TU"); +#endif + +#if JVET_P0058_CHROMA_TS + const int totalModesToTest = crossCPredictionModesToTest * nNumTransformCands; + bool cbfDCT2 = true; +#else const int totalModesToTest = crossCPredictionModesToTest; +#endif const bool isOneMode = false; maxModesTested = totalModesToTest > maxModesTested ? totalModesToTest : maxModesTested; @@ -3314,6 +3425,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio ctxStart = m_CABACEstimator->getCtx(); } +#if JVET_P0058_CHROMA_TS + for (int modeId = 0; modeId < nNumTransformCands; modeId++) +#endif { for (int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++) { @@ -3322,11 +3436,27 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio currTU.compAlpha [compID] = ( crossCPredictionModeId ? compAlpha[compID] : 0 ); +#if JVET_P0058_CHROMA_TS + currTU.mtsIdx[compID] = trModes[modeId].first; +#endif + currModeId++; const bool isFirstMode = (currModeId == 1); const bool isLastMode = false; // Always store output to saveCS and tmpTU +#if JVET_P0058_CHROMA_TS + //if DCT2's cbf==0, skip ts search + if (!cbfDCT2 && trModes[modeId].first == MTS_SKIP) + { + break; + } + if (!trModes[modeId].second) + { + continue; + } +#endif + if (!isFirstMode) // if not first mode to be tested { m_CABACEstimator->getCtx() = ctxStart; @@ -3334,9 +3464,24 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio singleDistCTmp = 0; +#if JVET_P0058_CHROMA_TS + if (nNumTransformCands > 1) + { + xIntraCodingTUBlock(currTU, compID, crossCPredictionModeId != 0, singleDistCTmp, default0Save1Load2, nullptr, modeId == 0 ? &trModes : nullptr, true); + } + else + { + xIntraCodingTUBlock(currTU, compID, crossCPredictionModeId != 0, singleDistCTmp, default0Save1Load2); + } +#else xIntraCodingTUBlock( currTU, compID, crossCPredictionModeId != 0, singleDistCTmp, default0Save1Load2 ); +#endif +#if JVET_P0058_CHROMA_TS + if (((crossCPredictionModeId == 1) && (currTU.compAlpha[compID] == 0)) || ((currTU.mtsIdx[compID] == MTS_SKIP) && !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. +#else 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. +#endif { singleCostTmp = MAX_DOUBLE; } @@ -3371,6 +3516,13 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio bestDistCr = singleDistCTmp; } +#if JVET_P0058_CHROMA_TS + if (currTU.mtsIdx[compID] == MTS_DCT2_DCT2) + { + cbfDCT2 = TU::getCbfAtDepth(currTU, compID, currDepth); + } +#endif + if( !isLastMode ) { #if KEEP_PRED_AND_RESI_SIGNALS @@ -3430,7 +3582,10 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio currTU.jointCbCr = (uint8_t)cbfMask; currTU.compAlpha[COMPONENT_Cb] = 0; currTU.compAlpha[COMPONENT_Cr] = 0; - +#if JVET_P0058_CHROMA_TS + // encoder bugfix: initialize mtsIdx for chroma under JointCbCrMode. + currTU.mtsIdx[COMPONENT_Cb] = currTU.mtsIdx[COMPONENT_Cr] = MTS_DCT2_DCT2; +#endif m_CABACEstimator->getCtx() = ctxStartTU; resiCb.copyFrom( orgResiCb[cbfMask] );