From 4076fc2fbe1c60d8b7b027ec94f21535e864281f Mon Sep 17 00:00:00 2001 From: Philippe de Lagrange <philippe.delagrange@technicolor.com> Date: Thu, 28 Feb 2019 17:46:50 +0100 Subject: [PATCH] JVET-M0113/M0188 quantization groups based on area --- cfg/encoder_intra_vtm.cfg | 2 +- cfg/encoder_lowdelay_P_vtm.cfg | 2 +- cfg/encoder_lowdelay_vtm.cfg | 2 +- cfg/encoder_randomaccess_vtm.cfg | 2 +- source/App/EncoderApp/EncApp.cpp | 5 ++ source/App/EncoderApp/EncAppCfg.cpp | 21 ++++++++ source/App/EncoderApp/EncAppCfg.h | 5 ++ source/Lib/CommonLib/ContextModelling.h | 9 ++++ source/Lib/CommonLib/Slice.cpp | 8 +++ source/Lib/CommonLib/Slice.h | 20 +++++++- source/Lib/CommonLib/TypeDef.h | 1 + source/Lib/CommonLib/UnitPartitioner.cpp | 48 ++++++++++++++++++ source/Lib/CommonLib/UnitPartitioner.h | 11 ++++ source/Lib/CommonLib/UnitTools.cpp | 2 + source/Lib/CommonLib/UnitTools.h | 2 + source/Lib/DecoderLib/CABACReader.cpp | 25 ++++++++- source/Lib/DecoderLib/VLCReader.cpp | 17 +++++++ source/Lib/EncoderLib/CABACWriter.cpp | 24 +++++++++ source/Lib/EncoderLib/EncCfg.h | 15 ++++++ source/Lib/EncoderLib/EncCu.cpp | 42 +++++++++++++++- source/Lib/EncoderLib/EncLib.cpp | 34 +++++++++++++ source/Lib/EncoderLib/EncModeCtrl.cpp | 64 ++++++++++++++++++++++++ source/Lib/EncoderLib/EncModeCtrl.h | 4 ++ source/Lib/EncoderLib/VLCWriter.cpp | 8 +++ 24 files changed, 365 insertions(+), 8 deletions(-) diff --git a/cfg/encoder_intra_vtm.cfg b/cfg/encoder_intra_vtm.cfg index 18ae597ec..80c2ee847 100644 --- a/cfg/encoder_intra_vtm.cfg +++ b/cfg/encoder_intra_vtm.cfg @@ -26,7 +26,7 @@ FDM : 1 # Fast Decision for Merge RD cost #======== Quantization ============= QP : 32 # Quantization parameter(0-51) MaxDeltaQP : 0 # CU-based multi-QP optimization -MaxCuDQPDepth : 0 # Max depth of a minimum CuDQP for sub-LCU-level delta QP +MaxCuDQPSubdiv : 0 # Maximum subdiv for CU luma Qp adjustment DeltaQpRD : 0 # Slice-based multi-QP optimization RDOQ : 1 # RDOQ RDOQTS : 1 # RDOQ for transform skip diff --git a/cfg/encoder_lowdelay_P_vtm.cfg b/cfg/encoder_lowdelay_P_vtm.cfg index 7256c3b0d..6d345e4c7 100644 --- a/cfg/encoder_lowdelay_P_vtm.cfg +++ b/cfg/encoder_lowdelay_P_vtm.cfg @@ -34,7 +34,7 @@ FDM : 1 # Fast Decision for Merge RD cost #======== Quantization ============= QP : 32 # Quantization parameter(0-51) MaxDeltaQP : 0 # CU-based multi-QP optimization -MaxCuDQPDepth : 0 # Max depth of a minimum CuDQP for sub-LCU-level delta QP +MaxCuDQPSubdiv : 0 # Maximum subdiv for CU luma Qp adjustment DeltaQpRD : 0 # Slice-based multi-QP optimization RDOQ : 1 # RDOQ RDOQTS : 1 # RDOQ for transform skip diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg index dc4902e24..07233c189 100644 --- a/cfg/encoder_lowdelay_vtm.cfg +++ b/cfg/encoder_lowdelay_vtm.cfg @@ -34,7 +34,7 @@ FDM : 1 # Fast Decision for Merge RD cost #======== Quantization ============= QP : 32 # Quantization parameter(0-51) MaxDeltaQP : 0 # CU-based multi-QP optimization -MaxCuDQPDepth : 0 # Max depth of a minimum CuDQP for sub-LCU-level delta QP +MaxCuDQPSubdiv : 0 # Maximum subdiv for CU luma Qp adjustment DeltaQpRD : 0 # Slice-based multi-QP optimization RDOQ : 1 # RDOQ RDOQTS : 1 # RDOQ for transform skip diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index 763c0ef98..389209a4c 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -48,7 +48,7 @@ FDM : 1 # Fast Decision for Merge RD cost #======== Quantization ============= QP : 32 # Quantization parameter(0-51) MaxDeltaQP : 0 # CU-based multi-QP optimization -MaxCuDQPDepth : 0 # Max depth of a minimum CuDQP for sub-LCU-level delta QP +MaxCuDQPSubdiv : 0 # Maximum subdiv for CU luma Qp adjustment DeltaQpRD : 0 # Slice-based multi-QP optimization RDOQ : 1 # RDOQ RDOQTS : 1 # RDOQ for transform skip diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index c0f2a3c5e..d54af7c56 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -216,8 +216,13 @@ void EncApp::xInitLibCfg() //====== Quality control ======== m_cEncLib.setMaxDeltaQP ( m_iMaxDeltaQP ); +#if JVET_M0113_M0188_QG_SIZE + m_cEncLib.setCuQpDeltaSubdiv ( m_cuQpDeltaSubdiv ); + m_cEncLib.setCuChromaQpOffsetSubdiv ( m_cuChromaQpOffsetSubdiv ); +#else m_cEncLib.setMaxCuDQPDepth ( m_iMaxCuDQPDepth ); m_cEncLib.setDiffCuChromaQpOffsetDepth ( m_diffCuChromaQpOffsetDepth ); +#endif m_cEncLib.setChromaCbQpOffset ( m_cbQpOffset ); m_cEncLib.setChromaCrQpOffset ( m_crQpOffset ); m_cEncLib.setChromaCbQpOffsetDualTree ( m_cbQpOffsetDualTree ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 4121873d6..2d44db673 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -997,8 +997,13 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #endif ("DeltaQpRD,-dqr", m_uiDeltaQpRD, 0u, "max dQp offset for slice") ("MaxDeltaQP,d", m_iMaxDeltaQP, 0, "max dQp offset for block") +#if JVET_M0113_M0188_QG_SIZE + ("MaxCuDQPSubdiv,-dqd", m_cuQpDeltaSubdiv, 0, "Maximum subdiv for CU luma Qp adjustment") + ("MaxCuChromaQpOffsetSubdiv", m_cuChromaQpOffsetSubdiv, -1, "Maximum subdiv for CU chroma Qp adjustment - set less than 0 to disable") +#else ("MaxCuDQPDepth,-dqd", m_iMaxCuDQPDepth, 0, "max depth for a minimum CuDQP") ("MaxCUChromaQpAdjustmentDepth", m_diffCuChromaQpOffsetDepth, -1, "Maximum depth for CU chroma Qp adjustment - set less than 0 to disable") +#endif ("FastDeltaQP", m_bFastDeltaQP, false, "Fast Delta QP Algorithm") #if SHARP_LUMA_DELTA_QP ("LumaLevelToDeltaQPMode", lumaLevelToDeltaQPMode, 0u, "Luma based Delta QP 0(default): not used. 1: Based on CTU average, 2: Based on Max luma in CTU") @@ -1573,7 +1578,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) !m_enableIntraReferenceSmoothing || m_persistentRiceAdaptationEnabledFlag || m_log2MaxTransformSkipBlockSize!=2; +#if JVET_M0113_M0188_QG_SIZE + const bool bUsingChromaQPAdjustment= m_cuChromaQpOffsetSubdiv >= 0; +#else const bool bUsingChromaQPAdjustment= m_diffCuChromaQpOffsetDepth >= 0; +#endif const bool bUsingExtendedPrecision = m_extendedPrecisionProcessingFlag; if (m_onePictureOnlyConstraintFlag) { @@ -2121,7 +2130,11 @@ bool EncAppCfg::xCheckParameter() !m_enableIntraReferenceSmoothing || m_persistentRiceAdaptationEnabledFlag || m_log2MaxTransformSkipBlockSize!=2; +#if JVET_M0113_M0188_QG_SIZE + const bool bUsingChromaQPTool = m_cuChromaQpOffsetSubdiv >= 0; +#else const bool bUsingChromaQPTool = m_diffCuChromaQpOffsetDepth >= 0; +#endif const bool bUsingExtendedPrecision = m_extendedPrecisionProcessingFlag; xConfirmPara((m_chromaFormatConstraint==CHROMA_420 || m_chromaFormatConstraint==CHROMA_400) && bUsingChromaQPTool, "CU Chroma QP adjustment cannot be used for 4:0:0 or 4:2:0 RExt profiles"); @@ -3088,7 +3101,11 @@ void EncAppCfg::xPrintParameter() #else msg( DETAILS, "QP : %5.2f\n", m_fQP ); #endif +#if JVET_M0113_M0188_QG_SIZE + msg( DETAILS, "Max dQP signaling subdiv : %d\n", m_cuQpDeltaSubdiv); +#else msg( DETAILS, "Max dQP signaling depth : %d\n", m_iMaxCuDQPDepth); +#endif msg( DETAILS, "Cb QP Offset (dual tree) : %d (%d)\n", m_cbQpOffset, m_cbQpOffsetDualTree); msg( DETAILS, "Cr QP Offset (dual tree) : %d (%d)\n", m_crQpOffset, m_crQpOffsetDualTree); @@ -3100,7 +3117,11 @@ void EncAppCfg::xPrintParameter() msg( DETAILS, "PCM sample bit depth : (Y:%d, C:%d)\n", m_bPCMInputBitDepthFlag ? m_MSBExtendedBitDepth[CHANNEL_TYPE_LUMA] : m_internalBitDepth[CHANNEL_TYPE_LUMA], m_bPCMInputBitDepthFlag ? m_MSBExtendedBitDepth[CHANNEL_TYPE_CHROMA] : m_internalBitDepth[CHANNEL_TYPE_CHROMA] ); msg( DETAILS, "Intra reference smoothing : %s\n", (m_enableIntraReferenceSmoothing ? "Enabled" : "Disabled") ); +#if JVET_M0113_M0188_QG_SIZE + msg( DETAILS, "cu_chroma_qp_offset_subdiv : %d\n", m_cuChromaQpOffsetSubdiv); +#else msg( DETAILS, "diff_cu_chroma_qp_offset_depth : %d\n", m_diffCuChromaQpOffsetDepth); +#endif msg( DETAILS, "extended_precision_processing_flag : %s\n", (m_extendedPrecisionProcessingFlag ? "Enabled" : "Disabled") ); msg( DETAILS, "implicit_rdpcm_enabled_flag : %s\n", (m_rdpcmEnabledFlag[RDPCM_SIGNAL_IMPLICIT] ? "Enabled" : "Disabled") ); msg( DETAILS, "explicit_rdpcm_enabled_flag : %s\n", (m_rdpcmEnabledFlag[RDPCM_SIGNAL_EXPLICIT] ? "Enabled" : "Disabled") ); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index da31485c4..f819cc1ba 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -205,8 +205,13 @@ protected: int* m_aidQP; ///< array of slice QP values int m_iMaxDeltaQP; ///< max. |delta QP| uint32_t m_uiDeltaQpRD; ///< dQP range for multi-pass slice QP optimization +#if JVET_M0113_M0188_QG_SIZE + int m_cuQpDeltaSubdiv; ///< Maximum subdiv for CU luma Qp adjustment (0:default) + int m_cuChromaQpOffsetSubdiv; ///< If negative, then do not apply chroma qp offsets. +#else int m_iMaxCuDQPDepth; ///< Max. depth for a minimum CuDQPSize (0:default) int m_diffCuChromaQpOffsetDepth; ///< If negative, then do not apply chroma qp offsets. +#endif bool m_bFastDeltaQP; ///< Fast Delta QP (false:default) int m_cbQpOffset; ///< Chroma Cb QP Offset (0:default) diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index c93dc780c..869a7e0b0 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -249,13 +249,22 @@ class CUCtx { public: CUCtx() : isDQPCoded(false), isChromaQpAdjCoded(false), +#if JVET_M0113_M0188_QG_SIZE + qgStart(false), +#endif numNonZeroCoeffNonTs(0) {} CUCtx(int _qp) : isDQPCoded(false), isChromaQpAdjCoded(false), +#if JVET_M0113_M0188_QG_SIZE + qgStart(false), +#endif numNonZeroCoeffNonTs(0), qp(_qp) {} ~CUCtx() {} public: bool isDQPCoded; bool isChromaQpAdjCoded; +#if JVET_M0113_M0188_QG_SIZE + bool qgStart; +#endif uint32_t numNonZeroCoeffNonTs; int8_t qp; // used as a previous(last) QP and for QP prediction }; diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index ec8f544c1..6c4afd219 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1879,7 +1879,11 @@ const int SPS::m_winUnitY[]={1,2,1,1}; PPSRExt::PPSRExt() : m_log2MaxTransformSkipBlockSize (2) , m_crossComponentPredictionEnabledFlag(false) +#if JVET_M0113_M0188_QG_SIZE +, m_cuChromaQpOffsetSubdiv (0) +#else , m_diffCuChromaQpOffsetDepth (0) +#endif , m_chromaQpOffsetListLen (0) // m_ChromaQpAdjTableIncludingNullEntry initialized below // m_log2SaoOffsetScale initialized below @@ -1899,7 +1903,11 @@ PPS::PPS() , m_useDQP (false) , m_bConstrainedIntraPred (false) , m_bSliceChromaQpFlag (false) +#if JVET_M0113_M0188_QG_SIZE +, m_cuQpDeltaSubdiv (0) +#else , m_uiMaxCuDQPDepth (0) +#endif , m_chromaCbQpOffset (0) , m_chromaCrQpOffset (0) , m_numRefIdxL0DefaultActive (1) diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index aed91d301..69d1c85cd 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -1330,7 +1330,11 @@ private: bool m_crossComponentPredictionEnabledFlag; // Chroma QP Adjustments +#if JVET_M0113_M0188_QG_SIZE + int m_cuChromaQpOffsetSubdiv; +#else int m_diffCuChromaQpOffsetDepth; +#endif int m_chromaQpOffsetListLen; // size (excludes the null entry used in the following array). ChromaQpAdj m_ChromaQpAdjTableIncludingNullEntry[1+MAX_QP_OFFSET_LIST_SIZE]; //!< Array includes entry [0] for the null offset used when cu_chroma_qp_offset_flag=0, and entries [cu_chroma_qp_offset_idx+1...] otherwise @@ -1356,8 +1360,13 @@ public: void clearChromaQpOffsetList() { m_chromaQpOffsetListLen = 0; } +#if JVET_M0113_M0188_QG_SIZE + uint32_t getCuChromaQpOffsetSubdiv () const { return m_cuChromaQpOffsetSubdiv; } + void setCuChromaQpOffsetSubdiv ( uint32_t u ) { m_cuChromaQpOffsetSubdiv = u; } +#else uint32_t getDiffCuChromaQpOffsetDepth () const { return m_diffCuChromaQpOffsetDepth; } void setDiffCuChromaQpOffsetDepth ( uint32_t u ) { m_diffCuChromaQpOffsetDepth = u; } +#endif bool getChromaQpOffsetListEnabledFlag() const { return getChromaQpOffsetListLen()>0; } int getChromaQpOffsetListLen() const { return m_chromaQpOffsetListLen; } @@ -1395,7 +1404,11 @@ private: bool m_bSliceChromaQpFlag; // slicelevel_chroma_qp_flag // access channel - uint32_t m_uiMaxCuDQPDepth; +#if JVET_M0113_M0188_QG_SIZE + uint32_t m_cuQpDeltaSubdiv; // cu_qp_delta_subdiv +#else + uint32_t m_uiMaxCuDQPDepth; +#endif int m_chromaCbQpOffset; int m_chromaCrQpOffset; @@ -1463,8 +1476,13 @@ public: bool getSliceChromaQpFlag() const { return m_bSliceChromaQpFlag; } void setSliceChromaQpFlag( bool b ) { m_bSliceChromaQpFlag = b; } +#if JVET_M0113_M0188_QG_SIZE + void setCuQpDeltaSubdiv( uint32_t u ) { m_cuQpDeltaSubdiv = u; } + uint32_t getCuQpDeltaSubdiv() const { return m_cuQpDeltaSubdiv; } +#else void setMaxCuDQPDepth( uint32_t u ) { m_uiMaxCuDQPDepth = u; } uint32_t getMaxCuDQPDepth() const { return m_uiMaxCuDQPDepth; } +#endif void setQpOffset(ComponentID compID, int i ) { diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index e91a15bd6..12c147c7e 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -372,6 +372,7 @@ typedef std::pair<int, int> TrCost; #define ER_CHROMA_QP_WCG_PPS 1 ///< Chroma QP model for WCG used in Anchor 3.2 #define ENABLE_QPA 1 ///< Non-normative perceptual QP adaptation according to JVET-H0047 and JVET-K0206. Deactivated by default, activated using encoder arguments --PerceptQPA=1 --SliceChromaQPOffsetPeriodicity=1 #define ENABLE_QPA_SUB_CTU ( 1 && ENABLE_QPA ) ///< when maximum delta-QP depth is greater than zero, use sub-CTU QPA +#define JVET_M0113_M0188_QG_SIZE 1 ///< JVET-M0113/M0188 quantization groups based on area #define RDOQ_CHROMA 1 ///< use of RDOQ in chroma diff --git a/source/Lib/CommonLib/UnitPartitioner.cpp b/source/Lib/CommonLib/UnitPartitioner.cpp index 849698ca2..fe5d47a07 100644 --- a/source/Lib/CommonLib/UnitPartitioner.cpp +++ b/source/Lib/CommonLib/UnitPartitioner.cpp @@ -53,6 +53,10 @@ PartLevel::PartLevel() , implicitSplit ( CU_DONT_SPLIT ) , firstSubPartSplit ( CU_DONT_SPLIT ) , canQtSplit ( true ) +#if JVET_M0113_M0188_QG_SIZE +, qgEnable ( true ) +, qgChromaEnable ( true ) +#endif { } @@ -65,6 +69,10 @@ PartLevel::PartLevel( const PartSplit _split, const Partitioning& _parts ) , implicitSplit ( CU_DONT_SPLIT ) , firstSubPartSplit ( CU_DONT_SPLIT ) , canQtSplit ( true ) +#if JVET_M0113_M0188_QG_SIZE +, qgEnable ( true ) +, qgChromaEnable ( true ) +#endif { } @@ -77,6 +85,10 @@ PartLevel::PartLevel( const PartSplit _split, Partitioning&& _parts ) , implicitSplit ( CU_DONT_SPLIT ) , firstSubPartSplit ( CU_DONT_SPLIT ) , canQtSplit ( true ) +#if JVET_M0113_M0188_QG_SIZE +, qgEnable ( true ) +, qgChromaEnable ( true ) +#endif { } @@ -117,6 +129,9 @@ void Partitioner::copyState( const Partitioner& other ) currDepth = other.currDepth; currMtDepth = other.currMtDepth; currTrDepth = other.currTrDepth; +#if JVET_M0113_M0188_QG_SIZE + currSubdiv = other.currSubdiv; +#endif currImplicitBtDepth = other.currImplicitBtDepth; chType = other.chType; @@ -224,6 +239,9 @@ void QTBTPartitioner::initCtu( const UnitArea& ctuArea, const ChannelType _chTyp currBtDepth = 0; currMtDepth = 0; currQtDepth = 0; +#if JVET_M0113_M0188_QG_SIZE + currSubdiv = 0; +#endif currImplicitBtDepth = 0; chType = _chType; @@ -237,6 +255,10 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur bool isImplicit = isSplitImplicit( split, cs ); bool canQtSplit = canSplit( CU_QUAD_SPLIT, cs ); +#if JVET_M0113_M0188_QG_SIZE + bool qgEnable = currQgEnable(); + bool qgChromaEnable = currQgChromaEnable(); +#endif switch( split ) { @@ -272,6 +294,9 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur } currDepth++; +#if JVET_M0113_M0188_QG_SIZE + currSubdiv++; +#endif #if _DEBUG m_currArea = m_partStack.back().parts.front(); #endif @@ -301,6 +326,9 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur { // first and last part of triple split are equivalent to double bt split currBtDepth++; +#if JVET_M0113_M0188_QG_SIZE + currSubdiv++; +#endif } m_partStack.back().canQtSplit = canQtSplit; } @@ -311,7 +339,14 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur currMtDepth = 0; currBtDepth = 0; currQtDepth++; +#if JVET_M0113_M0188_QG_SIZE + currSubdiv++; +#endif } +#if JVET_M0113_M0188_QG_SIZE + m_partStack.back().qgEnable = qgEnable && (currSubdiv <= cs.pps->getCuQpDeltaSubdiv()); + m_partStack.back().qgChromaEnable = qgChromaEnable && (currSubdiv <= cs.pps->getPpsRangeExtension().getCuChromaQpOffsetSubdiv()); +#endif } #if JVET_M0421_SPLIT_SIG @@ -630,6 +665,9 @@ void QTBTPartitioner::exitCurrSplit() CHECK( currDepth == 0, "depth is '0', although a split was performed" ); currDepth--; +#if JVET_M0113_M0188_QG_SIZE + currSubdiv--; +#endif #if _DEBUG m_currArea = m_partStack.back().parts[m_partStack.back().idx]; #endif @@ -646,6 +684,9 @@ void QTBTPartitioner::exitCurrSplit() { CHECK( currBtDepth == 0, "BT depth is '0', athough a TT split was performed" ); currBtDepth--; +#if JVET_M0113_M0188_QG_SIZE + currSubdiv--; +#endif } } else if( currSplit == TU_MAX_TR_SPLIT ) @@ -666,6 +707,9 @@ void QTBTPartitioner::exitCurrSplit() CHECK( currQtDepth == 0, "QT depth is '0', although a QT split was performed" ); currQtDepth--; +#if JVET_M0113_M0188_QG_SIZE + currSubdiv--; +#endif } } @@ -691,6 +735,10 @@ bool QTBTPartitioner::nextPart( const CodingStructure &cs, bool autoPop /*= fals // adapt the current bt depth if( currIdx == 1 ) currBtDepth--; else currBtDepth++; +#if JVET_M0113_M0188_QG_SIZE + if( currIdx == 1 ) currSubdiv--; + else currSubdiv++; +#endif } #if _DEBUG m_currArea = m_partStack.back().parts[currIdx]; diff --git a/source/Lib/CommonLib/UnitPartitioner.h b/source/Lib/CommonLib/UnitPartitioner.h index 3060e8459..b363b7b0c 100644 --- a/source/Lib/CommonLib/UnitPartitioner.h +++ b/source/Lib/CommonLib/UnitPartitioner.h @@ -100,6 +100,10 @@ struct PartLevel PartSplit implicitSplit; PartSplit firstSubPartSplit; bool canQtSplit; +#if JVET_M0113_M0188_QG_SIZE + bool qgEnable; + bool qgChromaEnable; +#endif PartLevel(); PartLevel( const PartSplit _split, const Partitioning& _parts ); @@ -123,6 +127,9 @@ public: unsigned currTrDepth; unsigned currBtDepth; unsigned currMtDepth; +#if JVET_M0113_M0188_QG_SIZE + unsigned currSubdiv; +#endif unsigned currImplicitBtDepth; ChannelType chType; @@ -133,6 +140,10 @@ public: const UnitArea& currArea () const { return currPartLevel().parts[currPartIdx()]; } const unsigned currPartIdx () const { return currPartLevel().idx; } const PartitioningStack& getPartStack () const { return m_partStack; } +#if JVET_M0113_M0188_QG_SIZE + const bool currQgEnable () const { return currPartLevel().qgEnable; } + const bool currQgChromaEnable () const { return currPartLevel().qgChromaEnable; } +#endif SplitSeries getSplitSeries () const; diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 015d752ca..c6828c143 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -196,6 +196,7 @@ int CU::predictQP( const CodingUnit& cu, const int prevQP ) return ( a + b + 1 ) >> 1; } +#if !JVET_M0113_M0188_QG_SIZE bool CU::isQGStart( const CodingUnit& cu, Partitioner& partitioner ) { int maxDqpDepth = cu.slice->getPPS()->getMaxCuDQPDepth(); @@ -211,6 +212,7 @@ bool CU::isQGStart( const CodingUnit& cu, Partitioner& partitioner ) else return true; } +#endif uint32_t CU::getNumPUs( const CodingUnit& cu ) { diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 06b4eefbd..682bbed54 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -77,7 +77,9 @@ namespace CU uint32_t getCtuAddr (const CodingUnit &cu); int predictQP (const CodingUnit& cu, const int prevQP ); +#if !JVET_M0113_M0188_QG_SIZE bool isQGStart (const CodingUnit& cu, Partitioner& partitioner ); // check if start of a Quantization Group +#endif uint32_t getNumPUs (const CodingUnit& cu); void addPUs ( CodingUnit& cu); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 92f87e1fc..903d0412a 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -385,11 +385,20 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU bool lastSegment = false; // Reset delta QP coding flag and ChromaQPAdjustemt coding flag +#if JVET_M0113_M0188_QG_SIZE + if( pps.getUseDQP() && partitioner.currQgEnable() ) + { + cuCtx.qgStart = true; + cuCtx.isDQPCoded = false; + } + if( cs.slice->getUseChromaQpAdj() && partitioner.currQgChromaEnable() ) +#else if( pps.getUseDQP() && partitioner.currDepth <= pps.getMaxCuDQPDepth() ) { cuCtx.isDQPCoded = false; } if( cs.slice->getUseChromaQpAdj() && partitioner.currDepth <= pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth() ) +#endif { cuCtx.isChromaQpAdjCoded = false; } @@ -397,12 +406,20 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU // Reset delta QP coding flag and ChromaQPAdjustemt coding flag if (CS::isDualITree(cs) && pPartitionerChroma != nullptr) { - +#if JVET_M0113_M0188_QG_SIZE + if (pps.getUseDQP() && pPartitionerChroma->currQgEnable()) + { + pCuCtxChroma->qgStart = true; + pCuCtxChroma->isDQPCoded = false; + } + if (cs.slice->getUseChromaQpAdj() && pPartitionerChroma->currQgChromaEnable()) +#else if (pps.getUseDQP() && pPartitionerChroma->currDepth <= pps.getMaxCuDQPDepth()) { pCuCtxChroma->isDQPCoded = false; } if (cs.slice->getUseChromaQpAdj() && pPartitionerChroma->currDepth <= pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth()) +#endif { pCuCtxChroma->isChromaQpAdjCoded = false; } @@ -638,8 +655,14 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU #endif // Predict QP on start of quantization group +#if JVET_M0113_M0188_QG_SIZE + if( cuCtx.qgStart ) + { + cuCtx.qgStart = false; +#else if( pps.getUseDQP() && !cuCtx.isDQPCoded && CU::isQGStart( cu, partitioner ) ) { +#endif cuCtx.qp = CU::predictQP( cu, cuCtx.qp ); } diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 32afc7e3f..16a26e145 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -413,12 +413,21 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS ) READ_FLAG( uiCode, "cu_qp_delta_enabled_flag" ); pcPPS->setUseDQP( uiCode ? true : false ); if( pcPPS->getUseDQP() ) { +#if JVET_M0113_M0188_QG_SIZE + READ_UVLC( uiCode, "cu_qp_delta_subdiv" ); + pcPPS->setCuQpDeltaSubdiv( uiCode ); +#else READ_UVLC( uiCode, "diff_cu_qp_delta_depth" ); pcPPS->setMaxCuDQPDepth( uiCode ); +#endif } else { +#if JVET_M0113_M0188_QG_SIZE + pcPPS->setCuQpDeltaSubdiv( 0 ); +#else pcPPS->setMaxCuDQPDepth( 0 ); +#endif } READ_SVLC( iCode, "pps_cb_qp_offset"); pcPPS->setQpOffset(COMPONENT_Cb, iCode); @@ -561,11 +570,19 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS ) if (uiCode == 0) { ppsRangeExtension.clearChromaQpOffsetList(); +#if JVET_M0113_M0188_QG_SIZE + ppsRangeExtension.setCuChromaQpOffsetSubdiv(0); +#else ppsRangeExtension.setDiffCuChromaQpOffsetDepth(0); +#endif } else { +#if JVET_M0113_M0188_QG_SIZE + READ_UVLC(uiCode, "cu_chroma_qp_offset_subdiv"); ppsRangeExtension.setCuChromaQpOffsetSubdiv(uiCode); +#else READ_UVLC(uiCode, "diff_cu_chroma_qp_offset_depth"); ppsRangeExtension.setDiffCuChromaQpOffsetDepth(uiCode); +#endif uint32_t tableSizeMinus1 = 0; READ_UVLC(tableSizeMinus1, "chroma_qp_offset_list_len_minus1"); CHECK(tableSizeMinus1 >= MAX_QP_OFFSET_LIST_SIZE, "Table size exceeds maximum"); diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 513f6a35a..ce1a899f6 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -375,22 +375,40 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione const CodingUnit &cu = *cs.getCU( currArea.blocks[partitioner.chType], partitioner.chType ); // Reset delta QP coding flag and ChromaQPAdjustemt coding flag +#if JVET_M0113_M0188_QG_SIZE + if( pps.getUseDQP() && partitioner.currQgEnable() ) + { + cuCtx.qgStart = true; + cuCtx.isDQPCoded = false; + } + if( cs.slice->getUseChromaQpAdj() && partitioner.currQgChromaEnable() ) +#else if( pps.getUseDQP() && partitioner.currDepth <= pps.getMaxCuDQPDepth() ) { cuCtx.isDQPCoded = false; } if( cs.slice->getUseChromaQpAdj() && partitioner.currDepth <= pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth() ) +#endif { cuCtx.isChromaQpAdjCoded = false; } // Reset delta QP coding flag and ChromaQPAdjustemt coding flag if (CS::isDualITree(cs) && pPartitionerChroma != nullptr) { +#if JVET_M0113_M0188_QG_SIZE + if (pps.getUseDQP() && pPartitionerChroma->currQgEnable()) + { + pCuCtxChroma->qgStart = true; + pCuCtxChroma->isDQPCoded = false; + } + if (cs.slice->getUseChromaQpAdj() && pPartitionerChroma->currQgChromaEnable()) +#else if (pps.getUseDQP() && pPartitionerChroma->currDepth <= pps.getMaxCuDQPDepth()) { pCuCtxChroma->isDQPCoded = false; } if (cs.slice->getUseChromaQpAdj() && pPartitionerChroma->currDepth <= pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth()) +#endif { pCuCtxChroma->isChromaQpAdjCoded = false; } @@ -521,8 +539,14 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione #endif // Predict QP on start of quantization group +#if JVET_M0113_M0188_QG_SIZE + if( cuCtx.qgStart ) + { + cuCtx.qgStart = false; +#else if( pps.getUseDQP() && !cuCtx.isDQPCoded && CU::isQGStart( cu, partitioner ) ) { +#endif cuCtx.qp = CU::predictQP( cu, cuCtx.qp ); } diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 6e25a19a1..8c85c8ba3 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -335,8 +335,13 @@ protected: //====== Quality control ======== int m_iMaxDeltaQP; // Max. absolute delta QP (1:default) +#if JVET_M0113_M0188_QG_SIZE + int m_cuQpDeltaSubdiv; // Max. subdivision level for a CuDQP (0:default) + int m_cuChromaQpOffsetSubdiv; ///< If negative, then do not apply chroma qp offsets. +#else int m_iMaxCuDQPDepth; // Max. depth for a minimum CuDQP (0:default) int m_diffCuChromaQpOffsetDepth; ///< If negative, then do not apply chroma qp offsets. +#endif int m_chromaCbQpOffset; // Chroma Cb QP Offset (0:default) int m_chromaCrQpOffset; // Chroma Cr Qp Offset (0:default) @@ -923,10 +928,16 @@ public: //====== Quality control ======== void setMaxDeltaQP ( int i ) { m_iMaxDeltaQP = i; } +#if JVET_M0113_M0188_QG_SIZE + void setCuQpDeltaSubdiv ( int i ) { m_cuQpDeltaSubdiv = i; } + int getCuChromaQpOffsetSubdiv () const { return m_cuChromaQpOffsetSubdiv; } + void setCuChromaQpOffsetSubdiv (int value) { m_cuChromaQpOffsetSubdiv = value; } +#else void setMaxCuDQPDepth ( int i ) { m_iMaxCuDQPDepth = i; } int getDiffCuChromaQpOffsetDepth () const { return m_diffCuChromaQpOffsetDepth; } void setDiffCuChromaQpOffsetDepth (int value) { m_diffCuChromaQpOffsetDepth = value; } +#endif void setChromaCbQpOffset ( int i ) { m_chromaCbQpOffset = i; } void setChromaCrQpOffset ( int i ) { m_chromaCrQpOffset = i; } @@ -1030,7 +1041,11 @@ public: //==== Quality control ======== int getMaxDeltaQP () const { return m_iMaxDeltaQP; } +#if JVET_M0113_M0188_QG_SIZE + int getCuQpDeltaSubdiv () const { return m_cuQpDeltaSubdiv; } +#else int getMaxCuDQPDepth () const { return m_iMaxCuDQPDepth; } +#endif bool getUseAdaptiveQP () const { return m_bUseAdaptiveQP; } int getQPAdaptationRange () const { return m_iQPAdaptationRange; } #if ENABLE_QPA diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index dd0321288..2eb72295a 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -668,8 +668,14 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par if( slice.getUseChromaQpAdj() ) { +#if JVET_M0113_M0188_QG_SIZE + // TODO M0133 : double check encoder decisions with respect to chroma QG detection and actual encode + int lgMinCuSize = sps.getLog2MinCodingBlockSize() + + std::max<int>( 0, sps.getLog2DiffMaxMinCodingBlockSize() - int( pps.getPpsRangeExtension().getCuChromaQpOffsetSubdiv()/2 ) ); +#else int lgMinCuSize = sps.getLog2MinCodingBlockSize() + std::max<int>( 0, sps.getLog2DiffMaxMinCodingBlockSize() - int( pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth() ) ); +#endif m_cuChromaQpOffsetIdxPlus1 = ( ( uiLPelX >> lgMinCuSize ) + ( uiTPelY >> lgMinCuSize ) ) % ( pps.getPpsRangeExtension().getChromaQpOffsetListLen() + 1 ); } @@ -711,7 +717,11 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par } #if SHARP_LUMA_DELTA_QP || ENABLE_QPA_SUB_CTU +#if JVET_M0113_M0188_QG_SIZE + if (partitioner.currQgEnable() && ( +#else if (partitioner.currDepth <= pps.getMaxCuDQPDepth() && ( +#endif #if SHARP_LUMA_DELTA_QP (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()) || #endif @@ -1127,12 +1137,14 @@ void EncCu::copyState( EncCu* other, Partitioner& partitioner, const UnitArea& c void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) { const int qp = encTestMode.qp; - const PPS &pps = *tempCS->pps; const Slice &slice = *tempCS->slice; const bool bIsLosslessMode = false; // False at this level. Next level down may set it to true. const int oldPrevQp = tempCS->prevQP[partitioner.chType]; const auto oldMotionLut = tempCS->motionLut; - const uint32_t currDepth = partitioner.currDepth; +#if !JVET_M0113_M0188_QG_SIZE + const PPS &pps = *tempCS->pps; + const uint32_t currDepth = partitioner.currDepth; +#endif const PartSplit split = getPartSplit( encTestMode ); @@ -1253,6 +1265,9 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, #endif partitioner.splitCurrArea( split, *tempCS ); +#if JVET_M0113_M0188_QG_SIZE + bool qgEnableChildren = partitioner.currQgEnable(); // QG possible at children level +#endif m_CurrCtx++; @@ -1308,7 +1323,11 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, bool keepResi = KEEP_PRED_AND_RESI_SIGNALS; tempCS->useSubStructure( *bestSubCS, partitioner.chType, CS::getArea( *tempCS, subCUArea, partitioner.chType ), KEEP_PRED_AND_RESI_SIGNALS, true, keepResi, keepResi ); +#if JVET_M0113_M0188_QG_SIZE + if( partitioner.currQgEnable() ) +#else if(currDepth < pps.getMaxCuDQPDepth()) +#endif { tempCS->prevQP[partitioner.chType] = bestSubCS->prevQP[partitioner.chType]; } @@ -1381,6 +1400,9 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, tempCS->cost = m_pcRdCost->calcRdCost( tempCS->fracBits, tempCS->dist ); // Check Delta QP bits for splitted structure +#if JVET_M0113_M0188_QG_SIZE + if( !qgEnableChildren ) // check at deepest QG level only +#endif xCheckDQP( *tempCS, partitioner, true ); // If the configuration being tested exceeds the maximum number of bytes for a slice / slice-segment, then @@ -1772,15 +1794,23 @@ void EncCu::xCheckDQP( CodingStructure& cs, Partitioner& partitioner, bool bKeep return; } +#if JVET_M0113_M0188_QG_SIZE + if( !partitioner.currQgEnable() ) // do not consider split or leaf/not leaf QG condition (checked by caller) +#else + // partitioner.currDepth != cs.pps->getMaxCuDQPDepth() means we are not at leaf QG level (condition needed to call predictQP only once per QG) if( bKeepCtx && partitioner.currDepth != cs.pps->getMaxCuDQPDepth() ) +#endif { return; } +#if !JVET_M0113_M0188_QG_SIZE + // not split or implicit, and deeper than QG (never happens with JVET_M0113_M0188_QG_SIZE) if( !bKeepCtx && partitioner.currDepth > cs.pps->getMaxCuDQPDepth() ) { return; } +#endif CodingUnit* cuFirst = cs.getCU( partitioner.chType ); @@ -3581,7 +3611,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct xCheckDQP (*tempCS, partitioner); #else // this if-check is redundant +#if JVET_M0113_M0188_QG_SIZE + if (tempCS->pps->getUseDQP() && partitioner.currQgEnable()) +#else if (tempCS->pps->getUseDQP() && (partitioner.currDepth) <= tempCS->pps->getMaxCuDQPDepth()) +#endif { xCheckDQP(*tempCS, partitioner); } @@ -3727,7 +3761,11 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best xCheckDQP (*tempCS, partitioner); #else // this if-check is redundant +#if JVET_M0113_M0188_QG_SIZE + if (tempCS->pps->getUseDQP() && partitioner.currQgEnable()) +#else if (tempCS->pps->getUseDQP() && (partitioner.currDepth) <= tempCS->pps->getMaxCuDQPDepth()) +#endif { xCheckDQP(*tempCS, partitioner); } diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index e62fedc1c..db1ef4502 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -777,7 +777,11 @@ void EncLib::xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Pict rpcPic->create( sps.getChromaFormatIdc(), Size( sps.getPicWidthInLumaSamples(), sps.getPicHeightInLumaSamples()), sps.getMaxCUWidth(), sps.getMaxCUWidth()+16, false ); if ( getUseAdaptiveQP() ) { +#if JVET_M0113_M0188_QG_SIZE + const uint32_t iMaxDQPLayer = pps.getCuQpDeltaSubdiv()/2+1; +#else const uint32_t iMaxDQPLayer = pps.getMaxCuDQPDepth()+1; +#endif rpcPic->aqlayer.resize( iMaxDQPLayer ); for (uint32_t d = 0; d < iMaxDQPLayer; d++) { @@ -1269,7 +1273,11 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) pps.setSPSId(sps.getSPSId()); pps.setConstrainedIntraPred( m_bUseConstrainedIntraPred ); +#if JVET_M0113_M0188_QG_SIZE + bool bUseDQP = (getCuQpDeltaSubdiv() > 0)? true : false; +#else bool bUseDQP = (getMaxCuDQPDepth() > 0)? true : false; +#endif if((getMaxDeltaQP() != 0 )|| getUseAdaptiveQP()) { @@ -1285,7 +1293,11 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) #if ENABLE_QPA if (getUsePerceptQPA() && !bUseDQP) { +#if JVET_M0113_M0188_QG_SIZE + CHECK( m_cuQpDeltaSubdiv != 0, "max. delta-QP subdiv must be zero!" ); +#else CHECK( m_iMaxCuDQPDepth != 0, "max. delta-QP depth must be zero!" ); +#endif bUseDQP = (getBaseQP() < 38) && (getSourceWidth() > 512 || getSourceHeight() > 320); } #endif @@ -1299,29 +1311,51 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) if ( m_RCEnableRateControl ) { pps.setUseDQP(true); +#if JVET_M0113_M0188_QG_SIZE + pps.setCuQpDeltaSubdiv( 0 ); +#else pps.setMaxCuDQPDepth( 0 ); +#endif } else if(bUseDQP) { pps.setUseDQP(true); +#if JVET_M0113_M0188_QG_SIZE + pps.setCuQpDeltaSubdiv( m_cuQpDeltaSubdiv ); +#else pps.setMaxCuDQPDepth( m_iMaxCuDQPDepth ); +#endif } else { pps.setUseDQP(false); +#if JVET_M0113_M0188_QG_SIZE + pps.setCuQpDeltaSubdiv( 0 ); +#else pps.setMaxCuDQPDepth( 0 ); +#endif } +#if JVET_M0113_M0188_QG_SIZE + if ( m_cuChromaQpOffsetSubdiv >= 0 ) + { + pps.getPpsRangeExtension().setCuChromaQpOffsetSubdiv(m_cuChromaQpOffsetSubdiv); +#else if ( m_diffCuChromaQpOffsetDepth >= 0 ) { pps.getPpsRangeExtension().setDiffCuChromaQpOffsetDepth(m_diffCuChromaQpOffsetDepth); +#endif pps.getPpsRangeExtension().clearChromaQpOffsetList(); pps.getPpsRangeExtension().setChromaQpOffsetListEntry(1, 6, 6); /* todo, insert table entries from command line (NB, 0 should not be touched) */ } else { +#if JVET_M0113_M0188_QG_SIZE + pps.getPpsRangeExtension().setCuChromaQpOffsetSubdiv(0); +#else pps.getPpsRangeExtension().setDiffCuChromaQpOffsetDepth(0); +#endif pps.getPpsRangeExtension().clearChromaQpOffsetList(); } pps.getPpsRangeExtension().setCrossComponentPredictionEnabledFlag(m_crossComponentPredictionEnabledFlag); diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index bbf54d978..6e5020f55 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -132,7 +132,11 @@ void EncModeCtrl::setBest( CodingStructure& cs ) } } +#if JVET_M0113_M0188_QG_SIZE +void EncModeCtrl::xGetMinMaxQP( int& minQP, int& maxQP, const CodingStructure& cs, const Partitioner &partitioner, const int baseQP, const SPS& sps, const PPS& pps, const PartSplit splitMode ) +#else void EncModeCtrl::xGetMinMaxQP( int& minQP, int& maxQP, const CodingStructure& cs, const Partitioner &partitioner, const int baseQP, const SPS& sps, const PPS& pps, const bool splitMode ) +#endif { if( m_pcEncCfg->getUseRateCtrl() ) { @@ -141,6 +145,37 @@ void EncModeCtrl::xGetMinMaxQP( int& minQP, int& maxQP, const CodingStructure& c return; } +#if JVET_M0113_M0188_QG_SIZE + const unsigned subdivIncr = (splitMode == CU_QUAD_SPLIT) ? 2 : (splitMode == CU_BT_SPLIT) ? 1 : 0; + const bool qgEnable = partitioner.currQgEnable(); // QG possible at current level + const bool qgEnableChildren = qgEnable && ((partitioner.currSubdiv + subdivIncr) <= pps.getCuQpDeltaSubdiv()) && (subdivIncr > 0); // QG possible at next level + const bool isLeafQG = (qgEnable && !qgEnableChildren); + + if( isLeafQG ) // QG at deepest level + { + int deltaQP = m_pcEncCfg->getMaxDeltaQP(); + minQP = Clip3( -sps.getQpBDOffset( CHANNEL_TYPE_LUMA ), MAX_QP, baseQP - deltaQP ); + maxQP = Clip3( -sps.getQpBDOffset( CHANNEL_TYPE_LUMA ), MAX_QP, baseQP + deltaQP ); + } + else if( qgEnableChildren ) // more splits and not the deepest QG level + { + minQP = baseQP; + maxQP = baseQP; + } + else // deeper than QG + { + minQP = cs.currQP[partitioner.chType]; + maxQP = cs.currQP[partitioner.chType]; + } + +#if SHARP_LUMA_DELTA_QP + if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() ) + { + minQP = Clip3( -sps.getQpBDOffset( CHANNEL_TYPE_LUMA ), MAX_QP, baseQP - m_lumaQPOffset ); + maxQP = minQP; + } +#endif +#else const uint32_t currDepth = partitioner.currDepth; if( !splitMode ) @@ -956,7 +991,11 @@ bool BestEncInfoCache::isValid( const CodingStructure& cs, const Partitioner& pa #else || encInfo.cu.ibc #endif +#if JVET_M0113_M0188_QG_SIZE + || partitioner.currQgEnable() || cs.currQP[partitioner.chType] != encInfo.cu.qp +#else || partitioner.currDepth <= cs.pps->getMaxCuDQPDepth() || cs.currQP[partitioner.chType] != encInfo.cu.qp +#endif ) { return false; @@ -979,7 +1018,11 @@ bool BestEncInfoCache::setCsFrom( CodingStructure& cs, EncTestMode& testMode, co , encInfo.pu, (cs.picture->Y().width), (cs.picture->Y().height) #endif ) +#if JVET_M0113_M0188_QG_SIZE + || partitioner.currQgEnable() || cs.currQP[partitioner.chType] != encInfo.cu.qp +#else || partitioner.currDepth <= cs.pps->getMaxCuDQPDepth() || cs.currQP[partitioner.chType] != encInfo.cu.qp +#endif ) { return false; @@ -1181,7 +1224,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru } #endif #if SHARP_LUMA_DELTA_QP +#if JVET_M0113_M0188_QG_SIZE + if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && partitioner.currQgEnable()) +#else if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && partitioner.currDepth <= cs.pps->getMaxCuDQPDepth()) +#endif { CompArea clipedArea = clipArea( cs.area.Y(), cs.picture->Y() ); // keep using the same m_QP_LUMA_OFFSET in the same CTU @@ -1192,7 +1239,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru int minQP = baseQP; int maxQP = baseQP; +#if JVET_M0113_M0188_QG_SIZE + xGetMinMaxQP( minQP, maxQP, cs, partitioner, baseQP, *cs.sps, *cs.pps, CU_QUAD_SPLIT ); +#else xGetMinMaxQP( minQP, maxQP, cs, partitioner, baseQP, *cs.sps, *cs.pps, true ); +#endif bool checkIbc = true; if (cs.chType == CHANNEL_TYPE_CHROMA) { @@ -1247,6 +1298,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru } } +#if JVET_M0113_M0188_QG_SIZE + int minQPq = minQP; + int maxQPq = maxQP; + xGetMinMaxQP( minQP, maxQP, cs, partitioner, baseQP, *cs.sps, *cs.pps, CU_BT_SPLIT ); +#endif if( partitioner.canSplit( CU_VERT_SPLIT, cs ) ) { // add split modes @@ -1277,7 +1333,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru if( cuECtx.get<bool>( QT_BEFORE_BT ) ) { +#if JVET_M0113_M0188_QG_SIZE + for( int qp = maxQPq; qp >= minQPq; qp-- ) +#else for( int qp = maxQP; qp >= minQP; qp-- ) +#endif { m_ComprCUCtxList.back().testModes.push_back( { ETM_SPLIT_QT, ETO_STANDARD, qp, false } ); } @@ -1285,7 +1345,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru m_ComprCUCtxList.back().testModes.push_back( { ETM_POST_DONT_SPLIT } ); +#if JVET_M0113_M0188_QG_SIZE + xGetMinMaxQP( minQP, maxQP, cs, partitioner, baseQP, *cs.sps, *cs.pps, CU_DONT_SPLIT ); +#else xGetMinMaxQP( minQP, maxQP, cs, partitioner, baseQP, *cs.sps, *cs.pps, false ); +#endif bool useLossless = false; int lowestQP = minQP; diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h index 505717ff3..553c9e811 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.h +++ b/source/Lib/EncoderLib/EncModeCtrl.h @@ -345,7 +345,11 @@ public: protected: void xExtractFeatures ( const EncTestMode encTestmode, CodingStructure& cs ); +#if JVET_M0113_M0188_QG_SIZE + void xGetMinMaxQP ( int& iMinQP, int& iMaxQP, const CodingStructure& cs, const Partitioner &pm, const int baseQP, const SPS& sps, const PPS& pps, const PartSplit splitMode ); +#else void xGetMinMaxQP ( int& iMinQP, int& iMaxQP, const CodingStructure& cs, const Partitioner &pm, const int baseQP, const SPS& sps, const PPS& pps, const bool splitMode ); +#endif int xComputeDQP ( const CodingStructure &cs, const Partitioner &pm ); }; diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 9b94251df..55c36ff77 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -233,7 +233,11 @@ void HLSWriter::codePPS( const PPS* pcPPS ) WRITE_FLAG( pcPPS->getUseDQP() ? 1 : 0, "cu_qp_delta_enabled_flag" ); if ( pcPPS->getUseDQP() ) { +#if JVET_M0113_M0188_QG_SIZE + WRITE_UVLC( pcPPS->getCuQpDeltaSubdiv(), "cu_qp_delta_subdiv" ); +#else WRITE_UVLC( pcPPS->getMaxCuDQPDepth(), "diff_cu_qp_delta_depth" ); +#endif } WRITE_SVLC( pcPPS->getQpOffset(COMPONENT_Cb), "pps_cb_qp_offset" ); @@ -341,7 +345,11 @@ void HLSWriter::codePPS( const PPS* pcPPS ) WRITE_FLAG(uint32_t(ppsRangeExtension.getChromaQpOffsetListEnabledFlag()), "chroma_qp_offset_list_enabled_flag" ); if (ppsRangeExtension.getChromaQpOffsetListEnabledFlag()) { +#if JVET_M0113_M0188_QG_SIZE + WRITE_UVLC(ppsRangeExtension.getCuChromaQpOffsetSubdiv(), "cu_chroma_qp_offset_subdiv"); +#else WRITE_UVLC(ppsRangeExtension.getDiffCuChromaQpOffsetDepth(), "diff_cu_chroma_qp_offset_depth"); +#endif WRITE_UVLC(ppsRangeExtension.getChromaQpOffsetListLen() - 1, "chroma_qp_offset_list_len_minus1"); /* skip zero index */ for (int cuChromaQpOffsetIdx = 0; cuChromaQpOffsetIdx < ppsRangeExtension.getChromaQpOffsetListLen(); cuChromaQpOffsetIdx++) -- GitLab