diff --git a/doc/software-manual.tex b/doc/software-manual.tex index 160b3aefe52e8c81856925f044c37a8943ed81fa..873f4f25ae38560688ae2b17d6d339f79b4a579b 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -2206,11 +2206,11 @@ Defines the periodicity for inter slices that use the slice-level chroma QP offs Defines the slice-level QP offset to be used for intra slices, or once every 'SliceChromaQPOffsetPeriodicity' pictures. \\ -\Option{MaxCuDQPDepth (-dqd)} & +\Option{MaxCuDQPSubdiv (-dqd)} & %\ShortOption{\None} & \Default{0} & -Defines maximum depth of a minimum CuDQP for sub-LCU-level delta QP. -MaxCuDQPDepth shall be greater than or equal to SliceGranularity. +Defines maximum CTU subdivision level defining luma Quantization Groups. A quantization group contains at most one luma QP delta (carried by the first coded TU), and all CUs inside a QG share the same luma QP predictor. +"Sbudivision level" means how many times the number of samples of the CTU is divided by two, e.g. a binary split increases subdiv by 1 and a quad split increases subdiv by 2. \\ \Option{RDOQ} & @@ -2330,10 +2330,26 @@ Specifies whether scaling matrices are disabled to blocks when the colour space Indicates if the designated colour space of scaling matrices is equal to the original colour space. \\ -\Option{MaxCUChromaQpAdjustmentDepth} & +\Option{MaxCuChromaQpOffsetSubdiv} & %\ShortOption{\None} & -\Default{-1} & -Specifies the maximum depth for CU chroma QP adjustment; if negative, CU chroma QP adjustment is disabled. +\Default{0} & +Specifies the maximum subdiv for CU chroma QP adjustment. Has no effect if CbQpOffsetList, etc. are left empty. +\\ + +\Option{SliceCuChromaQpOffsetEnabled} & +%\ShortOption{\None} & +\Default{true} & +Specifies whether CU chroma QP adjustment is enabled at slice level. Has no effect if CbQpOffsetList, etc. are left empty. +\\ + +\Option{CbQpOffsetList}% +\Option{CrQpOffsetList}% +\Option{CbCrQpOffsetList} & +%\ShortOption{\None} & +\Default{\NotSet} & +Comma-separated value lists specifying the Cb/Cr/CbCr QP offsets for each chroma QP adjustment index. Each list shall be the same length. +CbCrQpOffsetList may be omitted whereas CbQpOffsetList and CrQpOffsetList are specified, in which case it is filled with zeros. +Note that when CbCrQpOffset and CbCrQpOffsetList values are all zero, pps_joint_cbcr_qp_offset_present_flag will be automatically set to zero. \\ \end{OptionTableNoShorthand} diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 11679cf63499062a81a353614a01d57018b74293..e9a2ca876be43ec851239d9c83352625e14713b3 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -588,6 +588,8 @@ void EncApp::xInitLibCfg() m_cEncLib.setMaxDeltaQP ( m_iMaxDeltaQP ); m_cEncLib.setCuQpDeltaSubdiv ( m_cuQpDeltaSubdiv ); m_cEncLib.setCuChromaQpOffsetSubdiv ( m_cuChromaQpOffsetSubdiv ); + m_cEncLib.setCuChromaQpOffsetList ( m_cuChromaQpOffsetList ); + m_cEncLib.setCuChromaQpOffsetEnabled ( m_cuChromaQpOffsetEnabled ); 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 6305b22588a64610d6824aa6bd16f1e300d3e7ae..24b14a55df896078c2491583966568183f95cf04 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -606,6 +606,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) SMultiValueInput<int> cfg_qpOutValCr (MIN_QP_VALUE_FOR_16_BIT, MAX_QP, 0, MAX_NUM_QP_VALUES, zeroVector, 1); SMultiValueInput<int> cfg_qpInValCbCr (MIN_QP_VALUE_FOR_16_BIT, MAX_QP, 0, MAX_NUM_QP_VALUES, zeroVector, 1); SMultiValueInput<int> cfg_qpOutValCbCr (MIN_QP_VALUE_FOR_16_BIT, MAX_QP, 0, MAX_NUM_QP_VALUES, zeroVector, 1); + const int cQpOffsets[] = { 6 }; + SMultiValueInput<int> cfg_cbQpOffsetList (-12, 12, 0, 6, cQpOffsets, 0); + SMultiValueInput<int> cfg_crQpOffsetList (-12, 12, 0, 6, cQpOffsets, 0); + SMultiValueInput<int> cfg_cbCrQpOffsetList (-12, 12, 0, 6, cQpOffsets, 0); + const uint32_t defaultInputKneeCodes[3] = { 600, 800, 900 }; const uint32_t defaultOutputKneeCodes[3] = { 100, 250, 450 }; SMultiValueInput<uint32_t> cfg_kneeSEIInputKneePointValue (1, 999, 0, 999, defaultInputKneeCodes, sizeof(defaultInputKneeCodes )/sizeof(uint32_t)); @@ -1042,7 +1047,8 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("DeltaQpRD,-dqr", m_uiDeltaQpRD, 0u, "max dQp offset for slice") ("MaxDeltaQP,d", m_iMaxDeltaQP, 0, "max dQp offset for block") ("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") + ("MaxCuChromaQpOffsetSubdiv", m_cuChromaQpOffsetSubdiv, 0, "Maximum subdiv for CU chroma Qp adjustment") + ("SliceCuChromaQpOffsetEnabled", m_cuChromaQpOffsetEnabled, true, "Enable local chroma QP offsets (slice level flag)") ("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") @@ -1078,6 +1084,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("SliceCbQpOffsetIntraOrPeriodic", m_sliceChromaQpOffsetIntraOrPeriodic[0], 0, "Chroma Cb QP Offset at slice level for I slice or for periodic inter slices as defined by SliceChromaQPOffsetPeriodicity. Replaces offset in the GOP table.") ("SliceCrQpOffsetIntraOrPeriodic", m_sliceChromaQpOffsetIntraOrPeriodic[1], 0, "Chroma Cr QP Offset at slice level for I slice or for periodic inter slices as defined by SliceChromaQPOffsetPeriodicity. Replaces offset in the GOP table.") #endif + ("CbQpOffsetList", cfg_cbQpOffsetList, cfg_cbQpOffsetList, "Chroma Cb QP offset list for local adjustment") + ("CrQpOffsetList", cfg_crQpOffsetList, cfg_crQpOffsetList, "Chroma Cb QP offset list for local adjustment") + ("CbCrQpOffsetList", cfg_cbCrQpOffsetList, cfg_cbCrQpOffsetList, "Chroma joint Cb-Cr QP offset list for local adjustment") ("AdaptiveQP,-aq", m_bUseAdaptiveQP, false, "QP adaptation based on a psycho-visual model") ("MaxQPAdaptationRange,-aqr", m_iQPAdaptationRange, 6, "QP adaptation range") @@ -2145,6 +2154,22 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } } + /* Local chroma QP offsets configuration */ + CHECK(m_cuChromaQpOffsetSubdiv < 0, "MaxCuChromaQpOffsetSubdiv shall be >= 0"); + CHECK(cfg_crQpOffsetList.values.size() != cfg_cbQpOffsetList.values.size(), "Chroma QP offset lists shall be the same size"); + CHECK(cfg_cbCrQpOffsetList.values.size() != cfg_cbQpOffsetList.values.size() && cfg_cbCrQpOffsetList.values.size() > 0, "Chroma QP offset list for joint CbCr shall be either the same size as Cb and Cr or empty"); + if (m_cuChromaQpOffsetSubdiv > 0 && !cfg_cbQpOffsetList.values.size()) + { + msg(WARNING, "MaxCuChromaQpOffsetSubdiv has no effect when chroma QP offset lists are empty\n"); + } + m_cuChromaQpOffsetList.resize(cfg_cbQpOffsetList.values.size()); + for (int i=0; i < cfg_cbQpOffsetList.values.size(); i++) + { + m_cuChromaQpOffsetList[i].u.comp.CbOffset = cfg_cbQpOffsetList.values[i]; + m_cuChromaQpOffsetList[i].u.comp.CrOffset = cfg_crQpOffsetList.values[i]; + m_cuChromaQpOffsetList[i].u.comp.JointCbCrOffset = cfg_cbCrQpOffsetList.values.size() ? cfg_cbCrQpOffsetList.values[i] : 0; + } + #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET if ( m_LadfEnabed ) { @@ -3905,7 +3930,21 @@ void EncAppCfg::xPrintParameter() msg( DETAILS, "MSB-extended bit depth : (Y:%d, C:%d)\n", m_MSBExtendedBitDepth[CHANNEL_TYPE_LUMA], m_MSBExtendedBitDepth[CHANNEL_TYPE_CHROMA] ); msg( DETAILS, "Internal bit depth : (Y:%d, C:%d)\n", m_internalBitDepth[CHANNEL_TYPE_LUMA], m_internalBitDepth[CHANNEL_TYPE_CHROMA] ); msg( DETAILS, "Intra reference smoothing : %s\n", (m_enableIntraReferenceSmoothing ? "Enabled" : "Disabled") ); - msg( DETAILS, "cu_chroma_qp_offset_subdiv : %d\n", m_cuChromaQpOffsetSubdiv); + if (m_cuChromaQpOffsetList.size() > 0) + { + msg( DETAILS, "Chroma QP offset list : (" ); + for (int i=0; i < m_cuChromaQpOffsetList.size(); i++) + { + msg( DETAILS, "%d %d %d%s", m_cuChromaQpOffsetList[i].u.comp.CbOffset, m_cuChromaQpOffsetList[i].u.comp.CrOffset, m_cuChromaQpOffsetList[i].u.comp.JointCbCrOffset, + (i+1 < m_cuChromaQpOffsetList.size() ? ", " : ")\n") ); + } + msg( DETAILS, "cu_chroma_qp_offset_subdiv : %d\n", m_cuChromaQpOffsetSubdiv); + msg( DETAILS, "cu_chroma_qp_offset_enabled_flag : %s\n", (m_cuChromaQpOffsetEnabled ? "Enabled" : "Disabled") ); + } + else + { + msg( DETAILS, "Chroma QP offset list : Disabled\n" ); + } msg( DETAILS, "extended_precision_processing_flag : %s\n", (m_extendedPrecisionProcessingFlag ? "Enabled" : "Disabled") ); msg( DETAILS, "transform_skip_rotation_enabled_flag : %s\n", (m_transformSkipRotationEnabledFlag ? "Enabled" : "Disabled") ); msg( DETAILS, "transform_skip_context_enabled_flag : %s\n", (m_transformSkipContextEnabledFlag ? "Enabled" : "Disabled") ); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 8058fd38daa464e3ba1aa740bea3d663e6a6239e..fb76daaae92c2b2b501697c63f7ef11a46f99f12 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -256,9 +256,11 @@ protected: std::string m_dQPFileName; ///< QP offset for each slice (initialized from external file) 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 + uint32_t m_uiDeltaQpRD; ///< dQP range for multi-pass slice QP optimization int m_cuQpDeltaSubdiv; ///< Maximum subdiv for CU luma Qp adjustment (0:default) int m_cuChromaQpOffsetSubdiv; ///< If negative, then do not apply chroma qp offsets. + std::vector<ChromaQpAdj> m_cuChromaQpOffsetList; ///< Local chroma QP offsets list (to be signalled in PPS) + bool m_cuChromaQpOffsetEnabled; ///< Enable local chroma QP offsets (slice level flag) bool m_bFastDeltaQP; ///< Fast Delta QP (false:default) int m_cbQpOffset; ///< Chroma Cb QP Offset (0:default) diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 3b25374e3541233ecb85d339a454f6376c05625c..ea573ccf1ef22cfc1c218c4c2a7aff18a849aba3 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -2575,6 +2575,8 @@ void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, Partiti } } } + + DTRACE_COND( ( isEncoding() ), g_trace_ctx, D_DQP, "x=%d, y=%d, d=%d, qpAdj=%d\n", cu.blocks[cu.chType].lumaPos().x, cu.blocks[cu.chType].lumaPos().y, cu.qtDepth, cu.chromaQpAdj ); } void CABACWriter::cu_qp_delta( const CodingUnit& cu, int predQP, const int8_t qp ) diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 55ee0ac72a27dd1c8ff2b471502f8325d79f5c1b..1a81a3420764ebb38793138478a65023504d6d56 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -431,7 +431,9 @@ protected: //====== Quality control ======== int m_iMaxDeltaQP; // Max. absolute delta QP (1:default) int m_cuQpDeltaSubdiv; // Max. subdivision level for a CuDQP (0:default) - int m_cuChromaQpOffsetSubdiv; ///< If negative, then do not apply chroma qp offsets. + unsigned m_cuChromaQpOffsetSubdiv; ///< Max. subdivision level for a chroma QP adjustment (0:default) + bool m_cuChromaQpOffsetEnabled; ///< Local chroma QP offset enable flag + std::vector<ChromaQpAdj> m_cuChromaQpOffsetList; ///< Local chroma QP offsets list (to be signalled in PPS) int m_chromaCbQpOffset; // Chroma Cb QP Offset (0:default) int m_chromaCrQpOffset; // Chroma Cr Qp Offset (0:default) @@ -1250,8 +1252,11 @@ public: //====== Quality control ======== void setMaxDeltaQP ( int i ) { m_iMaxDeltaQP = i; } void setCuQpDeltaSubdiv ( int i ) { m_cuQpDeltaSubdiv = i; } - int getCuChromaQpOffsetSubdiv () const { return m_cuChromaQpOffsetSubdiv; } - void setCuChromaQpOffsetSubdiv (int value) { m_cuChromaQpOffsetSubdiv = value; } + unsigned getCuChromaQpOffsetSubdiv () const { return m_cuChromaQpOffsetSubdiv; } + void setCuChromaQpOffsetSubdiv ( unsigned value ) { m_cuChromaQpOffsetSubdiv = value; } + bool getCuChromaQpOffsetEnabled () const { return m_cuChromaQpOffsetEnabled; } + void setCuChromaQpOffsetEnabled ( bool value ) { m_cuChromaQpOffsetEnabled = value; } + void setCuChromaQpOffsetList (const std::vector<ChromaQpAdj> &list) { m_cuChromaQpOffsetList = list; } void setChromaCbQpOffset ( int i ) { m_chromaCbQpOffset = i; } void setChromaCrQpOffset ( int i ) { m_chromaCrQpOffset = i; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 0361b847ff3fa35336797a2fffbb5dfd9727a18a..1ae5af0997192bb4d0ed39a4329279a13c4b1e71 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -626,18 +626,20 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par m_CurrCtx->start = m_CABACEstimator->getCtx(); - m_cuChromaQpOffsetIdxPlus1 = 0; - if( slice.getUseChromaQpAdj() ) { // TODO M0133 : double check encoder decisions with respect to chroma QG detection and actual encode int lgMinCuSize = sps.getLog2MinCodingBlockSize() + - std::max<int>(0, floorLog2(sps.getCTUSize()) - sps.getLog2MinCodingBlockSize() - int(slice.getCuChromaQpOffsetSubdiv() / 2)); + std::max<int>(0, floorLog2(sps.getCTUSize()) - sps.getLog2MinCodingBlockSize() - int((slice.getCuChromaQpOffsetSubdiv()+1) / 2)); if( partitioner.currQgChromaEnable() ) { m_cuChromaQpOffsetIdxPlus1 = ( ( uiLPelX >> lgMinCuSize ) + ( uiTPelY >> lgMinCuSize ) ) % ( pps.getChromaQpOffsetListLen() + 1 ); } } + else + { + m_cuChromaQpOffsetIdxPlus1 = 0; + } if( !m_modeCtrl->anyMode() ) { @@ -1293,6 +1295,7 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, partitioner.splitCurrArea( split, *tempCS ); bool qgEnableChildren = partitioner.currQgEnable(); // QG possible at children level + bool qgChromaEnableChildren = partitioner.currQgChromaEnable(); // Chroma QG possible at children level m_CurrCtx++; @@ -1500,6 +1503,13 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, partitioner.treeType = TREE_D; partitioner.modeType = MODE_TYPE_ALL; } + else + { + if (!qgChromaEnableChildren) // check at deepest cQG level only + { + xCheckChromaQPOffset( *tempCS, partitioner ); + } + } // Finally, generate split-signaling bits for RD-cost check const PartSplit implicitSplit = partitioner.getImplicitSplit( *tempCS ); @@ -2156,43 +2166,47 @@ void EncCu::xCheckChromaQPOffset( CodingStructure& cs, Partitioner& partitioner return; } - // not needed after the first coded TU in the chroma QG + // check cost only at cQG top-level (everything below shall not be influenced by adj coding: it occurs only once) if( !partitioner.currQgChromaEnable() ) { return; } - CodingUnit& cu = *cs.getCU( partitioner.chType ); - // check if chroma is coded or not - bool hasResidual = false; - for( const TransformUnit &tu : CU::traverseTUs(cu) ) + bool isCoded = false; + for( auto &cu : cs.cus ) { - if( tu.cbf[COMPONENT_Cb] || tu.cbf[COMPONENT_Cr] ) + SizeType channelWidth = !cu->isSepTree() ? cu->lwidth() : cu->chromaSize().width; + SizeType channelHeight = !cu->isSepTree() ? cu->lheight() : cu->chromaSize().height; + + for( const TransformUnit &tu : CU::traverseTUs(*cu) ) { - hasResidual = true; + if( tu.cbf[COMPONENT_Cb] || tu.cbf[COMPONENT_Cr] || channelWidth > 64 || channelHeight > 64) + { + isCoded = true; + break; + } + } + if (isCoded) + { + // estimate cost for coding cu_chroma_qp_offset + TempCtx ctxTempAdjFlag( m_CtxCache ); + TempCtx ctxTempAdjIdc( m_CtxCache ); + ctxTempAdjFlag = SubCtx( Ctx::ChromaQpAdjFlag, m_CABACEstimator->getCtx() ); + ctxTempAdjIdc = SubCtx( Ctx::ChromaQpAdjIdc, m_CABACEstimator->getCtx() ); + m_CABACEstimator->resetBits(); + m_CABACEstimator->cu_chroma_qp_offset( *cu ); + cs.fracBits += m_CABACEstimator->getEstFracBits(); + cs.cost = m_pcRdCost->calcRdCost(cs.fracBits, cs.dist); + m_CABACEstimator->getCtx() = SubCtx( Ctx::ChromaQpAdjFlag, ctxTempAdjFlag ); + m_CABACEstimator->getCtx() = SubCtx( Ctx::ChromaQpAdjIdc, ctxTempAdjIdc ); break; } - } - - if( hasResidual ) - { - // estimate cost for coding cu_chroma_qp_offset - TempCtx ctxTempAdjFlag( m_CtxCache ); - TempCtx ctxTempAdjIdc( m_CtxCache ); - ctxTempAdjFlag = SubCtx( Ctx::ChromaQpAdjFlag, m_CABACEstimator->getCtx() ); - ctxTempAdjIdc = SubCtx( Ctx::ChromaQpAdjIdc, m_CABACEstimator->getCtx() ); - m_CABACEstimator->resetBits(); - m_CABACEstimator->cu_chroma_qp_offset( cu ); - cs.fracBits += m_CABACEstimator->getEstFracBits(); - cs.cost = m_pcRdCost->calcRdCost(cs.fracBits, cs.dist); - m_CABACEstimator->getCtx() = SubCtx( Ctx::ChromaQpAdjFlag, ctxTempAdjFlag ); - m_CABACEstimator->getCtx() = SubCtx( Ctx::ChromaQpAdjIdc, ctxTempAdjIdc ); - } - else - { - // reset chroma QP offset to 0 if it will not be coded - cu.chromaQpAdj = 0; + else + { + // chroma QP adj is forced to 0 for leading uncoded CUs + cu->chromaQpAdj = 0; + } } } @@ -2833,6 +2847,7 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure cu.predMode = MODE_INTER; cu.slice = tempCS->slice; cu.tileIdx = tempCS->pps->getTileIdx(tempCS->area.lumaPos()); + cu.chromaQpAdj = m_cuChromaQpOffsetIdxPlus1; cu.qp = encTestMode.qp; cu.affine = false; cu.mtsFlag = false; @@ -3052,6 +3067,7 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure cu.predMode = MODE_INTER; cu.slice = tempCS->slice; cu.tileIdx = tempCS->pps->getTileIdx(tempCS->area.lumaPos()); + cu.chromaQpAdj = m_cuChromaQpOffsetIdxPlus1; cu.qp = encTestMode.qp; cu.affine = false; cu.mtsFlag = false; diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 34c2862a1d49d63f1eb3e798b41c1a5e7cd05a70..af03029afa6aa61bd9d2d28767864d74c00d3e89 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -1609,11 +1609,15 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) pps.setUseDQP(false); } - if ( m_cuChromaQpOffsetSubdiv >= 0 ) + if ( m_cuChromaQpOffsetList.size() > 0 ) { + /* insert table entries from cfg parameters (NB, 0 should not be touched) */ pps.clearChromaQpOffsetList(); - pps.setChromaQpOffsetListEntry(1, 6, 6, 6); - /* todo, insert table entries from command line (NB, 0 should not be touched) */ + for (int i=0; i < m_cuChromaQpOffsetList.size(); i++) + { + pps.setChromaQpOffsetListEntry(i + 1, m_cuChromaQpOffsetList[i].u.comp.CbOffset, + m_cuChromaQpOffsetList[i].u.comp.CrOffset, m_cuChromaQpOffsetList[i].u.comp.JointCbCrOffset); + } } else { @@ -1635,13 +1639,18 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) pps.setPicInitQPMinus26( std::min( maxDQP, std::max( minDQP, baseQp ) )); } - if( sps.getJointCbCrEnabledFlag() == false || getChromaFormatIdc() == CHROMA_400 || m_chromaCbCrQpOffset == 0 ) + if (sps.getJointCbCrEnabledFlag() == false || getChromaFormatIdc() == CHROMA_400) { pps.setJointCbCrQpOffsetPresentFlag(false); } else { - pps.setJointCbCrQpOffsetPresentFlag(true); + bool enable = (m_chromaCbCrQpOffset != 0); + for (int i=0; i < m_cuChromaQpOffsetList.size(); i++) + { + enable |= (m_cuChromaQpOffsetList[i].u.comp.JointCbCrOffset != 0); + } + pps.setJointCbCrQpOffsetPresentFlag(enable); } #if ER_CHROMA_QP_WCG_PPS @@ -1929,17 +1938,8 @@ void EncLib::xInitPicHeader(PicHeader &picHeader, const SPS &sps, const PPS &pps picHeader.setCuQpDeltaSubdivInter( 0 ); } - if( m_cuChromaQpOffsetSubdiv >= 0 ) - { - picHeader.setCuChromaQpOffsetSubdivIntra(m_cuChromaQpOffsetSubdiv); - picHeader.setCuChromaQpOffsetSubdivInter(m_cuChromaQpOffsetSubdiv); - } - else - { - picHeader.setCuChromaQpOffsetSubdivIntra(0); - picHeader.setCuChromaQpOffsetSubdivInter(0); - } - + picHeader.setCuChromaQpOffsetSubdivIntra(m_cuChromaQpOffsetSubdiv); + picHeader.setCuChromaQpOffsetSubdivInter(m_cuChromaQpOffsetSubdiv); // virtual boundaries if( sps.getVirtualBoundariesEnabledFlag() ) diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index 26aac4f0746b9abdef86ac9ccc791b3c8fc4d3b4..ed4f7116ee10544afefee86b9c84accfaa3b5762 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -923,7 +923,7 @@ bool BestEncInfoCache::isValid( const CodingStructure& cs, const Partitioner& pa { return false; } - if( encInfo.cu.qp != qp ) + if( encInfo.cu.qp != qp || cs.slice->getUseChromaQpAdj()) return false; if( cs.picture->poc != encInfo.poc || CS::getArea( cs, cs.area, partitioner.chType ) != CS::getArea( cs, encInfo.cu, partitioner.chType ) || !isTheSameNbHood( encInfo.cu, cs, partitioner , encInfo.pu, (cs.picture->Y().width), (cs.picture->Y().height) diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index bec81962af9f8ea02edbde84e663750a480ed0d6..637c50754c55460ffccac0ea7dd38a34e54354cf 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -628,7 +628,7 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr rpcSlice->setSliceChromaQpDelta( COMPONENT_Cr, 0 ); rpcSlice->setSliceChromaQpDelta( JOINT_CbCr, 0 ); #endif - rpcSlice->setUseChromaQpAdj( rpcSlice->getPPS()->getCuChromaQpOffsetListEnabledFlag() ); + rpcSlice->setUseChromaQpAdj( m_pcCfg->getCuChromaQpOffsetEnabled() ); rpcSlice->setNumRefIdx(REF_PIC_LIST_0, m_pcCfg->getRPLEntry(0, iGOPid).m_numRefPicsActive); rpcSlice->setNumRefIdx(REF_PIC_LIST_1, m_pcCfg->getRPLEntry(1, iGOPid).m_numRefPicsActive); diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 1e8a56ff7f5ef06297d300142180befb0ff69564..6920137c18b08a411046ba69e1cf1dec5582a274 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -1875,10 +1875,6 @@ WRITE_FLAG(picHeader->getGdrOrIrapPicFlag(), "ph_gdr_or_irap_pic_flag"); { WRITE_UVLC( picHeader->getCuChromaQpOffsetSubdivIntra(), "ph_cu_chroma_qp_offset_subdiv_intra_slice" ); } - else - { - picHeader->setCuChromaQpOffsetSubdivIntra( 0 ); - } } @@ -1908,11 +1904,8 @@ WRITE_FLAG(picHeader->getGdrOrIrapPicFlag(), "ph_gdr_or_irap_pic_flag"); { WRITE_UVLC(picHeader->getCuChromaQpOffsetSubdivInter(), "ph_cu_chroma_qp_offset_subdiv_inter_slice"); } - else - { - picHeader->setCuChromaQpOffsetSubdivInter(0); - } - // temporal motion vector prediction + + // temporal motion vector prediction if (sps->getSPSTemporalMVPEnabledFlag()) { WRITE_FLAG( picHeader->getEnableTMVPFlag(), "ph_temporal_mvp_enabled_flag" );