diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index c3b70fe2b03a4e986411e633b68e2f7adb0a8c2a..673977990b4040248efa1770fcb435e3d4b5e35a 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -150,6 +150,7 @@ AffineAmvr : 1 LMCSEnable : 1 # LMCS: 0: disable, 1:enable LMCSSignalType : 0 # Input signal type: 0:SDR, 1:HDR-PQ, 2:HDR-HLG LMCSUpdateCtrl : 0 # LMCS model update control: 0:RA, 1:AI, 2:LDB/LDP +LMCSoffset : 6 # chroma residual scaling offset MIP : 1 DMVR : 1 SMVD : 1 diff --git a/cfg/per-class/classH1.cfg b/cfg/per-class/classH1.cfg index e7cefecf655c6684755617e8048d0e9dca006003..afde72f0bc268310eafa3fd442eaf0a829b1fbe8 100644 --- a/cfg/per-class/classH1.cfg +++ b/cfg/per-class/classH1.cfg @@ -5,6 +5,7 @@ isSDR : 0 # 1: SDR in PQ container, 0: HDR # ======= LMCS ======================= LMCSEnable : 1 # turned on in HDR CTC LMCSSignalType : 1 # Input signal type: 0:SDR, 1:HDR-PQ, 2:HDR-HLG +LMCSoffset : 1 # chroma residual scaling offset #======== Chroma QP scale ============ WCGPPSEnable : 0 # enable WCG Chroma scale diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index a774e69e169353242cbcaf428fa2cd0404a2e4d8..19148d5bb954824c05ab253b861cf445f729eef6 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -637,6 +637,9 @@ void EncApp::xInitLibCfg() m_cEncLib.setReshapeSignalType ( m_reshapeSignalType ); m_cEncLib.setReshapeIntraCMD ( m_intraCMD ); m_cEncLib.setReshapeCW ( m_reshapeCW ); +#if JVET_P0371_CHROMA_SCALING_OFFSET + m_cEncLib.setReshapeCSoffset ( m_CSoffset ); +#endif #if JVET_O0756_CALCULATE_HDRMETRICS for (int i=0; i<hdrtoolslib::NB_REF_WHITE; i++) diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 550b9c605c1ece48907a6faff15f935538edfe14..5b5784bac011f1bc0ea8d8fd57a1fe4afd5dc9de 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -993,6 +993,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) "1: rsp both (CW66 for QP<=22), 2: rsp TID0 (for all QP)," "3: rsp inter(CW66 for QP<=22), 4: rsp inter(for all QP).") ("LMCSInitialCW", m_initialCW, 0u, "LMCS initial total codeword (0~1023) when LMCSAdpOption > 0") +#if JVET_P0371_CHROMA_SCALING_OFFSET + ("LMCSOffset", m_CSoffset, 0, "LMCS chroma residual scaling offset") +#endif ("IntraCMD", m_intraCMD, 0u, "IntraChroma MD: 0: none, 1:fixed to default wPSNR weight") ("LCTUFast", m_useFastLCTU, false, "Fast methods for large CTU") ("FastMrg", m_useFastMrg, false, "Fast methods for inter merge") @@ -2709,6 +2712,10 @@ bool EncAppCfg::xCheckParameter() xConfirmPara(m_adpOption > 4, "Max. LMCS Adaptation Option is 4"); xConfirmPara(m_initialCW < 0, "Min. Initial Total Codeword is 0"); xConfirmPara(m_initialCW > 1023, "Max. Initial Total Codeword is 1023"); +#if JVET_P0371_CHROMA_SCALING_OFFSET + xConfirmPara(m_CSoffset < -7, "Min. LMCS Offset value is -7"); + xConfirmPara(m_CSoffset > 7, "Max. LMCS Offset value is 7"); +#endif if (m_updateCtrl > 0 && m_adpOption > 2) { m_adpOption -= 2; } } @@ -3718,6 +3725,9 @@ void EncAppCfg::xPrintParameter() msg(VERBOSE, "(Signal:%s ", m_reshapeSignalType == 0 ? "SDR" : (m_reshapeSignalType == 2 ? "HDR-HLG" : "HDR-PQ")); msg(VERBOSE, "Opt:%d", m_adpOption); if (m_adpOption > 0) { msg(VERBOSE, " CW:%d", m_initialCW); } +#if JVET_P0371_CHROMA_SCALING_OFFSET + msg(VERBOSE, " CSoffset:%d", m_CSoffset); +#endif msg(VERBOSE, ") "); } msg(VERBOSE, "MIP:%d ", m_MIP); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index c6493979f36b0833d07d020a4f460b7f17d08c3e..76ae65dd96eea0e4e4c3a3bf28d4e922745a3134 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -332,6 +332,9 @@ protected: int m_updateCtrl; int m_adpOption; uint32_t m_initialCW; +#if JVET_P0371_CHROMA_SCALING_OFFSET + int m_CSoffset; +#endif bool m_encDbOpt; unsigned m_uiMaxCUWidth; ///< max. CU width in pixel unsigned m_uiMaxCUHeight; ///< max. CU height in pixel diff --git a/source/Lib/CommonLib/Reshape.cpp b/source/Lib/CommonLib/Reshape.cpp index 40a5ed72316c760025a4dfd9159d668c520ccf8d..c029fec70bc1c98171db6f1da5c60139639bc0d6 100644 --- a/source/Lib/CommonLib/Reshape.cpp +++ b/source/Lib/CommonLib/Reshape.cpp @@ -225,6 +225,9 @@ void Reshape::copySliceReshaperInfo(SliceReshapeInfo& tInfo, SliceReshapeInfo& s tInfo.reshaperModelMinBinIdx = sInfo.reshaperModelMinBinIdx; memcpy(tInfo.reshaperModelBinCWDelta, sInfo.reshaperModelBinCWDelta, sizeof(int)*(PIC_CODE_CW_BINS)); tInfo.maxNbitsNeededDeltaCW = sInfo.maxNbitsNeededDeltaCW; +#if JVET_P0371_CHROMA_SCALING_OFFSET + tInfo.chrResScalingOffset = sInfo.chrResScalingOffset; +#endif } tInfo.sliceReshaperEnableFlag = sInfo.sliceReshaperEnableFlag; if (sInfo.sliceReshaperEnableFlag) @@ -262,7 +265,11 @@ void Reshape::constructReshaper() else { m_invScaleCoef[i] = (int32_t)(m_initCW * (1 << FP_PREC) / m_binCW[i]); +#if JVET_P0371_CHROMA_SCALING_OFFSET + m_chromaAdjHelpLUT[i] = (int32_t)(m_initCW * (1 << FP_PREC) / ( m_binCW[i] + m_sliceReshapeInfo.chrResScalingOffset ) ); +#else m_chromaAdjHelpLUT[i] = m_invScaleCoef[i]; +#endif } } for (int lumaSample = 0; lumaSample < m_reshapeLUTSize; lumaSample++) diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index c0d36fcd88c380e8f29e08c15b9cfcf88e8a0f22..ec635575a1d7437b6d36aa0983ad66a9eee95552 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -451,6 +451,9 @@ public: uint32_t reshaperModelMaxBinIdx; int reshaperModelBinCWDelta[PIC_CODE_CW_BINS]; int maxNbitsNeededDeltaCW; +#if JVET_P0371_CHROMA_SCALING_OFFSET + int chrResScalingOffset; +#endif void setUseSliceReshaper(bool b) { sliceReshaperEnableFlag = b; } bool getUseSliceReshaper() const { return sliceReshaperEnableFlag; } void setSliceReshapeModelPresentFlag(bool b) { sliceReshaperModelPresentFlag = b; } @@ -484,6 +487,12 @@ public: { return false; } +#if JVET_P0371_CHROMA_SCALING_OFFSET + if (chrResScalingOffset != other.chrResScalingOffset) + { + return false; + } +#endif if( memcmp( reshaperModelBinCWDelta, other.reshaperModelBinCWDelta, sizeof( reshaperModelBinCWDelta ) ) ) { return false; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index e4cfb8d141dc78d406f1ebc0aa80a4f2808ffdc0..d7b01ffb56e7e5965c5788c52d021674ed3ca8aa 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -53,6 +53,7 @@ #define JVET_P0345_LD_GOP_8 1 // JVET-P0345: low-delay gop size 8 +#define JVET_P0371_CHROMA_SCALING_OFFSET 1 // JVET-P0371: Signalling offset for chroma residual scaling #define JVET_P0803_COMBINED_MIP_CLEANUP 1 // JVET-P0803: Several MIP cleanups #define JVET_P0199_P0289_P0303_MIP_FULLMATRIX 1 // JVET-P0199/P0289/P0303: Full matrix multiplication for all MIP block shapes diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 58b680f472034e721f325330d8228222af96004f..051d1d161dfe181542067fcf0d5c8ce93a3159ad 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -1534,6 +1534,9 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl tInfo.reshaperModelMinBinIdx = sInfo.reshaperModelMinBinIdx; memcpy(tInfo.reshaperModelBinCWDelta, sInfo.reshaperModelBinCWDelta, sizeof(int)*(PIC_CODE_CW_BINS)); tInfo.maxNbitsNeededDeltaCW = sInfo.maxNbitsNeededDeltaCW; +#if JVET_P0371_CHROMA_SCALING_OFFSET + tInfo.chrResScalingOffset = sInfo.chrResScalingOffset; +#endif tInfo.setUseSliceReshaper(pcSlice->getLmcsEnabledFlag()); tInfo.setSliceReshapeChromaAdj(pcSlice->getLmcsChromaResidualScaleFlag()); tInfo.setSliceReshapeModelPresentFlag(true); diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 0e695a0f891385fdf056a233b952652009ecf9b3..3687b17bf2754744f9bcfcb5ae83db0b49028ecb 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -1004,6 +1004,17 @@ void HLSyntaxReader::parseLmcsAps( APS* aps ) int signCW = code; info.reshaperModelBinCWDelta[i] = (1 - 2 * signCW) * absCW; } +#if JVET_P0371_CHROMA_SCALING_OFFSET + READ_CODE(3, code, "lmcs_delta_abs_crs"); + int absCW = code; + if (absCW > 0) + { + READ_CODE(1, code, "lmcs_delta_sign_crs_flag"); + } + int signCW = code; + info.chrResScalingOffset = (1 - 2 * signCW) * absCW; +#endif + aps->setReshaperAPSInfo(info); } diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index feb45aadf93a4c8cf65471b1d023056721dfb63e..16eaf368d495b8e14ce01fbab07ac3ea5c91adab 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -340,6 +340,9 @@ protected: unsigned m_reshapeSignalType; unsigned m_intraCMD; ReshapeCW m_reshapeCW; +#if JVET_P0371_CHROMA_SCALING_OFFSET + int m_CSoffset; +#endif bool m_encDbOpt; bool m_useFastLCTU; bool m_useFastMrg; @@ -991,6 +994,10 @@ public: uint32_t getReshapeIntraCMD () { return m_intraCMD; } void setReshapeCW (const ReshapeCW &reshapeCW) { m_reshapeCW = reshapeCW; } const ReshapeCW& getReshapeCW () { return m_reshapeCW; } +#if JVET_P0371_CHROMA_SCALING_OFFSET + void setReshapeCSoffset (int CSoffset) { m_CSoffset = CSoffset; } + int getReshapeCSoffset () { return m_CSoffset; } +#endif void setMaxCUWidth ( uint32_t u ) { m_maxCUWidth = u; } uint32_t getMaxCUWidth () const { return m_maxCUWidth; } void setMaxCUHeight ( uint32_t u ) { m_maxCUHeight = u; } diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index d51c70c99cd35b31f31262fe72755c613b3a13e9..85f895a324f2a75ff386b2959423c31e8e3d0068 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -1753,6 +1753,10 @@ void EncGOP::xPicInitLMCS(Picture *pic, Slice *slice) m_pcReshaper->setSrcReshaped(false); m_pcReshaper->setRecReshaped(true); +#if JVET_P0371_CHROMA_SCALING_OFFSET + m_pcReshaper->getSliceReshaperInfo().chrResScalingOffset = m_pcCfg->getReshapeCSoffset(); +#endif + if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ) { m_pcReshaper->preAnalyzerHDR(pic, sliceType, m_pcCfg->getReshapeCW(), m_pcCfg->getDualITree()); @@ -1854,6 +1858,9 @@ void EncGOP::xPicInitLMCS(Picture *pic, Slice *slice) tInfo.reshaperModelMinBinIdx = sInfo.reshaperModelMinBinIdx; memcpy(tInfo.reshaperModelBinCWDelta, sInfo.reshaperModelBinCWDelta, sizeof(int)*(PIC_CODE_CW_BINS)); tInfo.maxNbitsNeededDeltaCW = sInfo.maxNbitsNeededDeltaCW; +#if JVET_P0371_CHROMA_SCALING_OFFSET + tInfo.chrResScalingOffset = sInfo.chrResScalingOffset; +#endif m_pcEncLib->getApsMap()->setChangedFlag((lmcsAPS->getAPSId() << NUM_APS_TYPE_LEN) + LMCS_APS); } diff --git a/source/Lib/EncoderLib/EncReshape.cpp b/source/Lib/EncoderLib/EncReshape.cpp index b92b0cdb46b4da91a6835d9046c3a23045cae6d3..034d6b11907b8ee5ee986491b32c14b039c3ac12 100644 --- a/source/Lib/EncoderLib/EncReshape.cpp +++ b/source/Lib/EncoderLib/EncReshape.cpp @@ -93,6 +93,9 @@ void EncReshape::createEnc(int picWidth, int picHeight, uint32_t maxCUWidth, ui m_sliceReshapeInfo.reshaperModelMinBinIdx = 0; m_sliceReshapeInfo.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS - 1; memset(m_sliceReshapeInfo.reshaperModelBinCWDelta, 0, (PIC_CODE_CW_BINS) * sizeof(int)); +#if JVET_P0371_CHROMA_SCALING_OFFSET + m_sliceReshapeInfo.chrResScalingOffset = 0; +#endif m_picWidth = picWidth; m_picHeight = picHeight; @@ -962,7 +965,11 @@ void EncReshape::initLUTfromdQPModel() else { m_invScaleCoef[i] = (int32_t)(m_initCW * (1 << FP_PREC) / m_binCW[i]); +#if JVET_P0371_CHROMA_SCALING_OFFSET + m_chromaAdjHelpLUT[i] = (int32_t)(m_initCW * (1 << FP_PREC) / (m_binCW[i] + m_sliceReshapeInfo.chrResScalingOffset)); +#else m_chromaAdjHelpLUT[i] = m_invScaleCoef[i]; +#endif } } for (int lumaSample = 0; lumaSample < m_reshapeLUTSize; lumaSample++) @@ -1054,7 +1061,11 @@ void EncReshape::constructReshaperLMCS() else { m_invScaleCoef[i] = (int32_t)(m_initCW * (1 << FP_PREC) / m_binCW[i]); +#if JVET_P0371_CHROMA_SCALING_OFFSET + m_chromaAdjHelpLUT[i] = (int32_t)(m_initCW * (1 << FP_PREC) / (m_binCW[i] + m_sliceReshapeInfo.chrResScalingOffset)); +#else m_chromaAdjHelpLUT[i] = m_invScaleCoef[i]; +#endif } } for (int lumaSample = 0; lumaSample < m_reshapeLUTSize; lumaSample++) diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 023d0a90c7e8f632f37134fbb2a20e84c32b5b9b..31005a474e413a1e4ebbd2e8c3d2ab0eb084e993 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -579,6 +579,16 @@ void HLSWriter::codeLmcsAps( APS* pcAPS ) WRITE_FLAG(signCW, "lmcs_delta_sign_cw_flag[ i ]"); } } +#if JVET_P0371_CHROMA_SCALING_OFFSET + int deltaCRS = param.chrResScalingOffset; + int signCRS = (deltaCRS < 0) ? 1 : 0; + int absCRS = (deltaCRS < 0) ? (-deltaCRS) : deltaCRS; + WRITE_CODE(absCRS, 3, "lmcs_delta_crs_val"); + if (absCRS > 0) + { + WRITE_FLAG(signCRS, "lmcs_delta_crs_val_flag"); + } +#endif } void HLSWriter::codeScalingListAps( APS* pcAPS )