From 442a044498beaced74d0e04c51cbcf4633300bc4 Mon Sep 17 00:00:00 2001 From: Taoran Lu <tlu@dolby.com> Date: Thu, 24 Jan 2019 16:28:18 -0800 Subject: [PATCH] merge JVET-M0427 into master --- cfg/encoder_intra_vtm.cfg | 1 + source/App/EncoderApp/EncApp.cpp | 6 + source/App/EncoderApp/EncAppCfg.cpp | 55 +- source/App/EncoderApp/EncAppCfg.h | 7 +- source/Lib/CommonLib/Buffer.cpp | 93 ++ source/Lib/CommonLib/Buffer.h | 5 + source/Lib/CommonLib/CodingStructure.cpp | 8 + source/Lib/CommonLib/CodingStructure.h | 3 + source/Lib/CommonLib/CommonDef.h | 14 +- source/Lib/CommonLib/Picture.cpp | 11 + source/Lib/CommonLib/Picture.h | 8 + source/Lib/CommonLib/RdCost.cpp | 103 ++ source/Lib/CommonLib/RdCost.h | 14 + source/Lib/CommonLib/Reshape.cpp | 232 +++ source/Lib/CommonLib/Reshape.h | 100 ++ source/Lib/CommonLib/Slice.cpp | 12 + source/Lib/CommonLib/Slice.h | 48 +- source/Lib/CommonLib/TypeDef.h | 13 + source/Lib/CommonLib/Unit.cpp | 7 + source/Lib/CommonLib/Unit.h | 7 + source/Lib/DecoderLib/DecCu.cpp | 139 ++ source/Lib/DecoderLib/DecCu.h | 14 +- source/Lib/DecoderLib/DecLib.cpp | 65 +- source/Lib/DecoderLib/DecLib.h | 6 + source/Lib/DecoderLib/VLCReader.cpp | 45 +- source/Lib/DecoderLib/VLCReader.h | 4 +- .../Lib/EncoderLib/EncAdaptiveLoopFilter.cpp | 31 + source/Lib/EncoderLib/EncAdaptiveLoopFilter.h | 6 + source/Lib/EncoderLib/EncCfg.h | 18 +- source/Lib/EncoderLib/EncCu.cpp | 87 ++ source/Lib/EncoderLib/EncCu.h | 4 +- source/Lib/EncoderLib/EncGOP.cpp | 135 ++ source/Lib/EncoderLib/EncGOP.h | 6 + source/Lib/EncoderLib/EncLib.cpp | 28 +- source/Lib/EncoderLib/EncLib.h | 10 + source/Lib/EncoderLib/EncReshape.cpp | 1260 +++++++++++++++++ source/Lib/EncoderLib/EncReshape.h | 149 ++ source/Lib/EncoderLib/EncSlice.cpp | 7 +- source/Lib/EncoderLib/InterSearch.cpp | 146 +- source/Lib/EncoderLib/InterSearch.h | 9 + source/Lib/EncoderLib/IntraSearch.cpp | 131 +- source/Lib/EncoderLib/IntraSearch.h | 13 +- source/Lib/EncoderLib/VLCWriter.cpp | 43 + source/Lib/EncoderLib/VLCWriter.h | 3 + 44 files changed, 3079 insertions(+), 27 deletions(-) create mode 100644 source/Lib/CommonLib/Reshape.cpp create mode 100644 source/Lib/CommonLib/Reshape.h create mode 100644 source/Lib/EncoderLib/EncReshape.cpp create mode 100644 source/Lib/EncoderLib/EncReshape.h diff --git a/cfg/encoder_intra_vtm.cfg b/cfg/encoder_intra_vtm.cfg index e3cc0a9ad..3495a5dd1 100644 --- a/cfg/encoder_intra_vtm.cfg +++ b/cfg/encoder_intra_vtm.cfg @@ -120,6 +120,7 @@ PBIntraFast : 1 FastMrg : 1 AMaxBT : 1 + ### DO NOT ADD ANYTHING BELOW THIS LINE ### ### DO NOT DELETE THE EMPTY LINE BELOW ### diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 611f6f82f..b68789432 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -550,6 +550,12 @@ void EncApp::xInitLibCfg() #endif m_cEncLib.setUseALF ( m_alf ); +#if JVET_M0427_INLOOP_RESHAPER + m_cEncLib.setReshaper ( m_bLumaReshapeEnable ); + m_cEncLib.setReshapeSignalType ( m_uiSignalType ); + m_cEncLib.setReshapeIntraCMD ( m_uiIntraCMD ); + m_cEncLib.setReshapeCW ( m_reshapeCW ); +#endif } void EncApp::xCreateLib( std::list<PelUnitBuf*>& recBufList diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index ea91679e6..9be42f93d 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -707,6 +707,13 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #endif int warnUnknowParameter = 0; +#if JVET_M0427_INLOOP_RESHAPER + const uint32_t defaultBinCW[CW_NUMS - 1] = { 38, 28 }; + const uint32_t defaultBinThr[CW_NUMS - 1] = { 2500, 4000 }; + SMultiValueInput<uint32_t> cfg_BinCW (0, 64, CW_NUMS - 1, CW_NUMS - 1, defaultBinCW, sizeof(defaultBinCW) / sizeof(uint32_t)); + SMultiValueInput<uint32_t> cfg_BinThr (0, std::numeric_limits<uint32_t>::max(), CW_NUMS - 1, CW_NUMS - 1, defaultBinThr, sizeof(defaultBinThr) / sizeof(uint32_t)); +#endif + #if ENABLE_TRACING string sTracingRule; string sTracingFile; @@ -882,7 +889,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("WrapAroundOffset", m_wrapAroundOffset, 0u, "Offset in luma samples used for computing the horizontal wrap-around position") // ADD_NEW_TOOL : (encoder app) add parsing parameters here - +#if JVET_M0427_INLOOP_RESHAPER + ("LumaReshapeEnable", m_bLumaReshapeEnable, false, "Enable Reshaping for Luma Channel") + ("ReshapeSignalType", m_uiSignalType, 0u, "Input signal type: 0: SDR, 1:PQ, 2:HLG") + ("IntraCMD", m_uiIntraCMD, 0u, "IntraChroma MD: 0: none, 1:fixed to default wPSNR weight") +#endif ("LCTUFast", m_useFastLCTU, false, "Fast methods for large CTU") ("FastMrg", m_useFastMrg, false, "Fast methods for inter merge") ("PBIntraFast", m_usePbIntraFast, false, "Fast assertion if the intra mode is probable") @@ -1836,6 +1847,15 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } } +#if JVET_M0427_INLOOP_RESHAPER + m_reshapeCW.BinCW.resize(CW_NUMS); + m_reshapeCW.RspFps = m_iFrameRate; + m_reshapeCW.RspIntraPeriod = m_iIntraPeriod; + m_reshapeCW.RspPicSize = m_iSourceWidth*m_iSourceHeight; + const int FpsToIpTable[MAX_FRAME_RATE + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128 }; + m_reshapeCW.RspFpsToIp = FpsToIpTable[m_iFrameRate]; + m_reshapeCW.RspBaseQP = m_iQP; +#endif #if ENABLE_TRACING g_trace_ctx = tracing_init(sTracingFile, sTracingRule); if( bTracingChannelsList && g_trace_ctx ) @@ -2219,6 +2239,30 @@ bool EncAppCfg::xCheckParameter() #if SHARP_LUMA_DELTA_QP xConfirmPara( m_lumaLevelToDeltaQPMapping.mode && m_uiDeltaQpRD > 0, "Luma-level-based Delta QP cannot be used together with slice level multiple-QP optimization\n" ); #endif +#if JVET_M0427_INLOOP_RESHAPER + if (m_bLumaReshapeEnable && (m_internalBitDepth[CHANNEL_TYPE_LUMA] != 10)) + { + m_bLumaReshapeEnable = false; + msg(WARNING, "Reshaping is implemented for 10bit luma internal bitdepth.\n"); + } + if (!m_bLumaReshapeEnable) + { + m_uiSignalType = RESHAPE_SIGNAL_NULL; + m_uiIntraCMD = 0; + } + if (m_bLumaReshapeEnable && m_uiSignalType == RESHAPE_SIGNAL_PQ) + { + m_uiIntraCMD = 1; + } + else if (m_bLumaReshapeEnable && m_uiSignalType == RESHAPE_SIGNAL_SDR) + { + m_uiIntraCMD = 0; + } + else + { + m_bLumaReshapeEnable = false; + } +#endif xConfirmPara( m_cbQpOffset < -12, "Min. Chroma Cb QP Offset is -12" ); xConfirmPara( m_cbQpOffset > 12, "Max. Chroma Cb QP Offset is 12" ); @@ -3164,7 +3208,14 @@ void EncAppCfg::xPrintParameter() msg( VERBOSE, "WrapAroundOffset:%d ", m_wrapAroundOffset ); } // ADD_NEW_TOOL (add some output indicating the usage of tools) - +#if JVET_M0427_INLOOP_RESHAPER + msg(VERBOSE, "Reshape:%d ", m_bLumaReshapeEnable); + if (m_bLumaReshapeEnable) + { + msg(VERBOSE, "(Sigal:%s ", m_uiSignalType==0? "SDR" : "HDR-PQ"); + msg(VERBOSE, ") "); + } +#endif msg( VERBOSE, "\nFAST TOOL CFG: " ); if( m_LargeCTU ) { diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 9d7b9a62c..3c1c617cf 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -256,7 +256,12 @@ protected: unsigned m_wrapAroundOffset; // ADD_NEW_TOOL : (encoder app) add tool enabling flags and associated parameters here - +#if JVET_M0427_INLOOP_RESHAPER + bool m_bLumaReshapeEnable; + uint32_t m_uiSignalType; + uint32_t m_uiIntraCMD; + ReshapeCW m_reshapeCW; +#endif unsigned m_uiMaxCUWidth; ///< max. CU width in pixel unsigned m_uiMaxCUHeight; ///< max. CU height in pixel unsigned m_uiMaxCUDepth; ///< max. CU depth (as specified by command line) diff --git a/source/Lib/CommonLib/Buffer.cpp b/source/Lib/CommonLib/Buffer.cpp index 9fd64da80..1fcae69fd 100644 --- a/source/Lib/CommonLib/Buffer.cpp +++ b/source/Lib/CommonLib/Buffer.cpp @@ -343,6 +343,99 @@ void AreaBuf<Pel>::addWeightedAvg(const AreaBuf<const Pel> &other1, const AreaBu #undef ADD_AVG_INC } +#if JVET_M0427_INLOOP_RESHAPER +template<> +void AreaBuf<Pel>::rspSignal(std::vector<Pel>& pLUT) +{ + Pel* dst = buf; + Pel* src = buf; + if (width == 1) + { + THROW("Blocks of width = 1 not supported"); + } + else + { + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < width; x++) + { + dst[x] = pLUT[src[x]]; + } + dst += stride; + src += stride; + } + } +} + +template<> +void AreaBuf<Pel>::scaleSignal(const int scale, const bool dir) +{ + Pel* dst = buf; + Pel* src = buf; + int sign, absval; + + if (dir) // forward + { + if (width == 1) + { + THROW("Blocks of width = 1 not supported"); + } + else + { + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < width; x++) + { + sign = src[x] >= 0 ? 1 : -1; + absval = sign * src[x]; + dst[x] = sign * (((absval << CSCALE_FP_PREC) + (scale >> 1)) / scale); + dst[x] = dst[x] > 1023 ? 1023 : dst[x] < -1023 ? -1023 : dst[x]; + } + dst += stride; + src += stride; + } + } + } + else // inverse + { + for (unsigned y = 0; y < height; y++) + { + for (unsigned x = 0; x < width; x++) + { + sign = src[x] >= 0 ? 1 : -1; + absval = sign * src[x]; + dst[x] = sign * ((absval * scale + (1 << (CSCALE_FP_PREC - 1))) >> CSCALE_FP_PREC); + } + dst += stride; + src += stride; + } + } +} + +template<> +Pel AreaBuf <Pel> ::computeAvg() const +{ + const Pel* src = buf; + + if (width == 1) + { + THROW("Blocks of width = 1 not supported"); + } + else + { + int32_t acc = 0; +#define AVG_INC \ + src += stride; +#define AVG_OP(ADDR) acc += src[ADDR] + SIZE_AWARE_PER_EL_OP(AVG_OP, AVG_INC); +#undef AVG_INC +#undef AVG_OP + return Pel((acc + (area() >> 1)) / area()); + } +} + +#endif + template<> void AreaBuf<Pel>::addAvg( const AreaBuf<const Pel> &other1, const AreaBuf<const Pel> &other2, const ClpRng& clpRng) { diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h index db9d69e5e..6347c675c 100644 --- a/source/Lib/CommonLib/Buffer.h +++ b/source/Lib/CommonLib/Buffer.h @@ -132,6 +132,11 @@ struct AreaBuf : public Size void toLast ( const ClpRng& clpRng ); +#if JVET_M0427_INLOOP_RESHAPER + void rspSignal ( std::vector<Pel>& pLUT ); + void scaleSignal ( const int scale, const bool dir ); + T computeAvg ( ) const; +#endif T& at( const int &x, const int &y ) { return buf[y * stride + x]; } const T& at( const int &x, const int &y ) const { return buf[y * stride + x]; } diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index e420621c3..829a7eeac 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -969,6 +969,14 @@ void CodingStructure::copyStructure( const CodingStructure& other, const Channel // copy data to picture picture->getRecoBuf( area ).copyFrom( recoBuf ); +#if JVET_M0427_INLOOP_RESHAPER + CPelUnitBuf predBuf = other.getPredBuf(area); + if (parent) + { + getPredBuf(area).copyFrom(predBuf); + } + picture->getPredBuf(area).copyFrom(predBuf); +#endif } } diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index 1b57a771f..d7ab5422b 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -53,6 +53,9 @@ enum PictureType { PIC_RECONSTRUCTION = 0, PIC_ORIGINAL, +#if JVET_M0427_INLOOP_RESHAPER + PIC_TRUE_ORIGINAL, +#endif PIC_PREDICTION, PIC_RESIDUAL, PIC_ORG_RESI, diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index dc4295c71..6333d0718 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -404,7 +404,19 @@ static const int CHROMA_REFINEMENT_CANDIDATES = 8; /// 8 candidates BV to choose static const int IBC_FAST_METHOD_NOINTRA_IBCCBF0 = 0x01; static const int IBC_FAST_METHOD_BUFFERBV = 0X02; static const int IBC_FAST_METHOD_ADAPTIVE_SEARCHRANGE = 0X04; - +#if JVET_M0427_INLOOP_RESHAPER +static const int MAX_LUMA_RESHAPING_LUT_SIZE = 1024; +static const int CSCALE_FP_PREC = 11; +static const int PIC_ANALYZE_CW_BINS = 32; +static const int FP_PREC = 14; +static const int log2_MAX_LUMA_RESHAPING_LUT_SIZE = 10; +static const int log2_PIC_ANALYZE_CW_BINS = 5; +static const int PIC_ANALYZE_WIN_SIZE = 5; +static const int CW_NUMS = 3; +static const int MAX_FRAME_RATE = 128; +static const int PIC_CODE_CW_BINS = 16; +static const int log2_PIC_CODE_CW_BINS = 4; +#endif #if JVET_M0512_MOTION_BUFFER_COMPRESSION static constexpr int MV_EXPONENT_BITCOUNT = 4; static constexpr int MV_MANTISSA_BITCOUNT = 6; diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index d319f1f7e..6157656dc 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -742,6 +742,9 @@ void Picture::create(const ChromaFormat &_chromaFormat, const Size &size, const if( !_decoder ) { M_BUFS( 0, PIC_ORIGINAL ). create( _chromaFormat, a ); +#if JVET_M0427_INLOOP_RESHAPER + M_BUFS( 0, PIC_TRUE_ORIGINAL ). create( _chromaFormat, a ); +#endif } #if !KEEP_PRED_AND_RESI_SIGNALS @@ -846,6 +849,14 @@ const CPelUnitBuf Picture::getOrigBuf(const UnitArea &unit) const { return getBu PelUnitBuf Picture::getOrigBuf() { return M_BUFS(0, PIC_ORIGINAL); } const CPelUnitBuf Picture::getOrigBuf() const { return M_BUFS(0, PIC_ORIGINAL); } +#if JVET_M0427_INLOOP_RESHAPER + PelBuf Picture::getOrigBuf(const ComponentID compID) { return getBuf(compID, PIC_ORIGINAL); } +const CPelBuf Picture::getOrigBuf(const ComponentID compID) const { return getBuf(compID, PIC_ORIGINAL); } + PelUnitBuf Picture::getTrueOrigBuf() { return M_BUFS(0, PIC_TRUE_ORIGINAL); } +const CPelUnitBuf Picture::getTrueOrigBuf() const { return M_BUFS(0, PIC_TRUE_ORIGINAL); } + PelBuf Picture::getTrueOrigBuf(const CompArea &blk) { return getBuf(blk, PIC_TRUE_ORIGINAL); } +const CPelBuf Picture::getTrueOrigBuf(const CompArea &blk) const { return getBuf(blk, PIC_TRUE_ORIGINAL); } +#endif PelBuf Picture::getPredBuf(const CompArea &blk) { return getBuf(blk, PIC_PREDICTION); } const CPelBuf Picture::getPredBuf(const CompArea &blk) const { return getBuf(blk, PIC_PREDICTION); } PelUnitBuf Picture::getPredBuf(const UnitArea &unit) { return getBuf(unit, PIC_PREDICTION); } diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 2e90cc538..3c9c4c650 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -192,6 +192,14 @@ struct Picture : public UnitArea const CPelUnitBuf getOrigBuf(const UnitArea &unit) const; PelUnitBuf getOrigBuf(); const CPelUnitBuf getOrigBuf() const; +#if JVET_M0427_INLOOP_RESHAPER + PelBuf getOrigBuf(const ComponentID compID); + const CPelBuf getOrigBuf(const ComponentID compID) const; + PelUnitBuf getTrueOrigBuf(); + const CPelUnitBuf getTrueOrigBuf() const; + PelBuf getTrueOrigBuf(const CompArea &blk); + const CPelBuf getTrueOrigBuf(const CompArea &blk) const; +#endif PelBuf getPredBuf(const CompArea &blk); const CPelBuf getPredBuf(const CompArea &blk) const; diff --git a/source/Lib/CommonLib/RdCost.cpp b/source/Lib/CommonLib/RdCost.cpp index 78fbcf0f3..e5976dc0d 100644 --- a/source/Lib/CommonLib/RdCost.cpp +++ b/source/Lib/CommonLib/RdCost.cpp @@ -176,6 +176,10 @@ void RdCost::init() m_motionLambda = 0; m_iCostScale = 0; +#if JVET_M0427_INLOOP_RESHAPER + m_iSignalType = RESHAPE_SIGNAL_NULL; + m_chroma_weight = 1.0; +#endif } @@ -2859,6 +2863,11 @@ Distortion RdCost::xGetHADs( const DistParam &rcDtParam ) #if WCG_EXT double RdCost::m_lumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE]; +#if JVET_M0427_INLOOP_RESHAPER +double RdCost::m_reshapeLumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE]; +uint32_t RdCost::m_iSignalType; +double RdCost::m_chroma_weight; +#endif void RdCost::saveUnadjustedLambda() { @@ -2868,6 +2877,18 @@ void RdCost::saveUnadjustedLambda() void RdCost::initLumaLevelToWeightTable() { +#if JVET_M0427_INLOOP_RESHAPER + if (m_iSignalType == RESHAPE_SIGNAL_SDR) + { + double weight = 1.0; + for (int i = 0; i < LUMA_LEVEL_TO_DQP_LUT_MAXSIZE; i++) + { + m_lumaLevelToWeightPLUT[i] = weight; + } + return; + } +#endif + for (int i = 0; i < LUMA_LEVEL_TO_DQP_LUT_MAXSIZE; i++) { double x = i; double y; @@ -2889,7 +2910,69 @@ void RdCost::initLumaLevelToWeightTable() m_lumaLevelToWeightPLUT[i] = pow(2.0, y / 3.0); // or power(10, dQp/10) they are almost equal } +#if JVET_M0427_INLOOP_RESHAPER + memcpy(m_reshapeLumaLevelToWeightPLUT, m_lumaLevelToWeightPLUT, LUMA_LEVEL_TO_DQP_LUT_MAXSIZE * sizeof(double)); +#endif +} + +#if JVET_M0427_INLOOP_RESHAPER +void RdCost::updateReshapeLumaLevelToWeightTableChromaMD(std::vector<Pel>& ILUT) +{ + for (int i = 0; i < LUMA_LEVEL_TO_DQP_LUT_MAXSIZE; i++) // idx in reshaped domain; + { + m_reshapeLumaLevelToWeightPLUT[i] = m_lumaLevelToWeightPLUT[ILUT[i]]; + } +} + +void RdCost::restoreReshapeLumaLevelToWeightTable() +{ + memcpy(m_reshapeLumaLevelToWeightPLUT, m_lumaLevelToWeightPLUT, LUMA_LEVEL_TO_DQP_LUT_MAXSIZE * sizeof(double)); +} + + +void RdCost::updateReshapeLumaLevelToWeightTable(sliceReshapeInfo &sliceReshape, Pel *wt_table, double cwt) +{ + if (m_iSignalType == RESHAPE_SIGNAL_SDR) + { + if (sliceReshape.getSliceReshapeModelPresentFlag()) + { + double w_bin = 1.0; + double weight = 1.0; + int hist_lens = MAX_LUMA_RESHAPING_LUT_SIZE / PIC_CODE_CW_BINS; + + for (int i = 0; i < PIC_CODE_CW_BINS; i++) + { + if ((i < sliceReshape.reshape_model_min_bin_idx) || (i > sliceReshape.reshape_model_max_bin_idx)) + weight = 1.0; + else + { + if (sliceReshape.reshape_model_bin_CW_delta[i] == 1 || sliceReshape.reshape_model_bin_CW_delta[i] == -1 * MAX_LUMA_RESHAPING_LUT_SIZE / PIC_CODE_CW_BINS) + weight = w_bin; + else + { + weight = (double)wt_table[i] / (double)hist_lens; + weight = weight*weight; + } + } + for (int j = 0; j < hist_lens; j++) + { + int ii = i*hist_lens + j; + m_reshapeLumaLevelToWeightPLUT[ii] = weight; + } + } + m_chroma_weight = cwt; + } + else + { + THROW("updateReshapeLumaLevelToWeightTable ERROR!!"); + } + } + else + { + THROW("updateReshapeLumaLevelToWeightTable not support other signal types!!"); + } } +#endif Distortion RdCost::getWeightedMSE(int compIdx, const Pel org, const Pel cur, const uint32_t uiShift, const Pel orgLuma) { @@ -2902,8 +2985,28 @@ Distortion RdCost::getWeightedMSE(int compIdx, const Pel org, const Pel cur, con CHECK(org!=orgLuma, ""); } // use luma to get weight +#if JVET_M0427_INLOOP_RESHAPER + double weight = 1.0; + if (m_iSignalType == RESHAPE_SIGNAL_SDR) + { + if (compIdx == COMPONENT_Y) + weight = m_reshapeLumaLevelToWeightPLUT[orgLuma]; + else + { + weight = m_chroma_weight; + } + } + else + weight = m_reshapeLumaLevelToWeightPLUT[orgLuma]; +#else double weight = m_lumaLevelToWeightPLUT[orgLuma]; +#endif +#if JVET_M0427_INLOOP_RESHAPER // FIXED_PT_WD_CALCULATION + int64_t fixedPTweight = (int64_t)(weight * (double)(1 << 16)); + Intermediate_Int mse = Intermediate_Int((fixedPTweight*(iTemp*iTemp) + (1 << 15)) >> 16); +#else Intermediate_Int mse = Intermediate_Int(weight*(double)iTemp*(double)iTemp+0.5); +#endif distortionVal = Distortion( mse >> uiShift); return distortionVal; } diff --git a/source/Lib/CommonLib/RdCost.h b/source/Lib/CommonLib/RdCost.h index ead8fd5cb..23d2aafa5 100644 --- a/source/Lib/CommonLib/RdCost.h +++ b/source/Lib/CommonLib/RdCost.h @@ -108,6 +108,11 @@ private: double m_dLambda_unadjusted; // TODO: check is necessary double m_DistScaleUnadjusted; static double m_lumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE]; +#if JVET_M0427_INLOOP_RESHAPER + static double m_reshapeLumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE]; + static uint32_t m_iSignalType; + static double m_chroma_weight; +#endif #endif double m_DistScale; double m_dLambdaMotionSAD[2 /* 0=standard, 1=for transquant bypass when mixed-lossless cost evaluation enabled*/]; @@ -290,6 +295,15 @@ public: void saveUnadjustedLambda (); void initLumaLevelToWeightTable (); inline double getWPSNRLumaLevelWeight (int val) { return m_lumaLevelToWeightPLUT[val]; } +#if JVET_M0427_INLOOP_RESHAPER + void updateReshapeLumaLevelToWeightTableChromaMD (std::vector<Pel>& ILUT); + void restoreReshapeLumaLevelToWeightTable (); + inline double getWPSNRReshapeLumaLevelWeight (int val) { return m_reshapeLumaLevelToWeightPLUT[val]; } + uint32_t getReshapeSignalType () const { return m_iSignalType; } + void setReshapeSignalType (uint32_t type) { m_iSignalType = type; } + void updateReshapeLumaLevelToWeightTable (sliceReshapeInfo &sliceReshape, Pel *wt_table, double cwt); + inline double* getLumaLevelWeightTable() { return m_lumaLevelToWeightPLUT; } +#endif #endif private: diff --git a/source/Lib/CommonLib/Reshape.cpp b/source/Lib/CommonLib/Reshape.cpp new file mode 100644 index 000000000..099b5cb54 --- /dev/null +++ b/source/Lib/CommonLib/Reshape.cpp @@ -0,0 +1,232 @@ +/* The copyright in this software is being made available under the BSD +* License, included below. This software may be subject to other third party +* and contributor rights, including patent rights, and no such rights are +* granted under this license. +* +* Copyright (c) 2010-2019, ITU/ISO/IEC +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may +* be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file Reshape.cpp + \brief common reshaper class +*/ +#include "Reshape.h" +#include <stdio.h> +#include <string.h> +#include <math.h> +#if JVET_M0427_INLOOP_RESHAPER + //! \ingroup CommonLib + //! \{ + + // ==================================================================================================================== + // Constructor / destructor / create / destroy + // ==================================================================================================================== + +Reshape::Reshape() +{ + m_bCTUFlag = false; + m_bRecReshaped = false; + m_bReshape = true; + m_uiCWOrg = MAX_LUMA_RESHAPING_LUT_SIZE / PIC_CODE_CW_BINS; +} + +Reshape::~Reshape() +{ +} + +void Reshape::create_dec() +{ + if (forwardReshapingLUT.empty()) + forwardReshapingLUT.resize(MAX_LUMA_RESHAPING_LUT_SIZE, 0); + if (inverseReshapingLUT.empty()) + inverseReshapingLUT.resize(MAX_LUMA_RESHAPING_LUT_SIZE, 0); + if (m_uiBinCWAll.empty()) + m_uiBinCWAll.resize(PIC_CODE_CW_BINS, 0); + if (m_ReshapePivot.empty()) + m_ReshapePivot.resize(PIC_CODE_CW_BINS + 1, 0); + if (ChromaAdjHelpLUT.empty()) + ChromaAdjHelpLUT.resize(PIC_CODE_CW_BINS, 2048); +} + +void Reshape::destroy() +{ +} + +/** +-Perform inverse of a one dimension LUT +\param InputLUT describing the input LUT +\retval OutputLUT describing the inversed LUT of InputLUT +\param lut_size size of LUT in number of samples +*/ +void Reshape::ReverseLUT(std::vector<Pel>& InputLUT, std::vector<Pel>& OutputLUT, uint16_t lut_size) +{ + int i, j; + OutputLUT[m_ReshapePivot[m_sliceReshapeInfo.reshape_model_min_bin_idx]] = m_sliceReshapeInfo.reshape_model_min_bin_idx*m_uiCWOrg; + for (i = m_sliceReshapeInfo.reshape_model_min_bin_idx; i <= m_sliceReshapeInfo.reshape_model_max_bin_idx; i++) + { + int16_t X1 = m_ReshapePivot[i]; + int16_t X2 = m_ReshapePivot[i + 1]; + OutputLUT[X2] = (i + 1)*m_uiCWOrg; + int16_t Y1 = OutputLUT[X1]; + int16_t Y2 = OutputLUT[X2]; + + if (X2 !=X1) + { + int32_t scale = (int32_t)(Y2 - Y1) * (1 << FP_PREC) / (int32_t)(X2 - X1); + for (j = X1 + 1; j < X2; j++) + { + OutputLUT[j] = (Pel)((scale*(int32_t)(j - X1) + (1 << (FP_PREC - 1))) >> FP_PREC) + Y1; + } + } + } + + for (i = 0; i < m_ReshapePivot[m_sliceReshapeInfo.reshape_model_min_bin_idx]; i++) + OutputLUT[i] = OutputLUT[m_ReshapePivot[m_sliceReshapeInfo.reshape_model_min_bin_idx]]; + for (i = m_ReshapePivot[m_sliceReshapeInfo.reshape_model_max_bin_idx + 1]; i < MAX_LUMA_RESHAPING_LUT_SIZE; i++) + OutputLUT[i] = OutputLUT[m_ReshapePivot[m_sliceReshapeInfo.reshape_model_max_bin_idx + 1]]; + + bool clipRange = ((m_sliceReshapeInfo.reshape_model_min_bin_idx > 0) && (m_sliceReshapeInfo.reshape_model_max_bin_idx < (PIC_CODE_CW_BINS - 1))); + for (i = 0; i < lut_size; i++) + { + if (clipRange) OutputLUT[i] = Clip3((Pel)64, (Pel)940, OutputLUT[i]); + else OutputLUT[i] = Clip3((Pel)0, (Pel)1023, OutputLUT[i]); + } +} + + +/** compute chroma residuce scale for TU +* \param average luma pred of TU +* \return chroma residue scale +*/ +int Reshape::calculateChromaAdj(Pel avgLuma) +{ + int lumaIdx = Clip3<int>(0, int(LUMA_LEVEL_TO_DQP_LUT_MAXSIZE) - 1, avgLuma); + int iAdj = ChromaAdjHelpLUT[getPWLIdxInv(lumaIdx)]; + return(iAdj); +} + + +/** find inx of PWL for inverse mapping +* \param average luma pred of TU +* \return idx of PWL for inverse mapping +*/ +int Reshape::getPWLIdxInv(int lumaVal) +{ + int idxS = 0; + if (lumaVal < m_ReshapePivot[m_sliceReshapeInfo.reshape_model_min_bin_idx + 1]) + return m_sliceReshapeInfo.reshape_model_min_bin_idx; + else if (lumaVal >= m_ReshapePivot[m_sliceReshapeInfo.reshape_model_max_bin_idx]) + return m_sliceReshapeInfo.reshape_model_max_bin_idx; + else + { + for (idxS = m_sliceReshapeInfo.reshape_model_min_bin_idx; (idxS < m_sliceReshapeInfo.reshape_model_max_bin_idx); idxS++) + { + if (lumaVal < m_ReshapePivot[idxS + 1]) break; + } + return idxS; + } +} + +/** +-copy Slice reshaper info structure +\param tInfo describing the target Slice reshaper info structure +\param sInfo describing the source Slice reshaper info structure +*/ +void Reshape::copySliceReshaperInfo(sliceReshapeInfo& tInfo, sliceReshapeInfo& sInfo) +{ + tInfo.slice_reshaper_model_present_flag = sInfo.slice_reshaper_model_present_flag; + if (sInfo.slice_reshaper_model_present_flag) + { + tInfo.reshape_model_max_bin_idx = sInfo.reshape_model_max_bin_idx; + tInfo.reshape_model_min_bin_idx = sInfo.reshape_model_min_bin_idx; + memcpy(tInfo.reshape_model_bin_CW_delta, sInfo.reshape_model_bin_CW_delta, sizeof(int)*(PIC_CODE_CW_BINS)); + tInfo.maxNbitsNeededDeltaCW = sInfo.maxNbitsNeededDeltaCW; + } + tInfo.slice_reshaper_enable_flag = sInfo.slice_reshaper_enable_flag; + if (sInfo.slice_reshaper_enable_flag) + tInfo.uiReshapeChromaAdj = sInfo.uiReshapeChromaAdj; + else + tInfo.uiReshapeChromaAdj = 0; +} + +/** Construct reshaper from syntax +* \param void +* \return void +*/ +void Reshape::constructReshaper() +{ + int pwlFwdLUTsize = PIC_CODE_CW_BINS; + int pwlFwdBinLen = MAX_LUMA_RESHAPING_LUT_SIZE / PIC_CODE_CW_BINS; + + for (int i = 0; i < m_sliceReshapeInfo.reshape_model_min_bin_idx; i++) + m_uiBinCWAll[i] = 0; + for (int i = m_sliceReshapeInfo.reshape_model_max_bin_idx + 1; i < PIC_CODE_CW_BINS; i++) + m_uiBinCWAll[i] = 0; + for (int i = m_sliceReshapeInfo.reshape_model_min_bin_idx; i <= m_sliceReshapeInfo.reshape_model_max_bin_idx; i++) + m_uiBinCWAll[i] = (uint16_t)(m_sliceReshapeInfo.reshape_model_bin_CW_delta[i] + (int)m_uiCWOrg); + + for (int i = 0; i < pwlFwdLUTsize; i++) + { + m_ReshapePivot[i + 1] = m_ReshapePivot[i] + m_uiBinCWAll[i]; + int16_t Y1 = m_ReshapePivot[i]; + int16_t Y2 = m_ReshapePivot[i + 1]; + + forwardReshapingLUT[i*pwlFwdBinLen] = Clip3((Pel)0, (Pel)1023, (Pel)Y1); + + int log2_pwlFwdBinLen = log2_MAX_LUMA_RESHAPING_LUT_SIZE - log2_PIC_CODE_CW_BINS; + + int32_t scale = ((int32_t)(Y2 - Y1) * (1 << FP_PREC) + (1 << (log2_pwlFwdBinLen - 1))) >> (log2_pwlFwdBinLen); + for (int j = 1; j < pwlFwdBinLen; j++) + { + int tempVal = Y1 + (((int32_t)scale * (int32_t)j + (1 << (FP_PREC - 1))) >> FP_PREC); + forwardReshapingLUT[i*pwlFwdBinLen + j] = Clip3((Pel)0, (Pel)1023, (Pel)tempVal); + } + } + ReverseLUT(forwardReshapingLUT, inverseReshapingLUT, MAX_LUMA_RESHAPING_LUT_SIZE); + updateChromaDQPLUT(); +} + +/** generate chroma residue scaling LUT +* \param void +* \return void +*/ +void Reshape::updateChromaDQPLUT() +{ + const int16_t CW_bin_SC_LUT[2 * PIC_ANALYZE_CW_BINS] = { 16384, 16384, 16384, 16384, 16384, 16384, 16384, 8192, 8192, 8192, 8192, 5461, 5461, 5461, 5461, 4096, 4096, 4096, 4096, 3277, 3277, 3277, 3277, 2731, 2731, 2731, 2731, 2341, 2341, 2341, 2048, 2048, 2048, 1820, 1820, 1820, 1638, 1638, 1638, 1638, 1489, 1489, 1489, 1489, 1365, 1365, 1365, 1365, 1260, 1260, 1260, 1260, 1170, 1170, 1170, 1170, 1092, 1092, 1092, 1092, 1024, 1024, 1024, 1024 }; //p=11 + for (int i = 0; i < PIC_CODE_CW_BINS; i++) + { + if ((i < m_sliceReshapeInfo.reshape_model_min_bin_idx) || (i > m_sliceReshapeInfo.reshape_model_max_bin_idx)) + ChromaAdjHelpLUT[i] = 1 << CSCALE_FP_PREC; + else + ChromaAdjHelpLUT[i] = CW_bin_SC_LUT[Clip3((uint16_t)1, (uint16_t)64, (uint16_t)(m_uiBinCWAll[i] >> 1)) - 1]; + } +} +#endif + + +// +//! \} diff --git a/source/Lib/CommonLib/Reshape.h b/source/Lib/CommonLib/Reshape.h new file mode 100644 index 000000000..4fec33805 --- /dev/null +++ b/source/Lib/CommonLib/Reshape.h @@ -0,0 +1,100 @@ +/* The copyright in this software is being made available under the BSD +* License, included below. This software may be subject to other third party +* and contributor rights, including patent rights, and no such rights are +* granted under this license. +* +* Copyright (c) 2010-2019, ITU/ISO/IEC +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may +* be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +*/ + + /** \file Reshape.h + \brief reshaping header and class (header) + */ + +#ifndef __RESHAPE__ +#define __RESHAPE__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "CommonDef.h" +#include "Rom.h" +#include "CommonLib/Picture.h" +#if JVET_M0427_INLOOP_RESHAPER +//! \ingroup CommonLib +//! \{ +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +class Reshape +{ +protected: + sliceReshapeInfo m_sliceReshapeInfo; + bool m_bCTUFlag; + bool m_bRecReshaped; + std::vector<Pel> inverseReshapingLUT; + std::vector<Pel> forwardReshapingLUT; + std::vector<int> ChromaAdjHelpLUT; + std::vector<uint16_t> m_uiBinCWAll; + uint16_t m_uiCWOrg; + bool m_bReshape; + std::vector<Pel> m_ReshapePivot; +public: + Reshape(); + ~Reshape(); + + void create_dec(); + void destroy(); + + void ReverseLUT(std::vector<Pel>& InputLUT, std::vector<Pel>& OutputLUT, uint16_t lut_size); + std::vector<Pel>& getFwdLUT() { return forwardReshapingLUT; } + std::vector<Pel>& getInvLUT() { return inverseReshapingLUT; } + std::vector<int>& getChromaAdjHelpLUT() { return ChromaAdjHelpLUT; } + + bool getCTUFlag() { return m_bCTUFlag; } + void setCTUFlag(bool bCTUFlag) { m_bCTUFlag = bCTUFlag; } + + bool getRecReshaped() { return m_bRecReshaped; } + void setRecReshaped(bool bPicReshaped) { m_bRecReshaped = bPicReshaped; } + int calculateChromaAdj(Pel avgLuma); + int getPWLIdxInv(int lumaVal); + sliceReshapeInfo& getSliceReshaperInfo() { return m_sliceReshapeInfo; } + void copySliceReshaperInfo(sliceReshapeInfo& tInfo, sliceReshapeInfo& sInfo); + + void constructReshaper(); + void updateChromaDQPLUT(); + bool getReshapeFlag() { return m_bReshape; } + void setReshapeFlag(bool val) { m_bReshape = val; } +};// END CLASS DEFINITION Reshape + +//! \} +#endif // +#endif // __RESHAPE__ + + diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index fe1541e00..731eb97e9 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -180,6 +180,15 @@ Slice::Slice() } initMotionLUTs(); + +#if JVET_M0427_INLOOP_RESHAPER + m_sliceReshapeInfo.setUseSliceReshaper(false); + m_sliceReshapeInfo.setSliceReshapeModelPresentFlag(false); + m_sliceReshapeInfo.setSliceReshapeChromaAdj(0); + m_sliceReshapeInfo.reshape_model_min_bin_idx = 0; + m_sliceReshapeInfo.reshape_model_max_bin_idx = PIC_CODE_CW_BINS - 1; + memset(m_sliceReshapeInfo.reshape_model_bin_CW_delta, 0, PIC_CODE_CW_BINS * sizeof(int)); +#endif } Slice::~Slice() @@ -1892,6 +1901,9 @@ SPS::SPS() , m_spsNextExtension (*this) , m_wrapAroundEnabledFlag (false) , m_wrapAroundOffset ( 0) +#if JVET_M0427_INLOOP_RESHAPER +, m_bUseReshape (false) +#endif { for(int ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++) { diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index a4e2a2093..d875cac8e 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -291,6 +291,38 @@ struct HrdSubLayerInfo uint32_t duBitRateValue [MAX_CPB_CNT][2]; }; +#if JVET_M0427_INLOOP_RESHAPER +class sliceReshapeInfo +{ +public: + bool slice_reshaper_enable_flag; + bool slice_reshaper_model_present_flag; + unsigned uiReshapeChromaAdj; + uint32_t reshape_model_min_bin_idx; + uint32_t reshape_model_max_bin_idx; + int reshape_model_bin_CW_delta[PIC_CODE_CW_BINS]; + int maxNbitsNeededDeltaCW; + void setUseSliceReshaper(bool b_useSliceReshaper) { slice_reshaper_enable_flag = b_useSliceReshaper; } + bool getUseSliceReshaper() const { return slice_reshaper_enable_flag; } + void setSliceReshapeModelPresentFlag(bool bflag) { slice_reshaper_model_present_flag = bflag; } + bool getSliceReshapeModelPresentFlag() const { return slice_reshaper_model_present_flag; } + void setSliceReshapeChromaAdj(unsigned uiChromaAdj) { uiReshapeChromaAdj = uiChromaAdj; } + unsigned getSliceReshapeChromaAdj() const { return uiReshapeChromaAdj; } +}; + +struct ReshapeCW +{ + std::vector<uint32_t> BinCW; + int RspPicSize; + int RspIntraPeriod; + int RspFps; + int RspBaseQP; + int Tid; + int SliceQP; + int RspFpsToIp; +}; +#endif + class HRD { private: @@ -1033,7 +1065,9 @@ private: bool m_wrapAroundEnabledFlag; unsigned m_wrapAroundOffset; - +#if JVET_M0427_INLOOP_RESHAPER + bool m_bUseReshape; +#endif public: SPS(); @@ -1252,6 +1286,10 @@ public: bool getWrapAroundEnabledFlag() const { return m_wrapAroundEnabledFlag; } void setWrapAroundOffset(unsigned offset) { m_wrapAroundOffset = offset; } unsigned getWrapAroundOffset() const { return m_wrapAroundOffset; } +#if JVET_M0427_INLOOP_RESHAPER + void setUseReshaper(bool b) { m_bUseReshape = b; } + bool getUseReshaper() const { return m_bUseReshape; } +#endif }; @@ -1682,6 +1720,9 @@ private: AlfSliceParam m_alfSliceParam; LutMotionCand* m_MotionCandLut; #if JVET_M0170_MRG_SHARELIST +#if JVET_M0427_INLOOP_RESHAPER + sliceReshapeInfo m_sliceReshapeInfo; +#endif public: LutMotionCand* m_MotionCandLuTsBkup; #endif @@ -1981,7 +2022,10 @@ public: void updateMotionLUTs(LutMotionCand* lutMC, CodingUnit & cu); void copyMotionLUTs(LutMotionCand* Src, LutMotionCand* Dst); - +#if JVET_M0427_INLOOP_RESHAPER + const sliceReshapeInfo& getReshapeInfo() const { return m_sliceReshapeInfo; } + sliceReshapeInfo& getReshapeInfo() { return m_sliceReshapeInfo; } +#endif protected: Picture* xGetRefPic (PicList& rcListPic, int poc); Picture* xGetLongTermRefPic(PicList& rcListPic, int poc, bool pocHasMsb); diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 20eb30481..59ef949fd 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -186,7 +186,11 @@ typedef std::pair<int, int> TrCost; #endif #endif // ! ENABLE_TRACING +#if JVET_M0427_INLOOP_RESHAPER +#define WCG_EXT 1 +#else #define WCG_EXT 0 // part of JEM sharp Luma qp +#endif #define WCG_WPSNR WCG_EXT #if HEVC_TOOLS @@ -1146,6 +1150,15 @@ enum MsgLevel VERBOSE = 5, DETAILS = 6 }; +#if JVET_M0427_INLOOP_RESHAPER +enum RESHAPE_SIGNAL_TYPE +{ + RESHAPE_SIGNAL_SDR = 0, + RESHAPE_SIGNAL_PQ = 1, + RESHAPE_SIGNAL_HLG = 2, + RESHAPE_SIGNAL_NULL = 100, +}; +#endif // --------------------------------------------------------------------------- diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index abcb04ae3..536d640ce 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -554,6 +554,9 @@ void TransformUnit::initData() #else emtIdx = 0; #endif +#if JVET_M0427_INLOOP_RESHAPER + m_iChromaAdj = 0; +#endif } void TransformUnit::init(TCoeff **coeffs, Pel **pcmbuf) @@ -631,3 +634,7 @@ const CCoeffBuf TransformUnit::getCoeffs(const ComponentID id) const { return CC PelBuf TransformUnit::getPcmbuf(const ComponentID id) { return PelBuf (m_pcmbuf[id], blocks[id]); } const CPelBuf TransformUnit::getPcmbuf(const ComponentID id) const { return CPelBuf (m_pcmbuf[id], blocks[id]); } +#if JVET_M0427_INLOOP_RESHAPER +int TransformUnit::getChromaAdj() const { return m_iChromaAdj; } +void TransformUnit::setChromaAdj(int iChromaAdj) { m_iChromaAdj = iChromaAdj; } +#endif \ No newline at end of file diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 9d5322234..811a63dd4 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -435,6 +435,9 @@ struct TransformUnit : public UnitArea CodingUnit *cu; CodingStructure *cs; ChannelType chType; + #if JVET_M0427_INLOOP_RESHAPER + int m_iChromaAdj; +#endif uint8_t depth; #if JVET_M0464_UNI_MTS @@ -467,6 +470,10 @@ struct TransformUnit : public UnitArea const CCoeffBuf getCoeffs(const ComponentID id) const; PelBuf getPcmbuf(const ComponentID id); const CPelBuf getPcmbuf(const ComponentID id) const; +#if JVET_M0427_INLOOP_RESHAPER + int getChromaAdj( ) const; + void setChromaAdj(int iChromaAdj); +#endif #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM int64_t cacheId; diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 3c2730c00..0cc6269f2 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -62,6 +62,9 @@ DecCu::DecCu() { +#if JVET_M0427_INLOOP_RESHAPER + m_tmpStorageLCU = NULL; +#endif } DecCu::~DecCu() @@ -74,6 +77,27 @@ void DecCu::init( TrQuant* pcTrQuant, IntraPrediction* pcIntra, InterPrediction* m_pcIntraPred = pcIntra; m_pcInterPred = pcInter; } +#if JVET_M0427_INLOOP_RESHAPER +void DecCu::initDecCuReshaper (Reshape* pcReshape, ChromaFormat chromaFormatIDC) +{ + m_pcReshape = pcReshape; + if (m_tmpStorageLCU == NULL) + { + m_tmpStorageLCU = new PelStorage; + m_tmpStorageLCU->create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE))); + } + +} +void DecCu::destoryDecCuReshaprBuf() +{ + if (m_tmpStorageLCU) + { + m_tmpStorageLCU->destroy(); + delete m_tmpStorageLCU; + m_tmpStorageLCU = NULL; + } +} +#endif // ==================================================================================================================== // Public member functions @@ -185,7 +209,21 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) { m_pcIntraPred->predIntraAng( compID, piPred, pu, bUseFilteredPredictions ); } +#if JVET_M0427_INLOOP_RESHAPER + const Slice &slice = *cs.slice; + bool bFlag = slice.getReshapeInfo().getUseSliceReshaper() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag() ) || (slice.getSliceType() == P_SLICE && slice.getSPS()->getSpsNext().getCPRMode())); + if (bFlag && slice.getReshapeInfo().getSliceReshapeChromaAdj() && (compID != COMPONENT_Y)) + { + const Area area = tu.Y().valid() ? tu.Y() : Area(recalcPosition(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].pos()), recalcSize(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].size())); + const CompArea &areaY = CompArea(COMPONENT_Y, tu.chromaFormat, area); + PelBuf piPredY; + piPredY = cs.picture->getPredBuf(areaY); + const Pel avgLuma = piPredY.computeAvg(); + int adj = m_pcReshape->calculateChromaAdj(avgLuma); + tu.setChromaAdj(adj); + } +#endif //===== inverse transform ===== PelBuf piResi = cs.getResiBuf( area ); @@ -201,6 +239,13 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) } //===== reconstruction ===== +#if JVET_M0427_INLOOP_RESHAPER + bFlag = bFlag && (tu.blocks[compID].width*tu.blocks[compID].height > 4); + if (bFlag && TU::getCbf(tu, compID) && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj()) + { + piResi.scaleSignal(tu.getChromaAdj(), 0); + } +#endif if( isChroma(compID) && tu.compAlpha[compID] != 0 ) { CrossComponentPrediction::crossComponentPrediction( tu, compID, cs.getResiBuf( tu.Y() ), piResi, piResi, true ); @@ -210,6 +255,21 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) cs.setDecomp( area ); +#if JVET_M0427_INLOOP_RESHAPER +#if REUSE_CU_RESULTS + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpPred; +#endif + if (slice.getReshapeInfo().getUseSliceReshaper() && (m_pcReshape->getCTUFlag() || slice.isIntra() || (slice.getSliceType() == P_SLICE && slice.getSPS()->getSpsNext().getCPRMode())) && compID == COMPONENT_Y) + { +#if REUSE_CU_RESULTS + { + tmpPred = m_tmpStorageLCU->getBuf(tmpArea); + tmpPred.copyFrom(piPred); + } +#endif + } +#endif #if KEEP_PRED_AND_RESI_SIGNALS pReco.reconstruct( piPred, piResi, tu.cu->cs->slice->clpRng( compID ) ); #else @@ -218,10 +278,23 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) #if !KEEP_PRED_AND_RESI_SIGNALS pReco.copyFrom( piPred ); #endif +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && (m_pcReshape->getCTUFlag() || slice.isIntra() || (slice.getSliceType() == P_SLICE && slice.getSPS()->getSpsNext().getCPRMode())) && compID == COMPONENT_Y) + { +#if REUSE_CU_RESULTS + { + piPred.copyFrom(tmpPred); + } +#endif + } +#endif #if REUSE_CU_RESULTS if( cs.pcv->isEncoder ) { cs.picture->getRecoBuf( area ).copyFrom( pReco ); +#if JVET_M0427_INLOOP_RESHAPER + cs.picture->getPredBuf(area).copyFrom(piPred); +#endif } #endif } @@ -394,6 +467,12 @@ void DecCu::xReconInter(CodingUnit &cu) if (cu.firstPU->mhIntraFlag) { +#if JVET_M0427_INLOOP_RESHAPER + if (cu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + cu.cs->getPredBuf(*cu.firstPU).Y().rspSignal(m_pcReshape->getFwdLUT()); + } +#endif m_pcIntraPred->geneWeightedPred(COMPONENT_Y, cu.cs->getPredBuf(*cu.firstPU).Y(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Y, 0)); m_pcIntraPred->geneWeightedPred(COMPONENT_Cb, cu.cs->getPredBuf(*cu.firstPU).Cb(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Cb, 0)); m_pcIntraPred->geneWeightedPred(COMPONENT_Cr, cu.cs->getPredBuf(*cu.firstPU).Cr(), *cu.firstPU, m_pcIntraPred->getPredictorPtr2(COMPONENT_Cr, 0)); @@ -410,16 +489,52 @@ void DecCu::xReconInter(CodingUnit &cu) if (cu.rootCbf) { +#if JVET_M0427_INLOOP_RESHAPER +#if REUSE_CU_RESULTS + const CompArea &area = cu.blocks[COMPONENT_Y]; + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpPred; +#endif + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { +#if REUSE_CU_RESULTS + if (cs.pcv->isEncoder) + { + tmpPred = m_tmpStorageLCU->getBuf(tmpArea); + tmpPred.copyFrom(cs.getPredBuf(cu).get(COMPONENT_Y)); + } +#endif + if (!cu.firstPU->mhIntraFlag && !cu.cpr ) + cs.getPredBuf(cu).get(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT()); + } +#endif #if KEEP_PRED_AND_RESI_SIGNALS cs.getRecoBuf( cu ).reconstruct( cs.getPredBuf( cu ), cs.getResiBuf( cu ), cs.slice->clpRngs() ); #else cs.getResiBuf( cu ).reconstruct( cs.getPredBuf( cu ), cs.getResiBuf( cu ), cs.slice->clpRngs() ); cs.getRecoBuf( cu ).copyFrom ( cs.getResiBuf( cu ) ); +#endif +#if JVET_M0427_INLOOP_RESHAPER + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { +#if REUSE_CU_RESULTS + if (cs.pcv->isEncoder) + { + cs.getPredBuf(cu).get(COMPONENT_Y).copyFrom(tmpPred); + } +#endif + } #endif } else { cs.getRecoBuf(cu).copyClip(cs.getPredBuf(cu), cs.slice->clpRngs()); +#if JVET_M0427_INLOOP_RESHAPER + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && !cu.firstPU->mhIntraFlag && !cu.cpr) + { + cs.getRecoBuf(cu).get(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT()); + } +#endif } DTRACE ( g_trace_ctx, D_TMP, "reco " ); @@ -451,6 +566,13 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID ) } //===== reconstruction ===== +#if JVET_M0427_INLOOP_RESHAPER + const Slice &slice = *cs.slice; + if ( slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && isChroma(compID) && TU::getCbf(currTU, compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() && currTU.blocks[compID].width*currTU.blocks[compID].height > 4 ) + { + resiBuf.scaleSignal(currTU.getChromaAdj(), 0); + } +#endif if( isChroma( compID ) && currTU.compAlpha[compID] != 0 ) { CrossComponentPrediction::crossComponentPrediction( currTU, compID, cs.getResiBuf( currTU.Y() ), resiBuf, resiBuf, true ); @@ -472,6 +594,23 @@ void DecCu::xDecodeInterTexture(CodingUnit &cu) for( auto& currTU : CU::traverseTUs( cu ) ) { +#if JVET_M0427_INLOOP_RESHAPER + CodingStructure &cs = *cu.cs; + const Slice &slice = *cs.slice; + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && slice.getReshapeInfo().getSliceReshapeChromaAdj() && (compID == COMPONENT_Y)) + { + const CompArea &areaY = currTU.blocks[COMPONENT_Y]; + PelBuf piPredY = cs.getPredBuf(areaY); + CompArea tmpArea(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpPred = m_tmpStorageLCU->getBuf(tmpArea); + tmpPred.copyFrom(piPredY); + if (!cu.firstPU->mhIntraFlag && !cu.cpr) + tmpPred.rspSignal(m_pcReshape->getFwdLUT()); + const Pel avgLuma = tmpPred.computeAvg(); + int adj = m_pcReshape->calculateChromaAdj(avgLuma); + currTU.setChromaAdj(adj); + } +#endif xDecodeInterTU( currTU, compID ); } } diff --git a/source/Lib/DecoderLib/DecCu.h b/source/Lib/DecoderLib/DecCu.h index 67e5dc4fb..40114ce68 100644 --- a/source/Lib/DecoderLib/DecCu.h +++ b/source/Lib/DecoderLib/DecCu.h @@ -48,7 +48,9 @@ #include "CommonLib/InterPrediction.h" #include "CommonLib/IntraPrediction.h" #include "CommonLib/Unit.h" - +#if JVET_M0427_INLOOP_RESHAPER +#include "CommonLib/Reshape.h" +#endif //! \ingroup DecoderLib //! \{ @@ -68,6 +70,12 @@ public: /// destroy internal buffers void decompressCtu ( CodingStructure& cs, const UnitArea& ctuArea ); +#if JVET_M0427_INLOOP_RESHAPER + Reshape* m_pcReshape; + Reshape* getReshape () { return m_pcReshape; } + void initDecCuReshaper ( Reshape* pcReshape, ChromaFormat chromaFormatIDC) ; + void destoryDecCuReshaprBuf(); +#endif #if JVET_M0170_MRG_SHARELIST void setShareStateDec (int shareStateDecIn) { m_shareStateDec = shareStateDecIn; } @@ -87,7 +95,9 @@ protected: void xDecodeInterTU ( TransformUnit& tu, const ComponentID compID ); void xDeriveCUMV ( CodingUnit& cu ); - +#if JVET_M0427_INLOOP_RESHAPER + PelStorage *m_tmpStorageLCU; +#endif private: TrQuant* m_pcTrQuant; IntraPrediction* m_pcIntraPred; diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 09b493dd5..1bc6e1227 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -353,6 +353,9 @@ DecLib::DecLib() , m_cSAO() #if JVET_J0090_MEMORY_BANDWITH_MEASURE , m_cacheModel() +#endif +#if JVET_M0427_INLOOP_RESHAPER + , m_cReshaper() #endif , m_pcPic(NULL) , m_prevPOC(MAX_INT) @@ -434,6 +437,10 @@ void DecLib::deletePicBuffer ( ) m_cacheModel.reportSequence( ); m_cacheModel.destroy( ); #endif +#if JVET_M0427_INLOOP_RESHAPER + m_cCuDecoder.destoryDecCuReshaprBuf(); + m_cReshaper.destroy(); +#endif } Picture* DecLib::xGetNewPicBuffer ( const SPS &sps, const PPS &pps, const uint32_t temporalLayer ) @@ -508,6 +515,14 @@ void DecLib::executeLoopFilters() CodingStructure& cs = *m_pcPic->cs; +#if JVET_M0427_INLOOP_RESHAPER + if (cs.sps->getUseReshaper() && m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper()) + { + CHECK((m_cReshaper.getRecReshaped() == false), "Rec picture is not reshaped!"); + m_pcPic->getRecoBuf(COMPONENT_Y).rspSignal(m_cReshaper.getInvLUT()); + m_cReshaper.setRecReshaped(false); + } +#endif // deblocking filter m_cLoopFilter.loopFilterPic( cs ); @@ -738,7 +753,12 @@ void DecLib::xActivateParameterSets() m_cLoopFilter.create( sps->getMaxCodingDepth() ); m_cIntraPred.init( sps->getChromaFormatIdc(), sps->getBitDepth( CHANNEL_TYPE_LUMA ) ); m_cInterPred.init( &m_cRdCost, sps->getChromaFormatIdc() ); - +#if JVET_M0427_INLOOP_RESHAPER + if (sps->getUseReshaper()) + { + m_cReshaper.create_dec(); + } +#endif bool isField = false; bool isTopField = false; @@ -765,6 +785,12 @@ void DecLib::xActivateParameterSets() // Recursive structure m_cCuDecoder.init( &m_cTrQuant, &m_cIntraPred, &m_cInterPred ); +#if JVET_M0427_INLOOP_RESHAPER + if (sps->getUseReshaper()) + { + m_cCuDecoder.initDecCuReshaper(&m_cReshaper, sps->getChromaFormatIdc()); + } +#endif m_cTrQuant.init( nullptr, sps->getMaxTrSize(), false, false, false, false, false ); // RdCost @@ -1233,6 +1259,43 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl CHECK(pcSlice->getRefPic(RefPicList(pcSlice->isInterB() ? 1 - pcSlice->getColFromL0Flag() : 0), pcSlice->getColRefIdx())->getPOC() == pcSlice->getPOC(), "curr ref picture cannot be collocated picture"); } +#if JVET_M0427_INLOOP_RESHAPER + if (pcSlice->getSPS()->getUseReshaper()) + { + m_cReshaper.copySliceReshaperInfo(m_cReshaper.getSliceReshaperInfo(), pcSlice->getReshapeInfo()); + if (pcSlice->getReshapeInfo().getSliceReshapeModelPresentFlag()) + { + m_cReshaper.constructReshaper(); + } + else + { + m_cReshaper.setReshapeFlag(false); + } + if ((pcSlice->getSliceType() == I_SLICE|| (pcSlice->getSliceType() == P_SLICE && pcSlice->getSPS()->getSpsNext().getCPRMode()) ) && m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper()) + { + m_cReshaper.setCTUFlag(false); + m_cReshaper.setRecReshaped(true); + } + else + { + if (m_cReshaper.getSliceReshaperInfo().getUseSliceReshaper()) + { + m_cReshaper.setCTUFlag(true); + m_cReshaper.setRecReshaped(true); + } + else + { + m_cReshaper.setCTUFlag(false); + m_cReshaper.setRecReshaped(false); + } + } + } + else + { + m_cReshaper.setCTUFlag(false); + m_cReshaper.setRecReshaped(false); + } +#endif // Decode a picture m_cSliceDecoder.decompressSlice( pcSlice, &(nalu.getBitstream()) ); diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 687ea822a..01e272fc8 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -53,6 +53,9 @@ #include "CommonLib/AdaptiveLoopFilter.h" #include "CommonLib/SEI.h" #include "CommonLib/Unit.h" +#if JVET_M0427_INLOOP_RESHAPER +#include "CommonLib/Reshape.h" +#endif class InputNALUnit; @@ -94,6 +97,9 @@ private: LoopFilter m_cLoopFilter; SampleAdaptiveOffset m_cSAO; AdaptiveLoopFilter m_cALF; +#if JVET_M0427_INLOOP_RESHAPER + Reshape m_cReshaper; ///< reshaper class +#endif // decoder side RD cost computation RdCost m_cRdCost; ///< RD cost computation class #if JVET_J0090_MEMORY_BANDWITH_MEASURE diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 94c056f88..44d883e21 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -853,6 +853,40 @@ void HLSyntaxReader::parseSPSNext( SPSNext& spsNext, const bool usePCM ) // ADD_NEW_TOOL : (sps extension parser) read tool enabling flags and associated parameters here } +#if JVET_M0427_INLOOP_RESHAPER +void HLSyntaxReader::parseReshaper (sliceReshapeInfo& info, const SPS* pcSPS, const bool isIntra) +{ + unsigned symbol = 0; + READ_FLAG(symbol, "slice_reshape_model_present_flag"); info.setSliceReshapeModelPresentFlag(symbol == 1); + if (info.getSliceReshapeModelPresentFlag()) + { + // parse slice reshaper model + memset(info.reshape_model_bin_CW_delta, 0, PIC_CODE_CW_BINS * sizeof(int)); + READ_UVLC(symbol, "reshaper_model_min_bin_idx"); info.reshape_model_min_bin_idx = symbol; + READ_UVLC(symbol, "max_bin_minus_reshape_model_max_bin_idx"); info.reshape_model_max_bin_idx = PIC_CODE_CW_BINS - 1 - symbol; + READ_UVLC(symbol, "reshaper_model_bin_delta_abs_cw_prec_minus1"); info.maxNbitsNeededDeltaCW = symbol+1; + assert(info.maxNbitsNeededDeltaCW > 0); + for (uint32_t i = info.reshape_model_min_bin_idx; i <= info.reshape_model_max_bin_idx; i++) + { + READ_CODE(info.maxNbitsNeededDeltaCW, symbol, "reshape_model_abs_CW"); int absCW = symbol; + if (absCW > 0) + READ_CODE(1, symbol, "reshape_model_sign_CW"); int signCW = symbol; + info.reshape_model_bin_CW_delta[i] = (1 - 2 * signCW) * absCW; + } + } + READ_FLAG(symbol, "slice_reshaper_enable_flag"); info.setUseSliceReshaper(symbol == 1); + + if (info.getUseSliceReshaper()) + { + if (!(pcSPS->getUseDualITree() && isIntra)) + { + READ_FLAG(symbol, "slice_reshaper_ChromaAdj"); info.setSliceReshapeChromaAdj(symbol); + } + else + info.setSliceReshapeChromaAdj(0); + } +} +#endif void HLSyntaxReader::parseSPS(SPS* pcSPS) { #if ENABLE_TRACING @@ -1171,7 +1205,9 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) } } } - +#if JVET_M0427_INLOOP_RESHAPER + READ_FLAG(uiCode, "sps_reshaper_enable_flag"); pcSPS->setUseReshaper(uiCode == 1); +#endif xReadRbspTrailingBits(); } @@ -1869,6 +1905,13 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para uiCode = pps->getLoopFilterAcrossSlicesEnabledFlag()?1:0; } pcSlice->setLFCrossSliceBoundaryFlag( (uiCode==1)?true:false); + +#if JVET_M0427_INLOOP_RESHAPER + if (sps->getUseReshaper()) + { + parseReshaper(pcSlice->getReshapeInfo(), sps, pcSlice->isIntra()); + } +#endif #if HEVC_DEPENDENT_SLICES } #endif diff --git a/source/Lib/DecoderLib/VLCReader.h b/source/Lib/DecoderLib/VLCReader.h index 56fc8eb43..a80eefc9d 100644 --- a/source/Lib/DecoderLib/VLCReader.h +++ b/source/Lib/DecoderLib/VLCReader.h @@ -163,7 +163,9 @@ public: void parseScalingList ( ScalingList* scalingList ); void decodeScalingList ( ScalingList *scalingList, uint32_t sizeId, uint32_t listId); #endif - +#if JVET_M0427_INLOOP_RESHAPER + void parseReshaper ( sliceReshapeInfo& sliceReshaperInfo, const SPS* pcSPS, const bool isIntra ); +#endif void alf( AlfSliceParam& alfSliceParam ); void alfFilter( AlfSliceParam& alfSliceParam, const bool isChroma ); diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp index f8a713d34..97340a546 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp @@ -40,6 +40,9 @@ #include "CommonLib/CodingStructure.h" #define AlfCtx(c) SubCtx( Ctx::ctbAlfFlag, c ) +#if JVET_M0427_INLOOP_RESHAPER +double EncAdaptiveLoopFilter::m_lumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE]; +#endif EncAdaptiveLoopFilter::EncAdaptiveLoopFilter() : m_CABACEstimator( nullptr ) @@ -55,6 +58,10 @@ EncAdaptiveLoopFilter::EncAdaptiveLoopFilter() m_filterCoeffQuant = nullptr; m_filterCoeffSet = nullptr; m_diffFilterCoeff = nullptr; + +#if JVET_M0427_INLOOP_RESHAPER + m_alfWSSD = 0; +#endif } void EncAdaptiveLoopFilter::create( const int picWidth, const int picHeight, const ChromaFormat chromaFormatIDC, const int maxCUWidth, const int maxCUHeight, const int maxCUDepth, const int inputBitDepth[MAX_NUM_CHANNEL_TYPE], const int internalBitDepth[MAX_NUM_CHANNEL_TYPE] ) @@ -1472,16 +1479,40 @@ void EncAdaptiveLoopFilter::getBlkStats( AlfCovariance* alfCovariace, const AlfF classIdx = cl.classIdx; } +#if JVET_M0427_INLOOP_RESHAPER + double weight = m_lumaLevelToWeightPLUT[org[j]]; +#endif int yLocal = org[j] - rec[j]; calcCovariance( ELocal, rec + j, recStride, shape.pattern.data(), shape.filterLength >> 1, transposeIdx ); for( int k = 0; k < shape.numCoeff; k++ ) { for( int l = k; l < shape.numCoeff; l++ ) { +#if JVET_M0427_INLOOP_RESHAPER + if (m_alfWSSD) + { + alfCovariace[classIdx].E[k][l] += weight * (double)(ELocal[k] * ELocal[l]); + } + else +#endif alfCovariace[classIdx].E[k][l] += ELocal[k] * ELocal[l]; } +#if JVET_M0427_INLOOP_RESHAPER + if (m_alfWSSD) + { + alfCovariace[classIdx].y[k] += weight * (double)(ELocal[k] * yLocal); + } + else +#endif alfCovariace[classIdx].y[k] += ELocal[k] * yLocal; } +#if JVET_M0427_INLOOP_RESHAPER + if (m_alfWSSD) + { + alfCovariace[classIdx].pixAcc += weight * (double)(yLocal * yLocal); + } + else +#endif alfCovariace[classIdx].pixAcc += yLocal * yLocal; } org += orgStride; diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h index da36a50e5..81a4ee2d0 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h @@ -151,6 +151,12 @@ class EncAdaptiveLoopFilter : public AdaptiveLoopFilter public: static constexpr int m_MAX_SCAN_VAL = 11; static constexpr int m_MAX_EXP_GOLOMB = 16; +#if JVET_M0427_INLOOP_RESHAPER + int m_alfWSSD; + inline void setAlfWSSD(int alfWSSD) { m_alfWSSD = alfWSSD; } + static double m_lumaLevelToWeightPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE]; + inline double* getLumaLevelWeightTable() { return m_lumaLevelToWeightPLUT; } +#endif private: AlfCovariance*** m_alfCovariance[MAX_NUM_COMPONENT]; // [compIdx][shapeIdx][ctbAddr][classIdx] diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index a34fdac1a..af9445baa 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -256,7 +256,12 @@ protected: unsigned m_wrapAroundOffset; // ADD_NEW_TOOL : (encoder lib) add tool enabling flags and associated parameters here - +#if JVET_M0427_INLOOP_RESHAPER + bool m_bUseReshape; + unsigned m_uiSignalType; + unsigned m_uiIntraCMD; + ReshapeCW m_reshapeCW; +#endif bool m_useFastLCTU; bool m_useFastMrg; bool m_usePbIntraFast; @@ -790,7 +795,16 @@ public: // ADD_NEW_TOOL : (encoder lib) add access functions here - +#if JVET_M0427_INLOOP_RESHAPER + void setReshaper ( bool b ) { m_bUseReshape = b; } + bool getReshaper () const { return m_bUseReshape; } + void setReshapeSignalType ( uint32_t uiSignalType ) { m_uiSignalType = uiSignalType; } + uint32_t getReshapeSignalType () const { return m_uiSignalType; } + void setReshapeIntraCMD (uint32_t uiIntraCMD) { m_uiIntraCMD = uiIntraCMD; } + uint32_t getReshapeIntraCMD () { return m_uiIntraCMD; } + void setReshapeCW (const ReshapeCW &reshapeCW) { m_reshapeCW = reshapeCW; } + const ReshapeCW& getReshapeCW () { return m_reshapeCW; } +#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/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 326393399..0c1b6d192 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -232,6 +232,14 @@ void EncCu::destroy() delete[] m_pBestMotLUTs; m_pBestMotLUTs = nullptr; delete[] m_pTempMotLUTs; m_pTempMotLUTs = nullptr; +#if JVET_M0427_INLOOP_RESHAPER && REUSE_CU_RESULTS + if (m_tmpStorageLCU) + { + m_tmpStorageLCU->destroy(); + delete m_tmpStorageLCU; m_tmpStorageLCU = nullptr; + } +#endif + #if REUSE_CU_RESULTS m_modeCtrl->destroy(); @@ -338,7 +346,15 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign #if !JVET_M0255_FRACMMVD_SWITCH if (m_pcEncCfg->getIBCHashSearch() && ctuRsAddr == 0 && cs.slice->getSPS()->getSpsNext().getIBCMode()) { +#if JVET_M0427_INLOOP_RESHAPER + if (cs.slice->getSPS()->getUseReshaper() && m_pcReshape->getCTUFlag()) + cs.picture->getOrigBuf(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT()); +#endif m_ibcHashMap.rebuildPicHashMap(cs.picture->getOrigBuf()); +#if JVET_M0427_INLOOP_RESHAPER + if (cs.slice->getSPS()->getUseReshaper() && m_pcReshape->getCTUFlag()) + cs.picture->getOrigBuf().copyFrom(cs.picture->getTrueOrigBuf()); +#endif } #endif m_modeCtrl->initCTUEncoding( *cs.slice ); @@ -404,7 +420,11 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign ); // all signals were already copied during compression if the CTU was split - at this point only the structures are copied to the top level CS +#if JVET_M0427_INLOOP_RESHAPER + const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1; +#else const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1 && KEEP_PRED_AND_RESI_SIGNALS; +#endif cs.useSubStructure( *bestCS, partitioner->chType, CS::getArea( *bestCS, area, partitioner->chType ), copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals ); cs.slice->copyMotionLUTs(bestMotCandLUTs, cs.slice->getMotionLUTs()); @@ -425,7 +445,11 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign , bestMotCandLUTs ); +#if JVET_M0427_INLOOP_RESHAPER + const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1; +#else const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1 && KEEP_PRED_AND_RESI_SIGNALS; +#endif cs.useSubStructure( *bestCS, partitioner->chType, CS::getArea( *bestCS, area, partitioner->chType ), copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals ); } @@ -841,6 +865,9 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par { bestCS->slice->updateMotionLUTs(bestMotCandLUTs, (*bestCS->cus.back())); } +#if JVET_M0427_INLOOP_RESHAPER + bestCS->picture->getPredBuf(currCsArea).copyFrom(bestCS->getPredBuf(currCsArea)); +#endif bestCS->picture->getRecoBuf( currCsArea ).copyFrom( bestCS->getRecoBuf( currCsArea ) ); m_modeCtrl->finishCULevel( partitioner ); @@ -1212,6 +1239,10 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, m_CurrCtx++; tempCS->getRecoBuf().fill( 0 ); + +#if JVET_M0427_INLOOP_RESHAPER + tempCS->getPredBuf().fill(0); +#endif AffineMVInfo tmpMVInfo; bool isAffMVInfoSaved; m_pcInterSearch->savePrevAffMVInfo(0, tmpMVInfo, isAffMVInfoSaved); @@ -1492,6 +1523,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC if( !CS::isDualITree( *tempCS ) ) { cu.cs->picture->getRecoBuf( cu.Y() ).copyFrom( cu.cs->getRecoBuf( COMPONENT_Y ) ); +#if JVET_M0427_INLOOP_RESHAPER + cu.cs->picture->getPredBuf(cu.Y()).copyFrom(cu.cs->getPredBuf(COMPONENT_Y)); +#endif } } @@ -1992,11 +2026,29 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& m_pcIntraSearch->switchBuffer(pu, COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt)); } pu.cs->getPredBuf(pu).copyFrom(acMergeBuffer[mergeCand]); +#if JVET_M0427_INLOOP_RESHAPER + if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT()); + } +#endif m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt)); // calculate cost +#if JVET_M0427_INLOOP_RESHAPER + if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getInvLUT()); + } +#endif distParam.cur = pu.cs->getPredBuf(pu).Y(); Distortion sadValue = distParam.distFunc(distParam); +#if JVET_M0427_INLOOP_RESHAPER + if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT()); + } +#endif m_CABACEstimator->getCtx() = SubCtx(Ctx::MHIntraPredMode, ctxStartIntraMode); uint64_t fracModeBits = m_pcIntraSearch->xFracModeBitsIntra(pu, pu.intraDir[0], CHANNEL_TYPE_LUMA); double cost = (double)sadValue + (double)(bitsCand + 1) * sqrtLambdaForFirstPass + (double)fracModeBits * sqrtLambdaForFirstPassIntra; @@ -2228,6 +2280,12 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& uint32_t bufIdx = (pu.intraDir[0] > 1) ? (pu.intraDir[0] == HOR_IDX ? 2 : 3) : pu.intraDir[0]; PelBuf tmpBuf = tempCS->getPredBuf(pu).Y(); tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Y()); +#if JVET_M0427_INLOOP_RESHAPER + if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + tmpBuf.rspSignal(m_pcReshape->getFwdLUT()); + } +#endif m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, bufIdx)); tmpBuf = tempCS->getPredBuf(pu).Cb(); tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cb()); @@ -2970,6 +3028,18 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct Picture* refPic = pu.cu->slice->getPic(); const CPelBuf refBuf = refPic->getRecoBuf(pu.blocks[COMPONENT_Y]); const Pel* piRefSrch = refBuf.buf; +#if JVET_M0427_INLOOP_RESHAPER + if (tempCS->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + const CompArea &area = cu.blocks[COMPONENT_Y]; + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpLuma = m_tmpStorageLCU->getBuf(tmpArea); + tmpLuma.copyFrom(tempCS->getOrgBuf().Y()); + tmpLuma.rspSignal(m_pcReshape->getFwdLUT()); + m_pcRdCost->setDistParam(distParam, tmpLuma, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard); + } + else +#endif m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard); int refStride = refBuf.stride; const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height)); @@ -4005,9 +4075,26 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best CPelBuf org = tempCS->getOrgBuf ( compID ); #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || ( + m_pcEncCfg->getReshaper() && (tempCS->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()))) +#else if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() ) +#endif { const CPelBuf orgLuma = tempCS->getOrgBuf(tempCS->area.blocks[COMPONENT_Y]); +#if JVET_M0427_INLOOP_RESHAPER + if (compID == COMPONENT_Y) + { + const CompArea &area = cu.blocks[COMPONENT_Y]; + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpRecLuma = m_tmpStorageLCU->getBuf(tmpArea); + tmpRecLuma.copyFrom(reco); + tmpRecLuma.rspSignal(m_pcReshape->getInvLUT()); + finalDistortion += m_pcRdCost->getDistPart(org, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else +#endif finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); } else diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index 920e0eca5..4ca7c3944 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -156,7 +156,9 @@ private: public: /// copy parameters from encoder class void init ( EncLib* pcEncLib, const SPS& sps PARL_PARAM( const int jId = 0 ) ); - +#if JVET_M0427_INLOOP_RESHAPER && REUSE_CU_RESULTS + void setDecCuReshaperInEncCU(EncReshape* pcReshape, ChromaFormat chromaFormatIDC) { initDecCuReshaper((Reshape*) pcReshape, chromaFormatIDC); } +#endif /// create internal buffers void create ( EncCfg* encCfg ); diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index bc863bb6c..93e6d85bb 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -178,7 +178,25 @@ void EncGOP::init ( EncLib* pcEncLib ) m_AUWriterIf = pcEncLib->getAUWriterIf(); #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcCfg->getReshaper()) + pcEncLib->getRdCost()->setReshapeSignalType(m_pcCfg->getReshapeSignalType()); +#endif pcEncLib->getRdCost()->initLumaLevelToWeightTable(); +#if JVET_M0427_INLOOP_RESHAPER + memcpy(pcEncLib->getALF()->getLumaLevelWeightTable(), pcEncLib->getRdCost()->getLumaLevelWeightTable(), LUMA_LEVEL_TO_DQP_LUT_MAXSIZE * sizeof(double)); + int alfWSSD = 0; + + if (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ ) + { + alfWSSD = 1; + } + + pcEncLib->getALF()->setAlfWSSD(alfWSSD); +#endif +#endif +#if JVET_M0427_INLOOP_RESHAPER + m_pcReshaper = pcEncLib->getReshaper(); #endif } @@ -2092,6 +2110,96 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, // now compress (trial encode) the various slice segments (slices, and dependent slices) { DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "poc", pocCurr ) ) ); +#if JVET_M0427_INLOOP_RESHAPER + if (pcSlice->getSPS()->getUseReshaper()) + { + m_pcReshaper->getReshapeCW()->Tid = pcSlice->getTLayer()+(pcSlice->isIntra()?0:1); + m_pcReshaper->getReshapeCW()->SliceQP = pcSlice->getSliceQp(); + + m_pcReshaper->setSrcReshaped(false); + m_pcReshaper->setRecReshaped(true); + + if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ) + { + m_pcReshaper->preAnalyzerHDR(pcPic, pcSlice->getSliceType(), m_pcCfg->getReshapeCW(), m_pcCfg->getDualITree(), m_pcCfg->getCPRMode()); + } + else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR) + { + m_pcReshaper->preAnalyzerSDR(pcPic, pcSlice->getSliceType(), m_pcCfg->getReshapeCW(), m_pcCfg->getDualITree(), m_pcCfg->getCPRMode()); + } + else + { + THROW("Reshaper for signal other than PQ and SDR currently not defined!"); + } + + if (pcSlice->getSliceType() == I_SLICE || (pcSlice->getSliceType()==P_SLICE && m_pcCfg->getCPRMode())) + { + if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ) + { + m_pcReshaper->initLUTfromdQPModel(); + m_pcEncLib->getRdCost()->updateReshapeLumaLevelToWeightTableChromaMD(m_pcReshaper->getInvLUT()); + } + else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR) + { + if (m_pcReshaper->getReshapeFlag()) + { + m_pcReshaper->constructReshaperSDR(); + m_pcEncLib->getRdCost()->updateReshapeLumaLevelToWeightTable(m_pcReshaper->getSliceReshaperInfo(), m_pcReshaper->getWeightTable(), m_pcReshaper->getCWeight()); + } + } + else + { + THROW("Reshaper for other signal currently not defined!"); + } + + m_pcReshaper->setCTUFlag(false); + + //reshape original signal + if (m_pcReshaper->getSliceReshaperInfo().getUseSliceReshaper()) + { + pcPic->getOrigBuf(COMPONENT_Y).rspSignal(m_pcReshaper->getFwdLUT()); + m_pcReshaper->setSrcReshaped(true); + m_pcReshaper->setRecReshaped(true); + } + } + else + { + if (!m_pcReshaper->getReshapeFlag()) + { + m_pcReshaper->setCTUFlag(false); + } + else + m_pcReshaper->setCTUFlag(true); + + m_pcReshaper->getSliceReshaperInfo().setSliceReshapeModelPresentFlag(false); + + if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ ) + { + m_pcEncLib->getRdCost()->restoreReshapeLumaLevelToWeightTable(); + } + else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR) + { + int modIP = pcPic->getPOC() - pcPic->getPOC() / m_pcCfg->getReshapeCW().RspFpsToIp * m_pcCfg->getReshapeCW().RspFpsToIp; + if (m_pcReshaper->getReshapeFlag() && m_pcCfg->getReshapeCW().RspIntraPeriod == -1 && modIP == 0) // for LDB, update reshaping curve every second + { + m_pcReshaper->getSliceReshaperInfo().setSliceReshapeModelPresentFlag(true); + m_pcReshaper->constructReshaperSDR(); + m_pcEncLib->getRdCost()->updateReshapeLumaLevelToWeightTable(m_pcReshaper->getSliceReshaperInfo(), m_pcReshaper->getWeightTable(), m_pcReshaper->getCWeight()); + } + } + else + { + THROW("Reshaper for other signal currently not defined!"); + } + } + + m_pcReshaper->copySliceReshaperInfo(pcSlice->getReshapeInfo(), m_pcReshaper->getSliceReshaperInfo()); + } + else + { + m_pcReshaper->setCTUFlag(false); + } +#endif pcSlice->setSliceCurStartCtuTsAddr( 0 ); #if HEVC_DEPENDENT_SLICES @@ -2161,6 +2269,17 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, CodingStructure& cs = *pcPic->cs; pcSlice = pcPic->slices[0]; +#if JVET_M0427_INLOOP_RESHAPER + if (pcSlice->getSPS()->getUseReshaper() && m_pcReshaper->getSliceReshaperInfo().getUseSliceReshaper()) + { + CHECK((m_pcReshaper->getRecReshaped() == false), "Rec picture is not reshaped!"); + pcPic->getRecoBuf(COMPONENT_Y).rspSignal(m_pcReshaper->getInvLUT()); + m_pcReshaper->setRecReshaped(false); + + pcPic->getOrigBuf().copyFrom(pcPic->getTrueOrigBuf()); + } +#endif + // SAO parameter estimation using non-deblocked pixels for CTU bottom and right boundary areas if( pcSlice->getSPS()->getSAOEnabledFlag() && m_pcCfg->getSaoCtuBoundary() ) { @@ -2527,7 +2646,11 @@ void EncGOP::printOutSummary(uint32_t uiNumAllPicCoded, bool isField, const bool const bool useWPSNR = m_pcEncLib->getUseWPSNR(); #endif #if WCG_WPSNR +#if JVET_M0427_INLOOP_RESHAPER + const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ); +#else const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled(); +#endif #endif if( m_pcCfg->getDecodeBitstream(0).empty() && m_pcCfg->getDecodeBitstream(1).empty() && !m_pcCfg->useFastForwardToPOC() ) @@ -2868,7 +2991,11 @@ uint64_t EncGOP::xFindDistortionPlane(const CPelBuf& pic0, const CPelBuf& pic1, double EncGOP::xFindDistortionPlaneWPSNR(const CPelBuf& pic0, const CPelBuf& pic1, const uint32_t rshift, const CPelBuf& picLuma0, ComponentID compID, const ChromaFormat chfmt ) { +#if JVET_M0427_INLOOP_RESHAPER + const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ); +#else const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled(); +#endif if (!useLumaWPSNR) { return 0; @@ -3001,13 +3128,21 @@ void EncGOP::xCalculateAddPSNR(Picture* pcPic, PelUnitBuf cPicD, const AccessUni const CPelUnitBuf& pic = cPicD; CHECK(!(conversion == IPCOLOURSPACE_UNCHANGED), "Unspecified error"); // const CPelUnitBuf& org = (conversion != IPCOLOURSPACE_UNCHANGED) ? pcPic->getPicYuvTrueOrg()->getBuf() : pcPic->getPicYuvOrg()->getBuf(); +#if JVET_M0427_INLOOP_RESHAPER + const CPelUnitBuf& org = sps.getUseReshaper() ? pcPic->getTrueOrigBuf() : pcPic->getOrigBuf(); +#else const CPelUnitBuf& org = pcPic->getOrigBuf(); +#endif #if ENABLE_QPA const bool useWPSNR = m_pcEncLib->getUseWPSNR(); #endif double dPSNR[MAX_NUM_COMPONENT]; #if WCG_WPSNR +#if JVET_M0427_INLOOP_RESHAPER + const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcCfg->getReshaper() && m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_PQ); +#else const bool useLumaWPSNR = m_pcEncLib->getLumaLevelToDeltaQPMapping().isEnabled(); +#endif double dPSNRWeighted[MAX_NUM_COMPONENT]; double MSEyuvframeWeighted[MAX_NUM_COMPONENT]; #endif diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h index ca2121451..e2c11c170 100644 --- a/source/Lib/EncoderLib/EncGOP.h +++ b/source/Lib/EncoderLib/EncGOP.h @@ -47,6 +47,9 @@ #include "CommonLib/NAL.h" #include "EncSampleAdaptiveOffset.h" #include "EncAdaptiveLoopFilter.h" +#if JVET_M0427_INLOOP_RESHAPER +#include "EncReshape.h" +#endif #include "EncSlice.h" #include "VLCWriter.h" #include "CABACWriter.h" @@ -139,6 +142,9 @@ private: //--Adaptive Loop filter EncSampleAdaptiveOffset* m_pcSAO; EncAdaptiveLoopFilter* m_pcALF; +#if JVET_M0427_INLOOP_RESHAPER + EncReshape* m_pcReshaper; +#endif RateCtrl* m_pcRateCtrl; // indicate sequence first bool m_bSeqFirst; diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 4d8506f02..b8ff0a60e 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -136,6 +136,12 @@ void EncLib::create () m_cEncALF.create( getSourceWidth(), getSourceHeight(), m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth, m_bitDepth, m_inputBitDepth ); } +#if JVET_M0427_INLOOP_RESHAPER + if (m_bUseReshape) + { + m_cReshaper.create_enc( getSourceWidth(), getSourceHeight(), m_maxCUWidth, m_maxCUHeight ); + } +#endif if ( m_RCEnableRateControl ) { m_cRateCtrl.init(m_framesToBeEncoded, m_RCTargetBitrate, (int)((double)m_iFrameRate / m_temporalSubsampleRatio + 0.5), m_iGOPSize, m_iSourceWidth, m_iSourceHeight, @@ -165,6 +171,9 @@ void EncLib::destroy () m_cEncSAO. destroy(); m_cLoopFilter. destroy(); m_cRateCtrl. destroy(); +#if JVET_M0427_INLOOP_RESHAPER + m_cReshaper. destroy(); +#endif #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for( int jId = 0; jId < m_numCuEncStacks; jId++ ) { @@ -318,13 +327,21 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) &m_cTrQuant, &m_cRdCost, cabacEstimator, - getCtxCache(), m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth ); + getCtxCache(), m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth +#if JVET_M0427_INLOOP_RESHAPER + , &m_cReshaper +#endif + ); m_cInterSearch.init( this, &m_cTrQuant, m_iSearchRange, m_bipredSearchRange, m_motionEstimationSearchMethod, - m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth, &m_cRdCost, cabacEstimator, getCtxCache() ); + m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth, &m_cRdCost, cabacEstimator, getCtxCache() +#if JVET_M0427_INLOOP_RESHAPER + , &m_cReshaper +#endif + ); // link temporary buffets from intra search with inter search to avoid unneccessary memory overhead m_cInterSearch.setTempBuffers( m_cIntraSearch.getSplitCSBuf(), m_cIntraSearch.getFullCSBuf(), m_cIntraSearch.getSaveCSBuf() ); @@ -551,6 +568,9 @@ void EncLib::encode( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYuvTru const SPS *pSPS=m_spsMap.getPS(pPPS->getSPSId()); pcPicCurr->M_BUFS( 0, PIC_ORIGINAL ).swap( *pcPicYuvOrg ); +#if JVET_M0427_INLOOP_RESHAPER + pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL).swap(*cPicYuvTrueOrg); +#endif pcPicCurr->finalInit( *pSPS, *pPPS ); } @@ -902,7 +922,9 @@ void EncLib::xInitSPS(SPS &sps) sps.setWrapAroundEnabledFlag ( m_wrapAround ); sps.setWrapAroundOffset ( m_wrapAroundOffset ); // ADD_NEW_TOOL : (encoder lib) set tool enabling flags and associated parameters here - +#if JVET_M0427_INLOOP_RESHAPER + sps.setUseReshaper(m_bUseReshape); +#endif int minCUSize = sps.getMaxCUWidth() >> sps.getLog2DiffMaxMinCodingBlockSize(); int log2MinCUSize = 0; while(minCUSize > 1) diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h index 07109efcd..f966d8277 100644 --- a/source/Lib/EncoderLib/EncLib.h +++ b/source/Lib/EncoderLib/EncLib.h @@ -53,6 +53,9 @@ #include "InterSearch.h" #include "IntraSearch.h" #include "EncSampleAdaptiveOffset.h" +#if JVET_M0427_INLOOP_RESHAPER +#include "EncReshape.h" +#endif #include "EncAdaptiveLoopFilter.h" #include "RateCtrl.h" @@ -98,6 +101,10 @@ private: CABACEncoder m_CABACEncoder; #endif +#if JVET_M0427_INLOOP_RESHAPER + EncReshape m_cReshaper; ///< reshaper class +#endif + // processing unit EncGOP m_cGOPEncoder; ///< GOP encoder EncSlice m_cSliceEncoder; ///< slice encoder @@ -219,6 +226,9 @@ public: int getNumCuEncStacks() const { return m_numCuEncStacks; } #endif +#if JVET_M0427_INLOOP_RESHAPER + EncReshape* getReshaper() { return &m_cReshaper; } +#endif // ------------------------------------------------------------------------------------------------------------------- // encoder function // ------------------------------------------------------------------------------------------------------------------- diff --git a/source/Lib/EncoderLib/EncReshape.cpp b/source/Lib/EncoderLib/EncReshape.cpp new file mode 100644 index 000000000..709060962 --- /dev/null +++ b/source/Lib/EncoderLib/EncReshape.cpp @@ -0,0 +1,1260 @@ +/* The copyright in this software is being made available under the BSD +* License, included below. This software may be subject to other third party +* and contributor rights, including patent rights, and no such rights are +* granted under this license. +* +* Copyright (c) 2010-2019, ITU/ISO/IEC +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may +* be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file EncReshape.cpp +\brief encoder reshaper class +*/ +#include "EncReshape.h" +#include <stdio.h> +#include <string.h> +#include <math.h> +#if JVET_M0427_INLOOP_RESHAPER +//! \ingroup EncLib +//! \{ + +// ==================================================================================================================== +// Constructor / destructor / create / destroy +// ==================================================================================================================== + +EncReshape::EncReshape() +{ + m_bCTUFlag = false; + m_bSrcReshaped = false; + m_bRecReshaped = false; + m_bReshape = true; + m_bExceedSTD = false; + m_uiCWOrgAnalyze = MAX_LUMA_RESHAPING_LUT_SIZE / PIC_ANALYZE_CW_BINS; + m_uiCWOrg = MAX_LUMA_RESHAPING_LUT_SIZE / PIC_CODE_CW_BINS; + m_tcase = 0; + m_rateAdpMode = 0; + m_chromaAdj = 0; +} + +EncReshape::~EncReshape() +{ +} + +void EncReshape::create_enc(int picWidth, int picHeight, uint32_t maxCUWidth, uint32_t maxCUHeight) +{ + if (forwardReshapingLUT.empty()) + forwardReshapingLUT.resize(MAX_LUMA_RESHAPING_LUT_SIZE, 0); + if (inverseReshapingLUT.empty()) + inverseReshapingLUT.resize(MAX_LUMA_RESHAPING_LUT_SIZE,0); + if (m_uiBinCWAll.empty()) + m_uiBinCWAll.resize(PIC_ANALYZE_CW_BINS); + if (m_uiBinImportance.empty()) + m_uiBinImportance.resize(PIC_ANALYZE_CW_BINS); + if (m_ReshapePivot.empty()) + m_ReshapePivot.resize(PIC_CODE_CW_BINS + 1, 0); + if (ChromaAdjHelpLUT.empty()) + ChromaAdjHelpLUT.resize(PIC_CODE_CW_BINS, 2048); + + m_sliceReshapeInfo.setUseSliceReshaper(true); + m_sliceReshapeInfo.setSliceReshapeChromaAdj(true); + m_sliceReshapeInfo.setSliceReshapeModelPresentFlag(true); + m_sliceReshapeInfo.reshape_model_min_bin_idx = 0; + m_sliceReshapeInfo.reshape_model_max_bin_idx = PIC_CODE_CW_BINS - 1; + memset(m_sliceReshapeInfo.reshape_model_bin_CW_delta, 0, (PIC_CODE_CW_BINS) * sizeof(int)); + + m_picWidth = picWidth; + m_picHeight = picHeight; + m_maxCUWidth = maxCUWidth; + m_maxCUHeight = maxCUHeight; + m_widthInCtus = (m_picWidth + m_maxCUWidth - 1) / m_maxCUWidth; + m_heightInCtus = (m_picHeight + m_maxCUHeight - 1) / m_maxCUHeight; + m_numCtuInFrame = m_widthInCtus * m_heightInCtus; +} + +void EncReshape::destroy() +{ +} + +/** +-Perform HDR set up +\param pcPic describe pointer of current coding picture +\param sliceType describe the slice type +*/ +void EncReshape::preAnalyzerHDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT, bool isCPR) +{ + m_sliceReshapeInfo.slice_reshaper_enable_flag = true; + if (reshapeCW.RspIntraPeriod == 1) + { + if (pcPic->getPOC() == 0) { m_sliceReshapeInfo.slice_reshaper_model_present_flag = true; } + else { m_sliceReshapeInfo.slice_reshaper_model_present_flag = false; } + } + else + { + if (sliceType == I_SLICE || (sliceType==P_SLICE && isCPR) ) { m_sliceReshapeInfo.slice_reshaper_model_present_flag = true; } + else { m_sliceReshapeInfo.slice_reshaper_model_present_flag = false; } + } + if ((sliceType == I_SLICE || (sliceType == P_SLICE && isCPR)) && isDualT) { m_sliceReshapeInfo.uiReshapeChromaAdj = 0; } + else { m_sliceReshapeInfo.uiReshapeChromaAdj = 1; } +} + +/** +-Perform picture analysis for SDR +\param pcPic describe pointer of current coding picture +\param sliceType describe the slice type +\param reshapeCW describe some input info +*/ +void EncReshape::preAnalyzerSDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT, bool isCPR) +{ + m_sliceReshapeInfo.slice_reshaper_model_present_flag = true; + m_sliceReshapeInfo.slice_reshaper_enable_flag = true; + + int modIP = pcPic->getPOC() - pcPic->getPOC() / reshapeCW.RspFpsToIp * reshapeCW.RspFpsToIp; + + if (sliceType == I_SLICE || (reshapeCW.RspIntraPeriod == -1 && modIP == 0) || (sliceType== P_SLICE && isCPR)) + { + if (m_sliceReshapeInfo.slice_reshaper_model_present_flag == true) + { + uint32_t uiStdMin = 16 * 4; + uint32_t uiStdMax = 235 * 4; + int bin_len = MAX_LUMA_RESHAPING_LUT_SIZE / PIC_ANALYZE_CW_BINS; + uint32_t min_start_bin_idx, max_end_bin_idx; + + m_reshapeCW = reshapeCW; + + for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) + { + m_uiBinImportance[b] = 0; + m_uiBinCWAll[b] = bin_len; + } + + min_start_bin_idx = int(floor((double(uiStdMin) / double(bin_len)))); + max_end_bin_idx = int(floor((double(uiStdMax) / double(bin_len)))); + + m_sliceReshapeInfo.reshape_model_min_bin_idx = min_start_bin_idx; + m_sliceReshapeInfo.reshape_model_max_bin_idx = max_end_bin_idx; + + PelBuf picY = pcPic->getOrigBuf(COMPONENT_Y); + const int iWidth = picY.width; + const int iHeight = picY.height; + const int iStride = picY.stride; + + double dBlockBinVarSum[PIC_ANALYZE_CW_BINS] = { 0.0 }; + uint32_t dBlockBinCnt[PIC_ANALYZE_CW_BINS] = { 0 }; + + const uint32_t uiWinSize = PIC_ANALYZE_WIN_SIZE; + const uint32_t uiWinLens = (uiWinSize - 1) >> 1; + + int64_t tempSq = 0; + int64_t leftSum = 0, leftSumSq = 0; + int64_t *leftColSum = new int64_t[iWidth]; + int64_t *leftColSumSq = new int64_t[iWidth]; + memset(leftColSum, 0, iWidth * sizeof(int64_t)); + memset(leftColSumSq, 0, iWidth * sizeof(int64_t)); + int64_t topSum = 0, topSumSq = 0; + int64_t *topRowSum = new int64_t[iHeight]; + int64_t *topRowSumSq = new int64_t[iHeight]; + memset(topRowSum, 0, iHeight * sizeof(int64_t)); + memset(topRowSumSq, 0, iHeight * sizeof(int64_t)); + int64_t *topColSum = new int64_t[iWidth]; + int64_t *topColSumSq = new int64_t[iWidth]; + memset(topColSum, 0, iWidth * sizeof(int64_t)); + memset(topColSumSq, 0, iWidth * sizeof(int64_t)); + + for (uint32_t y = 0; y < iHeight; y++) + { + for (uint32_t x = 0; x < iWidth; x++) + { + const Pel pPxlY = picY.buf[x]; + int64_t uiSum = 0; + int64_t uiSumSq = 0; + uint32_t uiNumPixInPart = 0; + + uint32_t y1 = std::max((int)(y - uiWinLens), 0); + uint32_t y2 = std::min((int)(y + uiWinLens), (iHeight - 1)); + uint32_t x1 = std::max((int)(x - uiWinLens), 0); + uint32_t x2 = std::min((int)(x + uiWinLens), (iWidth - 1)); + + + uint32_t bx = 0, by = 0; + const Pel *pWinY = &picY.buf[0]; + uiNumPixInPart = (x2 - x1 + 1) * (y2 - y1 + 1); + + if (x == 0 && y == 0) // for the 1st Pixel, calc all points + { + for (by = y1; by <= y2; by++) + { + for (bx = x1; bx <= x2; bx++) + { + tempSq = pWinY[bx] * pWinY[bx]; + leftSum += pWinY[bx]; + leftSumSq += tempSq; + leftColSum[bx] += pWinY[bx]; + leftColSumSq[bx] += tempSq; + topColSum[bx] += pWinY[bx]; + topColSumSq[bx] += tempSq; + topRowSum[by] += pWinY[bx]; + topRowSumSq[by] += tempSq; + } + pWinY += iStride; + } + topSum = leftSum; + topSumSq = leftSumSq; + uiSum = leftSum; + uiSumSq = leftSumSq; + } + else if (x == 0 && y > 0) // for the 1st column, calc the bottom stripe + { + if (y < iHeight - uiWinLens) + { + pWinY += uiWinLens*iStride; + topRowSum[y + uiWinLens] = 0; + topRowSumSq[y + uiWinLens] = 0; + for (bx = x1; bx <= x2; bx++) + { + topRowSum[y + uiWinLens] += pWinY[bx]; + topRowSumSq[y + uiWinLens] += pWinY[bx] * pWinY[bx]; + } + topSum += topRowSum[y + uiWinLens]; + topSumSq += topRowSumSq[y + uiWinLens]; + } + if (y > uiWinLens) + { + topSum -= topRowSum[y - 1 - uiWinLens]; + topSumSq -= topRowSumSq[y - 1 - uiWinLens]; + } + + memset(leftColSum, 0, iWidth * sizeof(int64_t)); + memset(leftColSumSq, 0, iWidth * sizeof(int64_t)); + pWinY = &picY.buf[0]; + pWinY -= (y <= uiWinLens ? y : uiWinLens)*iStride; + for (by = y1; by <= y2; by++) + { + for (bx = x1; bx <= x2; bx++) + { + leftColSum[bx] += pWinY[bx]; + leftColSumSq[bx] += pWinY[bx] * pWinY[bx]; + } + pWinY += iStride; + } + + leftSum = topSum; + leftSumSq = topSumSq; + uiSum = topSum; + uiSumSq = topSumSq; + } + + else if (x > 0) + { + if (x < iWidth - uiWinLens) + { + pWinY -= (y <= uiWinLens ? y : uiWinLens)*iStride; + if (y == 0) // for the 1st row, calc the right stripe + { + leftColSum[x + uiWinLens] = 0; + leftColSumSq[x + uiWinLens] = 0; + for (by = y1; by <= y2; by++) + { + leftColSum[x + uiWinLens] += pWinY[x + uiWinLens]; + leftColSumSq[x + uiWinLens] += pWinY[x + uiWinLens] * pWinY[x + uiWinLens]; + pWinY += iStride; + } + } + else // for the main area, calc the B-R point + { + leftColSum[x + uiWinLens] = topColSum[x + uiWinLens]; + leftColSumSq[x + uiWinLens] = topColSumSq[x + uiWinLens]; + if (y < iHeight - uiWinLens) + { + pWinY = &picY.buf[0]; + pWinY += uiWinLens * iStride; + leftColSum[x + uiWinLens] += pWinY[x + uiWinLens]; + leftColSumSq[x + uiWinLens] += pWinY[x + uiWinLens] * pWinY[x + uiWinLens]; + } + if (y > uiWinLens) + { + pWinY = &picY.buf[0]; + pWinY -= (uiWinLens + 1) * iStride; + leftColSum[x + uiWinLens] -= pWinY[x + uiWinLens]; + leftColSumSq[x + uiWinLens] -= pWinY[x + uiWinLens] * pWinY[x + uiWinLens]; + } + } + topColSum[x + uiWinLens] = leftColSum[x + uiWinLens]; + topColSumSq[x + uiWinLens] = leftColSumSq[x + uiWinLens]; + leftSum += leftColSum[x + uiWinLens]; + leftSumSq += leftColSumSq[x + uiWinLens]; + } + if (x > uiWinLens) + { + leftSum -= leftColSum[x - 1 - uiWinLens]; + leftSumSq -= leftColSumSq[x - 1 - uiWinLens]; + } + uiSum = leftSum; + uiSumSq = leftSumSq; + } + + double dAverage = double(uiSum) / uiNumPixInPart; + double dVariance = double(uiSumSq) / uiNumPixInPart - dAverage * dAverage; + double dVarLog10 = log10(dVariance + 1.0); + + uint32_t uiBinNum = (uint32_t)floor((double)pPxlY / (double)PIC_ANALYZE_CW_BINS); + dBlockBinVarSum[uiBinNum] += dVarLog10; + dBlockBinCnt[uiBinNum]++; + } + picY.buf += iStride; + } + + delete[] topColSum; + delete[] topColSumSq; + delete[] topRowSum; + delete[] topRowSumSq; + delete[] leftColSum; + delete[] leftColSumSq; + + for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) + { + if (dBlockBinCnt[b] > 0) + dBlockBinVarSum[b] = dBlockBinVarSum[b] / dBlockBinCnt[b]; + } + + m_bReshape = true; + m_bExceedSTD = false; + m_bUseAdpCW = false; + m_chromaWeight = 1.0; + m_sliceReshapeInfo.uiReshapeChromaAdj = 1; + bool bIntraAdp = false; + bool bInterAdp = true; + double dReshapeTH1 = 0.0; + double dReshapeTH2 = 5.0; + deriveReshapeParametersSDRfromStats(dBlockBinCnt, dBlockBinVarSum, &dReshapeTH1, &dReshapeTH2, &bIntraAdp, &bInterAdp); + + if (m_rateAdpMode == 2 && reshapeCW.RspBaseQP <= 22) + { + bIntraAdp = false; + bInterAdp = false; + } + + m_sliceReshapeInfo.slice_reshaper_enable_flag = bIntraAdp; + + if (!bIntraAdp && !bInterAdp) + { + m_sliceReshapeInfo.slice_reshaper_model_present_flag = false; + m_bReshape = false; + return; + } + + if (m_bExceedSTD) + { + min_start_bin_idx = 2; + max_end_bin_idx = 29; + for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) + { + if (dBlockBinCnt[b] > 0 && b < min_start_bin_idx) + min_start_bin_idx = b; + if (dBlockBinCnt[b] > 0 && b > max_end_bin_idx) + max_end_bin_idx = b; + } + m_sliceReshapeInfo.reshape_model_min_bin_idx = min_start_bin_idx; + m_sliceReshapeInfo.reshape_model_max_bin_idx = max_end_bin_idx; + } + + if (reshapeCW.RspBaseQP <= 22 && m_rateAdpMode == 1) + { + for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++) + { + if (i >= min_start_bin_idx && i <= max_end_bin_idx) + m_uiBinCWAll[i] = m_uiCWOrgAnalyze + 1; + else + m_uiBinCWAll[i] = 0; + } + } + else if (m_bUseAdpCW) + { + double Alpha = 1.0, Beta = 0.0; + deriveReshapeParameters(dBlockBinVarSum, min_start_bin_idx, max_end_bin_idx, m_reshapeCW, Alpha, Beta); + for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++) + { + if (i >= min_start_bin_idx && i <= max_end_bin_idx) + m_uiBinCWAll[i] = (uint32_t)round(Alpha*dBlockBinVarSum[i] + Beta); + else + m_uiBinCWAll[i] = 0; + } + } + else + { + for (int b = min_start_bin_idx; b <= max_end_bin_idx; b++) + { + if (dBlockBinVarSum[b] < dReshapeTH1) + m_uiBinImportance[b] = 2; + else if (dBlockBinVarSum[b] > dReshapeTH2) + m_uiBinImportance[b] = 3; + else + m_uiBinImportance[b] = 1; + } + + for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++) + { + if (m_uiBinImportance[i] == 0) + m_uiBinCWAll[i] = 0; + else if (m_uiBinImportance[i] == 1) + m_uiBinCWAll[i] = m_uiCWOrgAnalyze + 1; + else if (m_uiBinImportance[i] == 2) + m_uiBinCWAll[i] = m_reshapeCW.BinCW[0]; + else if (m_uiBinImportance[i] == 3) + m_uiBinCWAll[i] = m_reshapeCW.BinCW[1]; + else + THROW("SDR Reshape Bin Importance not supported"); + } + } + if (m_reshapeCW.RspPicSize <= 1497600 && reshapeCW.RspIntraPeriod == -1 && modIP == 0 && sliceType != I_SLICE) + { + m_sliceReshapeInfo.slice_reshaper_enable_flag = false; + } + + } + m_chromaAdj = m_sliceReshapeInfo.uiReshapeChromaAdj; + if ((sliceType == I_SLICE || (sliceType == P_SLICE && isCPR)) && isDualT) + { + m_sliceReshapeInfo.uiReshapeChromaAdj = 0; + } + } + else // Inter slices + { + m_sliceReshapeInfo.slice_reshaper_model_present_flag = false; + m_sliceReshapeInfo.uiReshapeChromaAdj = m_chromaAdj; + + if (!m_bReshape) + { + m_sliceReshapeInfo.slice_reshaper_enable_flag = false; + } + else + { + const int cTid = m_reshapeCW.Tid; + bool enableRsp = m_tcase == 5 ? false : (m_tcase < 5 ? (cTid < m_tcase + 1 ? false : true) : (cTid <= 10 - m_tcase ? true : false)); + m_sliceReshapeInfo.slice_reshaper_enable_flag = enableRsp; + } + } +} + +// Bubble Sort to descending order with index +void EncReshape::bubbleSortDsd(double* array, int * idx, int n) +{ + int i, j; + bool swapped; + for (i = 0; i < n - 1; i++) + { + swapped = false; + for (j = 0; j < n - i - 1; j++) + { + if (array[j] < array[j + 1]) + { + swap(&array[j], &array[j + 1]); + swap(&idx[j], &idx[j + 1]); + swapped = true; + } + } + if (swapped == false) + break; + } +} + +void EncReshape::deriveReshapeParametersSDRfromStats(uint32_t * dBlockBinCnt, double *dBlockBinVarSum, double* dReshapeTH1, double* dReshapeTH2, bool *bIntraAdp, bool *bInterAdp) +{ + int BinIdxSortDsd[PIC_ANALYZE_CW_BINS] = { 0 }; + double BinVarSortDsd[PIC_ANALYZE_CW_BINS] = { 0.0 }; + double BinHist[PIC_ANALYZE_CW_BINS] = { 0.0 }; + double BinVarSortDsdCDF[PIC_ANALYZE_CW_BINS] = { 0.0 }; + + double maxBinVar = 0.0, meanBinVar = 0.0, minBinVar = 5.0; + int nonZeroBinCt = 0; + for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) + { + BinHist[b] = (double)dBlockBinCnt[b] / (double)(m_reshapeCW.RspPicSize); + if (BinHist[b] > 0.001) + { + nonZeroBinCt++; + meanBinVar += dBlockBinVarSum[b]; + if (dBlockBinVarSum[b] > maxBinVar) { maxBinVar = dBlockBinVarSum[b]; } + if (dBlockBinVarSum[b] < minBinVar) { minBinVar = dBlockBinVarSum[b]; } + } + BinVarSortDsd[b] = dBlockBinVarSum[b]; + BinIdxSortDsd[b] = b; + } + if ((BinHist[0] + BinHist[1] + BinHist[PIC_ANALYZE_CW_BINS - 2] + BinHist[PIC_ANALYZE_CW_BINS - 1]) > 0.01) { m_bExceedSTD = true; } + if ((BinHist[PIC_ANALYZE_CW_BINS - 2] + BinHist[PIC_ANALYZE_CW_BINS - 1]) > 0.01) { *bInterAdp = false; return; } + else { *bInterAdp = true; } + + meanBinVar = meanBinVar / (double)nonZeroBinCt; + bubbleSortDsd(BinVarSortDsd, BinIdxSortDsd, PIC_ANALYZE_CW_BINS); + BinVarSortDsdCDF[0] = BinHist[BinIdxSortDsd[0]]; + for (int b = 1; b < PIC_ANALYZE_CW_BINS; b++) + { + BinVarSortDsdCDF[b] = BinVarSortDsdCDF[b - 1] + BinHist[BinIdxSortDsd[b]]; + } + + int firstBinVarLessThanVal1 = 0; // Val1 = 3.5 + int firstBinVarLessThanVal2 = 0; // Val2 = 3.0 + int firstBinVarLessThanVal3 = 0; // Val3 = 2.5 + int firstBinVarLessThanVal4 = 0; // Val4 = 2.0 + for (int b = 0; b < PIC_ANALYZE_CW_BINS - 1; b++) + { + if (BinVarSortDsd[b] > 3.5) { firstBinVarLessThanVal1 = b + 1; } + if (BinVarSortDsd[b] > 3.0) { firstBinVarLessThanVal2 = b + 1; } + if (BinVarSortDsd[b] > 2.5) { firstBinVarLessThanVal3 = b + 1; } + if (BinVarSortDsd[b] > 2.0) { firstBinVarLessThanVal4 = b + 1; } + } + + m_reshapeCW.BinCW[0] = 38; + m_reshapeCW.BinCW[1] = 28; + + if (m_reshapeCW.RspIntraPeriod == -1) + { + *bIntraAdp = true; + if (m_reshapeCW.RspPicSize > 1497600) + { + m_reshapeCW.BinCW[0] = 36; + *dReshapeTH1 = 2.4; + *dReshapeTH2 = 4.5; + m_rateAdpMode = 2; + + if (meanBinVar >= 2.52) + { + if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5) + { + *dReshapeTH1 = 2.5; + *dReshapeTH2 = 3.0; + } + else if (BinVarSortDsdCDF[firstBinVarLessThanVal2] < 0.1 && BinVarSortDsdCDF[firstBinVarLessThanVal1] > 0.02) + { + *dReshapeTH1 = 2.2; + } + else if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.25) + { + m_reshapeCW.BinCW[1] = 30; + *dReshapeTH1 = 2.0; + m_rateAdpMode = 0; + } + else + { + m_reshapeCW.BinCW[1] = 30; + m_rateAdpMode = 1; + } + } + } + else if (m_reshapeCW.RspPicSize > 660480) + { + m_reshapeCW.BinCW[0] = 34; + *dReshapeTH1 = 3.4; + *dReshapeTH2 = 4.0; + m_rateAdpMode = 2; + + if (BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.6) + { + if (maxBinVar < 3.5) + { + m_bUseAdpCW = true; + m_reshapeCW.BinCW[0] = 38; + } + else + { + m_reshapeCW.BinCW[0] = 40; + *dReshapeTH1 = 2.2; + *dReshapeTH2 = 4.5; + m_rateAdpMode = 0; + } + } + else + { + if (maxBinVar > 3.3) + { + m_reshapeCW.BinCW[1] = 30; + } + else + { + m_reshapeCW.BinCW[1] = 28; + } + } + } + else if (m_reshapeCW.RspPicSize > 249600) + { + m_reshapeCW.BinCW[0] = 36; + *dReshapeTH1 = 2.5; + *dReshapeTH2 = 4.5; + + if (m_bExceedSTD) + { + m_reshapeCW.BinCW[0] = 36; + m_reshapeCW.BinCW[1] = 30; + } + if (minBinVar > 2.6) + { + *dReshapeTH1 = 3.0; + } + else { + double diff1 = BinVarSortDsdCDF[firstBinVarLessThanVal4] - BinVarSortDsdCDF[firstBinVarLessThanVal3]; + double diff2 = BinVarSortDsdCDF[firstBinVarLessThanVal2] - BinVarSortDsdCDF[firstBinVarLessThanVal1]; + if (diff1 > 0.4 || BinVarSortDsdCDF[firstBinVarLessThanVal1] > 0.1) + { + m_bUseAdpCW = true; + m_rateAdpMode = 1; + } + else if (diff2 <= 0.1 && BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.99 && BinVarSortDsdCDF[firstBinVarLessThanVal3] > 0.642 && BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.03) + { + m_bUseAdpCW = true; + m_rateAdpMode = 1; + } + else + { + m_rateAdpMode = 2; + } + } + } + else + { + m_reshapeCW.BinCW[0] = 36; + *dReshapeTH1 = 2.6; + *dReshapeTH2 = 4.5; + + if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5 && maxBinVar < 4.7) + { + *dReshapeTH1 = 3.2; + m_rateAdpMode = 1; + } + } + } + else if (m_reshapeCW.RspIntraPeriod == 1) + { + *bIntraAdp = true; + if (m_reshapeCW.RspPicSize > 5184000) + { + *dReshapeTH1 = 2.0; + *dReshapeTH2 = 3.0; + m_rateAdpMode = 2; + + if (maxBinVar > 2.4) + { + if (BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.88) + { + if (maxBinVar < 2.695) + { + *dReshapeTH2 = 2.2; + } + else + { + if (BinVarSortDsdCDF[firstBinVarLessThanVal3] < 0.45) + { + *dReshapeTH1 = 2.5; + *dReshapeTH2 = 4.0; + m_reshapeCW.BinCW[0] = 36; + m_sliceReshapeInfo.uiReshapeChromaAdj = 0; + m_rateAdpMode = 0; + } + else + { + m_bUseAdpCW = true; + m_reshapeCW.BinCW[0] = 36; + m_reshapeCW.BinCW[1] = 30; + } + } + } + else + { + if (maxBinVar > 2.8) + { + *dReshapeTH1 = 2.2; + *dReshapeTH2 = 4.0; + m_reshapeCW.BinCW[0] = 36; + m_sliceReshapeInfo.uiReshapeChromaAdj = 0; + } + else + { + m_bUseAdpCW = true; + m_reshapeCW.BinCW[0] = 38; + m_reshapeCW.BinCW[1] = 28; + } + } + } + else + { + if (maxBinVar > 2.24) + { + m_bUseAdpCW = true; + m_reshapeCW.BinCW[0] = 34; + m_reshapeCW.BinCW[1] = 30; + } + } + } + else if (m_reshapeCW.RspPicSize > 1497600) + { + *dReshapeTH1 = 2.0; + *dReshapeTH2 = 4.5; + m_rateAdpMode = 2; + + if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.25) + { + int firstVarCDFLargerThanVal = 1; + for (int b = 0; b < PIC_ANALYZE_CW_BINS; b++) + { + if (BinVarSortDsdCDF[b] > 0.7) + { + firstVarCDFLargerThanVal = b; + break; + } + } + if (meanBinVar < 2.52 || BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5) + { + *dReshapeTH1 = 2.2; + *dReshapeTH2 = (BinVarSortDsd[firstVarCDFLargerThanVal] + BinVarSortDsd[firstVarCDFLargerThanVal - 1]) / 2.0; + } + else + { + m_reshapeCW.BinCW[1] = 30; + *dReshapeTH2 = 2.8; + } + } + else if (BinVarSortDsdCDF[firstBinVarLessThanVal2] < 0.1 && BinVarSortDsdCDF[firstBinVarLessThanVal1] > 0.02) + { + m_reshapeCW.BinCW[0] = 36; + *dReshapeTH1 = 3.5; + m_rateAdpMode = 1; + } + } + else if (m_reshapeCW.RspPicSize > 660480) + { + *dReshapeTH1 = 2.5; + *dReshapeTH2 = 4.5; + m_rateAdpMode = 1; + + if (BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.6) + { + if (maxBinVar < 3.5) + { + *dReshapeTH1 = 2.0; + } + } + else + { + if (maxBinVar > 3.3) + { + m_reshapeCW.BinCW[0] = 35; + } + else + { + *dReshapeTH1 = 2.8; + m_reshapeCW.BinCW[0] = 35; + } + } + } + else if (m_reshapeCW.RspPicSize > 249600) + { + m_rateAdpMode = 1; + m_reshapeCW.BinCW[0] = 36; + *dReshapeTH1 = 2.5; + *dReshapeTH2 = 4.5; + } + else + { + if (BinVarSortDsdCDF[firstBinVarLessThanVal2] < 0.33 && m_reshapeCW.RspFps>40) + { + *bIntraAdp = false; + *bInterAdp = false; + } + else + { + m_rateAdpMode = 1; + m_reshapeCW.BinCW[0] = 36; + *dReshapeTH1 = 3.0; + *dReshapeTH2 = 4.0; + } + } + } + else + { + if (m_reshapeCW.RspPicSize > 5184000) + { + m_reshapeCW.BinCW[0] = 40; + *dReshapeTH2 = 4.0; + m_rateAdpMode = 2; + + if (maxBinVar < 2.4) + { + *dReshapeTH1 = 3.0; + if (m_reshapeCW.RspBaseQP <= 22) + m_tcase = 3; + } + else if (maxBinVar > 3.0) + { + if (minBinVar > 1) + { + m_reshapeCW.BinCW[0] = 36; + *dReshapeTH1 = 2.8; + *dReshapeTH2 = 3.5; + m_sliceReshapeInfo.uiReshapeChromaAdj = 0; + m_chromaWeight = 1.05; + m_rateAdpMode = 0; + } + else + { + m_reshapeCW.BinCW[0] = 36; + *dReshapeTH1 = 2.2; + *dReshapeTH2 = 3.5; + m_sliceReshapeInfo.uiReshapeChromaAdj = 0; + m_chromaWeight = 0.95; + if (m_reshapeCW.RspBaseQP <= 27 && m_reshapeCW.RspBaseQP >=25) + m_tcase = 3; + } + } + else + { + *dReshapeTH1 = 1.5; + } + } + else if (m_reshapeCW.RspPicSize > 1497600) + { + *dReshapeTH1 = 2.5; + *dReshapeTH2 = 4.5; + m_rateAdpMode = 1; + + if (meanBinVar < 2.52) + { + *bIntraAdp = true; + m_rateAdpMode = 0; + m_tcase = 9; + } + else + { + if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5) + { + *dReshapeTH2 = 3.0; + *bIntraAdp = true; + } + else if (BinVarSortDsdCDF[firstBinVarLessThanVal2] < 0.1 && BinVarSortDsdCDF[firstBinVarLessThanVal1] > 0.02) + { + *dReshapeTH1 = 3.0; + *bIntraAdp = true; + m_rateAdpMode = 0; + m_tcase = 9; + } + else if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.25) + { + *dReshapeTH1 = 2.4; + m_reshapeCW.BinCW[0] = 36; + } + else + { + *dReshapeTH1 = 2.4; + m_reshapeCW.BinCW[0] = 36; + } + } + } + else if (m_reshapeCW.RspPicSize > 660480) + { + *bIntraAdp = true; + m_rateAdpMode = 1; + + if (BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.6) + { + if (maxBinVar < 3.5) + { + *dReshapeTH1 = 2.1; + *dReshapeTH2 = 3.5; + } + else + { + *dReshapeTH1 = 2.4; + *dReshapeTH2 = 4.5; + m_reshapeCW.BinCW[0] = 40; + m_rateAdpMode = 0; + } + } + else + { + if (maxBinVar > 3.3) + { + *dReshapeTH1 = 3.5; + *dReshapeTH2 = 3.8; + } + else + { + *dReshapeTH1 = 3.0; + *dReshapeTH2 = 4.0; + m_reshapeCW.BinCW[1] = 30; + } + } + } + else if (m_reshapeCW.RspPicSize > 249600) + { + m_reshapeCW.BinCW[1] = 30; + *dReshapeTH1 = 2.5; + *dReshapeTH2 = 4.5; + *bIntraAdp = true; + m_rateAdpMode = 1; + + if (minBinVar > 2.6) + { + *dReshapeTH1 = 3.2; + m_rateAdpMode = 0; + m_tcase = 9; + } + else { + double diff1 = BinVarSortDsdCDF[firstBinVarLessThanVal4] - BinVarSortDsdCDF[firstBinVarLessThanVal3]; + double diff2 = BinVarSortDsdCDF[firstBinVarLessThanVal2] - BinVarSortDsdCDF[firstBinVarLessThanVal1]; + if (diff1 > 0.4 || BinVarSortDsdCDF[firstBinVarLessThanVal1] > 0.1) + { + *dReshapeTH1 = 2.9; + *bIntraAdp = false; + } + else + { + if (diff2 > 0.1) + { + *dReshapeTH1 = 2.5; + } + else + { + *dReshapeTH1 = 2.9; + if (BinVarSortDsdCDF[firstBinVarLessThanVal4] > 0.99 && BinVarSortDsdCDF[firstBinVarLessThanVal3] > 0.642 && BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.03) + { + m_rateAdpMode = 0; + m_tcase = 9; + } + } + } + } + } + else + { + m_reshapeCW.BinCW[0] = 36; + m_reshapeCW.BinCW[1] = 30; + *dReshapeTH1 = 2.6; + *dReshapeTH2 = 4.5; + *bIntraAdp = true; + m_rateAdpMode = 1; + if (BinVarSortDsdCDF[firstBinVarLessThanVal2] > 0.5 && maxBinVar < 4.7) + { + *dReshapeTH1 = 3.4; + } + } + } +} + +void EncReshape::deriveReshapeParameters(double *array, int start, int end, ReshapeCW respCW, double &alpha, double &beta) +{ + double minVar = 10.0, maxVar = 0.0; + for (int b = start; b <= end; b++) + { + if (array[b] < minVar) minVar = array[b]; + if (array[b] > maxVar) maxVar = array[b]; + } + double maxCW = (double)respCW.BinCW[0]; + double minCW = (double)respCW.BinCW[1]; + alpha = (minCW - maxCW) / (maxVar - minVar); + beta = (maxCW*maxVar - minCW*minVar) / (maxVar - minVar); +} + +/** +-Init reshaping LUT from dQP model +*/ +void EncReshape::initLUTfromdQPModel() +{ + initModelParam(); + int pwlFwdLUTsize = PIC_CODE_CW_BINS; + int pwlFwdBinLen = MAX_LUMA_RESHAPING_LUT_SIZE / PIC_CODE_CW_BINS; + int p1 = m_DftModel.ScaleFracPrec; //=16, precision of 0.015 + int p2 = m_DftModel.OffsetFracPrec; //=1, precision of 7.5 + int total_shift = p1 + p2; + int scaleFP = (1 - 2 * m_DftModel.ScaleSign) * m_DftModel.ScaleAbs; + int offsetFP = (1 - 2 * m_DftModel.OffsetSign) * m_DftModel.OffsetAbs; + int maxQP = (1 - 2 * m_DftModel.MaxQPSign) * m_DftModel.MaxQPAbs; + int minQP = (1 - 2 * m_DftModel.MinQPSign) * m_DftModel.MinQPAbs; + int maxFP = maxQP * (1 << total_shift); + int minFP = minQP * (1 << total_shift); + int temp, signval, absval; + int dQPDIV6_FP; + int32_t * SlopeLUT = new int32_t[MAX_LUMA_RESHAPING_LUT_SIZE](); + int32_t * fLUT_HP = new int32_t[MAX_LUMA_RESHAPING_LUT_SIZE](); + + for (int i = 0; i < LUMA_LEVEL_TO_DQP_LUT_MAXSIZE; i++) + { + temp = int64_t((scaleFP*i) * (1 << p2)) + int64_t(offsetFP * (1 << p1)); + temp = temp > maxFP ? maxFP : temp < minFP ? minFP : temp; + signval = temp >= 0 ? 1 : -1; + absval = signval * temp; + dQPDIV6_FP = signval * (((absval + 3) / 6 + (1 << (total_shift - 17))) >> (total_shift - 16)); + SlopeLUT[i] = calcEXP2(dQPDIV6_FP); + } + + if (m_DftModel.FullRangeInputFlag == 0) + { + for (int i = 0; i < 64; i++) { SlopeLUT[i] = 0; } + for (int i = 940; i < MAX_LUMA_RESHAPING_LUT_SIZE; i++) { SlopeLUT[i] = 0; } + } + + for (int i = 0; i < MAX_LUMA_RESHAPING_LUT_SIZE - 1; i++) + fLUT_HP[i + 1] = fLUT_HP[i] + SlopeLUT[i]; + if (SlopeLUT != nullptr) { delete[] SlopeLUT; SlopeLUT = nullptr; } + + int max_Y = (fLUT_HP[MAX_LUMA_RESHAPING_LUT_SIZE - 1] + (1 << 7)) >> 8; + int Roffset = max_Y >> 1; + for (int i = 0; i < MAX_LUMA_RESHAPING_LUT_SIZE; i++) + { + forwardReshapingLUT[i] = (short)(((fLUT_HP[i] >> 8) * (MAX_LUMA_RESHAPING_LUT_SIZE - 1) + Roffset) / max_Y); + } + + if (fLUT_HP != nullptr) { delete[] fLUT_HP; fLUT_HP = nullptr; } + m_sliceReshapeInfo.reshape_model_min_bin_idx = 1; + m_sliceReshapeInfo.reshape_model_max_bin_idx = 14; + + for (int i = 0; i < pwlFwdLUTsize; i++) + { + int16_t X1 = i * pwlFwdBinLen; + m_ReshapePivot[i] = forwardReshapingLUT[X1]; + } + m_ReshapePivot[pwlFwdLUTsize] = 1023; + + for (int i = 0; i < pwlFwdLUTsize; i++) + { + m_uiBinCWAll[i] = m_ReshapePivot[i + 1] - m_ReshapePivot[i]; + } + + int maxAbsDeltaCW = 0, AbsDeltaCW = 0, DeltaCW = 0; + for (int i = m_sliceReshapeInfo.reshape_model_min_bin_idx; i <= m_sliceReshapeInfo.reshape_model_max_bin_idx; i++) + { + DeltaCW = (int)m_uiBinCWAll[i] - (int)m_uiCWOrg; + m_sliceReshapeInfo.reshape_model_bin_CW_delta[i] = DeltaCW; + AbsDeltaCW = (DeltaCW < 0) ? (-DeltaCW) : DeltaCW; + if (AbsDeltaCW > maxAbsDeltaCW) { maxAbsDeltaCW = AbsDeltaCW; } + } + m_sliceReshapeInfo.maxNbitsNeededDeltaCW = g_aucLog2[maxAbsDeltaCW << 1]; + + for (int i = 0; i < pwlFwdLUTsize; i++) + { + int16_t Y1 = m_ReshapePivot[i]; + int16_t Y2 = m_ReshapePivot[i + 1]; + forwardReshapingLUT[i*pwlFwdBinLen] = Clip3((Pel)0, (Pel)1023, (Pel)Y1); + int log2_pwlFwdBinLen = log2_MAX_LUMA_RESHAPING_LUT_SIZE - log2_PIC_CODE_CW_BINS; + int32_t scale = ((int32_t)(Y2 - Y1) * (1 << FP_PREC) + (1 << (log2_pwlFwdBinLen - 1))) >> (log2_pwlFwdBinLen); + for (int j = 1; j < pwlFwdBinLen; j++) + { + int tempVal = Y1 + (((int32_t)scale * (int32_t)j + (1 << (FP_PREC - 1))) >> FP_PREC); + forwardReshapingLUT[i*pwlFwdBinLen + j] = Clip3((Pel)0, (Pel)1023, (Pel)tempVal); + } + } + ReverseLUT(forwardReshapingLUT, inverseReshapingLUT, MAX_LUMA_RESHAPING_LUT_SIZE); + updateChromaDQPLUT(); +} + + +/** +-Perform fixe point exp2 calculation +\param val input value +\retval output value = exp2(val) +*/ +int EncReshape::calcEXP2(int val) +{ + int32_t i, f, r, s; + r = 0x00000e20; + + i = ((int32_t)(val)+0x8000) & ~0xffff; + f = (int32_t)(val)-i; + s = ((15 << 16) - i) >> 16; + + r = (r * f + 0x3e1cc333) >> 17; + r = (r * f + 0x58bd46a6) >> 16; + r = r * f + 0x7ffde4a3; + return (uint32_t)r >> s; +} + +void EncReshape::constructReshaperSDR() +{ + int used_codewords; + int tot_cw = MAX_LUMA_RESHAPING_LUT_SIZE; + int hist_bins = PIC_ANALYZE_CW_BINS; + int log2_hist_lens = log2_MAX_LUMA_RESHAPING_LUT_SIZE - log2_PIC_ANALYZE_CW_BINS; + int hist_lens = m_uiCWOrgAnalyze; + int16_t *Y_LUT_all = new int16_t[MAX_LUMA_RESHAPING_LUT_SIZE + 1](); + int i, j; + int cw_scale_bins1, cw_scale_bins2; + int max_allow_cw = tot_cw; + + cw_scale_bins1 = m_reshapeCW.BinCW[0]; + cw_scale_bins2 = m_reshapeCW.BinCW[1]; + + used_codewords = 0; + for (i = 0; i < hist_bins; i++) + used_codewords += m_uiBinCWAll[i]; + + if (used_codewords > max_allow_cw) + { + int cnt0 = 0, cnt1 = 0, cnt2 = 0; + for (i = 0; i < hist_bins; i++) + { + if (m_uiBinCWAll[i] == hist_lens + 1) cnt0++; + else if (m_uiBinCWAll[i] == cw_scale_bins1) cnt1++; + else if (m_uiBinCWAll[i] == cw_scale_bins2) cnt2++; + } + + int delta_cw = used_codewords - max_allow_cw; + int cw_reduce1 = (cw_scale_bins1 - hist_lens - 1) * cnt1; + int cw_reduce2 = (hist_lens + 1 - cw_scale_bins2) * cnt0; + + if (delta_cw <= cw_reduce1) + { + int idx = 0; + while (delta_cw > 0) + { + if (m_uiBinCWAll[idx] > (hist_lens + 1)) + { + m_uiBinCWAll[idx]--; + delta_cw--; + } + idx++; + if (idx == hist_bins) + idx = 0; + } + } + else if (delta_cw > cw_reduce1 && delta_cw <= (cw_reduce1 + cw_reduce2)) + { + delta_cw -= cw_reduce1; + int idx = 0; + while (delta_cw > 0) + { + if (m_uiBinCWAll[idx] > cw_scale_bins2 && m_uiBinCWAll[idx] < cw_scale_bins1) + { + m_uiBinCWAll[idx]--; + delta_cw--; + } + idx++; + if (idx == hist_bins) + idx = 0; + } + for (i = 0; i < hist_bins; i++) + { + if (m_uiBinCWAll[i] == cw_scale_bins1) + m_uiBinCWAll[i] = hist_lens + 1; + } + } + else if (delta_cw > (cw_reduce1 + cw_reduce2)) + { + delta_cw -= (cw_reduce1 + cw_reduce2); + int idx = 0; + while (delta_cw > 0) + { + if (m_uiBinCWAll[idx] > 0 && m_uiBinCWAll[idx] < (hist_lens + 1)) + { + m_uiBinCWAll[idx]--; + delta_cw--; + } + idx++; + if (idx == hist_bins) + idx = 0; + } + for (i = 0; i < hist_bins; i++) + { + if (m_uiBinCWAll[i] == m_uiCWOrgAnalyze + 1) + m_uiBinCWAll[i] = cw_scale_bins2; + if (m_uiBinCWAll[i] == cw_scale_bins1) + m_uiBinCWAll[i] = m_uiCWOrgAnalyze + 1; + } + } + } + + for (int i = 0; i < PIC_CODE_CW_BINS; i++) + { + m_uiBinCWAll[i] = m_uiBinCWAll[2 * i] + m_uiBinCWAll[2 * i + 1]; + } + m_sliceReshapeInfo.reshape_model_min_bin_idx = 0; + m_sliceReshapeInfo.reshape_model_max_bin_idx = PIC_CODE_CW_BINS - 1; + for (int i = 0; i < PIC_CODE_CW_BINS; i++) + { + if (m_uiBinCWAll[i] > 0) + { + m_sliceReshapeInfo.reshape_model_min_bin_idx = i; + break; + } + } + for (int i = PIC_CODE_CW_BINS - 1; i >= 0; i--) + { + if (m_uiBinCWAll[i] > 0) + { + m_sliceReshapeInfo.reshape_model_max_bin_idx = i; + break; + } + } + + int maxAbsDeltaCW = 0, AbsDeltaCW = 0, DeltaCW = 0; + for (int i = m_sliceReshapeInfo.reshape_model_min_bin_idx; i <= m_sliceReshapeInfo.reshape_model_max_bin_idx; i++) + { + DeltaCW = (int)m_uiBinCWAll[i] - (int)m_uiCWOrg; + m_sliceReshapeInfo.reshape_model_bin_CW_delta[i] = DeltaCW; + AbsDeltaCW = (DeltaCW < 0) ? (-DeltaCW) : DeltaCW; + if (AbsDeltaCW > maxAbsDeltaCW) { maxAbsDeltaCW = AbsDeltaCW; } + } + m_sliceReshapeInfo.maxNbitsNeededDeltaCW = g_aucLog2[maxAbsDeltaCW << 1]; + + hist_bins = PIC_CODE_CW_BINS; + log2_hist_lens = log2_MAX_LUMA_RESHAPING_LUT_SIZE - log2_PIC_CODE_CW_BINS; + hist_lens = m_uiCWOrg; + + int sum_bins = 0; + for (i = 0; i < hist_bins; i++) { sum_bins += m_uiBinCWAll[i]; } + + CHECK(sum_bins > max_allow_cw, "SDR CW assignment is wrong!!"); + + memset(Y_LUT_all, 0, (MAX_LUMA_RESHAPING_LUT_SIZE + 1) * sizeof(int16_t)); + Y_LUT_all[0] = 0; + + for (i = 0; i < hist_bins; i++) + { + Y_LUT_all[(i + 1)*hist_lens] = Y_LUT_all[i*hist_lens] + m_uiBinCWAll[i]; + int16_t Y1 = Y_LUT_all[i*hist_lens]; + int16_t Y2 = Y_LUT_all[(i + 1)*hist_lens]; + m_ReshapePivot[i + 1] = Y2; + int32_t scale = ((int32_t)(Y2 - Y1) * (1 << FP_PREC) + (1 << (log2_hist_lens - 1))) >> (log2_hist_lens); + forwardReshapingLUT[i*hist_lens] = Clip3((Pel)0, (Pel)1023, (Pel)Y1); + for (j = 1; j < hist_lens; j++) + { + Y_LUT_all[i*hist_lens + j] = Y1 + (((int32_t)scale * (int32_t)j + (1 << (FP_PREC - 1))) >> FP_PREC); + forwardReshapingLUT[i*hist_lens + j] = Clip3((Pel)0, (Pel)1023, (Pel)Y_LUT_all[i*hist_lens + j]); + } + } + + for (i = 0; i < PIC_CODE_CW_BINS; i++) + { + int i_start = i*hist_lens; + int i_end = (i + 1)*hist_lens - 1; + m_cwLumaWeight[i] = forwardReshapingLUT[i_end] - forwardReshapingLUT[i_start]; + } + + if (Y_LUT_all != nullptr) { delete[] Y_LUT_all; Y_LUT_all = nullptr; } + + ReverseLUT(forwardReshapingLUT, inverseReshapingLUT, MAX_LUMA_RESHAPING_LUT_SIZE); + updateChromaDQPLUT(); +} + +#endif +// +//! \} diff --git a/source/Lib/EncoderLib/EncReshape.h b/source/Lib/EncoderLib/EncReshape.h new file mode 100644 index 000000000..ea186506e --- /dev/null +++ b/source/Lib/EncoderLib/EncReshape.h @@ -0,0 +1,149 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2019, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + /** \file EncReshape.h + \brief encoder reshaping header and class (header) + */ + +#ifndef __ENCRESHAPE__ +#define __ENCRESHAPE__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +#include "CommonLib/Reshape.h" +#if JVET_M0427_INLOOP_RESHAPER + +//! \ingroup EncoderLib +//! \{ + +// ==================================================================================================================== +// Class definition +// ==================================================================================================================== + +struct ModelInfo +{ + unsigned FullRangeInputFlag; + unsigned ScaleIntPrec; + unsigned ScaleInt; + unsigned ScaleFracPrec; + unsigned ScaleFrac; + unsigned ScaleSign; + unsigned OffsetIntPrec; + unsigned OffsetInt; + unsigned OffsetFracPrec; + unsigned OffsetFrac; + unsigned OffsetSign; + unsigned MinMaxQPAbsPrec; + unsigned MaxQPAbs; + unsigned MaxQPSign; + unsigned MinQPAbs; + unsigned MinQPSign; + unsigned ScaleAbs; + unsigned OffsetAbs; +}; + +class EncReshape : public Reshape +{ +private: + bool m_bSrcReshaped; + int m_picWidth; + int m_picHeight; + uint32_t m_maxCUWidth; + uint32_t m_maxCUHeight; + uint32_t m_widthInCtus; + uint32_t m_heightInCtus; + uint32_t m_numCtuInFrame; + bool m_bExceedSTD; + std::vector<uint32_t> m_uiBinImportance; + int m_tcase; + int m_rateAdpMode; + bool m_bUseAdpCW; + uint16_t m_uiCWOrgAnalyze; + ModelInfo m_DftModel; + ReshapeCW m_reshapeCW; + Pel m_cwLumaWeight[PIC_CODE_CW_BINS]; + double m_chromaWeight; + int m_chromaAdj; +public: + + EncReshape(); + ~EncReshape(); + + void create_enc( int picWidth, int picHeight, uint32_t maxCUWidth, uint32_t maxCUHeight); + void destroy(); + + bool getSrcReshaped() { return m_bSrcReshaped; } + void setSrcReshaped(bool bPicReshaped) { m_bSrcReshaped = bPicReshaped; } + + void preAnalyzerSDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT, bool isCPR); + void preAnalyzerHDR(Picture *pcPic, const SliceType sliceType, const ReshapeCW& reshapeCW, bool isDualT, bool isCPR); + void bubbleSortDsd(double *array, int * idx, int n); + void swap(int *xp, int *yp) { int temp = *xp; *xp = *yp; *yp = temp; } + void swap(double *xp, double *yp) { double temp = *xp; *xp = *yp; *yp = temp; } + void deriveReshapeParametersSDRfromStats(uint32_t *, double*, double* dReshapeTH1, double* dReshapeTH2, bool *bIntraAdp, bool *bInterAdp); + void deriveReshapeParameters(double *array, int start, int end, ReshapeCW respCW, double &alpha, double &beta); + void initLUTfromdQPModel(); + int calcEXP2(int val); + void constructReshaperSDR(); + ReshapeCW * getReshapeCW() { return &m_reshapeCW; } + Pel * getWeightTable() { return m_cwLumaWeight; } + double getCWeight() { return m_chromaWeight; } + + void initModelParam(double dScale = 0.015, double dOffset = -7.5, int QPMax = 6, int QPMin = -3) + { + /// dQP model: dQP = clip3(QPMin, QPMax, dScale*Y+dOffset); + m_DftModel.FullRangeInputFlag = 0; + m_DftModel.ScaleIntPrec = 0; + m_DftModel.ScaleFracPrec = 16; + m_DftModel.OffsetIntPrec = 3; + m_DftModel.OffsetFracPrec = 1; + m_DftModel.MinMaxQPAbsPrec = 3; + m_DftModel.ScaleSign = dScale < 0 ? 1 : 0; + m_DftModel.ScaleAbs = unsigned((dScale < 0 ? -dScale : dScale) * (1 << m_DftModel.ScaleFracPrec)); + m_DftModel.ScaleInt = m_DftModel.ScaleAbs >> m_DftModel.ScaleFracPrec; + m_DftModel.ScaleFrac = m_DftModel.ScaleAbs - (m_DftModel.ScaleInt << m_DftModel.ScaleFracPrec); + m_DftModel.OffsetSign = dOffset < 0 ? 1 : 0; + m_DftModel.OffsetAbs = unsigned((dOffset < 0 ? -dOffset : dOffset) * (1 << m_DftModel.OffsetFracPrec)); + m_DftModel.OffsetInt = m_DftModel.OffsetAbs >> m_DftModel.OffsetFracPrec; + m_DftModel.OffsetFrac = m_DftModel.OffsetAbs - (m_DftModel.OffsetInt << m_DftModel.OffsetFracPrec); + m_DftModel.MaxQPSign = QPMax < 0 ? 1 : 0; + m_DftModel.MaxQPAbs = m_DftModel.MaxQPSign ? -QPMax : QPMax; + m_DftModel.MinQPSign = QPMin < 0 ? 1 : 0; + m_DftModel.MinQPAbs = m_DftModel.MinQPSign ? -QPMin : QPMin; + } +};// END CLASS DEFINITION EncReshape + +//! \} +#endif +#endif diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index 35f64d386..b847fd37f 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -1612,7 +1612,12 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons resetGbiCodingOrder(false, cs); m_pcInterSearch->initWeightIdxBits(); } - +#if JVET_M0427_INLOOP_RESHAPER && REUSE_CU_RESULTS + if (pcSlice->getSPS()->getUseReshaper()) + { + m_pcCuEncoder->setDecCuReshaperInEncCU(m_pcLib->getReshaper(), pcSlice->getSPS()->getChromaFormatIdc()); + } +#endif #if ENABLE_WPP_PARALLELISM pEncLib->getCuEncoder( dataId )->compressCtu( cs, ctuArea, ctuRsAddr, prevQP, currQP ); #else diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 1b5559dff..0da2c547d 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -89,6 +89,9 @@ InterSearch::InterSearch() , m_pFullCS (nullptr) , m_pcEncCfg (nullptr) , m_pcTrQuant (nullptr) +#if JVET_M0427_INLOOP_RESHAPER + , m_pcReshape (nullptr) +#endif , m_iSearchRange (0) , m_bipredSearchRange (0) , m_motionEstimationSearchMethod(MESEARCH_FULL) @@ -193,6 +196,9 @@ void InterSearch::init( EncCfg* pcEncCfg, RdCost* pcRdCost, CABACWriter* CABACEstimator, CtxCache* ctxCache +#if JVET_M0427_INLOOP_RESHAPER + , EncReshape* pcReshape +#endif ) { CHECK(m_isInitialized, "Already initialized"); @@ -205,6 +211,9 @@ void InterSearch::init( EncCfg* pcEncCfg, m_motionEstimationSearchMethod = motionEstimationSearchMethod; m_CABACEstimator = CABACEstimator; m_CtxCache = ctxCache; +#if JVET_M0427_INLOOP_RESHAPER + m_pcReshape = pcReshape; +#endif for( uint32_t iDir = 0; iDir < MAX_NUM_REF_LIST_ADAPT_SR; iDir++ ) { @@ -1268,6 +1277,18 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, CPelBuf tmpPattern = pBuf->Y(); CPelBuf* pcPatternKey = &tmpPattern; +#if JVET_M0427_INLOOP_RESHAPER + if ((pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())) + { + const CompArea &area = pu.blocks[COMPONENT_Y]; + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpOrgLuma = m_tmpStorageLCU.getBuf(tmpArea); + tmpOrgLuma.copyFrom(tmpPattern); + tmpOrgLuma.rspSignal(m_pcReshape->getFwdLUT()); + pcPatternKey = (CPelBuf*)&tmpOrgLuma; + } +#endif + m_lumaClpRng = pu.cs->slice->clpRng(COMPONENT_Y); Picture* refPic = pu.cu->slice->getPic(); @@ -5445,6 +5466,23 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par tu.emtIdx = 0; #endif +#if JVET_M0427_INLOOP_RESHAPER + const Slice &slice = *cs.slice; + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && slice.getReshapeInfo().getSliceReshapeChromaAdj()) + { + const CompArea &areaY = tu.blocks[COMPONENT_Y]; + PelBuf piPredY = cs.getPredBuf(areaY); + CompArea tmpArea(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea); + tmpPred.copyFrom(piPredY); + if (!cu.firstPU->mhIntraFlag && !cu.cpr) + tmpPred.rspSignal(m_pcReshape->getFwdLUT()); + const Pel avgLuma = tmpPred.computeAvg(); + int adj = m_pcReshape->calculateChromaAdj(avgLuma); + tu.setChromaAdj(adj); + } +#endif + double minCost [MAX_NUM_TBLOCKS]; #if !JVET_M0464_UNI_MTS bool checkTransformSkip [MAX_NUM_TBLOCKS]; @@ -5570,7 +5608,15 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par #if RDOQ_CHROMA_LAMBDA m_pcTrQuant->selectLambda(compID); #endif - +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj()) + { + int cScale = tu.getChromaAdj(); + double dCScale = round((double)(1 << CSCALE_FP_PREC) / (double)cScale); + double tmpWeight = dCScale*dCScale; + m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / tmpWeight); + } +#endif TCoeff currAbsSum = 0; uint64_t currCompFracBits = 0; Distortion currCompDist = 0; @@ -5584,7 +5630,14 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par PelBuf resiBuf = csFull->getResiBuf( compArea ); crossComponentPrediction( tu, compID, lumaResi, resiBuf, resiBuf, false ); } - +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() && tu.blocks[compID].width*tu.blocks[compID].height > 4 ) + { + PelBuf resiBuf = csFull->getResiBuf(compArea); + int cScale = tu.getChromaAdj(); + resiBuf.scaleSignal(cScale, 1); + } +#endif #if JVET_M0464_UNI_MTS if( nNumTransformCands > 1 ) { @@ -5666,6 +5719,13 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par CPelBuf orgResiBuf = csFull->getOrgResiBuf(compArea); m_pcTrQuant->invTransformNxN(tu, compID, resiBuf, cQP); +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() && tu.blocks[compID].width*tu.blocks[compID].height > 4 ) + { + int cScale = tu.getChromaAdj(); + resiBuf.scaleSignal(cScale, 0); + } +#endif if (bUseCrossCPrediction) { @@ -5941,6 +6001,12 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa cs.getResiBuf().fill(0); { cs.getRecoBuf().copyFrom(cs.getPredBuf() ); +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcEncCfg->getReshaper() && (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) && !cu.firstPU->mhIntraFlag && !cu.cpr) + { + cs.getRecoBuf().Y().rspSignal(m_pcReshape->getFwdLUT()); + } +#endif } @@ -5958,9 +6024,26 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa CPelBuf reco = cs.getRecoBuf (compID); CPelBuf org = cs.getOrgBuf (compID); #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || ( + m_pcEncCfg->getReshaper() && (cs.slice->getReshapeInfo().getUseSliceReshaper()&& m_pcReshape->getCTUFlag()))) +#else if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() ) +#endif { const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] ); +#if JVET_M0427_INLOOP_RESHAPER + if (compID == COMPONENT_Y) + { + const CompArea &areaY = cu.Y(); + CompArea tmpArea1(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1); + tmpRecLuma.copyFrom(reco); + tmpRecLuma.rspSignal(m_pcReshape->getInvLUT()); + distortion += m_pcRdCost->getDistPart(org, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else +#endif distortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); } else @@ -5999,6 +6082,21 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa if (luma) { cs.getResiBuf().bufs[0].copyFrom(cs.getOrgBuf().bufs[0]); +#if JVET_M0427_INLOOP_RESHAPER + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + const CompArea &areaY = cu.Y(); + CompArea tmpArea(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea); + tmpPred.copyFrom(cs.getPredBuf(COMPONENT_Y)); + + if (!cu.firstPU->mhIntraFlag && !cu.cpr) + tmpPred.rspSignal(m_pcReshape->getFwdLUT()); + cs.getResiBuf(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT()); + cs.getResiBuf(COMPONENT_Y).subtract(tmpPred); + } + else +#endif cs.getResiBuf().bufs[0].subtract(cs.getPredBuf().bufs[0]); } if (chroma) @@ -6087,7 +6185,30 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa if (luma) { - cs.getRecoBuf().bufs[0].reconstruct(cs.getPredBuf().bufs[0], cs.getResiBuf().bufs[0], cs.slice->clpRngs().comp[0]); +#if JVET_M0427_INLOOP_RESHAPER + if (cu.rootCbf && cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + const CompArea &areaY = cu.Y(); + CompArea tmpArea(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea); + tmpPred.copyFrom(cs.getPredBuf(COMPONENT_Y)); + + if (!cu.firstPU->mhIntraFlag && !cu.cpr) + tmpPred.rspSignal(m_pcReshape->getFwdLUT()); + + cs.getRecoBuf(COMPONENT_Y).reconstruct(tmpPred, cs.getResiBuf(COMPONENT_Y), cs.slice->clpRng(COMPONENT_Y)); + } + else + { +#endif + cs.getRecoBuf().bufs[0].reconstruct(cs.getPredBuf().bufs[0], cs.getResiBuf().bufs[0], cs.slice->clpRngs().comp[0]); +#if JVET_M0427_INLOOP_RESHAPER + if (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && !cu.firstPU->mhIntraFlag && !cu.cpr) + { + cs.getRecoBuf().bufs[0].rspSignal(m_pcReshape->getFwdLUT()); + } + } +#endif } if (chroma) { @@ -6109,10 +6230,27 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa CPelBuf org = cs.getOrgBuf (compID); #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || ( + m_pcEncCfg->getReshaper() && (cs.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() ) ) ) +#else if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() ) +#endif { const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] ); - finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); +#if JVET_M0427_INLOOP_RESHAPER + if (compID == COMPONENT_Y) + { + const CompArea &areaY = cu.Y(); + CompArea tmpArea1(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size()); + PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1); + tmpRecLuma.copyFrom(reco); + tmpRecLuma.rspSignal(m_pcReshape->getInvLUT()); + finalDistortion += m_pcRdCost->getDistPart(org, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else +#endif + finalDistortion += m_pcRdCost->getDistPart(org, reco, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); } else #endif diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h index 27030ab31..24f096b79 100644 --- a/source/Lib/EncoderLib/InterSearch.h +++ b/source/Lib/EncoderLib/InterSearch.h @@ -54,6 +54,9 @@ #include "CommonLib/IbcHashMap.h" #include <unordered_map> #include <vector> +#if JVET_M0427_INLOOP_RESHAPER +#include "EncReshape.h" +#endif //! \ingroup EncoderLib //! \{ @@ -126,6 +129,9 @@ protected: // interface to classes TrQuant* m_pcTrQuant; +#if JVET_M0427_INLOOP_RESHAPER + EncReshape* m_pcReshape; +#endif // ME parameters int m_iSearchRange; @@ -164,6 +170,9 @@ public: RdCost* pcRdCost, CABACWriter* CABACEstimator, CtxCache* ctxCache +#if JVET_M0427_INLOOP_RESHAPER + , EncReshape* m_pcReshape +#endif ); void destroy (); diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index ac23b0a31..b0b870af7 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -60,6 +60,9 @@ IntraSearch::IntraSearch() , m_pcEncCfg (nullptr) , m_pcTrQuant (nullptr) , m_pcRdCost (nullptr) +#if JVET_M0427_INLOOP_RESHAPER + , m_pcReshape (nullptr) +#endif , m_CABACEstimator(nullptr) , m_CtxCache (nullptr) , m_isInitialized (false) @@ -149,6 +152,9 @@ void IntraSearch::destroy() m_pSharedPredTransformSkip[ch] = nullptr; } +#if JVET_M0427_INLOOP_RESHAPER + m_tmpStorageLCU.destroy(); +#endif m_isInitialized = false; } @@ -168,6 +174,9 @@ void IntraSearch::init( EncCfg* pcEncCfg, const uint32_t maxCUWidth, const uint32_t maxCUHeight, const uint32_t maxTotalCUDepth +#if JVET_M0427_INLOOP_RESHAPER + , EncReshape* pcReshape +#endif ) { CHECK(m_isInitialized, "Already initialized"); @@ -176,10 +185,16 @@ void IntraSearch::init( EncCfg* pcEncCfg, m_pcRdCost = pcRdCost; m_CABACEstimator = CABACEstimator; m_CtxCache = ctxCache; +#if JVET_M0427_INLOOP_RESHAPER + m_pcReshape = pcReshape; +#endif const ChromaFormat cform = pcEncCfg->getChromaFormatIdc(); IntraPrediction::init( cform, pcEncCfg->getBitDepth( CHANNEL_TYPE_LUMA ) ); +#if JVET_M0427_INLOOP_RESHAPER + m_tmpStorageLCU.create(UnitArea(cform, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE))); +#endif for( uint32_t ch = 0; ch < MAX_NUM_TBLOCKS; ch++ ) { @@ -363,6 +378,17 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) const bool bUseHadamard = cu.transQuantBypass == 0; +#if JVET_M0427_INLOOP_RESHAPER + if (cu.slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()) + { + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpOrg = m_tmpStorageLCU.getBuf(tmpArea); + tmpOrg.copyFrom(piOrg); + tmpOrg.rspSignal(m_pcReshape->getFwdLUT()); + m_pcRdCost->setDistParam(distParam, tmpOrg, piPred, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard); + } + else +#endif m_pcRdCost->setDistParam(distParam, piOrg, piPred, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard); distParam.applyWeight = false; @@ -688,8 +714,11 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) csTemp->releaseIntermediateData(); } // Mode loop +#if JVET_M0427_INLOOP_RESHAPER + cs.useSubStructure(*csBest, partitioner.chType, pu.singleChan(CHANNEL_TYPE_LUMA), true, true, keepResi, keepResi); +#else cs.useSubStructure( *csBest, partitioner.chType, pu.singleChan( CHANNEL_TYPE_LUMA ), KEEP_PRED_AND_RESI_SIGNALS, true, keepResi, keepResi ); - +#endif csBest->releaseIntermediateData(); //=== update PU data ==== pu.intraDir[0] = uiBestPUMode; @@ -907,6 +936,10 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) #if KEEP_PRED_AND_RESI_SIGNALS saveCS.getPredBuf ( area ).copyFrom( cs.getPredBuf ( area ) ); saveCS.getResiBuf ( area ).copyFrom( cs.getResiBuf ( area ) ); +#endif +#if JVET_M0427_INLOOP_RESHAPER + saveCS.getPredBuf ( area ).copyFrom( cs.getPredBuf (area ) ); + cs.picture->getPredBuf( area ).copyFrom( cs.getPredBuf (area ) ); #endif cs.picture->getRecoBuf( area ).copyFrom( cs.getRecoBuf( area ) ); @@ -931,6 +964,11 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) cs.getPredBuf ( area ).copyFrom( saveCS.getPredBuf( area ) ); cs.getResiBuf ( area ).copyFrom( saveCS.getResiBuf( area ) ); #endif +#if JVET_M0427_INLOOP_RESHAPER + cs.getPredBuf ( area ).copyFrom( saveCS.getPredBuf( area ) ); + cs.picture->getPredBuf( area ).copyFrom( cs.getPredBuf ( area ) ); +#endif + cs.picture->getRecoBuf( area ).copyFrom( cs. getRecoBuf( area ) ); for( uint32_t j = 0; j < saveCS.tus.size(); j++ ) @@ -967,6 +1005,9 @@ void IntraSearch::IPCMSearch(CodingStructure &cs, Partitioner& partitioner) cs.cost = 0; cs.setDecomp(cs.area); +#if JVET_M0427_INLOOP_RESHAPER + cs.picture->getPredBuf(cs.area).copyFrom(cs.getPredBuf()); +#endif } void IntraSearch::xEncPCM(CodingStructure &cs, Partitioner& partitioner, const ComponentID &compID) @@ -1274,8 +1315,33 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp DTRACE( g_trace_ctx, D_PRED, "@(%4d,%4d) [%2dx%2d] IMode=%d\n", tu.lx(), tu.ly(), tu.lwidth(), tu.lheight(), uiChFinalMode ); //DTRACE_PEL_BUF( D_PRED, piPred, tu, tu.cu->predMode, COMPONENT_Y ); +#if JVET_M0427_INLOOP_RESHAPER + const Slice &slice = *cs.slice; + bool bFlag = slice.getReshapeInfo().getUseSliceReshaper() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag()) || (slice.getSliceType() == P_SLICE && slice.getSPS()->getSpsNext().getCPRMode())); + if (bFlag && slice.getReshapeInfo().getSliceReshapeChromaAdj() && isChroma(compID)) + { + const Area area = tu.Y().valid() ? tu.Y() : Area(recalcPosition(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].pos()), recalcSize(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].size())); + const CompArea &areaY = CompArea(COMPONENT_Y, tu.chromaFormat, area ); + PelBuf piPredY; + piPredY = cs.picture->getPredBuf(areaY); + const Pel avgLuma = piPredY.computeAvg(); + int adj = m_pcReshape->calculateChromaAdj(avgLuma); + tu.setChromaAdj(adj); + } +#endif //===== get residual signal ===== piResi.copyFrom( piOrg ); +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && compID==COMPONENT_Y) + { + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea); + tmpPred.copyFrom(piPred); + piResi.rspSignal(m_pcReshape->getFwdLUT()); + piResi.subtract(tmpPred); + } + else +#endif piResi.subtract( piPred ); if (pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isLuma(compID)) @@ -1303,6 +1369,19 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp m_pcTrQuant->selectLambda(compID); #endif +#if JVET_M0427_INLOOP_RESHAPER + bFlag = bFlag && (tu.blocks[compID].width*tu.blocks[compID].height > 4); // chroma blk size greater than 2x2 + if (bFlag && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() ) + { + int cScale = tu.getChromaAdj(); + double dCScale = round((double)(1 << CSCALE_FP_PREC) / (double)cScale); + double tmpWeight = dCScale*dCScale; + m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / tmpWeight); + + piResi.scaleSignal(tu.getChromaAdj(), 1); + } +#endif + #if JVET_M0464_UNI_MTS if( trModes ) { @@ -1329,19 +1408,51 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } //===== reconstruction ===== +#if JVET_M0427_INLOOP_RESHAPER + if (bFlag && uiAbsSum > 0 && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() ) + { + piResi.scaleSignal(tu.getChromaAdj(), 0); + } +#endif if (bUseCrossCPrediction) { CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, true); } +#if JVET_M0427_INLOOP_RESHAPER + if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && compID == COMPONENT_Y) + { + CompArea tmpArea(COMPONENT_Y, area.chromaFormat, Position(0,0), area.size()); + PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea); + tmpPred.copyFrom(piPred); + piReco.reconstruct(tmpPred, piResi, cs.slice->clpRng(compID)); + } + else +#endif piReco.reconstruct(piPred, piResi, cs.slice->clpRng( compID )); //===== update distortion ===== #if WCG_EXT +#if JVET_M0427_INLOOP_RESHAPER + if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getReshaper() + && slice.getReshapeInfo().getUseSliceReshaper() && (m_pcReshape->getCTUFlag() || (isChroma(compID) && m_pcEncCfg->getReshapeIntraCMD())))) +#else if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() ) +#endif { const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] ); - ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma ); +#if JVET_M0427_INLOOP_RESHAPER + if (compID == COMPONENT_Y) + { + CompArea tmpArea1(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1); + tmpRecLuma.copyFrom(piReco); + tmpRecLuma.rspSignal(m_pcReshape->getInvLUT()); + ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else +#endif + ruiDist += m_pcRdCost->getDistPart(piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma); } else #endif @@ -1602,7 +1713,7 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par if( bestModeId[COMPONENT_Y] != lastCheckId ) { -#if KEEP_PRED_AND_RESI_SIGNALS +#if KEEP_PRED_AND_RESI_SIGNALS || JVET_M0427_INLOOP_RESHAPER saveCS.getPredBuf( tu.Y() ).copyFrom( csFull->getPredBuf( tu.Y() ) ); #endif saveCS.getRecoBuf( tu.Y() ).copyFrom( csFull->getRecoBuf( tu.Y() ) ); @@ -1622,7 +1733,7 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par if( bestModeId[COMPONENT_Y] != lastCheckId ) { -#if KEEP_PRED_AND_RESI_SIGNALS +#if KEEP_PRED_AND_RESI_SIGNALS || JVET_M0427_INLOOP_RESHAPER csFull->getPredBuf( tu.Y() ).copyFrom( saveCS.getPredBuf( tu.Y() ) ); #endif csFull->getRecoBuf( tu.Y() ).copyFrom( saveCS.getRecoBuf( tu.Y() ) ); @@ -1707,6 +1818,9 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par { // otherwise this would've happened in useSubStructure cs.picture->getRecoBuf( currArea.Y() ).copyFrom( cs.getRecoBuf( currArea.Y() ) ); +#if JVET_M0427_INLOOP_RESHAPER + cs.picture->getPredBuf( currArea.Y() ).copyFrom( cs.getPredBuf( currArea.Y() ) ); +#endif } cs.cost = m_pcRdCost->calcRdCost( cs.fracBits, cs.dist ); @@ -1874,6 +1988,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition #if KEEP_PRED_AND_RESI_SIGNALS saveCS.getPredBuf (area).copyFrom(cs.getPredBuf (area)); saveCS.getOrgResiBuf(area).copyFrom(cs.getOrgResiBuf(area)); +#endif +#if JVET_M0427_INLOOP_RESHAPER + saveCS.getPredBuf (area).copyFrom(cs.getPredBuf (area)); #endif if( keepResi ) { @@ -1894,6 +2011,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition #if KEEP_PRED_AND_RESI_SIGNALS cs.getPredBuf (area).copyFrom(saveCS.getPredBuf (area)); cs.getOrgResiBuf(area).copyFrom(saveCS.getOrgResiBuf(area)); +#endif +#if JVET_M0427_INLOOP_RESHAPER + cs.getPredBuf (area).copyFrom(saveCS.getPredBuf (area)); #endif if( keepResi ) { @@ -1906,6 +2026,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition m_CABACEstimator->getCtx() = ctxBest; } +#if JVET_M0427_INLOOP_RESHAPER + cs.picture->getPredBuf(area).copyFrom(cs.getPredBuf(area)); +#endif cs.picture->getRecoBuf(area).copyFrom(cs.getRecoBuf(area)); cbfs.cbf(compID) = TU::getCbf(currTU, compID); diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 3c1ce2b81..e6d1cc736 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -48,6 +48,9 @@ #include "CommonLib/TrQuant.h" #include "CommonLib/Unit.h" #include "CommonLib/RdCost.h" +#if JVET_M0427_INLOOP_RESHAPER +#include "EncReshape.h" +#endif //! \ingroup EncoderLib //! \{ @@ -81,7 +84,9 @@ private: uint32_t m_savedRdModeList [4][NUM_LUMA_MODE], m_savedNumRdModes[4]; int m_savedExtendRefList[4][NUM_LUMA_MODE]; #endif - +#if JVET_M0427_INLOOP_RESHAPER + PelStorage m_tmpStorageLCU; +#endif protected: // interface to option EncCfg* m_pcEncCfg; @@ -89,6 +94,9 @@ protected: // interface to classes TrQuant* m_pcTrQuant; RdCost* m_pcRdCost; +#if JVET_M0427_INLOOP_RESHAPER + EncReshape* m_pcReshape; +#endif // RD computation CABACWriter* m_CABACEstimator; @@ -109,6 +117,9 @@ public: const uint32_t maxCUWidth, const uint32_t maxCUHeight, const uint32_t maxTotalCUDepth +#if JVET_M0427_INLOOP_RESHAPER + , EncReshape* m_pcReshape +#endif ); void destroy (); diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 82300aae2..32a2d0735 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -593,6 +593,39 @@ void HLSWriter::codeSPSNext( const SPSNext& spsNext, const bool usePCM ) // ADD_NEW_TOOL : (sps extension writer) write tool enabling flags and associated parameters here } +#if JVET_M0427_INLOOP_RESHAPER +void HLSWriter::codeReshaper(const sliceReshapeInfo& pSliceReshaperInfo, const SPS* pcSPS, const bool isIntra) +{ + WRITE_FLAG(pSliceReshaperInfo.getSliceReshapeModelPresentFlag() ? 1 : 0, "slice_reshaper_model_present_flag"); + if (pSliceReshaperInfo.getSliceReshapeModelPresentFlag()) + { + // code slice reshaper model + WRITE_UVLC(pSliceReshaperInfo.reshape_model_min_bin_idx, "reshaper_model_min_bin_idx"); + WRITE_UVLC(PIC_CODE_CW_BINS - 1 - pSliceReshaperInfo.reshape_model_max_bin_idx, "reshaper_model_max_bin_idx"); + assert(pSliceReshaperInfo.maxNbitsNeededDeltaCW > 0); + WRITE_UVLC(pSliceReshaperInfo.maxNbitsNeededDeltaCW-1, "reshaper_model_bin_delta_abs_cw_prec_minus1"); + + for (int i = pSliceReshaperInfo.reshape_model_min_bin_idx; i <= pSliceReshaperInfo.reshape_model_max_bin_idx; i++) + { + int CW_delta = pSliceReshaperInfo.reshape_model_bin_CW_delta[i]; + int signCW = (CW_delta < 0) ? 1 : 0; + int absCW = (CW_delta < 0) ? (-CW_delta) : CW_delta; + WRITE_CODE(absCW, pSliceReshaperInfo.maxNbitsNeededDeltaCW, "reshape_model_abs_CW"); + if (absCW > 0) + WRITE_FLAG(signCW, "reshape_model_sign_CW"); + } + } + + WRITE_FLAG(pSliceReshaperInfo.getUseSliceReshaper() ? 1 : 0, "slice_reshaper_enable_flag"); + + if (!pSliceReshaperInfo.getUseSliceReshaper()) + return; + + if (!(pcSPS->getUseDualITree() && isIntra)) + WRITE_FLAG(pSliceReshaperInfo.getSliceReshapeChromaAdj(), "slice_reshaper_chromaAdj"); +}; +#endif // #if JVET_M0427_INLOOP_RESHAPER + void HLSWriter::codeSPS( const SPS* pcSPS ) { @@ -838,6 +871,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) } } } +#if JVET_M0427_INLOOP_RESHAPER + WRITE_FLAG(pcSPS->getUseReshaper() ? 1 : 0, "sps_reshaper_enable_flag"); +#endif xWriteRbspTrailingBits(); } @@ -1341,6 +1377,13 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) { WRITE_FLAG(pcSlice->getLFCrossSliceBoundaryFlag()?1:0, "slice_loop_filter_across_slices_enabled_flag"); } + +#if JVET_M0427_INLOOP_RESHAPER + if (pcSlice->getSPS()->getUseReshaper()) + { + codeReshaper(pcSlice->getReshapeInfo(), pcSlice->getSPS(), pcSlice->isIntra()); + } +#endif #if HEVC_DEPENDENT_SLICES } #endif diff --git a/source/Lib/EncoderLib/VLCWriter.h b/source/Lib/EncoderLib/VLCWriter.h index 2e3dd35f9..1b9cb53f4 100644 --- a/source/Lib/EncoderLib/VLCWriter.h +++ b/source/Lib/EncoderLib/VLCWriter.h @@ -145,6 +145,9 @@ private: void alfGolombEncode( const int coeff, const int k ); void truncatedUnaryEqProb( int symbol, int maxSymbol ); +#if JVET_M0427_INLOOP_RESHAPER + void codeReshaper ( const sliceReshapeInfo& pSliceReshaperInfo, const SPS* pcSPS, const bool isIntra); +#endif }; //! \} -- GitLab