From b7228c35f0366b18eaf4757c556351d54290f98e Mon Sep 17 00:00:00 2001 From: Chia-Ming Tsai <chia-ming.tsai@mediatek.com> Date: Mon, 8 May 2023 17:42:14 +0000 Subject: [PATCH] JVET-AD0188 (EE2 Test-1.6c): Non-local cross-component prediction and cross-component merge mode --- source/App/EncoderApp/EncApp.cpp | 3 + source/App/EncoderApp/EncAppCfg.cpp | 3 + source/App/EncoderApp/EncAppCfg.h | 3 + source/Lib/CommonLib/CodingStructure.cpp | 13 +- source/Lib/CommonLib/CodingStructure.h | 45 + source/Lib/CommonLib/Common.h | 258 ++ source/Lib/CommonLib/CommonDef.h | 9 + source/Lib/CommonLib/Contexts.cpp | 17 + source/Lib/CommonLib/Contexts.h | 3 + source/Lib/CommonLib/IntraPrediction.cpp | 3320 +++++++++++++++++++++- source/Lib/CommonLib/IntraPrediction.h | 41 +- source/Lib/CommonLib/Slice.h | 8 +- source/Lib/CommonLib/TypeDef.h | 1 + source/Lib/CommonLib/Unit.cpp | 13 + source/Lib/CommonLib/Unit.h | 4 + source/Lib/CommonLib/UnitTools.cpp | 462 +++ source/Lib/CommonLib/UnitTools.h | 29 + source/Lib/DecoderLib/CABACReader.cpp | 26 + source/Lib/DecoderLib/CABACReader.h | 3 + source/Lib/DecoderLib/DecCu.cpp | 100 + source/Lib/DecoderLib/DecSlice.cpp | 13 +- source/Lib/DecoderLib/VLCReader.cpp | 3 + source/Lib/EncoderLib/CABACWriter.cpp | 24 + source/Lib/EncoderLib/CABACWriter.h | 3 + source/Lib/EncoderLib/EncCfg.h | 7 + source/Lib/EncoderLib/EncCu.cpp | 23 + source/Lib/EncoderLib/EncLib.cpp | 3 + source/Lib/EncoderLib/EncSlice.cpp | 13 + source/Lib/EncoderLib/IntraSearch.cpp | 291 +- source/Lib/EncoderLib/IntraSearch.h | 12 + source/Lib/EncoderLib/VLCWriter.cpp | 4 + 31 files changed, 4604 insertions(+), 153 deletions(-) diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 5b7ec86f3..da2cd59cc 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -900,6 +900,9 @@ void EncApp::xInitLibCfg() #if JVET_AC0147_CCCM_NO_SUBSAMPLING m_cEncLib.setUseCccm ( m_cccm ); #endif +#if JVET_AD0188_CCP_MERGE + m_cEncLib.setUseCcpMerge ( m_ccpMerge ); +#endif #if ENABLE_OBMC m_cEncLib.setUseObmc ( m_OBMC ); #endif diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 0c18ef6a2..4c4a6731b 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1123,6 +1123,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #if JVET_AC0147_CCCM_NO_SUBSAMPLING ( "CCCM", m_cccm, 2, "CCCM mode (0:off, 1:on, 2:on subsampling and no subsampling) [default: 2]") #endif +#if JVET_AD0188_CCP_MERGE + ( "CCPMerge", m_ccpMerge, true, "Enable cross-componet prediction merge mode for chroma intra coding" ) +#endif #if ENABLE_OBMC ("OBMC", m_OBMC, true, "Overlapping Block Motion Compensation") #endif diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 32ab826e4..edec8beaf 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -478,6 +478,9 @@ protected: #if JVET_AC0147_CCCM_NO_SUBSAMPLING int m_cccm; #endif +#if JVET_AD0188_CCP_MERGE + bool m_ccpMerge; +#endif #if ENABLE_OBMC bool m_OBMC; #endif diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index 4504d91bb..3fbee8ed9 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -2244,7 +2244,9 @@ void CodingStructure::initSubStructure( CodingStructure& subStruct, const Channe subStruct.m_isTuEnc = isTuEnc; subStruct.motionLut = motionLut; - +#if JVET_AD0188_CCP_MERGE + subStruct.ccpLut = ccpLut; +#endif subStruct.prevPLT = prevPLT; #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS subStruct.treeType = treeType; @@ -2381,6 +2383,10 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C motionLut = subStruct.motionLut; } +#if JVET_AD0188_CCP_MERGE + ccpLut = subStruct.ccpLut; +#endif + #if JVET_W0123_TIMD_FUSION if (!subStruct.m_isTuEnc && chType != CHANNEL_TYPE_CHROMA) { @@ -2529,6 +2535,11 @@ void CodingStructure::copyStructure( const CodingStructure& other, const Channel motionLut = other.motionLut; } + +#if JVET_AD0188_CCP_MERGE + ccpLut = other.ccpLut; +#endif + #if JVET_W0123_TIMD_FUSION IpmBuf ownIB = getIpmBuf(); CIpmBuf subIB = other.getIpmBuf(); diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index b2369ba86..5a1f44fa2 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -263,6 +263,12 @@ public: LutMotionCand motionLut; +#if JVET_AD0188_CCP_MERGE + LutCCP ccpLut; + template<class T> void addCCPToLut(static_vector<T, MAX_NUM_HCCP_CANDS> &lut, const T &model, int reusePos); + template<class T> void getOneModelFromCCPLut(const static_vector<T, MAX_NUM_HCCP_CANDS> &lut, T &model, int pos); +#endif + void addMiToLut(static_vector<MotionInfo, MAX_NUM_HMVP_CANDS>& lut, const MotionInfo &mi); #if JVET_Z0075_IBC_HMVP_ENLARGE void addMiToLutIBC(static_vector<MotionInfo, MAX_NUM_HMVP_IBC_CANDS>& lut, const MotionInfo &mi); @@ -520,5 +526,44 @@ private: static inline uint32_t getNumberValidTBlocks(const PreCalcValues& pcv) { return (pcv.chrFormat==CHROMA_400) ? 1 : ( pcv.multiBlock422 ? MAX_NUM_TBLOCKS : MAX_NUM_COMPONENT ); } +#if JVET_AD0188_CCP_MERGE +template<class T> +void CodingStructure::addCCPToLut(static_vector<T, MAX_NUM_HCCP_CANDS> &lut, const T &model, int reusePos) +{ + int currCnt = (int) lut.size(); + + int erasePos = 0; + + if (reusePos == -1) + { + for (int j = 0; j < currCnt; j++) + { + if (lut[currCnt - j - 1] == model) + { + reusePos = j; + break; + } + } + } + if (reusePos != -1) + { + erasePos = currCnt - 1 - reusePos; // reverse the order + } + if (reusePos != -1 || currCnt == lut.capacity()) + { + lut.erase(lut.begin() + erasePos); + } + lut.push_back(model); +} + +template<class T> +void CodingStructure::getOneModelFromCCPLut(const static_vector<T, MAX_NUM_HCCP_CANDS> &lut, T &model, int pos) +{ + size_t currCnt = lut.size(); + CHECK(pos >= currCnt, "Invalid entry in CCP LUT"); + model = lut[currCnt - pos - 1]; +} + +#endif #endif diff --git a/source/Lib/CommonLib/Common.h b/source/Lib/CommonLib/Common.h index 11e81d98d..7a807bd7e 100644 --- a/source/Lib/CommonLib/Common.h +++ b/source/Lib/CommonLib/Common.h @@ -295,6 +295,264 @@ public: } }; +#if JVET_AD0188_CCP_MERGE +enum CCPType +{ + CCP_TYPE_NONE = 0, + CCP_TYPE_CCLM = 1, + CCP_TYPE_MMLM = (1 << 1), + CCP_TYPE_GLM0123 = (1 << 2), + CCP_TYPE_GLM4567 = (1 << 3), + CCP_TYPE_CCCM = (1 << 4), + CCP_TYPE_GLCCCM = (1 << 5), + CCP_TYPE_NSCCCM = (1 << 6), + CCP_TYPE_MDFCCCM = (1 << 7), + NUM_CCP_TYPE +}; + +struct CCPModelCandidate +{ + int64_t params[2][NUM_CCP_PARAMS] = { 0 }; +#if MMLM + int64_t params2[2][NUM_CCP_PARAMS] = { 0 }; + int shift2[2] = { 0 }; + int yThres = 0; +#endif + int shift[2] = { 0 }; + int bd = 0; + int midVal = 0; + int type = 0; +#if JVET_AB0174_CCCM_DIV_FREE + int lumaOffset = 0; +#endif +#if JVET_AC0054_GLCCCM || JVET_AD0202_CCCM_MDF + int corOffX = 0; + int corOffY = 0; +#endif +#if JVET_AD0202_CCCM_MDF + int cccmMultiFilterIdx = 0; +#endif +#if JVET_AA0126_GLM + int8_t glmIdc = 0; +#endif + + template<int NUM> + inline bool isTheSameParams(const CCPModelCandidate& p) const + { + for (int i = 0; i < NUM; ++i) + { + if (params[0][i] != p.params[0][i] || params[1][i] != p.params[1][i]) + { + return false; + } + } + return true; + } + + template<int NUM> + inline bool isTheSameParams2(const CCPModelCandidate& p) const + { + for (int i = 0; i < NUM; ++i) + { + if (params2[0][i] != p.params2[0][i] || params2[1][i] != p.params2[1][i]) + { + return false; + } + } + return true; + } + bool operator==(const CCPModelCandidate& cand) const + { + if (type != cand.type) + { + return false; + } + + if ((type & CCP_TYPE_MMLM) != (cand.type & CCP_TYPE_MMLM)) + { + return false; + } + + if (type & (CCP_TYPE_CCCM | CCP_TYPE_GLCCCM)) + { +#if JVET_AB0174_CCCM_DIV_FREE + if (lumaOffset != cand.lumaOffset) + { + return false; + } +#endif + if (type & CCP_TYPE_MMLM) + { + if (yThres != cand.yThres) + { + return false; + } + if (isTheSameParams<CCCM_NUM_PARAMS>(cand) && isTheSameParams2<CCCM_NUM_PARAMS>(cand)) + { + return true; + } + } + else + { + if (isTheSameParams<CCCM_NUM_PARAMS>(cand)) + { + return true; + } + } + return false; + } + else if (type & (CCP_TYPE_CCLM | CCP_TYPE_GLM0123)) + { + if (type & CCP_TYPE_MMLM) + { + if (yThres != cand.yThres) + { + return false; + } + if (params[0][0] == cand.params[0][0] && shift[0] == cand.shift[0] + && params[1][0] == cand.params[1][0] && shift[1] == cand.shift[1] + && params2[0][0] == cand.params2[0][0] && shift2[0] == cand.shift2[0] + && params2[1][0] == cand.params2[1][0] && shift2[1] == cand.shift2[1]) + { + return true; + } + } + else + { + if (params[0][0] == cand.params[0][0] && shift[0] == cand.shift[0] + && params[1][0] == cand.params[1][0] && shift[1] == cand.shift[1]) + { + return true; + } + } + return false; + } + else if (type & CCP_TYPE_GLM4567) + { +#if JVET_AB0174_CCCM_DIV_FREE + if (lumaOffset != cand.lumaOffset) + { + return false; + } +#endif + if (type & CCP_TYPE_MMLM) + { + if (yThres != cand.yThres) + { + return false; + } + if (isTheSameParams<GLM_NUM_PARAMS>(cand) && isTheSameParams2<GLM_NUM_PARAMS>(cand)) + { + return true; + } + } + else + { + if (isTheSameParams<GLM_NUM_PARAMS>(cand)) + { + return true; + } + } + return false; + } +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + else if (type & CCP_TYPE_NSCCCM) + { +#if JVET_AB0174_CCCM_DIV_FREE + if (lumaOffset != cand.lumaOffset) + { + return false; + } +#endif + if (type & CCP_TYPE_MMLM) + { + if (yThres != cand.yThres) + { + return false; + } + if (isTheSameParams<CCCM_NO_SUB_NUM_PARAMS>(cand) && isTheSameParams2<CCCM_NO_SUB_NUM_PARAMS>(cand)) + { + return true; + } + } + else + { + if (isTheSameParams<CCCM_NO_SUB_NUM_PARAMS>(cand)) + { + return true; + } + } + return false; + } +#endif +#if JVET_AD0202_CCCM_MDF + else if (type & CCP_TYPE_MDFCCCM) + { + if (cccmMultiFilterIdx != cand.cccmMultiFilterIdx) + { + return false; + } +#if JVET_AB0174_CCCM_DIV_FREE + if (lumaOffset != cand.lumaOffset) + { + return false; + } +#endif + if (type & CCP_TYPE_MMLM) + { + if (yThres != cand.yThres) + { + return false; + } + if (cccmMultiFilterIdx == 1) + { + if (isTheSameParams<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(cand) && isTheSameParams2<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(cand)) + { + return true; + } + } + else + { + if (isTheSameParams<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(cand) && isTheSameParams2<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(cand)) + { + return true; + } + } + } + else + { + if (cccmMultiFilterIdx == 1) + { + if (isTheSameParams<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(cand)) + { + return true; + } + } + else + { + if (isTheSameParams<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(cand)) + { + return true; + } + } + } + return false; + } +#endif + else + { + THROW("Wrong Type"); + // return pos == cand.pos; + } + } +}; + +struct LutCCP +{ + static_vector<CCPModelCandidate, MAX_NUM_HCCP_CANDS> lutCCP; + // Postions for future extensions +}; +#endif #endif diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 586311c2c..c1b1f20bc 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -1403,6 +1403,15 @@ static const int EXT_PICTURE_SIZE = 16; static const int IBC_BVD_PREDICTION_MAX_BIN_NUM = 4; #endif +#if JVET_AD0188_CCP_MERGE +static const int MAX_CCP_CAND_LIST_SIZE = 12; +static const int MAX_NUM_HCCP_CANDS = 6; +#if JVET_AC0147_CCCM_NO_SUBSAMPLING +static const int NUM_CCP_PARAMS = CCCM_NO_SUB_NUM_PARAMS; +#else +static const int NUM_CCP_PARAMS = CCCM_NUM_PARAMS; +#endif +#endif // ==================================================================================================================== // Macro functions diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index f7123c412..2eafb7028 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -3415,6 +3415,23 @@ const CtxSet ContextSetCfg::TmrlDerive = ContextSetCfg::addCtxSet }); #endif +#if JVET_AD0188_CCP_MERGE +const CtxSet ContextSetCfg::nonLocalCCP = ContextSetCfg::addCtxSet +({ + { CNU, }, + { CNU, }, + { CNU, }, + { DWS, }, + { DWS, }, + { DWS, }, + { DWE, }, + { DWE, }, + { DWE, }, + { DWO, }, + { DWO, }, +}); +#endif + #elif SLICE_TYPE_WIN_SIZE const CtxSet ContextSetCfg::SplitFlag = ContextSetCfg::addCtxSet ({ diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 1baa3abb1..c31367b23 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -367,6 +367,9 @@ public: static const CtxSet CclmModeFlag; static const CtxSet CclmModeIdx; static const CtxSet IntraChromaPredMode; +#if JVET_AD0188_CCP_MERGE + static const CtxSet nonLocalCCP; +#endif #if JVET_Z0050_DIMD_CHROMA_FUSION #if ENABLE_DIMD static const CtxSet DimdChromaMode; diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index 168c8f76f..6fb7eb05b 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -2312,6 +2312,16 @@ void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf &piPred CccmModel<GLM_NUM_PARAMS> glmModel(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)); xGlmCalcModel(pu, compID, chromaArea, glmModel); xGlmApplyModel(pu, compID, chromaArea, glmModel, piPred); + + #if JVET_AD0188_CCP_MERGE + const_cast<PredictionUnit &>(pu).curCand.type = CCP_TYPE_GLM4567; + const_cast<PredictionUnit &>(pu).curCand.glmIdc = pu.glmIdc.getIdc(compID, 0); + PU::glmModelToCcpParams(compID, const_cast<PredictionUnit&>(pu).curCand, glmModel +#if JVET_AB0174_CCCM_DIV_FREE + , m_glmLumaOffset +#endif + ); +#endif return; } #endif @@ -2376,6 +2386,17 @@ void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf &piPred #endif #endif +#if JVET_AD0188_CCP_MERGE + int glmIdc = pu.glmIdc.getIdc(compID, 0); + const_cast<PredictionUnit&>(pu).curCand.type = (glmIdc > 0) ? CCP_TYPE_GLM0123 : CCP_TYPE_CCLM; + if (PU::isMultiModeLM(pu.intraDir[1])) + { + const_cast<PredictionUnit&>(pu).curCand.type |= CCP_TYPE_MMLM; + } + const_cast<PredictionUnit&>(pu).curCand.glmIdc = glmIdc; + PU::cclmModelToCcpParams(compID, const_cast<PredictionUnit&>(pu).curCand, cclmModel); +#endif + ////// final prediction piPred.copyFrom(temp); #if MMLM @@ -3361,6 +3382,16 @@ void IntraPrediction::geneChromaFusionPred(const ComponentID compId, PelBuf &piP } #endif predIntraChromaLM(compId, predLmBuffer, pu2, area, pu2.intraDir[1]); + +#if JVET_AD0188_CCP_MERGE + const_cast<PredictionUnit&>(pu).curCand = pu2.curCand; + const_cast<PredictionUnit &>(pu).curCand.type = CCP_TYPE_CCLM; + if (PU::isMultiModeLM(pu2.intraDir[1])) + { + const_cast<PredictionUnit&>(pu).curCand.type |= CCP_TYPE_MMLM; + } +#endif + #if JVET_AC0071_DBV && JVET_AA0070_RRIBC if (pu.intraDir[1] == DBV_CHROMA_IDX && pu.cu->rribcFlipType != 0) { @@ -12533,191 +12564,3011 @@ int IntraPrediction::calcTemplateDiff( Pel* ref, unsigned int uiStride, Pel** ta #endif #endif -#if JVET_AB0174_CCCM_DIV_FREE -#define DIV_PREC_BITS 14 -#define DIV_PREC_BITS_POW2 8 -#define DIV_SLOT_BITS 3 -#define DIV_INTR_BITS (DIV_PREC_BITS - DIV_SLOT_BITS) -#define DIV_INTR_ROUND (1 << DIV_INTR_BITS >> 1) -int64_t xDivide(int64_t num, int64_t denom) // Note: assumes positive denominator +#if JVET_AD0188_CCP_MERGE +void IntraPrediction::xGlmApplyModelOffset(const PredictionUnit &pu, const ComponentID compId, + const CompArea &chromaArea, CccmModel<GLM_NUM_PARAMS> &glmModel, int glmIdc, + PelBuf &piPred, int lumaOffset, int chromaOffset) const { - static const int pow2W[8] = { 214, 153, 113, 86, 67, 53, 43, 35 }; // DIV_PREC_BITS_POW2 - static const int pow2O[8] = { 4822, 5952, 6624, 6792, 6408, 5424, 3792, 1466 }; // DIV_PREC_BITS - static const int pow2B[8] = { 12784, 12054, 11670, 11583, 11764, 12195, 12870, 13782 }; // DIV_PREC_BITS + const ClpRng &clpRng(pu.cu->cs->slice->clpRng(compId)); + static Pel samples[GLM_NUM_PARAMS]; - int shift = floorLog2Uint64(denom); - int round = 1 << shift >> 1; - int normDiff = (((denom << DIV_PREC_BITS) + round) >> shift) & ((1 << DIV_PREC_BITS) - 1); - int diffFull = normDiff >> DIV_INTR_BITS; - int normDiff2 = normDiff - pow2O[diffFull]; + CPelBuf refLumaBlk = xGlmGetGradPuBuf(pu, chromaArea, 0); + CPelBuf refGradBlk = xGlmGetGradPuBuf(pu, chromaArea, glmIdc); - int scale = ((pow2W[diffFull] * ((normDiff2 * normDiff2) >> DIV_PREC_BITS)) >> DIV_PREC_BITS_POW2) - (normDiff2 >> 1) + pow2B[diffFull]; + for (int y = 0; y < refLumaBlk.height; y++) + { + for (int x = 0; x < refLumaBlk.width; x++) + { + samples[0] = refGradBlk.at(x, y); // luma gradient + samples[1] = refLumaBlk.at(x, y) + lumaOffset; // luma value + samples[2] = glmModel.bias(); - return ( (num << (CCCM_DECIM_BITS - DIV_PREC_BITS)) * scale + round) >> shift; + piPred.at(x, y) = ClipPel<Pel>(glmModel.convolve(samples) + chromaOffset, clpRng); + } + } } - -#if JVET_AC0053_GAUSSIAN_SOLVER -void xGetDivScaleRoundShift(int64_t denom, int &scale, int &round, int &shift) // Note: assumes positive denominator +void IntraPrediction::xCccmApplyModelOffset(const PredictionUnit &pu, const ComponentID compId, + const CccmModel<CCCM_NUM_PARAMS> &cccmModel, int modelId, int modelThr, + PelBuf &piPred, int lumaOffset, int chromaOffset[], int type,int refSizeX, int refSizeY) const { - static const int pow2W[8] = { 214, 153, 113, 86, 67, 53, 43, 35 }; // DIV_PREC_BITS_POW2 - static const int pow2O[8] = { 4822, 5952, 6624, 6792, 6408, 5424, 3792, 1466 }; // DIV_PREC_BITS - static const int pow2B[8] = { 12784, 12054, 11670, 11583, 11764, 12195, 12870, 13782 }; // DIV_PREC_BITS + const ClpRng &clpRng(pu.cu->cs->slice->clpRng(compId)); + static Pel samples[CCCM_NUM_PARAMS]; - shift = floorLog2Uint64(denom); - round = 1 << shift >> 1; - int normDiff = (((denom << DIV_PREC_BITS) + round) >> shift) & ((1 << DIV_PREC_BITS) - 1); - int diffFull = normDiff >> DIV_INTR_BITS; - int normDiff2 = normDiff - pow2O[diffFull]; + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu); - scale = ((pow2W[diffFull] * ((normDiff2 * normDiff2) >> DIV_PREC_BITS)) >> DIV_PREC_BITS_POW2) - (normDiff2 >> 1) + pow2B[diffFull]; - scale <<= CCCM_DECIM_BITS - DIV_PREC_BITS; -} -#endif + int offset = modelId == 2 ? chromaOffset[1] : chromaOffset[0]; -#undef DIV_PREC_BITS -#undef DIV_PREC_BITS_POW2 -#undef DIV_SLOT_BITS -#undef DIV_INTR_BITS -#undef DIV_INTR_ROUND + if (type & CCP_TYPE_CCCM) + { + for (int y = 0; y < refLumaBlk.height; y++) + { + for (int x = 0; x < refLumaBlk.width; x++) + { + if (modelId == 1 && (refLumaBlk.at(x, y) + lumaOffset) > modelThr) // Model 1: Include only samples below or equal to the threshold + { + continue; + } + if (modelId == 2 && (refLumaBlk.at(x, y) + lumaOffset) <= modelThr) // Model 2: Include only samples above the threshold + { + continue; + } -int xCccmDivideLowPrec(int64_t num, int64_t denom) -{ - if ( num < 0 ) + // 7-tap cross + samples[0] = refLumaBlk.at(x, y) + lumaOffset; // C + samples[1] = refLumaBlk.at(x, y - 1) + lumaOffset; // N + samples[2] = refLumaBlk.at(x, y + 1) + lumaOffset; // S + samples[3] = refLumaBlk.at(x - 1, y) + lumaOffset; // W + samples[4] = refLumaBlk.at(x + 1, y) + lumaOffset; // E + samples[5] = const_cast<CccmModel<CCCM_NUM_PARAMS> &>(cccmModel).nonlinear(refLumaBlk.at(x, y) + lumaOffset); + samples[6] = const_cast<CccmModel<CCCM_NUM_PARAMS> &>(cccmModel).bias(); + + piPred.at(x, y) = ClipPel<Pel>(const_cast<CccmModel<CCCM_NUM_PARAMS> &>(cccmModel).convolve(samples) + offset, clpRng); + } + } + } +#if JVET_AC0054_GLCCCM + else if (type & CCP_TYPE_GLCCCM) { - return -int(xDivide(-num, denom) >> CCCM_DECIM_BITS); + for (int y = 0; y < refLumaBlk.height; y++) + { + for (int x = 0; x < refLumaBlk.width; x++) + { + if (modelId == 1 && (refLumaBlk.at(x, y) + lumaOffset) > modelThr) // Model 1: Include only samples below or equal to the threshold + { + continue; + } + if (modelId == 2 && (refLumaBlk.at(x, y) + lumaOffset) <= modelThr) // Model 2: Include only samples above the threshold + { + continue; + } + + samples[0] = refLumaBlk.at(x, y) + lumaOffset; // C + samples[1] = (2 * refLumaBlk.at(x, y - 1) + refLumaBlk.at(x - 1, y - 1) + refLumaBlk.at(x + 1, y - 1)) + - (2 * refLumaBlk.at(x, y + 1) + refLumaBlk.at(x - 1, y + 1) + refLumaBlk.at(x + 1, y + 1)); // Vertical gradient + samples[2] = (2 * refLumaBlk.at(x - 1, y) + refLumaBlk.at(x - 1, y - 1) + refLumaBlk.at(x - 1, y + 1)) + - (2 * refLumaBlk.at(x + 1, y) + refLumaBlk.at(x + 1, y - 1) + refLumaBlk.at(x + 1, y + 1)); // Horizontal gradient + samples[3] = ((y + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[4] = ((x + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[5] = const_cast<CccmModel<CCCM_NUM_PARAMS> &>(cccmModel).nonlinear(refLumaBlk.at(x, y) + lumaOffset); + samples[6] = const_cast<CccmModel<CCCM_NUM_PARAMS> &>(cccmModel).bias(); + + piPred.at(x, y) = ClipPel<Pel>(const_cast<CccmModel<CCCM_NUM_PARAMS> &>(cccmModel).convolve(samples) + offset, clpRng); + } + } } +#endif else { - return int(xDivide(num, denom) >> CCCM_DECIM_BITS); + THROW("Invalid type"); } } -int64_t xCccmDivide(int64_t num, int64_t denom) // Note: assumes positive denominator +#if JVET_AD0202_CCCM_MDF +void IntraPrediction::xMFCccmApplyModelOffset1(const PredictionUnit &pu, const ComponentID compId, + const CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModel, int modelId, + int modelThr, PelBuf &piPred, int lumaOffset, int chromaOffset[2]) const { - return xDivide(num, denom); -} + const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compId)); + static Pel samples[CCCM_MULTI_PRED_FILTER_NUM_PARAMS]; + +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + CHECK(pu.cccmNoSubFlag, "cccmNoSubFlag shall be disabled"); +#endif +#if JVET_AC0054_GLCCCM + int refSizeX = m_cccmBlkArea.x - m_cccmRefArea.x; // Reference lines available left and above + int refSizeY = m_cccmBlkArea.y - m_cccmRefArea.y; #endif + CPelBuf refLumaBlk1, refLumaBlk2, refLumaBlk3; + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu, 0, 3, &refLumaBlk1, &refLumaBlk3, &refLumaBlk2); -#if JVET_AA0057_CCCM || JVET_AC0119_LM_CHROMA_FUSION -#if JVET_AB0174_CCCM_DIV_FREE -void IntraPrediction::xCccmSetLumaRefValue(const PredictionUnit& pu) -{ - int lumaPosX = m_cccmBlkArea.x << getComponentScaleX(COMPONENT_Cb, pu.cu->chromaFormat); - int lumaPosY = m_cccmBlkArea.y << getComponentScaleY(COMPONENT_Cb, pu.cu->chromaFormat); + int offset = modelId == 2 ? chromaOffset[1] : chromaOffset[0]; - if (lumaPosX || lumaPosY) + for (int y = 0; y < refLumaBlk.height; y++) { - lumaPosX = lumaPosX ? lumaPosX - 1 : 0; - lumaPosY = lumaPosY ? lumaPosY - 1 : 0; + for (int x = 0; x < refLumaBlk.width; x++) + { + if (modelId == 1 && (refLumaBlk.at(x, y) + lumaOffset) > modelThr) // Model 1: Include only samples below or equal to the threshold + { + continue; + } + if (modelId == 2 && (refLumaBlk.at(x, y) + lumaOffset) <= modelThr) // Model 2: Include only samples above the threshold + { + continue; + } - m_cccmLumaOffset = pu.cs->picture->getRecoBuf(COMPONENT_Y).at(lumaPosX, lumaPosY); - } - else - { - m_cccmLumaOffset = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 1); + // 7-tap cross + samples[0] = refLumaBlk.at(x, y) + lumaOffset; // C + samples[1] = refLumaBlk1.at(x, y) + lumaOffset; // W + samples[2] = refLumaBlk2.at(x, y) + lumaOffset; // E + samples[3] = refLumaBlk3.at(x, y) + lumaOffset; + samples[4] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>&>(cccmModel).nonlinear(refLumaBlk.at(x, y) + lumaOffset); + samples[5] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>&>(cccmModel).nonlinear(refLumaBlk1.at(x, y) + lumaOffset); + samples[6] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>&>(cccmModel).nonlinear(refLumaBlk2.at(x, y) + lumaOffset); + samples[7] = ((y + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[8] = ((x + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[9] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>&>(cccmModel).bias(); + + piPred.at(x, y) = ClipPel<Pel>(const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>&>(cccmModel).convolve(samples) + offset, clpRng); + } } } -#endif -// Calculate a single downsampled luma reference value (copied from IntraPrediction::xGetLumaRecPixels) -Pel IntraPrediction::xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, const int x, const int y -#if JVET_AD0202_CCCM_MDF - , int downsFilterIdx -#endif -) const +void IntraPrediction::xMFCccmApplyModelOffset23(const PredictionUnit &pu, const ComponentID compId, + const CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModel, int modelId, + int modelThr, PelBuf &piPred, int lumaOffset, int chromaOffset[2]) const { - const Pel* piSrc = pi.buf; - const int iRecStride = pi.stride; - Pel ypval = 0; + const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compId)); + static Pel samples[CCCM_MULTI_PRED_FILTER_NUM_PARAMS2]; + #if JVET_AC0147_CCCM_NO_SUBSAMPLING - if (pu.cccmNoSubFlag || pu.chromaFormat == CHROMA_444) -#else - if (pu.chromaFormat == CHROMA_444) + CHECK(pu.cccmNoSubFlag, "cccmNoSubFlag shall be disabled"); #endif - { - ypval = piSrc[x + iRecStride * y]; - } - else if (pu.chromaFormat == CHROMA_422) - { - int s = 2; - int offLeft = x > 0 ? -1 : 0; - s += piSrc[2 * x + iRecStride * y] * 2; - s += piSrc[2 * x + offLeft + iRecStride * y]; - s += piSrc[2 * x + 1 + iRecStride * y]; - ypval = s >> 2; - } - else if (pu.cs->sps->getCclmCollocatedChromaFlag()) - { - int s = 4; - int offLeft = x > 0 ? -1 : 0; - int offAbove = y > 0 ? -1 : 0; - s += piSrc[2 * x + iRecStride * 2 * y] * 4; - s += piSrc[2 * x + offLeft + iRecStride * 2 * y]; - s += piSrc[2 * x + 1 + iRecStride * 2 * y]; - s += piSrc[2 * x + iRecStride * (2 * y + 1)]; - s += piSrc[2 * x + iRecStride * (2 * y + offAbove)]; - ypval = s >> 3; - } - else - { -#if JVET_AD0202_CCCM_MDF - const int lumaPosPicX1 = 2 * x; - const int lumaPosPicY1 = 2 * y; - int lumaPosPicX0 = lumaPosPicX1 - 1; lumaPosPicX0 = lumaPosPicX0 < 0 ? 0 : lumaPosPicX0; - const int lumaPosPicX2 = lumaPosPicX1 + 1; - const int lumaPosPicY2 = lumaPosPicY1 + 1; - const int shift0 = iRecStride * lumaPosPicY1; - const int shift1 = iRecStride * lumaPosPicY2; - - if (downsFilterIdx == 0) - { - int s = 4; +#if JVET_AC0054_GLCCCM + int refSizeX = m_cccmBlkArea.x - m_cccmRefArea.x; // Reference lines available left and above + int refSizeY = m_cccmBlkArea.y - m_cccmRefArea.y; +#endif + CPelBuf refLumaBlk1, refLumaBlk3; + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu, 0, 2, &refLumaBlk1, &refLumaBlk3); + int offset = modelId == 2 ? chromaOffset[1] : chromaOffset[0]; - s += piSrc[lumaPosPicX1 + shift0] * 2; - s += piSrc[lumaPosPicX0 + shift0]; - s += piSrc[lumaPosPicX2 + shift0]; - s += piSrc[lumaPosPicX1 + shift1] * 2; - s += piSrc[lumaPosPicX0 + shift1]; - s += piSrc[lumaPosPicX2 + shift1]; - ypval = s >> 3; - } - else if (downsFilterIdx == 1) + for (int y = 0; y < refLumaBlk.height; y++) + { + for (int x = 0; x < refLumaBlk.width; x++) { - int s = 0; + if (modelId == 1 && (refLumaBlk.at(x, y) + lumaOffset) > modelThr) // Model 1: Include only samples below or equal to the threshold + { + continue; + } + if (modelId == 2 && (refLumaBlk.at(x, y) + lumaOffset) <= modelThr) // Model 2: Include only samples above the threshold + { + continue; + } - s += piSrc[lumaPosPicX0 + shift0]; - s -= piSrc[lumaPosPicX2 + shift0]; - s += piSrc[lumaPosPicX0 + shift1]; - s -= piSrc[lumaPosPicX2 + shift1]; + // 7-tap cross + if (pu.cccmMultiFilterIdx == 2) + { + samples[0] = refLumaBlk.at(x, y) + lumaOffset; // C + samples[1] = refLumaBlk.at(x - 1, y) + lumaOffset; // W + samples[2] = refLumaBlk.at(x + 1, y) + lumaOffset; // E + samples[3] = refLumaBlk1.at(x, y) + lumaOffset; // C + samples[4] = refLumaBlk1.at(x - 1, y) + lumaOffset; // W + samples[5] = refLumaBlk1.at(x + 1, y) + lumaOffset; // E + samples[6] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>&>(cccmModel).nonlinear(refLumaBlk.at(x, y)) + lumaOffset; + samples[7] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>&>(cccmModel).nonlinear(refLumaBlk.at(x - 1, y)) + lumaOffset; + samples[8] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>&>(cccmModel).nonlinear(refLumaBlk.at(x + 1, y)) + lumaOffset; + samples[9] = ((x + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[10] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>&>(cccmModel).bias(); + } + else if (pu.cccmMultiFilterIdx == 3) + { + samples[0] = refLumaBlk.at(x, y) + lumaOffset; // C + samples[1] = refLumaBlk.at(x + 1, y - 1) + lumaOffset; // EN + samples[2] = refLumaBlk.at(x - 1, y + 1) + lumaOffset; // WS + samples[3] = refLumaBlk3.at(x, y) + lumaOffset; // C + samples[4] = refLumaBlk3.at(x + 1, y - 1) + lumaOffset; // EN + samples[5] = refLumaBlk3.at(x - 1, y + 1) + lumaOffset; // WS + samples[6] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>&>(cccmModel).nonlinear(refLumaBlk.at(x, y)) + lumaOffset; + samples[7] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>&>(cccmModel).nonlinear(refLumaBlk.at(x + 1, y - 1)) + lumaOffset; + samples[8] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>&>(cccmModel).nonlinear(refLumaBlk.at(x - 1, y + 1)) + lumaOffset; + samples[9] = ((y + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[10] = const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>&>(cccmModel).bias(); + } + else + { + THROW("Invalid cccmMultiFilterIdx"); + } - ypval = s < 0 ? 0 : s; + piPred.at(x, y) = ClipPel<Pel>(const_cast<CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>&>(cccmModel).convolve(samples) + offset, clpRng); } - else if (downsFilterIdx == 2) - { - int s = 0; + } +} - s += piSrc[lumaPosPicX0 + shift0]; - s += piSrc[lumaPosPicX1 + shift0] * 2; - s += piSrc[lumaPosPicX2 + shift0]; - s -= piSrc[lumaPosPicX0 + shift1]; - s -= piSrc[lumaPosPicX1 + shift1] * 2; - s -= piSrc[lumaPosPicX2 + shift1]; +void IntraPrediction::xGetUpdatedOffsetMFCCCM1(const PredictionUnit& pu, const ComponentID compID, int modelNum, + const CompArea& chromaArea, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModel[2], + int modelThr, int lumaOffset, int chromaOffset[], int type, int refSizeX, int refSizeY) +{ + CHECK(compID != chromaArea.compID, "Invalid component ID"); - ypval = s < 0 ? 0 : s; - } - else - { - int s = 0; + static Pel samples[CCCM_MULTI_PRED_FILTER_NUM_PARAMS]; - s -= piSrc[lumaPosPicX0 + shift0]; - s += piSrc[lumaPosPicX1 + shift0]; - s += piSrc[lumaPosPicX2 + shift0] * 2; - s -= piSrc[lumaPosPicX0 + shift1] * 2; - s -= piSrc[lumaPosPicX1 + shift1]; - s += piSrc[lumaPosPicX2 + shift1]; + CPelBuf refLumaBlk1, refLumaBlk2, refLumaBlk3; + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu, 0, 3, &refLumaBlk1, &refLumaBlk3, &refLumaBlk2); - ypval = s < 0 ? 0 : s; + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure& cs = *(pu.cs); + const CodingUnit& cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + const Pel* curChroma0; + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + Pel* curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int totalOffset[2] = { 0, 0 }; + int count[2] = { 0, 0 }; + + Pel predChroma; + + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; +#if MMLM + if (type & CCP_TYPE_MMLM) + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk1.at(pos, -1) + lumaOffset; // W + samples[2] = refLumaBlk2.at(pos, -1) + lumaOffset; // E + samples[3] = refLumaBlk3.at(pos, -1) + lumaOffset; + samples[4] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[5] = cccmModel[0].nonlinear(refLumaBlk1.at(pos, -1) + lumaOffset); + samples[6] = cccmModel[0].nonlinear(refLumaBlk2.at(pos, -1) + lumaOffset); + samples[7] = (( -1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[8] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[9] = cccmModel[0].bias(); + if ((refLumaBlk.at(pos, -1) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos] - predChroma; + count[1]++; + } + } + } + else +#endif + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk1.at(pos, -1) + lumaOffset; // W + samples[2] = refLumaBlk2.at(pos, -1) + lumaOffset; // E + samples[3] = refLumaBlk3.at(pos, -1) + lumaOffset; + samples[4] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[5] = cccmModel[0].nonlinear(refLumaBlk1.at(pos, -1) + lumaOffset); + samples[6] = cccmModel[0].nonlinear(refLumaBlk2.at(pos, -1) + lumaOffset); + samples[7] = (( -1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[8] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[9] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; +#if MMLM + if (type & CCP_TYPE_MMLM) + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk1.at(-1, pos) + lumaOffset; // W + samples[2] = refLumaBlk2.at(-1, pos) + lumaOffset; // E + samples[3] = refLumaBlk3.at(-1, pos) + lumaOffset; + samples[4] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos) + lumaOffset); + samples[5] = cccmModel[0].nonlinear(refLumaBlk1.at(-1, pos) + lumaOffset); + samples[6] = cccmModel[0].nonlinear(refLumaBlk2.at(-1, pos) + lumaOffset); + samples[7] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[8] = (( -1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[9] = cccmModel[0].bias(); + if ((refLumaBlk.at(-1, pos) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos * curStride] - predChroma; + count[1]++; + } + } + } + else +#endif + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk1.at(-1, pos) + lumaOffset; // W + samples[2] = refLumaBlk2.at(-1, pos) + lumaOffset; // E + samples[3] = refLumaBlk3.at(-1, pos) + lumaOffset; + samples[4] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos) + lumaOffset); + samples[5] = cccmModel[0].nonlinear(refLumaBlk1.at(-1, pos) + lumaOffset); + samples[6] = cccmModel[0].nonlinear(refLumaBlk2.at(-1, pos) + lumaOffset); + samples[7] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[8] = (( -1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[9] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + } + } + + chromaOffset[0] = chromaOffset[1] = 0; + + if (modelNum == 2) + { + if (count[0]) + { + chromaOffset[0] = PU::getMeanValue(totalOffset[0], count[0]); // totalOffset[0] / count[0]; + } + if (count[1]) + { + chromaOffset[1] = PU::getMeanValue(totalOffset[1], count[1]); // totalOffset[1] / count[1]; + } + } + else + { + if (count[0]) + { + chromaOffset[0] = PU::getMeanValue(totalOffset[0], count[0]); // totalOffset[0] / count[0]; + } + } +} + +void IntraPrediction::xGetUpdatedOffsetMFCCCM23(const PredictionUnit& pu, const ComponentID compID, int modelNum, + const CompArea& chromaArea, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModel[2], + int modelThr, int lumaOffset, int chromaOffset[], int type, int refSizeX, int refSizeY) +{ + CHECK(compID != chromaArea.compID, "Invalid component ID"); + + static Pel samples[CCCM_MULTI_PRED_FILTER_NUM_PARAMS2]; + + CPelBuf refLumaBlk1, refLumaBlk3; + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu, 0, 2, &refLumaBlk1, &refLumaBlk3); + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure& cs = *(pu.cs); + const CodingUnit& cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + const Pel* curChroma0; + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + Pel* curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int totalOffset[2] = { 0, 0 }; + int count[2] = { 0, 0 }; + + Pel predChroma; + + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; +#if MMLM + if (type & CCP_TYPE_MMLM) + { + if (pu.cccmMultiFilterIdx == 2) + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk.at(pos - 1, -1) + lumaOffset; // W + samples[2] = refLumaBlk.at(pos + 1, -1) + lumaOffset; // E + samples[3] = refLumaBlk1.at(pos, -1) + lumaOffset; // C + samples[4] = refLumaBlk1.at(pos - 1, -1) + lumaOffset; // W + samples[5] = refLumaBlk1.at(pos + 1, -1) + lumaOffset; // E + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(pos - 1, -1) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(pos + 1, -1) + lumaOffset); + samples[9] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[10] = cccmModel[0].bias(); + if ((refLumaBlk.at(pos, -1) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos] - predChroma; + count[1]++; + } + } + } + else if (pu.cccmMultiFilterIdx == 3) + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk.at(pos + 1, -2) + lumaOffset; // EN + samples[2] = refLumaBlk.at(pos - 1, 0) + lumaOffset; // WS + samples[3] = refLumaBlk3.at(pos, -1) + lumaOffset; // C + samples[4] = refLumaBlk3.at(pos + 1, -2) + lumaOffset; // EN + samples[5] = refLumaBlk3.at(pos - 1, 0) + lumaOffset; // WS + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(pos + 1, -2) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(pos - 1, 0) + lumaOffset); + samples[9] = ((-1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[10] = cccmModel[0].bias(); + if ((refLumaBlk.at(pos, -1) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos] - predChroma; + count[1]++; + } + } + } + else + { + THROW("Invalid cccmMultiFilterIdx"); + } + } + else +#endif + { + if (pu.cccmMultiFilterIdx == 2) + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk.at(pos - 1, -1) + lumaOffset; // W + samples[2] = refLumaBlk.at(pos + 1, -1) + lumaOffset; // E + samples[3] = refLumaBlk1.at(pos, -1) + lumaOffset; // C + samples[4] = refLumaBlk1.at(pos - 1, -1) + lumaOffset; // W + samples[5] = refLumaBlk1.at(pos + 1, -1) + lumaOffset; // E + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(pos - 1, -1) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(pos + 1, -1) + lumaOffset); + samples[9] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[10] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + } + else if (pu.cccmMultiFilterIdx == 3) + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk.at(pos + 1, -2) + lumaOffset; // EN + samples[2] = refLumaBlk.at(pos - 1, 0) + lumaOffset; // WS + samples[3] = refLumaBlk3.at(pos, -1) + lumaOffset; // C + samples[4] = refLumaBlk3.at(pos + 1, -2) + lumaOffset; // EN + samples[5] = refLumaBlk3.at(pos - 1, 0) + lumaOffset; // WS + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(pos + 1, -2) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(pos - 1, 0) + lumaOffset); + samples[9] = ((-1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[10] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + } + else + { + THROW("Invalid cccmMultiFilterIdx"); + } + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; +#if MMLM + if (type & CCP_TYPE_MMLM) + { + if (pu.cccmMultiFilterIdx == 2) + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk.at(-2, pos) + lumaOffset; // W + samples[2] = refLumaBlk.at(0, pos) + lumaOffset; // E + samples[3] = refLumaBlk1.at(-1, pos) + lumaOffset; // C + samples[4] = refLumaBlk1.at(-2, pos) + lumaOffset; // W + samples[5] = refLumaBlk1.at(0, pos) + lumaOffset; // E + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(-2, pos) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(0, pos) + lumaOffset); + samples[9] = ((-1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[10] = cccmModel[0].bias(); + if ((refLumaBlk.at(-1, pos) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos * curStride] - predChroma; + count[1]++; + } + } + } + else if (pu.cccmMultiFilterIdx == 3) + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk.at(0, pos - 1) + lumaOffset; // EN + samples[2] = refLumaBlk.at(-2, pos + 1) + lumaOffset; // WS + samples[3] = refLumaBlk3.at(-1, pos) + lumaOffset; // C + samples[4] = refLumaBlk3.at(0, pos - 1) + lumaOffset; // EN + samples[5] = refLumaBlk3.at(-2, pos + 1) + lumaOffset; // WS + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(0, pos - 1) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(-2, pos + 1) + lumaOffset); + samples[9] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[10] = cccmModel[0].bias(); + if ((refLumaBlk.at(-1, pos) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos * curStride] - predChroma; + count[1]++; + } + } + } + else + { + THROW("Invalid cccmMultiFilterIdx"); + } + } + else +#endif + { + if (pu.cccmMultiFilterIdx == 2) + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk.at(-2, pos) + lumaOffset; // W + samples[2] = refLumaBlk.at(0, pos) + lumaOffset; // E + samples[3] = refLumaBlk1.at(-1, pos) + lumaOffset; // C + samples[4] = refLumaBlk1.at(-2, pos) + lumaOffset; // W + samples[5] = refLumaBlk1.at(0, pos) + lumaOffset; // E + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos)) + lumaOffset; + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(-2, pos)) + lumaOffset; + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(0, pos)) + lumaOffset; + samples[9] = ((-1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[10] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + } + else if (pu.cccmMultiFilterIdx == 3) + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk.at(0, pos - 1) + lumaOffset; // EN + samples[2] = refLumaBlk.at(-2, pos + 1) + lumaOffset; // WS + samples[3] = refLumaBlk3.at(-1, pos) + lumaOffset; // C + samples[4] = refLumaBlk3.at(0, pos - 1) + lumaOffset; // EN + samples[5] = refLumaBlk3.at(-2, pos + 1) + lumaOffset; // WS + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(0, pos - 1) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(-2, pos + 1) + lumaOffset); + samples[9] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[10] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + } + else + { + THROW("Invalid cccmMultiFilterIdx"); + } + } + } + + chromaOffset[0] = chromaOffset[1] = 0; + + if (modelNum == 2) + { + if (count[0]) + { + chromaOffset[0] = PU::getMeanValue(totalOffset[0], count[0]); // totalOffset[0] / count[0]; + } + if (count[1]) + { + chromaOffset[1] = PU::getMeanValue(totalOffset[1], count[1]); // totalOffset[1] / count[1]; + } + } + else + { + if (count[0]) + { + chromaOffset[0] = PU::getMeanValue(totalOffset[0], count[0]); // totalOffset[0] / count[0]; + } + } +} +#endif + +#if JVET_AC0147_CCCM_NO_SUBSAMPLING +void IntraPrediction::xNSCccmApplyModelOffset(const PredictionUnit &pu, const ComponentID compId, + const CccmModel<CCCM_NO_SUB_NUM_PARAMS> &cccmModel, int modelId, + int modelThr, PelBuf &piPred, int lumaOffset, int chromaOffset[2]) const +{ + const ClpRng &clpRng(pu.cu->cs->slice->clpRng(compId)); + static Pel samples[CCCM_NO_SUB_NUM_PARAMS]; + + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu); + const int chromaScaleX = getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, pu.cu->slice->getSPS()->getChromaFormatIdc()); + const int chromaScaleY = getChannelTypeScaleY(CHANNEL_TYPE_CHROMA, pu.cu->slice->getSPS()->getChromaFormatIdc()); + const int stepX = 1 << chromaScaleX; + const int stepY = 1 << chromaScaleY; + int offset = modelId == 2 ? chromaOffset[1] : chromaOffset[0]; + + for (int y = 0; y < refLumaBlk.height; y += stepY) + { + for (int x = 0; x < refLumaBlk.width; x += stepX) + { + const Pel *src0 = refLumaBlk.bufAt(x, y); + const Pel *src1 = refLumaBlk.bufAt(x, y + 1); + + if (modelId == 1 && (src0[0] + lumaOffset) > modelThr) // Model 1: Include only samples below or equal to the threshold + { + continue; + } + if (modelId == 2 && (src0[0] + lumaOffset) <= modelThr) // Model 2: Include only samples above the threshold + { + continue; + } + + samples[0] = src0[0] + lumaOffset; + samples[1] = src0[-1] + lumaOffset; + samples[2] = src0[1] + lumaOffset; + samples[3] = src1[0] + lumaOffset; + samples[4] = src1[-1] + lumaOffset; + samples[5] = src1[1] + lumaOffset; + samples[6] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel).nonlinear(src0[0] + lumaOffset); + samples[7] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel).nonlinear(src1[0] + lumaOffset); + samples[8] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel).nonlinear(src0[1] + lumaOffset); + samples[9] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel).nonlinear(src0[-1] + lumaOffset); + samples[10] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel).bias(); + piPred.at(x >> chromaScaleX, y >> chromaScaleY) = + ClipPel<Pel>(const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel).convolve(samples) + offset, clpRng); + } + } +} +void IntraPrediction::xGetUpdatedOffsetNSCCCM(const PredictionUnit &pu, const ComponentID compID, int modelNum, + const CompArea &chromaArea, + CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModel[2], + int modelThr, int lumaOffset, int chromaOffset[]) +{ + static Pel samples[CCCM_NO_SUB_NUM_PARAMS]; + + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu); + const int chromaScaleX = getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, pu.cu->slice->getSPS()->getChromaFormatIdc()); + const int chromaScaleY = getChannelTypeScaleY(CHANNEL_TYPE_CHROMA, pu.cu->slice->getSPS()->getChromaFormatIdc()); + const int stepX = 1 << chromaScaleX; + const int stepY = 1 << chromaScaleY; + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure &cs = *(pu.cs); + const CodingUnit &cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + const Pel *curChroma0; + + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + + Pel *curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int totalOffset[2] = { 0, 0 }; + int count[2] = { 0, 0 }; + + Pel predChroma; + + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; +#if MMLM + if (modelNum == 2) + { + for (int pos = 0, x = 0; pos < cWidth; pos++, x += stepX) + { + const Pel *src0 = refLumaBlk.bufAt(x, -stepY); + const Pel *src1 = refLumaBlk.bufAt(x, -stepY + 1); + samples[0] = src0[0] + lumaOffset; + samples[1] = src0[-1] + lumaOffset; + samples[2] = src0[1] + lumaOffset; + samples[3] = src1[0] + lumaOffset; + samples[4] = src1[-1] + lumaOffset; + samples[5] = src1[1] + lumaOffset; + samples[6] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[0] + lumaOffset); + samples[7] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src1[0] + lumaOffset); + samples[8] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[1] + lumaOffset); + samples[9] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[-1] + lumaOffset); + samples[10] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).bias(); + + if (src0[0] + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos] - predChroma; + count[1]++; + } + } + } + else +#endif + { + for (int pos = 0, x = 0; pos < cWidth; pos++, x += stepX) + { + const Pel *src0 = refLumaBlk.bufAt(x, -stepY); + const Pel *src1 = refLumaBlk.bufAt(x, -stepY + 1); + samples[0] = src0[0] + lumaOffset; + samples[1] = src0[-1] + lumaOffset; + samples[2] = src0[1] + lumaOffset; + samples[3] = src1[0] + lumaOffset; + samples[4] = src1[-1] + lumaOffset; + samples[5] = src1[1] + lumaOffset; + samples[6] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[0] + lumaOffset); + samples[7] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src1[0] + lumaOffset); + samples[8] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[1] + lumaOffset); + samples[9] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[-1] + lumaOffset); + samples[10] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; +#if MMLM + if (modelNum == 2) + { + for (int pos = 0, y = 0; pos < cHeight; pos++, y += stepY) + { + const Pel *src0 = refLumaBlk.bufAt(-stepX, y); + const Pel *src1 = refLumaBlk.bufAt(-stepX, y + 1); + samples[0] = src0[0] + lumaOffset; + samples[1] = src0[-1] + lumaOffset; + samples[2] = src0[1] + lumaOffset; + samples[3] = src1[0] + lumaOffset; + samples[4] = src1[-1] + lumaOffset; + samples[5] = src1[1] + lumaOffset; + samples[6] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[0] + lumaOffset); + samples[7] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src1[0] + lumaOffset); + samples[8] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[1] + lumaOffset); + samples[9] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[-1] + lumaOffset); + samples[10] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).bias(); + + if (src0[0] + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos * curStride] - predChroma; + count[1]++; + } + } + } + else +#endif + { + for (int pos = 0, y = 0; pos < cHeight; pos++, y += stepY) + { + const Pel *src0 = refLumaBlk.bufAt(-stepX, y); + const Pel *src1 = refLumaBlk.bufAt(-stepX, y + 1); + samples[0] = src0[0] + lumaOffset; + samples[1] = src0[-1] + lumaOffset; + samples[2] = src0[1] + lumaOffset; + samples[3] = src1[0] + lumaOffset; + samples[4] = src1[-1] + lumaOffset; + samples[5] = src1[1] + lumaOffset; + samples[6] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[0] + lumaOffset); + samples[7] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src1[0] + lumaOffset); + samples[8] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[1] + lumaOffset); + samples[9] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[-1] + lumaOffset); + samples[10] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).bias(); + + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + } + } + + chromaOffset[0] = chromaOffset[1] = 0; + + if (modelNum == 2) + { + if (count[0]) + { + chromaOffset[0] = PU::getMeanValue(totalOffset[0], count[0]); // totalOffset[0] / count[0]; + } + if (count[1]) + { + chromaOffset[1] = PU::getMeanValue(totalOffset[1], count[1]); // totalOffset[1] / count[1]; + } + } + else + { + if (count[0]) + { + chromaOffset[0] = PU::getMeanValue(totalOffset[0], count[0]); // totalOffset[0] / count[0]; + } + } +} + +int IntraPrediction::xGetCostNSCCCM(const PredictionUnit &pu, const ComponentID compID, int modelNum, + const CompArea &chromaArea, CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModel[2], + int modelThr, int lumaOffset, int chromaOffset[]) +{ + const ClpRng &clpRng(pu.cu->cs->slice->clpRng(compID)); + static Pel samples[CCCM_NO_SUB_NUM_PARAMS]; + + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu); + const int chromaScaleX = getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, pu.cu->slice->getSPS()->getChromaFormatIdc()); + const int chromaScaleY = getChannelTypeScaleY(CHANNEL_TYPE_CHROMA, pu.cu->slice->getSPS()->getChromaFormatIdc()); + const int stepX = 1 << chromaScaleX; + const int stepY = 1 << chromaScaleY; + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure &cs = *(pu.cs); + const CodingUnit &cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + const Pel *curChroma0; + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + + Pel *curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int sad = 0; + + Pel predChroma; + + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; +#if MMLM + if (modelNum == 2) + { + for (int pos = 0, x = 0; pos < cWidth; pos++, x += stepX) + { + const Pel *src0 = refLumaBlk.bufAt(x, -stepY); + const Pel *src1 = refLumaBlk.bufAt(x, -stepY + 1); + samples[0] = src0[0] + lumaOffset; + samples[1] = src0[-1] + lumaOffset; + samples[2] = src0[1] + lumaOffset; + samples[3] = src1[0] + lumaOffset; + samples[4] = src1[-1] + lumaOffset; + samples[5] = src1[1] + lumaOffset; + samples[6] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[0] + lumaOffset); + samples[7] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src1[0] + lumaOffset); + samples[8] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[1] + lumaOffset); + samples[9] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[-1] + lumaOffset); + samples[10] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).bias(); + + if (src0[0] + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } + else +#endif + { + for (int pos = 0, x = 0; pos < cWidth; pos++, x += stepX) + { + const Pel *src0 = refLumaBlk.bufAt(x, -stepY); + const Pel *src1 = refLumaBlk.bufAt(x, -stepY + 1); + samples[0] = src0[0] + lumaOffset; + samples[1] = src0[-1] + lumaOffset; + samples[2] = src0[1] + lumaOffset; + samples[3] = src1[0] + lumaOffset; + samples[4] = src1[-1] + lumaOffset; + samples[5] = src1[1] + lumaOffset; + samples[6] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[0] + lumaOffset); + samples[7] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src1[0] + lumaOffset); + samples[8] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[1] + lumaOffset); + samples[9] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[-1] + lumaOffset); + samples[10] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; +#if MMLM + if (modelNum == 2) + { + for (int pos = 0, y = 0; pos < cHeight; pos++, y += stepY) + { + const Pel *src0 = refLumaBlk.bufAt(-stepX, y); + const Pel *src1 = refLumaBlk.bufAt(-stepX, y + 1); + samples[0] = src0[0] + lumaOffset; + samples[1] = src0[-1] + lumaOffset; + samples[2] = src0[1] + lumaOffset; + samples[3] = src1[0] + lumaOffset; + samples[4] = src1[-1] + lumaOffset; + samples[5] = src1[1] + lumaOffset; + samples[6] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[0] + lumaOffset); + samples[7] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src1[0] + lumaOffset); + samples[8] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[1] + lumaOffset); + samples[9] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[-1] + lumaOffset); + samples[10] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).bias(); + + if (src0[0] + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + else +#endif + { + for (int pos = 0, y = 0; pos < cHeight; pos++, y += stepY) + { + const Pel *src0 = refLumaBlk.bufAt(-stepX, y); + const Pel *src1 = refLumaBlk.bufAt(-stepX, y + 1); + samples[0] = src0[0] + lumaOffset; + samples[1] = src0[-1] + lumaOffset; + samples[2] = src0[1] + lumaOffset; + samples[3] = src1[0] + lumaOffset; + samples[4] = src1[-1] + lumaOffset; + samples[5] = src1[1] + lumaOffset; + samples[6] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[0] + lumaOffset); + samples[7] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src1[0] + lumaOffset); + samples[8] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[1] + lumaOffset); + samples[9] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).nonlinear(src0[-1] + lumaOffset); + samples[10] = const_cast<CccmModel<CCCM_NO_SUB_NUM_PARAMS> &>(cccmModel[0]).bias(); + + predChroma = cccmModel[0].convolve(samples); + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + } + return sad; +} +#endif + +void IntraPrediction::xGetUpdatedOffsetCCLM(const PredictionUnit &pu, const ComponentID compID, + const CompArea &chromaArea, CclmModel &cclmModel, int modelNum, int glmIdc) +{ + int srcStride = 0; + PelBuf temp; + + if (glmIdc > 0) + { + Pel *glmTemp = m_glmTempCb[glmIdc]; + srcStride = 2 * MAX_CU_SIZE + 1; + temp = PelBuf(glmTemp + srcStride + 1, srcStride, Size(chromaArea)); + } + else + { + srcStride = MAX_CU_SIZE + 1; + temp = PelBuf(m_piTemp + srcStride + 1, srcStride, Size(chromaArea)); + } + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure &cs = *(pu.cs); + const CodingUnit &cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + Pel *srcColor0, *curChroma0; + + srcColor0 = temp.bufAt(0, 0); + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + + Pel *curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int totalOffset[2] = { 0, 0 }; + int count[2] = { 0, 0 }; + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; + Pel *src = srcColor0 - srcStride; + if (modelNum == 2) + { + Pel predChroma; + for (int pos = 0; pos < cWidth; pos++) + { + if (src[pos] <= cclmModel.yThres) + { + predChroma = rightShift(cclmModel.a * src[pos], cclmModel.shift) + cclmModel.b; + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + else + { + predChroma = rightShift(cclmModel.a2 * src[pos], cclmModel.shift2) + cclmModel.b2; + totalOffset[1] += curChroma0[pos] - predChroma; + count[1]++; + } + } + } + else + { + for (int pos = 0; pos < cWidth; pos++) + { + Pel predChroma = rightShift(cclmModel.a * src[pos], cclmModel.shift) + cclmModel.b; + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; + Pel *src = srcColor0 - 1; + if (modelNum == 2) + { + Pel predChroma; + for (int pos = 0; pos < cHeight; pos++) + { + if (src[pos * srcStride] <= cclmModel.yThres) + { + predChroma = rightShift(cclmModel.a * src[pos * srcStride], cclmModel.shift) + cclmModel.b; + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + else + { + predChroma = rightShift(cclmModel.a2 * src[pos * srcStride], cclmModel.shift2) + cclmModel.b2; + totalOffset[1] += curChroma0[pos * curStride] - predChroma; + count[1]++; + } + } + } + else + { + for (int pos = 0; pos < cHeight; pos++) + { + Pel predChroma = rightShift(cclmModel.a * src[pos * srcStride], cclmModel.shift) + cclmModel.b; + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + } + } + + if (modelNum == 2) + { + if (count[0]) + { + cclmModel.b += PU::getMeanValue(totalOffset[0], count[0]); // totalOffset[0] / count[0]; + } + if (count[1]) + { + cclmModel.b2 += PU::getMeanValue(totalOffset[1], count[1]); //totalOffset[1] / count[1]; + } + } + else + { + if (count[0]) + { + cclmModel.b += PU::getMeanValue(totalOffset[0], count[0]); //totalOffset[0] / count[0]; + } + } +} + +int IntraPrediction::xGetCostCCLM(const PredictionUnit &pu, const ComponentID compID, const CompArea &chromaArea,CclmModel &cclmModel, int modelNum, int glmIdc) +{ + int srcStride = 0; + PelBuf temp; + + if (glmIdc > 0) + { + Pel *glmTemp = m_glmTempCb[glmIdc]; + srcStride = 2 * MAX_CU_SIZE + 1; + temp = PelBuf(glmTemp + srcStride + 1, srcStride, Size(chromaArea)); + } + else + { + srcStride = MAX_CU_SIZE + 1; + temp = PelBuf(m_piTemp + srcStride + 1, srcStride, Size(chromaArea)); + } + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure &cs = *(pu.cs); + const CodingUnit &cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + Pel *srcColor0, *curChroma0; + + srcColor0 = temp.bufAt(0, 0); + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + + Pel *curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int sad = 0; + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; + Pel *src = srcColor0 - srcStride; + if (modelNum == 2) + { + Pel predChroma; + for (int pos = 0; pos < cWidth; pos++) + { + if (src[pos] <= cclmModel.yThres) + { + predChroma = rightShift(cclmModel.a * src[pos], cclmModel.shift) + cclmModel.b; + } + else + { + predChroma = rightShift(cclmModel.a2 * src[pos], cclmModel.shift2) + cclmModel.b2; + } + sad += abs( curChroma0[pos] - predChroma); + } + } + else + { + for (int pos = 0; pos < cWidth; pos++) + { + Pel predChroma = rightShift(cclmModel.a * src[pos], cclmModel.shift) + cclmModel.b; + sad += abs(curChroma0[pos] - predChroma); + } + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; + Pel *src = srcColor0 - 1; + if (modelNum == 2) + { + Pel predChroma; + for (int pos = 0; pos < cHeight; pos++) + { + if (src[pos * srcStride] <= cclmModel.yThres) + { + predChroma = rightShift(cclmModel.a * src[pos * srcStride], cclmModel.shift) + cclmModel.b; + + } + else + { + predChroma = rightShift(cclmModel.a2 * src[pos * srcStride], cclmModel.shift2) + cclmModel.b2; + } + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + else + { + for (int pos = 0; pos < cHeight; pos++) + { + Pel predChroma = rightShift(cclmModel.a * src[pos * srcStride], cclmModel.shift) + cclmModel.b; + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + } + return sad; +} + +void IntraPrediction::xGetUpdatedOffsetCCCM(const PredictionUnit &pu, const ComponentID compID, int modelNum, + const CompArea &chromaArea, CccmModel<CCCM_NUM_PARAMS> cccmModel[2], + int modelThr, int lumaOffset, int chromaOffset[], int type, + int refSizeX, int refSizeY) +{ + int srcStride = 0; + + CHECK(compID != chromaArea.compID, "Invalid component ID"); + + static Pel samples[CCCM_NUM_PARAMS]; + + CPelBuf temp = xCccmGetLumaPuBuf(pu); + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure &cs = *(pu.cs); + const CodingUnit &cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + const Pel *srcColor0, *curChroma0; + + srcColor0 = temp.bufAt(0, 0); + srcStride = temp.stride; + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + + Pel *curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int totalOffset[2] = { 0, 0 }; + int count[2] = { 0, 0 }; + + Pel predChroma; + + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; + const Pel *src = srcColor0 - srcStride; +#if MMLM + if (modelNum == 2) + { + if (type & CCP_TYPE_CCCM) + { + for (int pos = 0; pos < cWidth; pos++, src++) + { + samples[0] = *src + lumaOffset; // C + samples[1] = *(src - srcStride) + lumaOffset; // N + samples[2] = *(src + srcStride) + lumaOffset; // S + samples[3] = *(src - 1) + lumaOffset; // W + samples[4] = *(src + 1) + lumaOffset; // E + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + if (*src + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos] - predChroma; + count[1]++; + } + } + } +#if JVET_AC0054_GLCCCM + else if (type & CCP_TYPE_GLCCCM) + { + for (int pos = 0; pos < cWidth; pos++, src++) + { + samples[0] = *src + lumaOffset; // C + samples[1] = (2 * (*(src - srcStride)) + (*(src - 1 - srcStride)) + (*(src - srcStride + 1))) + - (2 * (*(src + srcStride)) + (*(src - 1 + srcStride)) + (*(src + srcStride + 1))); // Vertical gradient + samples[2] = (2 * (*(src - 1)) + (*(src - 1 - srcStride)) + (*(src - 1 + srcStride))) + - (2 * (*(src + 1)) + (*(src + 1 - srcStride)) + (*(src + 1 + srcStride))); // Horizontal gradient + samples[3] = (( -1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[4] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + if (*src + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos] - predChroma; + count[1]++; + } + } + } + else + { + THROW("Invalid type"); + } +#endif + } + else +#endif + { + if (type & CCP_TYPE_CCCM) + { + for (int pos = 0; pos < cWidth; pos++, src++) + { + samples[0] = *src + lumaOffset; // C + samples[1] = *(src - srcStride) + lumaOffset; // N + samples[2] = *(src + srcStride) + lumaOffset; // S + samples[3] = *(src - 1) + lumaOffset; // W + samples[4] = *(src + 1) + lumaOffset; // E + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + } +#if JVET_AC0054_GLCCCM + else if (type & CCP_TYPE_GLCCCM) + { + for (int pos = 0; pos < cWidth; pos++, src++) + { + samples[0] = *src + lumaOffset; // C + samples[1] = (2 * (*(src - srcStride)) + (*(src - 1 - srcStride)) + (*(src - srcStride + 1))) + - (2 * (*(src + srcStride)) + (*(src - 1 + srcStride)) + (*(src + srcStride + 1))); // Vertical gradient + samples[2] = (2 * (*(src - 1)) + (*(src - 1 - srcStride)) + (*(src - 1 + srcStride))) + - (2 * (*(src + 1)) + (*(src + 1 - srcStride)) + (*(src + 1 + srcStride))); // Horizontal gradient + samples[3] = (( -1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[4] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos] - predChroma; + count[0]++; + } + } + else + { + THROW("Invalid type"); + } +#endif + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; + const Pel *src = srcColor0 - 1; +#if MMLM + if (modelNum == 2) + { + if (type & CCP_TYPE_CCCM) + { + for (int pos = 0; pos < cHeight; pos++, src += srcStride) + { + samples[0] = *src + lumaOffset; // C + samples[1] = *(src - srcStride) + lumaOffset; // N + samples[2] = *(src + srcStride) + lumaOffset; // S + samples[3] = *(src - 1) + lumaOffset; // W + samples[4] = *(src + 1) + lumaOffset; // E + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + if (*src + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos * curStride] - predChroma; + count[1]++; + } + } + } +#if JVET_AC0054_GLCCCM + else if (type & CCP_TYPE_GLCCCM) + { + for (int pos = 0; pos < cHeight; pos++, src += srcStride) + { + samples[0] = *src + lumaOffset; // C + samples[1] = (2 * (*(src - srcStride)) + (*(src - 1 - srcStride)) + (*(src - srcStride + 1))) + - (2 * (*(src + srcStride)) + (*(src - 1 + srcStride)) + (*(src + srcStride + 1))); // Vertical gradient + samples[2] = (2 * (*(src - 1)) + (*(src - 1 - srcStride)) + (*(src - 1 + srcStride))) + - (2 * (*(src + 1)) + (*(src + 1 - srcStride)) + (*(src + 1 + srcStride))); // Horizontal gradient + samples[3] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[4] = (( -1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + if (*src + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + else + { + predChroma = cccmModel[1].convolve(samples); + totalOffset[1] += curChroma0[pos * curStride] - predChroma; + count[1]++; + } + } + } + else + { + THROW("Invalid type"); + } +#endif + } + else +#endif + { + if (type & CCP_TYPE_CCCM) + { + for (int pos = 0; pos < cHeight; pos++, src += srcStride) + { + samples[0] = *src + lumaOffset; // C + samples[1] = *(src - srcStride) + lumaOffset; // N + samples[2] = *(src + srcStride) + lumaOffset; // S + samples[3] = *(src - 1) + lumaOffset; // W + samples[4] = *(src + 1) + lumaOffset; // E + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + } +#if JVET_AC0054_GLCCCM + else if (type & CCP_TYPE_GLCCCM) + { + for (int pos = 0; pos < cHeight; pos++, src += srcStride) + { + samples[0] = *src + lumaOffset; // C + samples[1] = (2 * (*(src - srcStride)) + (*(src - 1 - srcStride)) + (*(src - srcStride + 1))) + - (2 * (*(src + srcStride)) + (*(src - 1 + srcStride)) + (*(src + srcStride + 1))); // Vertical gradient + samples[2] = (2 * (*(src - 1)) + (*(src - 1 - srcStride)) + (*(src - 1 + srcStride))) + - (2 * (*(src + 1)) + (*(src + 1 - srcStride)) + (*(src + 1 + srcStride))); // Horizontal gradient + samples[3] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[4] = (( -1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples); + totalOffset[0] += curChroma0[pos * curStride] - predChroma; + count[0]++; + } + } + else + { + THROW("Invalid type"); + } +#endif + } + } + + chromaOffset[0] = chromaOffset[1] = 0; + + if (modelNum == 2) + { + if (count[0]) + { + chromaOffset[0] = PU::getMeanValue(totalOffset[0], count[0]); // totalOffset[0] / count[0]; + } + if (count[1]) + { + chromaOffset[1] = PU::getMeanValue(totalOffset[1], count[1]); // totalOffset[1] / count[1]; + } + } + else + { + if (count[0]) + { + chromaOffset[0] = PU::getMeanValue(totalOffset[0], count[0]); // totalOffset[0] / count[0]; + } + } +} +int IntraPrediction::xGetCostCCCM(const PredictionUnit &pu, const ComponentID compID, int modelNum, + const CompArea &chromaArea, CccmModel<CCCM_NUM_PARAMS> cccmModel[2], + int modelThr, int lumaOffset, int chromaOffset[], int type, int refSizeX, int refSizeY) +{ + int srcStride = 0; + const ClpRng &clpRng(pu.cu->cs->slice->clpRng(compID)); + + CHECK(compID != chromaArea.compID, "Invalid component ID"); + + static Pel samples[CCCM_NUM_PARAMS]; + + CPelBuf temp = xCccmGetLumaPuBuf(pu); + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure &cs = *(pu.cs); + const CodingUnit &cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + const Pel *srcColor0, *curChroma0; + + srcColor0 = temp.bufAt(0, 0); + srcStride = temp.stride; + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + + Pel *curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int sad = 0; + + Pel predChroma; + + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; + const Pel *src = srcColor0 - srcStride; +#if MMLM + if (type & CCP_TYPE_MMLM) + { + if (type & CCP_TYPE_CCCM) + { + for (int pos = 0; pos < cWidth; pos++, src++) + { + samples[0] = *src + lumaOffset; // C + samples[1] = *(src - srcStride) + lumaOffset; // N + samples[2] = *(src + srcStride) + lumaOffset; // S + samples[3] = *(src - 1) + lumaOffset; // W + samples[4] = *(src + 1) + lumaOffset; // E + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + if (*src + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } +#if JVET_AC0054_GLCCCM + else if (type & CCP_TYPE_GLCCCM) + { + + for (int pos = 0; pos < cWidth; pos++, src++) + { + samples[0] = *src + lumaOffset; // C + samples[1] = (2 * (*(src - srcStride)) + (*(src - 1 - srcStride)) + (*(src - srcStride + 1))) + - (2 * (*(src + srcStride)) + (*(src - 1 + srcStride)) + (*(src + srcStride + 1))); // Vertical gradient + samples[2] = (2 * (*(src - 1)) + (*(src - 1 - srcStride)) + (*(src - 1 + srcStride))) + - (2 * (*(src + 1)) + (*(src + 1 - srcStride)) + (*(src + 1 + srcStride))); // Horizontal gradient + samples[3] = (( -1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[4] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + if (*src + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + + } + else + { + THROW("Invalid type"); + } +#endif + } + else +#endif + { + if (type & CCP_TYPE_CCCM) + { + for (int pos = 0; pos < cWidth; pos++, src++) + { + samples[0] = *src + lumaOffset; // C + samples[1] = *(src - srcStride) + lumaOffset; // N + samples[2] = *(src + srcStride) + lumaOffset; // S + samples[3] = *(src - 1) + lumaOffset; // W + samples[4] = *(src + 1) + lumaOffset; // E + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } +#if JVET_AC0054_GLCCCM + else if (type & CCP_TYPE_GLCCCM) + { + for (int pos = 0; pos < cWidth; pos++, src++) + { + samples[0] = *src + lumaOffset; // C + samples[1] = (2 * (*(src - srcStride)) + (*(src - 1 - srcStride)) + (*(src - srcStride + 1))) + - (2 * (*(src + srcStride)) + (*(src - 1 + srcStride)) + (*(src + srcStride + 1))); // Vertical gradient + samples[2] = (2 * (*(src - 1)) + (*(src - 1 - srcStride)) + (*(src - 1 + srcStride))) + - (2 * (*(src + 1)) + (*(src + 1 - srcStride)) + (*(src + 1 + srcStride))); // Horizontal gradient + samples[3] = (( -1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[4] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } + else + { + THROW("Invalid type"); + } +#endif + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; + const Pel *src = srcColor0 - 1; +#if MMLM + if (type & CCP_TYPE_MMLM) + { + if (type & CCP_TYPE_CCCM) + { + for (int pos = 0; pos < cHeight; pos++, src += srcStride) + { + samples[0] = *src + lumaOffset; // C + samples[1] = *(src - srcStride) + lumaOffset; // N + samples[2] = *(src + srcStride) + lumaOffset; // S + samples[3] = *(src - 1) + lumaOffset; // W + samples[4] = *(src + 1) + lumaOffset; // E + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + if (*src + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } +#if JVET_AC0054_GLCCCM + else if (type & CCP_TYPE_GLCCCM) + { + for (int pos = 0; pos < cHeight; pos++, src += srcStride) + { + samples[0] = *src + lumaOffset; // C + samples[1] = (2 * (*(src - srcStride)) + (*(src - 1 - srcStride)) + (*(src - srcStride + 1))) + - (2 * (*(src + srcStride)) + (*(src - 1 + srcStride)) + (*(src + srcStride + 1))); // Vertical gradient + samples[2] = (2 * (*(src - 1)) + (*(src - 1 - srcStride)) + (*(src - 1 + srcStride))) + - (2 * (*(src + 1)) + (*(src + 1 - srcStride)) + (*(src + 1 + srcStride))); // Horizontal gradient + samples[3] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[4] = (( -1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + if (*src + lumaOffset <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + else + { + THROW("Invalid type"); + } +#endif + } + else +#endif + { + if (type & CCP_TYPE_CCCM) + { + for (int pos = 0; pos < cHeight; pos++, src += srcStride) + { + samples[0] = *src + lumaOffset; // C + samples[1] = *(src - srcStride) + lumaOffset; // N + samples[2] = *(src + srcStride) + lumaOffset; // S + samples[3] = *(src - 1) + lumaOffset; // W + samples[4] = *(src + 1) + lumaOffset; // E + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } +#if JVET_AC0054_GLCCCM + else if (type & CCP_TYPE_GLCCCM) + { + for (int pos = 0; pos < cHeight; pos++, src += srcStride) + { + samples[0] = *src + lumaOffset; // C + samples[1] = (2 * (*(src - srcStride)) + (*(src - 1 - srcStride)) + (*(src - srcStride + 1))) + - (2 * (*(src + srcStride)) + (*(src - 1 + srcStride)) + (*(src + srcStride + 1))); // Vertical gradient + samples[2] = (2 * (*(src - 1)) + (*(src - 1 - srcStride)) + (*(src - 1 + srcStride))) + - (2 * (*(src + 1)) + (*(src + 1 - srcStride)) + (*(src + 1 + srcStride))); // Horizontal gradient + samples[3] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[4] = (( -1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[5] = cccmModel[0].nonlinear(*src + lumaOffset); + samples[6] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + else + { + THROW("Invalid type"); + } +#endif + } + } + return sad; +} + +#if JVET_AD0202_CCCM_MDF +int IntraPrediction::xGetCostMFCCCM1(const PredictionUnit& pu, const ComponentID compID, int modelNum, + const CompArea& chromaArea, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModel[2], + int modelThr, int lumaOffset, int chromaOffset[], int type, int refSizeX, int refSizeY) +{ + CHECK(compID != chromaArea.compID, "Invalid component ID"); + + const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compID)); + static Pel samples[CCCM_MULTI_PRED_FILTER_NUM_PARAMS]; + + CPelBuf refLumaBlk1, refLumaBlk2, refLumaBlk3; + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu, 0, 3, &refLumaBlk1, &refLumaBlk3, &refLumaBlk2); + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure& cs = *(pu.cs); + const CodingUnit& cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + const Pel* curChroma0; + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + + Pel* curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int sad = 0; + + Pel predChroma; + + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; +#if MMLM + if (type & CCP_TYPE_MMLM) + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk1.at(pos, -1) + lumaOffset; // W + samples[2] = refLumaBlk2.at(pos, -1) + lumaOffset; // E + samples[3] = refLumaBlk3.at(pos, -1) + lumaOffset; + samples[4] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[5] = cccmModel[0].nonlinear(refLumaBlk1.at(pos, -1) + lumaOffset); + samples[6] = cccmModel[0].nonlinear(refLumaBlk2.at(pos, -1) + lumaOffset); + samples[7] = ((-1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[8] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[9] = cccmModel[0].bias(); + if ((refLumaBlk.at(pos, -1) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } + else +#endif + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk1.at(pos, -1) + lumaOffset; // W + samples[2] = refLumaBlk2.at(pos, -1) + lumaOffset; // E + samples[3] = refLumaBlk3.at(pos, -1) + lumaOffset; + samples[4] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[5] = cccmModel[0].nonlinear(refLumaBlk1.at(pos, -1) + lumaOffset); + samples[6] = cccmModel[0].nonlinear(refLumaBlk2.at(pos, -1) + lumaOffset); + samples[7] = ((-1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[8] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[9] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; +#if MMLM + if (type & CCP_TYPE_MMLM) + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk1.at(-1, pos) + lumaOffset; // W + samples[2] = refLumaBlk2.at(-1, pos) + lumaOffset; // E + samples[3] = refLumaBlk3.at(-1, pos) + lumaOffset; + samples[4] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos) + lumaOffset); + samples[5] = cccmModel[0].nonlinear(refLumaBlk1.at(-1, pos) + lumaOffset); + samples[6] = cccmModel[0].nonlinear(refLumaBlk2.at(-1, pos) + lumaOffset); + samples[7] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[8] = ((-1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[9] = cccmModel[0].bias(); + if ((refLumaBlk.at(-1, pos) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + else +#endif + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk1.at(-1, pos) + lumaOffset; // W + samples[2] = refLumaBlk2.at(-1, pos) + lumaOffset; // E + samples[3] = refLumaBlk3.at(-1, pos) + lumaOffset; + samples[4] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos) + lumaOffset); + samples[5] = cccmModel[0].nonlinear(refLumaBlk1.at(-1, pos) + lumaOffset); + samples[6] = cccmModel[0].nonlinear(refLumaBlk2.at(-1, pos) + lumaOffset); + samples[7] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[8] = ((-1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[9] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + } + return sad; +} + +int IntraPrediction::xGetCostMFCCCM23(const PredictionUnit& pu, const ComponentID compID, int modelNum, + const CompArea& chromaArea, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModel[2], + int modelThr, int lumaOffset, int chromaOffset[], int type, int refSizeX, int refSizeY) +{ + CHECK(compID != chromaArea.compID, "Invalid component ID"); + + const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compID)); + static Pel samples[CCCM_MULTI_PRED_FILTER_NUM_PARAMS2]; + + CPelBuf refLumaBlk1, refLumaBlk3; + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu, 0, 2, &refLumaBlk1, &refLumaBlk3); + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure& cs = *(pu.cs); + const CodingUnit& cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + const Pel* curChroma0; + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + Pel* curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int sad = 0; + + Pel predChroma; + + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; +#if MMLM + if (type & CCP_TYPE_MMLM) + { + if (pu.cccmMultiFilterIdx == 2) + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk.at(pos - 1, -1) + lumaOffset; // W + samples[2] = refLumaBlk.at(pos + 1, -1) + lumaOffset; // E + samples[3] = refLumaBlk1.at(pos, -1) + lumaOffset; // C + samples[4] = refLumaBlk1.at(pos - 1, -1) + lumaOffset; // W + samples[5] = refLumaBlk1.at(pos + 1, -1) + lumaOffset; // E + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(pos - 1, -1) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(pos + 1, -1) + lumaOffset); + samples[9] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[10] = cccmModel[0].bias(); + if ((refLumaBlk.at(pos, -1) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } + else if(pu.cccmMultiFilterIdx == 3) + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk.at(pos + 1, -2) + lumaOffset; // EN + samples[2] = refLumaBlk.at(pos - 1, 0) + lumaOffset; // WS + samples[3] = refLumaBlk3.at(pos, -1) + lumaOffset; // C + samples[4] = refLumaBlk3.at(pos + 1, -2) + lumaOffset; // EN + samples[5] = refLumaBlk3.at(pos - 1, 0) + lumaOffset; // WS + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(pos + 1, -2) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(pos - 1, 0) + lumaOffset); + samples[9] = ((-1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[10] = cccmModel[0].bias(); + if ((refLumaBlk.at(pos, -1) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } + } + else +#endif + { + if (pu.cccmMultiFilterIdx == 2) + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk.at(pos - 1, -1) + lumaOffset; // W + samples[2] = refLumaBlk.at(pos + 1, -1) + lumaOffset; // E + samples[3] = refLumaBlk1.at(pos, -1) + lumaOffset; // C + samples[4] = refLumaBlk1.at(pos - 1, -1) + lumaOffset; // W + samples[5] = refLumaBlk1.at(pos + 1, -1) + lumaOffset; // E + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(pos - 1, -1) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(pos + 1, -1) + lumaOffset); + samples[9] = ((pos + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[10] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } + else // if (pu.cccmMultiFilterIdx == 3) + { + for (int pos = 0; pos < cWidth; pos++) + { + samples[0] = refLumaBlk.at(pos, -1) + lumaOffset; // C + samples[1] = refLumaBlk.at(pos + 1, -2) + lumaOffset; // EN + samples[2] = refLumaBlk.at(pos - 1, 0) + lumaOffset; // WS + samples[3] = refLumaBlk3.at(pos, -1) + lumaOffset; // C + samples[4] = refLumaBlk3.at(pos + 1, -2) + lumaOffset; // EN + samples[5] = refLumaBlk3.at(pos - 1, 0) + lumaOffset; // WS + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(pos, -1) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(pos + 1, -2) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(pos - 1, 0) + lumaOffset); + samples[9] = ((-1 + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[10] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; +#if MMLM + if (type & CCP_TYPE_MMLM) + { + if (pu.cccmMultiFilterIdx == 2) + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk.at(-2, pos) + lumaOffset; // W + samples[2] = refLumaBlk.at( 0, pos) + lumaOffset; // E + samples[3] = refLumaBlk1.at(-1, pos) + lumaOffset; // C + samples[4] = refLumaBlk1.at(-2, pos) + lumaOffset; // W + samples[5] = refLumaBlk1.at( 0, pos) + lumaOffset; // E + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(-2, pos) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at( 0, pos) + lumaOffset); + samples[9] = ((-1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[10] = cccmModel[0].bias(); + if ((refLumaBlk.at(-1, pos) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + else // if (pu.cccmMultiFilterIdx == 3) + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk.at( 0, pos - 1) + lumaOffset; // EN + samples[2] = refLumaBlk.at(-2, pos + 1) + lumaOffset; // WS + samples[3] = refLumaBlk3.at(-1, pos) + lumaOffset; // C + samples[4] = refLumaBlk3.at( 0, pos - 1) + lumaOffset; // EN + samples[5] = refLumaBlk3.at(-2, pos + 1) + lumaOffset; // WS + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at( 0, pos - 1) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(-2, pos + 1) + lumaOffset); + samples[9] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[10] = cccmModel[0].bias(); + if ((refLumaBlk.at(-1, pos) + lumaOffset) <= modelThr) + { + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + } + else + { + predChroma = cccmModel[1].convolve(samples) + chromaOffset[1]; + } + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + } + else +#endif + { + if (pu.cccmMultiFilterIdx == 2) + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk.at(-2, pos) + lumaOffset; // W + samples[2] = refLumaBlk.at( 0, pos) + lumaOffset; // E + samples[3] = refLumaBlk1.at(-1, pos) + lumaOffset; // C + samples[4] = refLumaBlk1.at(-2, pos) + lumaOffset; // W + samples[5] = refLumaBlk1.at( 0, pos) + lumaOffset; // E + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos)) + lumaOffset; + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at(-2, pos)) + lumaOffset; + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at( 0, pos)) + lumaOffset; + samples[9] = ((-1 + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate + samples[10] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + else // if (pu.cccmMultiFilterIdx == 3) + { + for (int pos = 0; pos < cHeight; pos++) + { + samples[0] = refLumaBlk.at(-1, pos) + lumaOffset; // C + samples[1] = refLumaBlk.at( 0, pos - 1) + lumaOffset; // EN + samples[2] = refLumaBlk.at(-2, pos + 1) + lumaOffset; // WS + samples[3] = refLumaBlk3.at(-1, pos) + lumaOffset; // C + samples[4] = refLumaBlk3.at( 0, pos - 1) + lumaOffset; // EN + samples[5] = refLumaBlk3.at(-2, pos + 1) + lumaOffset; // WS + samples[6] = cccmModel[0].nonlinear(refLumaBlk.at(-1, pos) + lumaOffset); + samples[7] = cccmModel[0].nonlinear(refLumaBlk.at( 0, pos - 1) + lumaOffset); + samples[8] = cccmModel[0].nonlinear(refLumaBlk.at(-2, pos + 1) + lumaOffset); + samples[9] = ((pos + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate + samples[10] = cccmModel[0].bias(); + predChroma = cccmModel[0].convolve(samples) + chromaOffset[0]; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + } + } + return sad; +} +#endif + +void IntraPrediction::xGetUpdatedOffsetGLM(const PredictionUnit &pu, const ComponentID compID, + const CompArea &chromaArea, CccmModel<GLM_NUM_PARAMS> &glmModel, int glmIdc, + int lumaOffset, int &chromaOffset) +{ + CHECK(compID != chromaArea.compID, "Invalid component ID"); + + static Pel samples[GLM_NUM_PARAMS]; + + CPelBuf refLumaBlk = xGlmGetGradPuBuf(pu, chromaArea, 0); + CPelBuf refGradBlk = xGlmGetGradPuBuf(pu, chromaArea, glmIdc); + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure &cs = *(pu.cs); + const CodingUnit &cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + const Pel *srcColor0, *srcColor1, *curChroma0; + + srcColor0 = refGradBlk.bufAt(0, 0); + int srcStride0 = refGradBlk.stride; + srcColor1 = refLumaBlk.bufAt(0, 0); + int srcStride1 = refLumaBlk.stride; + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + + Pel *curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int totalOffset = 0; + int count = 0; + + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; + const Pel *src0 = srcColor0 - srcStride0; + const Pel *src1 = srcColor1 - srcStride1; + + { + for (int pos = 0; pos < cWidth; pos++, src0++, src1++) + { + samples[0] = *src0; // luma gradient + samples[1] = *src1 + lumaOffset; // luma value + samples[2] = glmModel.bias(); + + Pel predChroma = glmModel.convolve(samples); + totalOffset += curChroma0[pos] - predChroma; + count++; + } + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; + + const Pel *src0 = srcColor0 - 1; + const Pel *src1 = srcColor1 - 1; + + for (int pos = 0; pos < cHeight; pos++, src0 += srcStride0, src1 += srcStride1) + { + samples[0] = *src0; // luma gradient + samples[1] = *src1 + lumaOffset; // luma value + samples[2] = glmModel.bias(); + + Pel predChroma = glmModel.convolve(samples); + totalOffset += curChroma0[pos * curStride] - predChroma; + count++; + } + } + + chromaOffset = 0; + + if (count) + { + chromaOffset = PU::getMeanValue(totalOffset, count); // totalOffset / count; + } +} +int IntraPrediction::xGetCostGLM(const PredictionUnit &pu, const ComponentID compID, const CompArea &chromaArea, + CccmModel<GLM_NUM_PARAMS> &glmModel, int glmIdc, int lumaOffset, int &chromaOffset) +{ + const ClpRng &clpRng(pu.cu->cs->slice->clpRng(compID)); + CHECK(compID != chromaArea.compID, "Invalid component ID"); + + static Pel samples[GLM_NUM_PARAMS]; + + CPelBuf refLumaBlk = xGlmGetGradPuBuf(pu, chromaArea, 0); + CPelBuf refGradBlk = xGlmGetGradPuBuf(pu, chromaArea, glmIdc); + + const SizeType cWidth = chromaArea.width; + const SizeType cHeight = chromaArea.height; + + CodingStructure &cs = *(pu.cs); + const CodingUnit &cu = *(pu.cu); + + const bool aboveAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(0, -1), toChannelType(compID)) ? true : false; + const bool leftAvailable = cu.cs->getCU(cu.blocks[compID].pos().offset(-1, 0), toChannelType(compID)) ? true : false; + + const Pel *srcColor0, *srcColor1, *curChroma0; + + srcColor0 = refGradBlk.bufAt(0, 0); + int srcStride0 = refGradBlk.stride; + srcColor1 = refLumaBlk.bufAt(0, 0); + int srcStride1 = refLumaBlk.stride; + + PelBuf chromaReco = cs.picture->getRecoBuf(chromaArea); + + Pel *curChromaBuf = chromaReco.buf; + const int curStride = chromaReco.stride; + + int sad = 0; + + if (aboveAvailable) + { + curChroma0 = curChromaBuf - curStride; + const Pel *src0 = srcColor0 - srcStride0; + const Pel *src1 = srcColor1 - srcStride1; + + { + for (int pos = 0; pos < cWidth; pos++, src0++, src1++) + { + samples[0] = *src0; // luma gradient + samples[1] = *src1 + lumaOffset; // luma value + samples[2] = glmModel.bias(); + + Pel predChroma = glmModel.convolve(samples) + chromaOffset; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos] - predChroma); + } + } + } + + if (leftAvailable) + { + curChroma0 = curChromaBuf - 1; + + const Pel *src0 = srcColor0 - 1; + const Pel *src1 = srcColor1 - 1; + + for (int pos = 0; pos < cHeight; pos++, src0 += srcStride0, src1 += srcStride1) + { + samples[0] = *src0; // luma gradient + samples[1] = *src1 + lumaOffset; // luma value + samples[2] = glmModel.bias(); + + Pel predChroma = glmModel.convolve(samples) + chromaOffset; + predChroma = ClipPel<Pel>(predChroma, clpRng); + sad += abs(curChroma0[pos * curStride] - predChroma); + } + } + + return sad; +} +void IntraPrediction::xCclmApplyModel(const PredictionUnit &pu, const ComponentID compId, + CccmModel<CCCM_NUM_PARAMS> &cccmModel, int modelId, int modelThr, + PelBuf &piPred) const +{ + const ClpRng &clpRng(pu.cu->cs->slice->clpRng(compId)); + static Pel samples[CCCM_NUM_PARAMS]; + + CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu); + + for (int y = 0; y < refLumaBlk.height; y++) + { + for (int x = 0; x < refLumaBlk.width; x++) + { + if (modelId == 1 && refLumaBlk.at(x, y) > modelThr) // Model 1: Include only samples below or equal to the threshold + { + continue; + } + if (modelId == 2 && refLumaBlk.at(x, y) <= modelThr) // Model 2: Include only samples above the threshold + { + continue; + } + samples[0] = refLumaBlk.at(x, y); // C + samples[1] = cccmModel.bias(); + + piPred.at(x, y) = ClipPel<Pel>(Pel((cccmModel.params[0] * samples[0] + cccmModel.params[1] * samples[1] + CCCM_DECIM_ROUND) >> CCCM_DECIM_BITS), clpRng); + } + } +} + +void IntraPrediction::reorderCCPCandidates(const PredictionUnit &pu, CCPModelCandidate candList[], int reorderlistSize) +{ + int candCost[MAX_CCP_CAND_LIST_SIZE]; + for (int i = 0; i < reorderlistSize; i++) + { + candCost[i] = xGetOneCCPCandCost(pu, candList[i]); + } + + //Inserting sorting + for (int i = 1; i < reorderlistSize; i++) + { + for (int j = 0; j < i; j++) + { + if (candCost[i] < candCost[j]) + { + CCPModelCandidate tmpCand = candList[i]; + int tmpCost = candCost[i]; + for (int k = i; k > j; k--) + { + candList[k] = candList[k - 1]; + candCost[k] = candCost[k - 1]; + } + candList[j] = tmpCand; + candCost[j] = tmpCost; + break; + } + } + } +} + +int IntraPrediction::xGetOneCCPCandCost(const PredictionUnit &pu, CCPModelCandidate &ccpCand) +{ + CompArea chromaArea = pu.Cb(); + int cost = 0; + const int modelNum = (ccpCand.type & CCP_TYPE_MMLM) ? 2 : 1; + const int bitDepth = pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA); + int offsetCb[2] = { 0, 0 }; + int offsetCr[2] = { 0, 0 }; + + CHECK(ccpCand.type == CCP_TYPE_NONE, "CCP model with no type") + { + if (ccpCand.type & (CCP_TYPE_CCCM | CCP_TYPE_GLCCCM)) + { +#if JVET_AB0174_CCCM_DIV_FREE + int lumaOffset = m_cccmLumaOffset - ccpCand.lumaOffset; +#else + int lumaOffset = 0; +#endif + int refSizeX = ccpCand.corOffX; + int refSizeY = ccpCand.corOffY; + + CccmModel<CCCM_NUM_PARAMS> cccmModelCb[2] = { CccmModel<CCCM_NUM_PARAMS>(bitDepth), CccmModel<CCCM_NUM_PARAMS>(bitDepth) }; + CccmModel<CCCM_NUM_PARAMS> cccmModelCr[2] = { CccmModel<CCCM_NUM_PARAMS>(bitDepth), CccmModel<CCCM_NUM_PARAMS>(bitDepth) }; + + PU::ccpParamsToCccmModel(ccpCand, cccmModelCb, cccmModelCr); + + cost += xGetCostCCCM(pu, COMPONENT_Cb, modelNum, pu.Cb(), cccmModelCb, ccpCand.yThres, lumaOffset, offsetCb, ccpCand.type, refSizeX, refSizeY); + cost += xGetCostCCCM(pu, COMPONENT_Cr, modelNum, pu.Cr(), cccmModelCr, ccpCand.yThres, lumaOffset, offsetCr, ccpCand.type, refSizeX, refSizeY); + } +#if JVET_AD0202_CCCM_MDF + else if (ccpCand.type & (CCP_TYPE_MDFCCCM)) + { + const_cast<PredictionUnit&>(pu).cccmMultiFilterIdx = ccpCand.cccmMultiFilterIdx; +#if JVET_AB0174_CCCM_DIV_FREE + int lumaOffset = m_cccmLumaOffset - ccpCand.lumaOffset; +#else + int lumaOffset = 0; +#endif + int refSizeX = ccpCand.corOffX; + int refSizeY = ccpCand.corOffY; + + if (ccpCand.cccmMultiFilterIdx == 1) + { + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCb[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(bitDepth), CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(bitDepth) }; + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCr[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(bitDepth), CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(bitDepth) }; + + PU::ccpParamsToCccmModel(ccpCand, cccmModelCb, cccmModelCr); + + cost += xGetCostMFCCCM1(pu, COMPONENT_Cb, modelNum, pu.Cb(), cccmModelCb, ccpCand.yThres, lumaOffset, offsetCb, ccpCand.type, refSizeX, refSizeY); + cost += xGetCostMFCCCM1(pu, COMPONENT_Cr, modelNum, pu.Cr(), cccmModelCr, ccpCand.yThres, lumaOffset, offsetCr, ccpCand.type, refSizeX, refSizeY); + } + else + { + CHECK(ccpCand.cccmMultiFilterIdx != 2 && ccpCand.cccmMultiFilterIdx != 3, "Unexpected cccmMultiFilterIdx"); + + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModelCb[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(bitDepth), CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(bitDepth) }; + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModelCr[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(bitDepth), CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(bitDepth) }; + + PU::ccpParamsToCccmModel(ccpCand, cccmModelCb, cccmModelCr); + + cost += xGetCostMFCCCM23(pu, COMPONENT_Cb, modelNum, pu.Cb(), cccmModelCb, ccpCand.yThres, lumaOffset, offsetCb, ccpCand.type, refSizeX, refSizeY); + cost += xGetCostMFCCCM23(pu, COMPONENT_Cr, modelNum, pu.Cr(), cccmModelCr, ccpCand.yThres, lumaOffset, offsetCr, ccpCand.type, refSizeX, refSizeY); + } + const_cast<PredictionUnit&>(pu).cccmMultiFilterIdx = 0; + } +#endif +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + else if (ccpCand.type & CCP_TYPE_NSCCCM) + { +#if JVET_AB0174_CCCM_DIV_FREE + int lumaOffset = m_cccmLumaOffset - ccpCand.lumaOffset; +#else + int lumaOffset = 0; +#endif + const_cast<PredictionUnit &>(pu).cccmNoSubFlag = 1; + + CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCb[2] = { CccmModel<CCCM_NO_SUB_NUM_PARAMS>(bitDepth), CccmModel<CCCM_NO_SUB_NUM_PARAMS>(bitDepth) }; + CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCr[2] = { CccmModel<CCCM_NO_SUB_NUM_PARAMS>(bitDepth), CccmModel<CCCM_NO_SUB_NUM_PARAMS>(bitDepth) }; + + PU::ccpParamsToCccmModel(ccpCand, cccmModelCb, cccmModelCr); + + cost += xGetCostNSCCCM(pu, COMPONENT_Cb, modelNum, pu.Cb(), cccmModelCb, ccpCand.yThres, lumaOffset, offsetCb); + cost += xGetCostNSCCCM(pu, COMPONENT_Cr, modelNum, pu.Cr(), cccmModelCr, ccpCand.yThres, lumaOffset, offsetCr); + + const_cast<PredictionUnit &>(pu).cccmNoSubFlag = 0; + } +#endif + else if (ccpCand.type & (CCP_TYPE_CCLM | CCP_TYPE_GLM0123)) + { + CPelBuf temp; + int lumaStride; + + if (ccpCand.type & CCP_TYPE_GLM0123) + { + Pel *glmTemp = m_glmTempCb[ccpCand.glmIdc]; + lumaStride = 2 * MAX_CU_SIZE + 1; + temp = PelBuf(glmTemp + lumaStride + 1, lumaStride, Size(chromaArea)); + } + else + { + lumaStride = MAX_CU_SIZE + 1; + temp = PelBuf(m_piTemp + lumaStride + 1, lumaStride, Size(chromaArea)); + } + + CclmModel cclmModels; + PU::ccpParamsToCclmModel(COMPONENT_Cb, ccpCand, cclmModels); + cost += xGetCostCCLM(pu, COMPONENT_Cb, pu.Cb(), cclmModels, 1, ccpCand.glmIdc); + PU::ccpParamsToCclmModel(COMPONENT_Cr, ccpCand, cclmModels); + cost += xGetCostCCLM(pu, COMPONENT_Cr, pu.Cr(), cclmModels, 1, ccpCand.glmIdc); + } + else if (ccpCand.type & CCP_TYPE_GLM4567) + { + int glmIdc = ccpCand.glmIdc; + int chromaOffset = 0; +#if JVET_AB0174_CCCM_DIV_FREE + int lumaOffset = m_glmLumaOffset - ccpCand.lumaOffset; +#else + int lumaOffset = 0; +#endif + CccmModel<GLM_NUM_PARAMS> glmModel(bitDepth); + PU::ccpParamsToGlmModel(COMPONENT_Cb, ccpCand, glmModel); + cost += xGetCostGLM(pu, COMPONENT_Cb, pu.Cb(), glmModel, glmIdc, lumaOffset, chromaOffset); + PU::ccpParamsToGlmModel(COMPONENT_Cr, ccpCand, glmModel); + cost += xGetCostGLM(pu, COMPONENT_Cr, pu.Cr(), glmModel, glmIdc, lumaOffset, chromaOffset); + } + else + { + THROW("Invalid type!"); + } + } + return cost; +} + +void IntraPrediction::predCCPCandidate(const PredictionUnit &pu, PelBuf &predCb, PelBuf &predCr) +{ + const int bitDepth = pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA); + + if (pu.idxNonLocalCCP) + { + CompArea chromaArea = pu.Cb(); + int cWidth = chromaArea.width; + int cHeight = chromaArea.height; + CccmModel<CCCM_NUM_PARAMS> cccmModelCb[2] = { CccmModel<CCCM_NUM_PARAMS>(bitDepth), CccmModel<CCCM_NUM_PARAMS>(bitDepth) }; + CccmModel<CCCM_NUM_PARAMS> cccmModelCr[2] = { CccmModel<CCCM_NUM_PARAMS>(bitDepth), CccmModel<CCCM_NUM_PARAMS>(bitDepth) }; + + CHECK(pu.curCand.type == CCP_TYPE_NONE, "CCP model with no type") + { + int modelNum = (pu.curCand.type & CCP_TYPE_MMLM) ? 2 : 1; + + if (pu.curCand.type & (CCP_TYPE_CCCM | CCP_TYPE_GLCCCM)) + { +#if JVET_AB0174_CCCM_DIV_FREE + int lumaOffset = m_cccmLumaOffset - pu.curCand.lumaOffset; +#else + int lumaOffset = 0; +#endif + int refSizeX = pu.curCand.corOffX; + int refSizeY = pu.curCand.corOffY; + int offsetCb[2] = { 0, 0 }; + int offsetCr[2] = { 0, 0 }; + + PU::ccpParamsToCccmModel(pu.curCand, cccmModelCb, cccmModelCr); + + if (!(pu.curCand.type & CCP_TYPE_MMLM)) + { + xGetUpdatedOffsetCCCM(pu, COMPONENT_Cb, modelNum, pu.Cb(), cccmModelCb, 0, lumaOffset, offsetCb, pu.curCand.type, refSizeX, refSizeY); + xGetUpdatedOffsetCCCM(pu, COMPONENT_Cr, modelNum, pu.Cr(), cccmModelCr, 0, lumaOffset, offsetCr, pu.curCand.type, refSizeX, refSizeY); + + xCccmApplyModelOffset(pu, COMPONENT_Cb, cccmModelCb[0], 0, 0, predCb, lumaOffset, offsetCb, pu.curCand.type, refSizeX, refSizeY); + xCccmApplyModelOffset(pu, COMPONENT_Cr, cccmModelCr[0], 0, 0, predCr, lumaOffset, offsetCr, pu.curCand.type, refSizeX, refSizeY); + } + else + { + // Multimode case + int modelThr = pu.curCand.yThres; + + xGetUpdatedOffsetCCCM(pu, COMPONENT_Cb, modelNum, pu.Cb(), cccmModelCb, modelThr, lumaOffset, offsetCb, pu.curCand.type, refSizeX, refSizeY); + xGetUpdatedOffsetCCCM(pu, COMPONENT_Cr, modelNum, pu.Cr(), cccmModelCr, modelThr, lumaOffset, offsetCr, pu.curCand.type, refSizeX, refSizeY); + + xCccmApplyModelOffset(pu, COMPONENT_Cb, cccmModelCb[0], 1, modelThr, predCb, lumaOffset, offsetCb, pu.curCand.type, refSizeX, refSizeY); + xCccmApplyModelOffset(pu, COMPONENT_Cr, cccmModelCr[0], 1, modelThr, predCr, lumaOffset, offsetCr, pu.curCand.type, refSizeX, refSizeY); + + xCccmApplyModelOffset(pu, COMPONENT_Cb, cccmModelCb[1], 2, modelThr, predCb, lumaOffset, offsetCb, pu.curCand.type, refSizeX, refSizeY); + xCccmApplyModelOffset(pu, COMPONENT_Cr, cccmModelCr[1], 2, modelThr, predCr, lumaOffset, offsetCr, pu.curCand.type, refSizeX, refSizeY); + } + } +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + else if (pu.curCand.type & CCP_TYPE_NSCCCM) + { + CccmModel<CCCM_NO_SUB_NUM_PARAMS> nscccmModelCb[2] = { CccmModel<CCCM_NO_SUB_NUM_PARAMS>(bitDepth), CccmModel<CCCM_NO_SUB_NUM_PARAMS>(bitDepth) }; + CccmModel<CCCM_NO_SUB_NUM_PARAMS> nscccmModelCr[2] = { CccmModel<CCCM_NO_SUB_NUM_PARAMS>(bitDepth), CccmModel<CCCM_NO_SUB_NUM_PARAMS>(bitDepth) }; +#if JVET_AB0174_CCCM_DIV_FREE + int lumaOffset = m_cccmLumaOffset - pu.curCand.lumaOffset; +#else + int lumaOffset = 0; +#endif + const_cast<PredictionUnit &>(pu).cccmNoSubFlag = 1; + int offsetCb[2] = { 0, 0 }; + int offsetCr[2] = { 0, 0 }; + + PU::ccpParamsToCccmModel(pu.curCand, nscccmModelCb, nscccmModelCr); + + if (!(pu.curCand.type & CCP_TYPE_MMLM)) + { + xGetUpdatedOffsetNSCCCM(pu, COMPONENT_Cb, modelNum, pu.Cb(), nscccmModelCb, 0, lumaOffset, offsetCb); + xGetUpdatedOffsetNSCCCM(pu, COMPONENT_Cr, modelNum, pu.Cr(), nscccmModelCr, 0, lumaOffset, offsetCr); + + xNSCccmApplyModelOffset(pu, COMPONENT_Cb, nscccmModelCb[0], 0, 0, predCb, lumaOffset, offsetCb); + xNSCccmApplyModelOffset(pu, COMPONENT_Cr, nscccmModelCr[0], 0, 0, predCr, lumaOffset, offsetCr); + } + else + { + // Multimode case + int modelThr = pu.curCand.yThres; + + xGetUpdatedOffsetNSCCCM(pu, COMPONENT_Cb, modelNum, pu.Cb(), nscccmModelCb, modelThr, lumaOffset, offsetCb); + xGetUpdatedOffsetNSCCCM(pu, COMPONENT_Cr, modelNum, pu.Cr(), nscccmModelCr, modelThr, lumaOffset, offsetCr); + + xNSCccmApplyModelOffset(pu, COMPONENT_Cb, nscccmModelCb[0], 1, modelThr, predCb, lumaOffset, offsetCb); + xNSCccmApplyModelOffset(pu, COMPONENT_Cr, nscccmModelCr[0], 1, modelThr, predCr, lumaOffset, offsetCr); + + xNSCccmApplyModelOffset(pu, COMPONENT_Cb, nscccmModelCb[1], 2, modelThr, predCb, lumaOffset, offsetCb); + xNSCccmApplyModelOffset(pu, COMPONENT_Cr, nscccmModelCr[1], 2, modelThr, predCr, lumaOffset, offsetCr); + } + + const_cast<PredictionUnit &>(pu).cccmNoSubFlag = 0; + } +#endif +#if JVET_AD0202_CCCM_MDF + else if (pu.curCand.type & CCP_TYPE_MDFCCCM) + { + const_cast<PredictionUnit&>(pu).cccmMultiFilterIdx = pu.curCand.cccmMultiFilterIdx; +#if JVET_AB0174_CCCM_DIV_FREE + int lumaOffset = m_cccmLumaOffset - pu.curCand.lumaOffset; +#else + int lumaOffset = 0; +#endif + int refSizeX = pu.curCand.corOffX; + int refSizeY = pu.curCand.corOffY; + int offsetCb[2] = { 0, 0 }; + int offsetCr[2] = { 0, 0 }; + + if (pu.curCand.cccmMultiFilterIdx == 1) + { + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> mfcccmModelCb[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(bitDepth), CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(bitDepth) }; + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> mfcccmModelCr[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(bitDepth), CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(bitDepth) }; + + PU::ccpParamsToCccmModel(pu.curCand, mfcccmModelCb, mfcccmModelCr); + + if (!(pu.curCand.type & CCP_TYPE_MMLM)) + { + xGetUpdatedOffsetMFCCCM1(pu, COMPONENT_Cb, modelNum, pu.Cb(), mfcccmModelCb, 0, lumaOffset, offsetCb, pu.curCand.type, refSizeX, refSizeY); + xGetUpdatedOffsetMFCCCM1(pu, COMPONENT_Cr, modelNum, pu.Cr(), mfcccmModelCr, 0, lumaOffset, offsetCr, pu.curCand.type, refSizeX, refSizeY); + + xMFCccmApplyModelOffset1(pu, COMPONENT_Cb, mfcccmModelCb[0], 0, 0, predCb, lumaOffset, offsetCb); + xMFCccmApplyModelOffset1(pu, COMPONENT_Cr, mfcccmModelCr[0], 0, 0, predCr, lumaOffset, offsetCr); + } + else + { + // Multimode case + int modelThr = pu.curCand.yThres; + + xGetUpdatedOffsetMFCCCM1(pu, COMPONENT_Cb, modelNum, pu.Cb(), mfcccmModelCb, modelThr, lumaOffset, offsetCb, pu.curCand.type, refSizeX, refSizeY); + xGetUpdatedOffsetMFCCCM1(pu, COMPONENT_Cr, modelNum, pu.Cr(), mfcccmModelCr, modelThr, lumaOffset, offsetCr, pu.curCand.type, refSizeX, refSizeY); + + xMFCccmApplyModelOffset1(pu, COMPONENT_Cb, mfcccmModelCb[0], 1, modelThr, predCb, lumaOffset, offsetCb); + xMFCccmApplyModelOffset1(pu, COMPONENT_Cr, mfcccmModelCr[0], 1, modelThr, predCr, lumaOffset, offsetCr); + + xMFCccmApplyModelOffset1(pu, COMPONENT_Cb, mfcccmModelCb[1], 2, modelThr, predCb, lumaOffset, offsetCb); + xMFCccmApplyModelOffset1(pu, COMPONENT_Cr, mfcccmModelCr[1], 2, modelThr, predCr, lumaOffset, offsetCr); + } + } + else // if (pu.curCand.cccmMultiFilterIdx == 2 || pu.curCand.cccmMultiFilterIdx == 3) + { + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> mfcccmModelCb[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(bitDepth), CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(bitDepth) }; + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> mfcccmModelCr[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(bitDepth), CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(bitDepth) }; + + PU::ccpParamsToCccmModel(pu.curCand, mfcccmModelCb, mfcccmModelCr); + + if (!(pu.curCand.type & CCP_TYPE_MMLM)) + { + xGetUpdatedOffsetMFCCCM23(pu, COMPONENT_Cb, modelNum, pu.Cb(), mfcccmModelCb, 0, lumaOffset, offsetCb, pu.curCand.type, refSizeX, refSizeY); + xGetUpdatedOffsetMFCCCM23(pu, COMPONENT_Cr, modelNum, pu.Cr(), mfcccmModelCr, 0, lumaOffset, offsetCr, pu.curCand.type, refSizeX, refSizeY); + + xMFCccmApplyModelOffset23(pu, COMPONENT_Cb, mfcccmModelCb[0], 0, 0, predCb, lumaOffset, offsetCb); + xMFCccmApplyModelOffset23(pu, COMPONENT_Cr, mfcccmModelCr[0], 0, 0, predCr, lumaOffset, offsetCr); + } + else + { + // Multimode case + int modelThr = pu.curCand.yThres; + + xGetUpdatedOffsetMFCCCM23(pu, COMPONENT_Cb, modelNum, pu.Cb(), mfcccmModelCb, modelThr, lumaOffset, offsetCb, pu.curCand.type, refSizeX, refSizeY); + xGetUpdatedOffsetMFCCCM23(pu, COMPONENT_Cr, modelNum, pu.Cr(), mfcccmModelCr, modelThr, lumaOffset, offsetCr, pu.curCand.type, refSizeX, refSizeY); + + xMFCccmApplyModelOffset23(pu, COMPONENT_Cb, mfcccmModelCb[0], 1, modelThr, predCb, lumaOffset, offsetCb); + xMFCccmApplyModelOffset23(pu, COMPONENT_Cr, mfcccmModelCr[0], 1, modelThr, predCr, lumaOffset, offsetCr); + + xMFCccmApplyModelOffset23(pu, COMPONENT_Cb, mfcccmModelCb[1], 2, modelThr, predCb, lumaOffset, offsetCb); + xMFCccmApplyModelOffset23(pu, COMPONENT_Cr, mfcccmModelCr[1], 2, modelThr, predCr, lumaOffset, offsetCr); + } + } + + const_cast<PredictionUnit&>(pu).cccmMultiFilterIdx = 0; + } +#endif + else if (pu.curCand.type & (CCP_TYPE_CCLM | CCP_TYPE_GLM0123)) + { + CPelBuf temp; + int lumaStride; + + if (pu.curCand.type & CCP_TYPE_GLM0123) + { + Pel *glmTemp = m_glmTempCb[pu.curCand.glmIdc]; + lumaStride = 2 * MAX_CU_SIZE + 1; + temp = PelBuf(glmTemp + lumaStride + 1, lumaStride, Size(chromaArea)); + } + else + { + lumaStride = MAX_CU_SIZE + 1; + temp = PelBuf(m_piTemp + lumaStride + 1, lumaStride, Size(chromaArea)); + } + + CclmModel modelsCb, modelsCr; + PU::ccpParamsToCclmModel(COMPONENT_Cb, pu.curCand, modelsCb); + PU::ccpParamsToCclmModel(COMPONENT_Cr, pu.curCand, modelsCr); + + if (!(pu.curCand.type & CCP_TYPE_MMLM)) + { + xGetUpdatedOffsetCCLM(pu, COMPONENT_Cb, pu.Cb(), modelsCb, 1, pu.curCand.glmIdc); + xGetUpdatedOffsetCCLM(pu, COMPONENT_Cr, pu.Cr(), modelsCr, 1, pu.curCand.glmIdc); + + predCb.copyFrom(temp); + predCr.copyFrom(temp); + + predCb.linearTransform(modelsCb.a, modelsCb.shift, modelsCb.b, true, pu.cs->slice->clpRng(COMPONENT_Cb)); + predCr.linearTransform(modelsCr.a, modelsCr.shift, modelsCr.b, true, pu.cs->slice->clpRng(COMPONENT_Cb)); + } + else + { + xGetUpdatedOffsetCCLM(pu, COMPONENT_Cb, pu.Cb(), modelsCb, 2, pu.curCand.glmIdc); + xGetUpdatedOffsetCCLM(pu, COMPONENT_Cr, pu.Cr(), modelsCr, 2, pu.curCand.glmIdc); + + auto applyMMCM = [&](PelBuf &predBuf, const CclmModel &cclmModel) + { + Pel *chromaPred = predBuf.bufAt(0, 0); + const Pel *lumaReco = temp.bufAt(0, 0); + int chromaStride = predBuf.stride; + + for (int i = 0; i < cHeight; i++) + { + for (int j = 0; j < cWidth; j++) + { + if (lumaReco[j] <= cclmModel.yThres) + { + chromaPred[j] = (Pel) ClipPel(((cclmModel.a * lumaReco[j]) >> cclmModel.shift) + cclmModel.b, pu.cs->slice->clpRng(COMPONENT_Cb)); + } + else + { + chromaPred[j] = (Pel) ClipPel(((cclmModel.a2 * lumaReco[j]) >> cclmModel.shift2) + cclmModel.b2, pu.cs->slice->clpRng(COMPONENT_Cb)); + } + } + chromaPred += chromaStride; + lumaReco += lumaStride; + } + }; + applyMMCM(predCb, modelsCb); + applyMMCM(predCr, modelsCr); + } + PU::cclmModelToCcpParams(COMPONENT_Cb, const_cast<PredictionUnit&>(pu).curCand, modelsCb); + PU::cclmModelToCcpParams(COMPONENT_Cr, const_cast<PredictionUnit&>(pu).curCand, modelsCr); + } + else if (pu.curCand.type & CCP_TYPE_GLM4567) + { +#if JVET_AB0174_CCCM_DIV_FREE + int lumaOffset = m_glmLumaOffset - pu.curCand.lumaOffset; +#else + int lumaOffset = 0; +#endif + int glmIdc = pu.curCand.glmIdc; + int chromaOffset = 0; + CccmModel<GLM_NUM_PARAMS> glmModel(bitDepth); + + PU::ccpParamsToGlmModel(COMPONENT_Cb, pu.curCand, glmModel); + xGetUpdatedOffsetGLM(pu, COMPONENT_Cb, pu.Cb(), glmModel, glmIdc, lumaOffset, chromaOffset); + xGlmApplyModelOffset(pu, COMPONENT_Cb, pu.Cb(), glmModel, glmIdc, predCb, lumaOffset, chromaOffset); + + PU::ccpParamsToGlmModel(COMPONENT_Cr, pu.curCand, glmModel); + xGetUpdatedOffsetGLM(pu, COMPONENT_Cr, pu.Cr(), glmModel, glmIdc, lumaOffset, chromaOffset); + xGlmApplyModelOffset(pu, COMPONENT_Cr, pu.Cr(), glmModel, glmIdc, predCr, lumaOffset, chromaOffset); + } + else + { + THROW("Invalid Type"); + } + } + } +} +#endif + +#if JVET_AB0174_CCCM_DIV_FREE +#define DIV_PREC_BITS 14 +#define DIV_PREC_BITS_POW2 8 +#define DIV_SLOT_BITS 3 +#define DIV_INTR_BITS (DIV_PREC_BITS - DIV_SLOT_BITS) +#define DIV_INTR_ROUND (1 << DIV_INTR_BITS >> 1) + +int64_t xDivide(int64_t num, int64_t denom) // Note: assumes positive denominator +{ + static const int pow2W[8] = { 214, 153, 113, 86, 67, 53, 43, 35 }; // DIV_PREC_BITS_POW2 + static const int pow2O[8] = { 4822, 5952, 6624, 6792, 6408, 5424, 3792, 1466 }; // DIV_PREC_BITS + static const int pow2B[8] = { 12784, 12054, 11670, 11583, 11764, 12195, 12870, 13782 }; // DIV_PREC_BITS + + int shift = floorLog2Uint64(denom); + int round = 1 << shift >> 1; + int normDiff = (((denom << DIV_PREC_BITS) + round) >> shift) & ((1 << DIV_PREC_BITS) - 1); + int diffFull = normDiff >> DIV_INTR_BITS; + int normDiff2 = normDiff - pow2O[diffFull]; + + int scale = ((pow2W[diffFull] * ((normDiff2 * normDiff2) >> DIV_PREC_BITS)) >> DIV_PREC_BITS_POW2) - (normDiff2 >> 1) + pow2B[diffFull]; + + return ( (num << (CCCM_DECIM_BITS - DIV_PREC_BITS)) * scale + round) >> shift; +} + +#if JVET_AC0053_GAUSSIAN_SOLVER +void xGetDivScaleRoundShift(int64_t denom, int &scale, int &round, int &shift) // Note: assumes positive denominator +{ + static const int pow2W[8] = { 214, 153, 113, 86, 67, 53, 43, 35 }; // DIV_PREC_BITS_POW2 + static const int pow2O[8] = { 4822, 5952, 6624, 6792, 6408, 5424, 3792, 1466 }; // DIV_PREC_BITS + static const int pow2B[8] = { 12784, 12054, 11670, 11583, 11764, 12195, 12870, 13782 }; // DIV_PREC_BITS + + shift = floorLog2Uint64(denom); + round = 1 << shift >> 1; + int normDiff = (((denom << DIV_PREC_BITS) + round) >> shift) & ((1 << DIV_PREC_BITS) - 1); + int diffFull = normDiff >> DIV_INTR_BITS; + int normDiff2 = normDiff - pow2O[diffFull]; + + scale = ((pow2W[diffFull] * ((normDiff2 * normDiff2) >> DIV_PREC_BITS)) >> DIV_PREC_BITS_POW2) - (normDiff2 >> 1) + pow2B[diffFull]; + scale <<= CCCM_DECIM_BITS - DIV_PREC_BITS; +} +#endif + +#undef DIV_PREC_BITS +#undef DIV_PREC_BITS_POW2 +#undef DIV_SLOT_BITS +#undef DIV_INTR_BITS +#undef DIV_INTR_ROUND + +int xCccmDivideLowPrec(int64_t num, int64_t denom) +{ + if ( num < 0 ) + { + return -int(xDivide(-num, denom) >> CCCM_DECIM_BITS); + } + else + { + return int(xDivide(num, denom) >> CCCM_DECIM_BITS); + } +} + +int64_t xCccmDivide(int64_t num, int64_t denom) // Note: assumes positive denominator +{ + return xDivide(num, denom); +} +#endif + +#if JVET_AA0057_CCCM || JVET_AC0119_LM_CHROMA_FUSION +#if JVET_AB0174_CCCM_DIV_FREE +void IntraPrediction::xCccmSetLumaRefValue(const PredictionUnit& pu) +{ + int lumaPosX = m_cccmBlkArea.x << getComponentScaleX(COMPONENT_Cb, pu.cu->chromaFormat); + int lumaPosY = m_cccmBlkArea.y << getComponentScaleY(COMPONENT_Cb, pu.cu->chromaFormat); + + if (lumaPosX || lumaPosY) + { + lumaPosX = lumaPosX ? lumaPosX - 1 : 0; + lumaPosY = lumaPosY ? lumaPosY - 1 : 0; + + m_cccmLumaOffset = pu.cs->picture->getRecoBuf(COMPONENT_Y).at(lumaPosX, lumaPosY); + } + else + { + m_cccmLumaOffset = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 1); + } +} +#endif + +// Calculate a single downsampled luma reference value (copied from IntraPrediction::xGetLumaRecPixels) +Pel IntraPrediction::xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, const int x, const int y +#if JVET_AD0202_CCCM_MDF + , int downsFilterIdx +#endif +) const +{ + const Pel* piSrc = pi.buf; + const int iRecStride = pi.stride; + Pel ypval = 0; +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + if (pu.cccmNoSubFlag || pu.chromaFormat == CHROMA_444) +#else + if (pu.chromaFormat == CHROMA_444) +#endif + { + ypval = piSrc[x + iRecStride * y]; + } + else if (pu.chromaFormat == CHROMA_422) + { + int s = 2; + int offLeft = x > 0 ? -1 : 0; + s += piSrc[2 * x + iRecStride * y] * 2; + s += piSrc[2 * x + offLeft + iRecStride * y]; + s += piSrc[2 * x + 1 + iRecStride * y]; + ypval = s >> 2; + } + else if (pu.cs->sps->getCclmCollocatedChromaFlag()) + { + int s = 4; + int offLeft = x > 0 ? -1 : 0; + int offAbove = y > 0 ? -1 : 0; + s += piSrc[2 * x + iRecStride * 2 * y] * 4; + s += piSrc[2 * x + offLeft + iRecStride * 2 * y]; + s += piSrc[2 * x + 1 + iRecStride * 2 * y]; + s += piSrc[2 * x + iRecStride * (2 * y + 1)]; + s += piSrc[2 * x + iRecStride * (2 * y + offAbove)]; + ypval = s >> 3; + } + else + { +#if JVET_AD0202_CCCM_MDF + const int lumaPosPicX1 = 2 * x; + const int lumaPosPicY1 = 2 * y; + int lumaPosPicX0 = lumaPosPicX1 - 1; lumaPosPicX0 = lumaPosPicX0 < 0 ? 0 : lumaPosPicX0; + const int lumaPosPicX2 = lumaPosPicX1 + 1; + const int lumaPosPicY2 = lumaPosPicY1 + 1; + const int shift0 = iRecStride * lumaPosPicY1; + const int shift1 = iRecStride * lumaPosPicY2; + + if (downsFilterIdx == 0) + { + int s = 4; + + s += piSrc[lumaPosPicX1 + shift0] * 2; + s += piSrc[lumaPosPicX0 + shift0]; + s += piSrc[lumaPosPicX2 + shift0]; + s += piSrc[lumaPosPicX1 + shift1] * 2; + s += piSrc[lumaPosPicX0 + shift1]; + s += piSrc[lumaPosPicX2 + shift1]; + ypval = s >> 3; + } + else if (downsFilterIdx == 1) + { + int s = 0; + + s += piSrc[lumaPosPicX0 + shift0]; + s -= piSrc[lumaPosPicX2 + shift0]; + s += piSrc[lumaPosPicX0 + shift1]; + s -= piSrc[lumaPosPicX2 + shift1]; + + ypval = s < 0 ? 0 : s; + } + else if (downsFilterIdx == 2) + { + int s = 0; + + s += piSrc[lumaPosPicX0 + shift0]; + s += piSrc[lumaPosPicX1 + shift0] * 2; + s += piSrc[lumaPosPicX2 + shift0]; + s -= piSrc[lumaPosPicX0 + shift1]; + s -= piSrc[lumaPosPicX1 + shift1] * 2; + s -= piSrc[lumaPosPicX2 + shift1]; + + ypval = s < 0 ? 0 : s; + } + else + { + int s = 0; + + s -= piSrc[lumaPosPicX0 + shift0]; + s += piSrc[lumaPosPicX1 + shift0]; + s += piSrc[lumaPosPicX2 + shift0] * 2; + s -= piSrc[lumaPosPicX0 + shift1] * 2; + s -= piSrc[lumaPosPicX1 + shift1]; + s += piSrc[lumaPosPicX2 + shift1]; + + ypval = s < 0 ? 0 : s; } #else int s = 4; @@ -12746,8 +15597,15 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P #if JVET_AC0147_CCCM_NO_SUBSAMPLING if( pu.cccmNoSubFlag ) { +#if JVET_AD0188_CCP_MERGE + CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCb[2] = { CccmModel<CCCM_NO_SUB_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)), + CccmModel<CCCM_NO_SUB_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)) }; + CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCr[2] = { CccmModel<CCCM_NO_SUB_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)), + CccmModel<CCCM_NO_SUB_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)) }; +#else CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCb( pu.cu->slice->getSPS()->getBitDepth( CHANNEL_TYPE_LUMA ) ); CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCr( pu.cu->slice->getSPS()->getBitDepth( CHANNEL_TYPE_LUMA ) ); +#endif #if JVET_AB0143_CCCM_TS if( intraDir == LM_CHROMA_IDX || intraDir == MDLM_L_IDX || intraDir == MDLM_T_IDX ) @@ -12755,15 +15613,44 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P if( PU::cccmSingleModeAvail( pu, intraDir ) ) #endif { +#if JVET_AD0188_CCP_MERGE + xCccmCalcModels(pu, cccmModelCb[0], cccmModelCr[0], 0, 0); + xCccmApplyModel(pu, COMPONENT_Cb, cccmModelCb[0], 0, 0, predCb); + xCccmApplyModel(pu, COMPONENT_Cr, cccmModelCr[0], 0, 0, predCr); + + const_cast<PredictionUnit &>(pu).curCand.type = CCP_TYPE_NSCCCM; + PU::cccmModelToCcpParams(const_cast<PredictionUnit&>(pu).curCand, cccmModelCb, cccmModelCr, 0 +#if JVET_AB0174_CCCM_DIV_FREE + , m_cccmLumaOffset +#endif + ); +#else xCccmCalcModels( pu, cccmModelCb, cccmModelCr, 0, 0 ); xCccmApplyModel( pu, COMPONENT_Cb, cccmModelCb, 0, 0, predCb ); xCccmApplyModel( pu, COMPONENT_Cr, cccmModelCr, 0, 0, predCr ); +#endif } else { // Multimode case int modelThr = xCccmCalcRefAver( pu ); +#if JVET_AD0188_CCP_MERGE + xCccmCalcModels( pu, cccmModelCb[0], cccmModelCr[0], 1, modelThr ); + xCccmApplyModel( pu, COMPONENT_Cb, cccmModelCb[0], 1, modelThr, predCb ); + xCccmApplyModel( pu, COMPONENT_Cr, cccmModelCr[0], 1, modelThr, predCr ); + + xCccmCalcModels( pu, cccmModelCb[1], cccmModelCr[1], 2, modelThr ); + xCccmApplyModel( pu, COMPONENT_Cb, cccmModelCb[1], 2, modelThr, predCb ); + xCccmApplyModel( pu, COMPONENT_Cr, cccmModelCr[1], 2, modelThr, predCr ); + + const_cast<PredictionUnit &>(pu).curCand.type = (CCP_TYPE_NSCCCM | CCP_TYPE_MMLM); + PU::cccmModelToCcpParams(const_cast<PredictionUnit&>(pu).curCand, cccmModelCb, cccmModelCr, modelThr +#if JVET_AB0174_CCCM_DIV_FREE + , m_cccmLumaOffset +#endif + ); +#else xCccmCalcModels( pu, cccmModelCb, cccmModelCr, 1, modelThr ); xCccmApplyModel( pu, COMPONENT_Cb, cccmModelCb, 1, modelThr, predCb ); xCccmApplyModel( pu, COMPONENT_Cr, cccmModelCr, 1, modelThr, predCr ); @@ -12771,6 +15658,7 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P xCccmCalcModels( pu, cccmModelCb, cccmModelCr, 2, modelThr ); xCccmApplyModel( pu, COMPONENT_Cb, cccmModelCb, 2, modelThr, predCb ); xCccmApplyModel( pu, COMPONENT_Cr, cccmModelCr, 2, modelThr, predCr ); +#endif } } else @@ -12778,8 +15666,15 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P #if JVET_AD0202_CCCM_MDF if (pu.cccmMultiFilterIdx == 1) { +#if JVET_AD0188_CCP_MERGE + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCb[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)), + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)) }; + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCr[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)), + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)) }; +#else CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCb(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)); CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCr(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)); +#endif #if JVET_AB0143_CCCM_TS if (intraDir == LM_CHROMA_IDX || intraDir == MDLM_L_IDX || intraDir == MDLM_T_IDX) @@ -12787,15 +15682,52 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P if (PU::cccmSingleModeAvail(pu, intraDir)) #endif { +#if JVET_AD0188_CCP_MERGE + xCccmCalcModels2(pu, cccmModelCb[0], cccmModelCr[0], 0, 0); + xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb[0], 0, 0, predCb); + xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr[0], 0, 0, predCr); + + const_cast<PredictionUnit&>(pu).curCand.type = CCP_TYPE_MDFCCCM; + const_cast<PredictionUnit&>(pu).curCand.cccmMultiFilterIdx = pu.cccmMultiFilterIdx; + const_cast<PredictionUnit&>(pu).curCand.corOffX = m_cccmBlkArea.x - m_cccmRefArea.x; + const_cast<PredictionUnit&>(pu).curCand.corOffY = m_cccmBlkArea.y - m_cccmRefArea.y; + + PU::cccmModelToCcpParams(const_cast<PredictionUnit&>(pu).curCand, cccmModelCb, cccmModelCr, 0 +#if JVET_AB0174_CCCM_DIV_FREE + , m_cccmLumaOffset +#endif + ); +#else xCccmCalcModels2(pu, cccmModelCb, cccmModelCr, 0, 0); xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb, 0, 0, predCb); xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr, 0, 0, predCr); +#endif } else { // Multimode case int modelThr = xCccmCalcRefAver(pu); +#if JVET_AD0188_CCP_MERGE + xCccmCalcModels2(pu, cccmModelCb[0], cccmModelCr[0], 1, modelThr); + xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb[0], 1, modelThr, predCb); + xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr[0], 1, modelThr, predCr); + + xCccmCalcModels2(pu, cccmModelCb[1], cccmModelCr[1], 2, modelThr); + xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb[1], 2, modelThr, predCb); + xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr[1], 2, modelThr, predCr); + + const_cast<PredictionUnit&>(pu).curCand.type = CCP_TYPE_MDFCCCM | CCP_TYPE_MMLM; + const_cast<PredictionUnit&>(pu).curCand.cccmMultiFilterIdx = pu.cccmMultiFilterIdx; + const_cast<PredictionUnit&>(pu).curCand.corOffX = m_cccmBlkArea.x - m_cccmRefArea.x; + const_cast<PredictionUnit&>(pu).curCand.corOffY = m_cccmBlkArea.y - m_cccmRefArea.y; + + PU::cccmModelToCcpParams(const_cast<PredictionUnit&>(pu).curCand, cccmModelCb, cccmModelCr, modelThr +#if JVET_AB0174_CCCM_DIV_FREE + , m_cccmLumaOffset +#endif + ); +#else xCccmCalcModels2(pu, cccmModelCb, cccmModelCr, 1, modelThr); xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb, 1, modelThr, predCb); xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr, 1, modelThr, predCr); @@ -12803,12 +15735,20 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P xCccmCalcModels2(pu, cccmModelCb, cccmModelCr, 2, modelThr); xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb, 2, modelThr, predCb); xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr, 2, modelThr, predCr); +#endif } } else if (pu.cccmMultiFilterIdx > 1) { +#if JVET_AD0188_CCP_MERGE + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModelCb[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)), + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)) }; + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModelCr[2] = { CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)), + CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)) }; +#else CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModelCb(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)); CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModelCr(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)); +#endif #if JVET_AB0143_CCCM_TS if (intraDir == LM_CHROMA_IDX || intraDir == MDLM_L_IDX || intraDir == MDLM_T_IDX) @@ -12816,15 +15756,52 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P if (PU::cccmSingleModeAvail(pu, intraDir)) #endif { +#if JVET_AD0188_CCP_MERGE + xCccmCalcModels3(pu, cccmModelCb[0], cccmModelCr[0], 0, 0); + xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb[0], 0, 0, predCb); + xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr[0], 0, 0, predCr); + + const_cast<PredictionUnit&>(pu).curCand.type = CCP_TYPE_MDFCCCM; + const_cast<PredictionUnit&>(pu).curCand.cccmMultiFilterIdx = pu.cccmMultiFilterIdx; + const_cast<PredictionUnit&>(pu).curCand.corOffX = m_cccmBlkArea.x - m_cccmRefArea.x; + const_cast<PredictionUnit&>(pu).curCand.corOffY = m_cccmBlkArea.y - m_cccmRefArea.y; + + PU::cccmModelToCcpParams(const_cast<PredictionUnit&>(pu).curCand, cccmModelCb, cccmModelCr, 0 +#if JVET_AB0174_CCCM_DIV_FREE + , m_cccmLumaOffset +#endif + ); +#else xCccmCalcModels3(pu, cccmModelCb, cccmModelCr, 0, 0); xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb, 0, 0, predCb); xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr, 0, 0, predCr); +#endif } else { // Multimode case int modelThr = xCccmCalcRefAver(pu); +#if JVET_AD0188_CCP_MERGE + xCccmCalcModels3(pu, cccmModelCb[0], cccmModelCr[0], 1, modelThr); + xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb[0], 1, modelThr, predCb); + xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr[0], 1, modelThr, predCr); + + xCccmCalcModels3(pu, cccmModelCb[1], cccmModelCr[1], 2, modelThr); + xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb[1], 2, modelThr, predCb); + xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr[1], 2, modelThr, predCr); + + const_cast<PredictionUnit&>(pu).curCand.type = CCP_TYPE_MDFCCCM | CCP_TYPE_MMLM; + const_cast<PredictionUnit&>(pu).curCand.cccmMultiFilterIdx = pu.cccmMultiFilterIdx; + const_cast<PredictionUnit&>(pu).curCand.corOffX = m_cccmBlkArea.x - m_cccmRefArea.x; + const_cast<PredictionUnit&>(pu).curCand.corOffY = m_cccmBlkArea.y - m_cccmRefArea.y; + + PU::cccmModelToCcpParams(const_cast<PredictionUnit&>(pu).curCand, cccmModelCb, cccmModelCr, modelThr +#if JVET_AB0174_CCCM_DIV_FREE + , m_cccmLumaOffset +#endif + ); +#else xCccmCalcModels3(pu, cccmModelCb, cccmModelCr, 1, modelThr); xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb, 1, modelThr, predCb); xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr, 1, modelThr, predCr); @@ -12832,14 +15809,22 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P xCccmCalcModels3(pu, cccmModelCb, cccmModelCr, 2, modelThr); xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb, 2, modelThr, predCb); xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr, 2, modelThr, predCr); +#endif } } else #endif if ( pu.cccmFlag ) { +#if JVET_AD0188_CCP_MERGE + CccmModel<CCCM_NUM_PARAMS> cccmModelCb[2] = { CccmModel<CCCM_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)), + CccmModel<CCCM_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)) }; + CccmModel<CCCM_NUM_PARAMS> cccmModelCr[2] = { CccmModel<CCCM_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)), + CccmModel<CCCM_NUM_PARAMS>(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)) }; +#else CccmModel<CCCM_NUM_PARAMS> cccmModelCb( pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) ); CccmModel<CCCM_NUM_PARAMS> cccmModelCr( pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) ); +#endif #if JVET_AB0143_CCCM_TS if ( intraDir == LM_CHROMA_IDX || intraDir == MDLM_L_IDX || intraDir == MDLM_T_IDX ) @@ -12847,15 +15832,55 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P if ( PU::cccmSingleModeAvail(pu, intraDir) ) #endif { +#if JVET_AD0188_CCP_MERGE + xCccmCalcModels(pu, cccmModelCb[0], cccmModelCr[0], 0, 0); + xCccmApplyModel(pu, COMPONENT_Cb, cccmModelCb[0], 0, 0, predCb); + xCccmApplyModel(pu, COMPONENT_Cr, cccmModelCr[0], 0, 0, predCr); + +#if JVET_AC0054_GLCCCM + const_cast<PredictionUnit&>(pu).curCand.type = (pu.glCccmFlag ? CCP_TYPE_GLCCCM : CCP_TYPE_CCCM); + const_cast<PredictionUnit&>(pu).curCand.corOffX = m_cccmBlkArea.x - m_cccmRefArea.x; + const_cast<PredictionUnit&>(pu).curCand.corOffY = m_cccmBlkArea.y - m_cccmRefArea.y; +#else + const_cast<PredictionUnit&>(pu).curCand.type = CCP_TYPE_CCCM; +#endif + PU::cccmModelToCcpParams(const_cast<PredictionUnit&>(pu).curCand, cccmModelCb, cccmModelCr, 0 +#if JVET_AB0174_CCCM_DIV_FREE + , m_cccmLumaOffset +#endif + ); +#else xCccmCalcModels(pu, cccmModelCb, cccmModelCr, 0, 0); xCccmApplyModel(pu, COMPONENT_Cb, cccmModelCb, 0, 0, predCb); xCccmApplyModel(pu, COMPONENT_Cr, cccmModelCr, 0, 0, predCr); +#endif } else { // Multimode case int modelThr = xCccmCalcRefAver(pu); - +#if JVET_AD0188_CCP_MERGE + xCccmCalcModels(pu, cccmModelCb[0], cccmModelCr[0], 1, modelThr); + xCccmApplyModel(pu, COMPONENT_Cb, cccmModelCb[0], 1, modelThr, predCb); + xCccmApplyModel(pu, COMPONENT_Cr, cccmModelCr[0], 1, modelThr, predCr); + + xCccmCalcModels(pu, cccmModelCb[1], cccmModelCr[1], 2, modelThr); + xCccmApplyModel(pu, COMPONENT_Cb, cccmModelCb[1], 2, modelThr, predCb); + xCccmApplyModel(pu, COMPONENT_Cr, cccmModelCr[1], 2, modelThr, predCr); + +#if JVET_AC0054_GLCCCM + const_cast<PredictionUnit&>(pu).curCand.type = ((pu.glCccmFlag ? CCP_TYPE_GLCCCM : CCP_TYPE_CCCM) | CCP_TYPE_MMLM); + const_cast<PredictionUnit&>(pu).curCand.corOffX = m_cccmBlkArea.x - m_cccmRefArea.x; + const_cast<PredictionUnit&>(pu).curCand.corOffY = m_cccmBlkArea.y - m_cccmRefArea.y; +#else + const_cast<PredictionUnit&>(pu).curCand.type = (CCP_TYPE_CCCM | CCP_TYPE_MMLM); +#endif + PU::cccmModelToCcpParams(const_cast<PredictionUnit &>(pu).curCand, cccmModelCb, cccmModelCr, modelThr +#if JVET_AB0174_CCCM_DIV_FREE + , m_cccmLumaOffset +#endif + ); +#else xCccmCalcModels(pu, cccmModelCb, cccmModelCr, 1, modelThr); xCccmApplyModel(pu, COMPONENT_Cb, cccmModelCb, 1, modelThr, predCb); xCccmApplyModel(pu, COMPONENT_Cr, cccmModelCr, 1, modelThr, predCr); @@ -12863,6 +15888,7 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P xCccmCalcModels(pu, cccmModelCb, cccmModelCr, 2, modelThr); xCccmApplyModel(pu, COMPONENT_Cb, cccmModelCb, 2, modelThr, predCb); xCccmApplyModel(pu, COMPONENT_Cr, cccmModelCr, 2, modelThr, predCr); +#endif } } } diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index 1eb31b51d..2c70a4050 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -470,7 +470,7 @@ public: void xCccmApplyModel (const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_NUM_PARAMS> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const; void xCccmCreateLumaRef (const PredictionUnit& pu, CompArea chromaArea #if JVET_AD0202_CCCM_MDF - , int downsFilterIdx + , int downsFilterIdx = 0 #endif ); PelBuf xCccmGetLumaRefBuf (const PredictionUnit& pu, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY @@ -520,6 +520,45 @@ public: void xCflmCalcRefArea (const PredictionUnit& pu, const CompArea& chromaArea); #endif +#if JVET_AD0188_CCP_MERGE + void reorderCCPCandidates(const PredictionUnit &pu, CCPModelCandidate candList[], int reorderlistSize); + int xGetOneCCPCandCost(const PredictionUnit &pu, CCPModelCandidate &ccpCand); + void predCCPCandidate(const PredictionUnit &pu, PelBuf &predCb, PelBuf &predCr); + + void xCclmApplyModel(const PredictionUnit &pu, const ComponentID compId, CccmModel<CCCM_NUM_PARAMS> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const; + void xCccmApplyModelOffset(const PredictionUnit& pu, const ComponentID compId, const CccmModel<CCCM_NUM_PARAMS>& cccmModel, int modelId, int modelThr, PelBuf& piPred, int lumaOffset, int chromaOffset[2], int type, int refSizeX, int refSizeY) const; + void xGlmApplyModelOffset(const PredictionUnit& pu, const ComponentID compId, const CompArea& chromaArea, CccmModel<GLM_NUM_PARAMS>& glmModel, int glmIdc, PelBuf& piPred, int lumaOffset, int chromaOffset) const; +#if JVET_AD0202_CCCM_MDF + void xMFCccmApplyModelOffset1(const PredictionUnit& pu, const ComponentID compId, const CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS>& cccmModel, int modelId, int modelThr, PelBuf& piPred, int lumaOffset, int chromaOffset[2]) const; + void xMFCccmApplyModelOffset23(const PredictionUnit& pu, const ComponentID compId, const CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2>& cccmModel, int modelId, int modelThr, PelBuf& piPred, int lumaOffset, int chromaOffset[2]) const; +#endif +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + void xNSCccmApplyModelOffset(const PredictionUnit& pu, const ComponentID compId, const CccmModel<CCCM_NO_SUB_NUM_PARAMS>& cccmModel, int modelId, int modelThr, PelBuf& piPred, int lumaOffset, int chromaOffset[2]) const; +#endif + + void xGetUpdatedOffsetCCLM(const PredictionUnit &pu, const ComponentID compID, const CompArea &chromaArea, CclmModel &cclmModel, int modelNum, int glmIdc); + void xGetUpdatedOffsetCCCM(const PredictionUnit& pu, const ComponentID compID, int modelNum, const CompArea& chromaArea, CccmModel<CCCM_NUM_PARAMS> cccmModel[2], int modelThr, int lumaOffset, int chromaOffset[2], int type, int refSizeX, int refSizeY); + void xGetUpdatedOffsetGLM(const PredictionUnit& pu, const ComponentID compID, const CompArea& chromaArea, CccmModel<GLM_NUM_PARAMS>& glmModel, int glmIdc, int lumaOffset, int& chromaOffset); +#if JVET_AD0202_CCCM_MDF + void xGetUpdatedOffsetMFCCCM1(const PredictionUnit& pu, const ComponentID compID, int modelNum, const CompArea& chromaArea, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModel[2], int modelThr, int lumaOffset, int chromaOffset[2], int type, int refSizeX, int refSizeY); + void xGetUpdatedOffsetMFCCCM23(const PredictionUnit& pu, const ComponentID compID, int modelNum, const CompArea& chromaArea, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModel[2], int modelThr, int lumaOffset, int chromaOffset[2], int type, int refSizeX, int refSizeY); +#endif +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + void xGetUpdatedOffsetNSCCCM(const PredictionUnit& pu, const ComponentID compID, int modelNum, const CompArea& chromaArea, CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModel[2], int modelThr, int lumaOffset, int chromaOffset[]); +#endif + + int xGetCostCCLM(const PredictionUnit &pu, const ComponentID compID, const CompArea &chromaArea, CclmModel &cclmModel, int modelNum, int glmIdc); + int xGetCostCCCM(const PredictionUnit &pu, const ComponentID compID, int modelNum, const CompArea &chromaArea, CccmModel<CCCM_NUM_PARAMS> cccmModel[2], int modelThr, int lumaOffset, int chromaOffset[2], int type, int refSizeX, int refSizeY); + int xGetCostGLM(const PredictionUnit& pu, const ComponentID compID, const CompArea& chromaArea, CccmModel<GLM_NUM_PARAMS>& glmModel, int glmIdc, int lumaOffset, int& chromaOffset); +#if JVET_AD0202_CCCM_MDF + int xGetCostMFCCCM1(const PredictionUnit& pu, const ComponentID compID, int modelNum, const CompArea& chromaArea, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModel[2], int modelThr, int lumaOffset, int chromaOffset[2], int type, int refSizeX, int refSizeY); + int xGetCostMFCCCM23(const PredictionUnit& pu, const ComponentID compID, int modelNum, const CompArea& chromaArea, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModel[2], int modelThr, int lumaOffset, int chromaOffset[2], int type, int refSizeX, int refSizeY); +#endif +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + int xGetCostNSCCCM(const PredictionUnit& pu, const ComponentID compID, int modelNum, const CompArea& chromaArea, CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModel[2], int modelThr, int lumaOffset, int chromaOffset[]); +#endif +#endif + #if ENABLE_DIMD #if JVET_AC0115_INTRA_TMP_DIMD_MTS_LFNST static int deriveDimdIntraTmpModePred(const CodingUnit cu, CPelBuf predBuf); // using prediction samples diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 1c0bb5a6f..317e25736 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -1767,6 +1767,9 @@ private: #if JVET_AC0147_CCCM_NO_SUBSAMPLING int m_cccm; #endif +#if JVET_AD0188_CCP_MERGE + bool m_ccpMerge; +#endif #if JVET_V0130_INTRA_TMP bool m_intraTMP; ///< intra Template Matching unsigned m_intraTmpMaxSize; ///< max CU size for which intra TMP is allowed @@ -2380,7 +2383,10 @@ void setCCALFEnabledFlag( bool b ) void setUseCccm( int i ) { m_cccm = i; } int getUseCccm() const { return m_cccm; } #endif - +#if JVET_AD0188_CCP_MERGE + void setUseCcpMerge ( bool i ) { m_ccpMerge = i; } + bool getUseCcpMerge () const { return m_ccpMerge; } +#endif #if ENABLE_OBMC void setUseOBMC ( bool b ) { m_OBMC = b; } bool getUseOBMC () const { return m_OBMC; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 58efef890..69c4c639e 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -181,6 +181,7 @@ #define JVET_AC0105_DIRECTIONAL_PLANAR 1 // JVET-AC0105: Directional planar #define JVET_AD0184_REMOVAL_OF_DIVISION_OPERATIONS 1 // JVET-AD0184: Removal of division operations #define JVET_AD0085_MPM_SORTING 1 // JVET-AD0085: Template-based intra MPM list construction +#define JVET_AD0188_CCP_MERGE 1 // JVET_AD0188: Non-local cross-component prediction and cross-component merge mode //IBC #define JVET_Y0058_IBC_LIST_MODIFY 1 // JVET-Y0058: Modifications of IBC merge/AMVP list construction, ARMC-TM-IBC part is included under JVET_W0090_ARMC_TM diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 8538bca2b..714499db0 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -887,6 +887,11 @@ void PredictionUnit::initData() #if JVET_AD0202_CCCM_MDF cccmMultiFilterIdx = 0; #endif +#endif +#if JVET_AD0188_CCP_MERGE + idxNonLocalCCP = 0; + curCand = {}; + curCand.type = CCP_TYPE_NONE; #endif // inter data #if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION @@ -1044,6 +1049,10 @@ PredictionUnit& PredictionUnit::operator=(const IntraPredictionData& predData) #if JVET_AD0202_CCCM_MDF cccmMultiFilterIdx = predData.cccmMultiFilterIdx; #endif +#endif +#if JVET_AD0188_CCP_MERGE + idxNonLocalCCP = predData.idxNonLocalCCP; + curCand = predData.curCand; #endif return *this; } @@ -1201,6 +1210,10 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other ) #if JVET_AD0202_CCCM_MDF cccmMultiFilterIdx = other.cccmMultiFilterIdx; #endif +#endif +#if JVET_AD0188_CCP_MERGE + idxNonLocalCCP = other.idxNonLocalCCP; + curCand = other.curCand; #endif mergeFlag = other.mergeFlag; diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index df31788a5..38939c544 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -539,6 +539,10 @@ struct IntraPredictionData int cccmMultiFilterIdx; #endif #endif +#if JVET_AD0188_CCP_MERGE + int idxNonLocalCCP; + CCPModelCandidate curCand; +#endif }; struct InterPredictionData diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index d91f1cd15..34f5384bb 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -2554,6 +2554,468 @@ bool PU::allowMPMSorted(const PredictionUnit& pu) } #endif +#if JVET_AD0188_CCP_MERGE +bool PU::hasNonLocalCCP(const PredictionUnit &pu) +{ + if (!pu.cs->sps->getUseLMChroma() || !pu.cu->slice->getSPS()->getUseCcpMerge()) + { + return false; + } + if (pu.cu->ispMode && !CS::isDualITree(*pu.cs)) + { + return false; + } + if (pu.chromaSize().width * pu.chromaSize().height <= 16) + { + return false; + } + return true; +} + +const PredictionUnit *PU::getPUFromPos(const PredictionUnit &pu, const ChannelType &chType, const Position &refPos) +{ + const CodingStructure &cs = *pu.cs; + + if (!cs.isDecomp(refPos, chType)) + { + return nullptr; + } + + return cs.getPURestricted(refPos, pu, chType); +} + +int PU::getCCPModelCandidateList(const PredictionUnit &pu, CCPModelCandidate candList[], int selIdx) +{ + int maxCandIdx = 0; + bool found1stCCLM = false; + int64_t scaleCclm[2] = { 0 }; + int shiftCclm[2] = { 3 }; + + int iW = pu.blocks[1].width; + int iH = pu.blocks[1].height; + + auto tryToAddOnePU = [&](const PredictionUnit *puRef) + { + candList[maxCandIdx] = puRef->curCand; + + for (int j = 0; j < maxCandIdx; j++) + { + if (candList[maxCandIdx] == candList[j]) + { + return false; + } + } + return true; + }; + + const Position posCand[5] = { + pu.chromaPos().offset(-1, iH - 1), + pu.chromaPos().offset(iW - 1, -1), + pu.chromaPos().offset(-1, iH), + pu.chromaPos().offset(iW, -1), + pu.chromaPos().offset(-1, -1) + }; + + for (const Position &posLT : posCand) + { + const PredictionUnit* puRef = getPUFromPos(pu, CHANNEL_TYPE_CHROMA, posLT); + if (puRef != nullptr && puRef->curCand.type > 0) + { + if (!tryToAddOnePU(puRef)) + { + continue; + } + if (!found1stCCLM && candList[maxCandIdx].type == CCP_TYPE_CCLM) + { + scaleCclm[0] = candList[maxCandIdx].params[0][0]; + shiftCclm[0] = candList[maxCandIdx].shift[0]; + scaleCclm[1] = candList[maxCandIdx].params[1][0]; + shiftCclm[1] = candList[maxCandIdx].shift[1]; + found1stCCLM = true; + } + maxCandIdx++; + if (maxCandIdx == MAX_CCP_CAND_LIST_SIZE) + { + return maxCandIdx; + } + } + } + + int offsetX = 0; int offsetY = 0; + int offsetX0 = 0; int offsetX1 = 0; int offsetX2 = pu.chType == CHANNEL_TYPE_LUMA ? pu.Y().width >> 1 : pu.Cb().width >> 1; + int offsetY0 = 0; int offsetY1 = 0; int offsetY2 = pu.chType == CHANNEL_TYPE_LUMA ? pu.Y().height >> 1 : pu.Cb().height >> 1; + + const int horNAInterval = std::max((int)(pu.chType == CHANNEL_TYPE_LUMA ? pu.Y().width * 2 : pu.Cb().width * 2) >> 1, 4); + const int verNAInterval = std::max((int)(pu.chType == CHANNEL_TYPE_LUMA ? pu.Y().height * 2 : pu.Cb().height * 2) >> 1, 4); + const int numNACandidate[7] = { 5, 9, 9, 9, 9, 9, 9 }; + const int idxMap[7][9] = { + { 0, 1, 2, 3, 4 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8 } + }; + + for (int iDistanceIndex = 0; iDistanceIndex < 7 && maxCandIdx < MAX_CCP_CAND_LIST_SIZE; iDistanceIndex++) + { + const int iNADistanceHor = horNAInterval * (iDistanceIndex + 1); + const int iNADistanceVer = verNAInterval * (iDistanceIndex + 1); + + for (int naspIdx = 0; naspIdx < numNACandidate[iDistanceIndex] && maxCandIdx < MAX_CCP_CAND_LIST_SIZE; naspIdx++) + { + switch (idxMap[iDistanceIndex][naspIdx]) + { + case 0: offsetX = offsetX0 = -iNADistanceHor - 1; offsetY = offsetY0 = verNAInterval + iNADistanceVer - 1; break; + case 1: offsetX = offsetX1 = horNAInterval + iNADistanceHor - 1; offsetY = offsetY1 = -iNADistanceVer - 1; break; + case 2: offsetX = offsetX2; offsetY = offsetY1; break; + case 3: offsetX = offsetX0; offsetY = offsetY2; break; + case 4: offsetX = offsetX0; offsetY = offsetY1; break; + case 5: offsetX = -1; offsetY = offsetY0; break; + case 6: offsetX = offsetX1; offsetY = -1; break; + case 7: offsetX = offsetX0 >> 1; offsetY = offsetY0; break; + case 8: offsetX = offsetX1; offsetY = offsetY1 >> 1; break; + default: printf("error!"); exit(0); break; + } + + Position posLT(pu.chromaPos().x + offsetX, pu.chromaPos().y + offsetY); + + const PredictionUnit *puRef = getPUFromPos(pu, CHANNEL_TYPE_CHROMA, posLT); + + if (puRef != nullptr && puRef->curCand.type > 0) + { + if (!tryToAddOnePU(puRef)) + { + continue; + } + if (!found1stCCLM && candList[maxCandIdx].type == CCP_TYPE_CCLM) + { + scaleCclm[0] = candList[maxCandIdx].params[0][0]; + shiftCclm[0] = candList[maxCandIdx].shift[0]; + scaleCclm[1] = candList[maxCandIdx].params[1][0]; + shiftCclm[1] = candList[maxCandIdx].shift[1]; + found1stCCLM = true; + } + maxCandIdx++; + if (maxCandIdx == MAX_CCP_CAND_LIST_SIZE) + { + return maxCandIdx; + } + } + } + } + + // Non-adjacent candidates round 2 + const int numNACandidate2[7] = { 4, 4, 4, 4, 4, 4, 4 }; + const int idxMap2[7][5] = { { 0, 1, 2, 3 }, { 0, 1, 2, 3 }, { 0, 1, 2, 3 }, { 0, 1, 2, 3 }, + { 0, 1, 2, 3 }, { 0, 1, 2, 3 }, { 0, 1, 2, 3 } }; + + for (int iDistanceIndex = 0; iDistanceIndex < 7 && maxCandIdx < MAX_CCP_CAND_LIST_SIZE; iDistanceIndex++) + { + const int horNADistance = horNAInterval * (iDistanceIndex + 1); + const int verNADistance = verNAInterval * (iDistanceIndex + 1); + + for (int naspIdx = 0; naspIdx < numNACandidate2[iDistanceIndex] && maxCandIdx < MAX_CCP_CAND_LIST_SIZE; naspIdx++) + { + switch (idxMap2[iDistanceIndex][naspIdx]) + { + case 0: offsetX = offsetX0 = -horNADistance - 1; offsetY = offsetY2 + ((verNAInterval + verNADistance - 1 - offsetY2) >> 1); break; + case 1: offsetX = offsetX2 + ((horNAInterval + horNADistance - 1 - offsetX2) >> 1); offsetY = offsetY0 = -verNADistance - 1; break; + case 2: offsetX = offsetX0; offsetY = offsetY0 + ((offsetY2 - offsetY0) >> 1); break; + case 3: offsetX = offsetX0 + ((offsetX2 - offsetX0) >> 1); offsetY = offsetY0; break; + default: printf("error!"); exit(0); break; + } + + Position posLT(pu.chromaPos().x + offsetX, pu.chromaPos().y + offsetY); + + const PredictionUnit *puRef = getPUFromPos(pu, CHANNEL_TYPE_CHROMA, posLT); + + if (puRef != nullptr && puRef->curCand.type > 0) + { + if (!tryToAddOnePU(puRef)) + { + continue; + } + if (!found1stCCLM && candList[maxCandIdx].type == CCP_TYPE_CCLM) + { + scaleCclm[0] = candList[maxCandIdx].params[0][0]; + shiftCclm[0] = candList[maxCandIdx].shift[0]; + scaleCclm[1] = candList[maxCandIdx].params[1][0]; + shiftCclm[1] = candList[maxCandIdx].shift[1]; + found1stCCLM = true; + } + maxCandIdx++; + if (maxCandIdx == MAX_CCP_CAND_LIST_SIZE) + { + return maxCandIdx; + } + } + } + } + + auto tryHistCCP = [&](const LutCCP &ccpLut) + { + for (int idx = 0; idx < ccpLut.lutCCP.size(); idx++) + { + CCPModelCandidate curModel; + pu.cs->getOneModelFromCCPLut(ccpLut.lutCCP, curModel, idx); + candList[maxCandIdx] = curModel; + bool duplication = false; + for (int j = 0; j < maxCandIdx; j++) + { + if (candList[maxCandIdx] == candList[j]) + { + duplication = true; + // THROW("Should not duplicaten"); + break; + } + } + if (duplication) + { + continue; + } + if (!found1stCCLM && candList[maxCandIdx].type == CCP_TYPE_CCLM) + { + scaleCclm[0] = candList[maxCandIdx].params[0][0]; + shiftCclm[0] = candList[maxCandIdx].shift[0]; + scaleCclm[1] = candList[maxCandIdx].params[1][0]; + shiftCclm[1] = candList[maxCandIdx].shift[1]; + found1stCCLM = true; + } + maxCandIdx++; + if (maxCandIdx == MAX_CCP_CAND_LIST_SIZE) + { + return maxCandIdx; + } + } + return -1; + }; + + int ret = tryHistCCP(pu.cs->ccpLut); + if (ret != -1) + { + return ret; + } + + if (maxCandIdx < MAX_CCP_CAND_LIST_SIZE) + { + unsigned uiInternalBitDepth = pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA); + const int defaultA[MAX_CCP_CAND_LIST_SIZE] = { 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6 }; + const int defaultB = 1 << (uiInternalBitDepth - 1); + const int defaultShift = 3; + + for (int posIdx = 0; posIdx < MAX_CCP_CAND_LIST_SIZE; posIdx++) + { + CCPModelCandidate curModel; + curModel.type = CCP_TYPE_CCLM; + curModel.params[0][0] = scaleCclm[0]; + curModel.params[0][1] = defaultB; + curModel.shift[0] = shiftCclm[0]; + curModel.params[1][0] = scaleCclm[1]; + curModel.params[1][1] = defaultB; + curModel.shift[1] = shiftCclm[1]; + + if (found1stCCLM && defaultA[posIdx]) + { + int dCb = curModel.params[0][0] > 0 ? -defaultA[posIdx] : defaultA[posIdx]; + if (curModel.shift[0] < defaultShift) + { + curModel.params[0][0] <<= (defaultShift - curModel.shift[0]); + curModel.shift[0] = defaultShift; + } + else if (curModel.shift[0] > defaultShift) + { + dCb <<= (curModel.shift[0] - defaultShift); + } + curModel.params[0][0] += dCb; + + int dCr = curModel.params[1][0] > 0 ? -defaultA[posIdx] : defaultA[posIdx]; + if (curModel.shift[1] < defaultShift) + { + curModel.params[1][0] <<= (defaultShift - curModel.shift[1]); + curModel.shift[1] = defaultShift; + } + else if (curModel.shift[1] > defaultShift) + { + dCr <<= (curModel.shift[1] - defaultShift); + } + curModel.params[1][0] += dCr; + } + else + { + curModel.params[0][0] = curModel.params[1][0] = defaultA[posIdx]; + curModel.shift[0] = curModel.shift[1] = defaultShift; + } + + bool duplication = false; + for (int j = 0; j < maxCandIdx; j++) + { + if (candList[j] == curModel) + { + duplication = true; + // THROW("Should not duplicaten"); + break; + } + } + if (duplication) + { + continue; + } + candList[maxCandIdx] = curModel; + if (selIdx == maxCandIdx) + { + return maxCandIdx + 1; + } + maxCandIdx++; + if (maxCandIdx == MAX_CCP_CAND_LIST_SIZE) + { + return maxCandIdx; + } + } + } + + CHECK(maxCandIdx > MAX_CCP_CAND_LIST_SIZE, "Invlid number of non-adj CCCM candidates"); + return maxCandIdx; +} + +void CU::saveModelsInHCCP(const CodingUnit &cu) +{ + bool lumaUsesISP = !CS::isDualITree(*cu.cs) && cu.ispMode; + if (cu.chromaFormat == CHROMA_400 || (CS::isDualITree(*cu.cs) && cu.chType == CHANNEL_TYPE_LUMA) || !CU::isIntra(cu)) + { + return; + } + if (lumaUsesISP) + { + return; + } + const PredictionUnit &pu = *cu.firstPU; + CodingStructure &cs = *cu.cs; + + if (PU::isLMCMode(pu.intraDir[1]) && pu.curCand.type != CCP_TYPE_NONE) + { + cs.addCCPToLut(cs.ccpLut.lutCCP, pu.curCand, -1); + } +} + +void PU::ccpParamsToCclmModel(const ComponentID compId, const CCPModelCandidate& params, CclmModel& cclmModel) +{ + cclmModel.a = int(params.params[compId - 1][0]); + cclmModel.b = int(params.params[compId - 1][1]); + cclmModel.shift = params.shift[compId - 1]; +#if MMLM + if (params.type & CCP_TYPE_MMLM) + { + cclmModel.a2 = int(params.params2[compId - 1][0]); + cclmModel.b2 = int(params.params2[compId - 1][1]); + cclmModel.shift2 = params.shift2[compId - 1]; + cclmModel.yThres = params.yThres; + } +#endif +} + +void PU::cclmModelToCcpParams(const ComponentID compId, CCPModelCandidate& params, const CclmModel& cclmModel) +{ + params.params[compId - 1][0] = cclmModel.a; + params.params[compId - 1][1] = cclmModel.b; + params.shift[compId - 1] = cclmModel.shift; +#if MMLM + params.params2[compId - 1][0] = cclmModel.a2; + params.params2[compId - 1][1] = cclmModel.b2; + params.shift2[compId - 1] = cclmModel.shift2; + params.yThres = cclmModel.yThres; +#endif +} + +template <int NUM> +#if JVET_AB0174_CCCM_DIV_FREE +void PU::cccmModelToCcpParams(CCPModelCandidate& params, const CccmModel<NUM> cccmModelCb[2], const CccmModel<NUM> cccmModelCr[2], const int yThres, const int cccmLumaOffset) +#else +void PU::cccmModelToCcpParams(CCPModelCandidate& params, const CccmModel<NUM> cccmModelCb[2], const CccmModel<NUM> cccmModelCr[2], const int yThres) +#endif +{ + std::memcpy(params.params[0], cccmModelCb[0].params, sizeof(TCccmCoeff) * NUM); + std::memcpy(params.params[1], cccmModelCr[0].params, sizeof(TCccmCoeff) * NUM); + params.midVal = cccmModelCb[0].midVal; + params.bd = cccmModelCb[0].bd; +#if JVET_AB0174_CCCM_DIV_FREE + params.lumaOffset = cccmLumaOffset; +#endif +#if MMLM + std::memcpy(params.params2[0], cccmModelCb[1].params, sizeof(TCccmCoeff) * NUM); + std::memcpy(params.params2[1], cccmModelCr[1].params, sizeof(TCccmCoeff) * NUM); + params.yThres = yThres; +#endif +} + +template<int NUM> +void PU::ccpParamsToCccmModel(const CCPModelCandidate& params, CccmModel<NUM> cccmModelCb[2], CccmModel<NUM> cccmModelCr[2]) +{ + std::memcpy(cccmModelCb[0].params, params.params[0], sizeof(TCccmCoeff) * NUM); + std::memcpy(cccmModelCr[0].params, params.params[1], sizeof(TCccmCoeff) * NUM); + cccmModelCb[0].midVal = cccmModelCr[0].midVal = params.midVal; + cccmModelCb[0].bd = cccmModelCr[0].bd = params.bd; +#if MMLM + if (params.type & CCP_TYPE_MMLM) + { + std::memcpy(cccmModelCb[1].params, params.params2[0], sizeof(TCccmCoeff) * NUM); + std::memcpy(cccmModelCr[1].params, params.params2[1], sizeof(TCccmCoeff) * NUM); + cccmModelCb[1].midVal = cccmModelCr[1].midVal = params.midVal; + cccmModelCb[1].bd = cccmModelCr[1].bd = params.bd; + } +#endif +} + +#if JVET_AB0174_CCCM_DIV_FREE +template void PU::cccmModelToCcpParams(CCPModelCandidate& params, const CccmModel<CCCM_NUM_PARAMS> cccmModelCb[2], const CccmModel<CCCM_NUM_PARAMS> cccmModelCr[2], const int yThres, const int cccmLumaOffset); +#else +template void PU::cccmModelToCcpParams(CCPModelCandidate& params, const CccmModel<CCCM_NUM_PARAMS> cccmModelCb[2], const CccmModel<CCCM_NUM_PARAMS> cccmModelCr[2], const int yThres); +#endif +template void PU::ccpParamsToCccmModel(const CCPModelCandidate& params, CccmModel<CCCM_NUM_PARAMS> cccmModelCb[2], CccmModel<CCCM_NUM_PARAMS> cccmModelCr[2]); + +#if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AB0174_CCCM_DIV_FREE +template void PU::cccmModelToCcpParams(CCPModelCandidate& params, const CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCb[2], const CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCr[2], const int yThres, const int cccmLumaOffset); +#else +template void PU::cccmModelToCcpParams(CCPModelCandidate ¶ms, const CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCb[2], const CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCr[2], const int yThres); +#endif +template void PU::ccpParamsToCccmModel(const CCPModelCandidate& params, CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCb[2], CccmModel<CCCM_NO_SUB_NUM_PARAMS> cccmModelCr[2]); +#endif + +#if JVET_AD0202_CCCM_MDF +#if JVET_AB0174_CCCM_DIV_FREE +template void PU::cccmModelToCcpParams(CCPModelCandidate& params, const CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCb[2], const CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCr[2], const int yThres, const int cccmLumaOffset); +#else +template void PU::cccmModelToCcpParams(CCPModelCandidate& params, const CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCb[2], const CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCr[2], const int yThres); +#endif +template void PU::ccpParamsToCccmModel(const CCPModelCandidate& params, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCb[2], CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCr[2]); +#endif + +#if JVET_AB0092_GLM_WITH_LUMA +#if JVET_AB0174_CCCM_DIV_FREE +void PU::glmModelToCcpParams(const ComponentID compId, CCPModelCandidate& params, const CccmModel<GLM_NUM_PARAMS> &glmModel, const int lumaOffset) +#else +void PU::glmModelToCcpParams(const ComponentID compId, CCPModelCandidate& params, const CccmModel<GLM_NUM_PARAMS> &glmModel) +#endif +{ + std::memcpy(params.params[compId - 1], glmModel.params, sizeof(TCccmCoeff) * GLM_NUM_PARAMS); + params.midVal = glmModel.midVal; + params.bd = glmModel.bd; +#if JVET_AB0174_CCCM_DIV_FREE + params.lumaOffset = lumaOffset; +#endif +} + +void PU::ccpParamsToGlmModel(const ComponentID compId, const CCPModelCandidate& params, CccmModel<GLM_NUM_PARAMS> &glmModel) +{ + std::memcpy(glmModel.params, params.params[compId - 1], sizeof(TCccmCoeff) * GLM_NUM_PARAMS); + glmModel.midVal = params.midVal; + glmModel.bd = params.bd; +} +#endif +#endif + #if JVET_AB0155_SGPM bool PU::isSgpm(const PredictionUnit &pu, const ChannelType &chType) { diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 12d0140ec..8a77ccc3a 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -79,6 +79,9 @@ namespace CU void addPUs ( CodingUnit& cu); void saveMotionInHMVP (const CodingUnit& cu, const bool isToBeDone ); +#if JVET_AD0188_CCP_MERGE + void saveModelsInHCCP (const CodingUnit &cu); +#endif PartSplit getSplitAtDepth (const CodingUnit& cu, const unsigned depth); #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS @@ -673,6 +676,32 @@ namespace PU #if JVET_AD0085_MPM_SORTING bool allowMPMSorted(const PredictionUnit& pu); #endif +#if JVET_AD0188_CCP_MERGE + void ccpParamsToCclmModel(const ComponentID compID, const CCPModelCandidate& params, CclmModel& cclmModel); + void cclmModelToCcpParams(const ComponentID compId, CCPModelCandidate& params, const CclmModel& cclmModel); + + template <int NUM> +#if JVET_AB0174_CCCM_DIV_FREE + void cccmModelToCcpParams(CCPModelCandidate& params, const CccmModel<NUM> cccmModelCb[2], const CccmModel<NUM> cccmModelCr[2], const int yThres = 0, const int cccmLumaOffset = 0); +#else + void cccmModelToCcpParams(CCPModelCandidate& params, const CccmModel<NUM> cccmModelCb[2], const CccmModel<NUM> cccmModelCr[2], const int yThres = 0); +#endif + template<int NUM> + void ccpParamsToCccmModel(const CCPModelCandidate& params, CccmModel<NUM> cccmModelCb[2], CccmModel<NUM> cccmModelCr[2]); + +#if JVET_AB0092_GLM_WITH_LUMA +#if JVET_AB0174_CCCM_DIV_FREE + void glmModelToCcpParams(const ComponentID compId, CCPModelCandidate& params, const CccmModel<GLM_NUM_PARAMS> &glmModel, const int lumaOffset); +#else + void glmModelToCcpParams(const ComponentID compId, CCPModelCandidate& params, const CccmModel<GLM_NUM_PARAMS> &glmModel); +#endif + void ccpParamsToGlmModel(const ComponentID compId, const CCPModelCandidate& params, CccmModel<GLM_NUM_PARAMS> &glmModel); +#endif + + const PredictionUnit *getPUFromPos(const PredictionUnit &pu, const ChannelType &chType, const Position &refPos); + bool hasNonLocalCCP(const PredictionUnit &pu); + int getCCPModelCandidateList(const PredictionUnit &pu, CCPModelCandidate candList[], int selIdx = -1); +#endif } // TU tools diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 998ecef33..a63eeae09 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -2556,8 +2556,34 @@ void CABACReader::glmIdc(PredictionUnit& pu) } } #endif + +#if JVET_AD0188_CCP_MERGE +void CABACReader::nonLocalCCPIndex(PredictionUnit &pu) +{ + pu.idxNonLocalCCP = 0; + + if (PU::hasNonLocalCCP(pu)) + { + pu.idxNonLocalCCP = m_BinDecoder.decodeBin(Ctx::nonLocalCCP(0)); + if (pu.idxNonLocalCCP) + { + pu.idxNonLocalCCP += unary_max_eqprob(MAX_CCP_CAND_LIST_SIZE - 1); + pu.cccmFlag = 0; + pu.intraDir[1] = LM_CHROMA_IDX; + } + } +} +#endif + bool CABACReader::intra_chroma_lmc_mode(PredictionUnit& pu) { +#if JVET_AD0188_CCP_MERGE + nonLocalCCPIndex(pu); + if (pu.idxNonLocalCCP) + { + return true; + } +#endif #if MMLM int lmModeList[NUM_CHROMA_MODE]; #else diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 6bc5d81a2..55cd6c300 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -131,6 +131,9 @@ public: #if JVET_AA0057_CCCM void cccmFlag ( PredictionUnit& pu ); #endif +#if JVET_AD0188_CCP_MERGE + void nonLocalCCPIndex ( PredictionUnit& pu ); +#endif #if ENABLE_DIMD void cu_dimd_flag (CodingUnit& cu); #endif diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 11335d1a9..18166a2ce 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -510,6 +510,9 @@ void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea ) #endif #endif xReconIntraQT( currCU ); +#if JVET_AD0188_CCP_MERGE + CU::saveModelsInHCCP(currCU); +#endif break; default: THROW( "Invalid prediction mode" ); @@ -633,6 +636,99 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) } //===== get prediction signal ===== +#if JVET_AD0188_CCP_MERGE + if (compID != COMPONENT_Y && pu.idxNonLocalCCP) + { + if (compID == COMPONENT_Cb) + { + PelBuf predCr = cs.getPredBuf(tu.blocks[COMPONENT_Cr]); + CCPModelCandidate candList[MAX_CCP_CAND_LIST_SIZE]; + + int candIdx = pu.idxNonLocalCCP - 1; + + int candNum = PU::getCCPModelCandidateList(pu, candList); + bool hasFilteredCCCM = false; + bool hasFilteredCCLM = false; + bool hasFilteredNSCCCM = false; + bool hasFilteredGLM[8] = { false, false, false, false, false, false, false, false}; +#if JVET_AD0202_CCCM_MDF + bool hasFilteredMFCCCM = false; +#endif + + for (int i = 0; i < candNum; i++) + { + if (candList[i].type & (CCP_TYPE_CCCM | CCP_TYPE_GLCCCM)) + { + if (!hasFilteredCCCM) + { + m_pcIntraPred->xCccmCreateLumaRef(pu, area); + hasFilteredCCCM = true; + } + } +#if JVET_AD0202_CCCM_MDF + else if (candList[i].type & CCP_TYPE_MDFCCCM) + { + if (!hasFilteredMFCCCM) + { + pu.cccmMultiFilterIdx = candList[i].cccmMultiFilterIdx; + if (!hasFilteredCCCM) + { + m_pcIntraPred->xCccmCreateLumaRef(pu, area, 0); + hasFilteredCCCM = true; + } + m_pcIntraPred->xCccmCreateLumaRef(pu, area, 1); + m_pcIntraPred->xCccmCreateLumaRef(pu, area, 2); + m_pcIntraPred->xCccmCreateLumaRef(pu, area, 3); + pu.cccmMultiFilterIdx = 0; + hasFilteredMFCCCM = true; + } + } +#endif +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + else if (candList[i].type & CCP_TYPE_NSCCCM) + { + if (!hasFilteredNSCCCM) + { + pu.cccmNoSubFlag = 1; + m_pcIntraPred->xCccmCreateLumaNoSubRef(pu, area); + pu.cccmNoSubFlag = 0; + hasFilteredNSCCCM = true; + } + } +#endif + else if (candList[i].type & CCP_TYPE_CCLM) + { + if (!hasFilteredCCLM) + { + m_pcIntraPred->xGetLumaRecPixels(pu, area); + hasFilteredCCLM = true; + } + } + else if (candList[i].type & (CCP_TYPE_GLM0123 | CCP_TYPE_GLM4567)) + { + int filtertype = candList[i].glmIdc - 1; + if (!hasFilteredGLM[filtertype]) + { + pu.glmIdc.cr0 = pu.glmIdc.cb0 = filtertype + 1; + m_pcIntraPred->xGetLumaRecPixels(pu, area); + pu.glmIdc.cr0 = pu.glmIdc.cb0 = 0; + hasFilteredGLM[filtertype] = true; + } + } + else + { + THROW("Invalid type"); + } + } + CHECK(pu.idxNonLocalCCP < 1 || pu.idxNonLocalCCP > MAX_CCP_CAND_LIST_SIZE, " Invalid idxNonLocalCCP index"); + + m_pcIntraPred->reorderCCPCandidates(pu, candList, candNum); + pu.curCand = candList[candIdx]; + m_pcIntraPred->predCCPCandidate(pu, piPred, predCr); + } + } + else +#endif #if JVET_AA0057_CCCM if( compID != COMPONENT_Y && pu.cccmFlag ) { @@ -794,7 +890,11 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) } #if SIGN_PREDICTION #if JVET_AA0057_CCCM +#if JVET_AD0188_CCP_MERGE + if (isJCCR && compID == COMPONENT_Cb && !pu.cccmFlag && !pu.idxNonLocalCCP) // Cr prediction was done already for CCCM +#else if(isJCCR && compID == COMPONENT_Cb && !pu.cccmFlag) // Cr prediction was done already for CCCM +#endif #else if(isJCCR && compID == COMPONENT_Cb) #endif diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp index f752af445..60a94adc6 100644 --- a/source/Lib/DecoderLib/DecSlice.cpp +++ b/source/Lib/DecoderLib/DecSlice.cpp @@ -233,7 +233,11 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb #if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT static Ctx storedCtx; #endif - +#if JVET_AD0188_CCP_MERGE + { + cs.ccpLut.lutCCP.resize(0); + } +#endif unsigned subStrmId = 0; for( unsigned ctuIdx = 0; ctuIdx < slice->getNumCtuInSlice(); ctuIdx++ ) { @@ -363,7 +367,12 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb cs.resetIBCBuffer = true; #endif } - +#if JVET_AD0188_CCP_MERGE + if (ctuXPosInCtus == tileXPosInCtus) + { + cs.ccpLut.lutCCP.resize(0); + } +#endif if( !cs.slice->isIntra() ) { pic->mctsInfo.init( &cs, getCtuAddr( ctuArea.lumaPos(), *( cs.pcv ) ) ); diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index ef815682b..7de36778e 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -2549,6 +2549,9 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) #endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING READ_UVLC(uiCode, "sps_cccm_cand"); pcSPS->setUseCccm(uiCode); +#endif +#if JVET_AD0188_CCP_MERGE + READ_UVLC(uiCode, "sps_ccp_merge"); pcSPS->setUseCcpMerge(uiCode); #endif if( pcSPS->getChromaFormatIdc() != CHROMA_400) { diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index ec2a72227..95ad5de11 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -2279,6 +2279,13 @@ void CABACWriter::glmIdc(const PredictionUnit& pu) #endif void CABACWriter::intra_chroma_lmc_mode(const PredictionUnit& pu) { +#if JVET_AD0188_CCP_MERGE + nonLocalCCPIndex(pu); + if (pu.idxNonLocalCCP) + { + return; + } +#endif const unsigned intraDir = pu.intraDir[1]; #if MMLM int lmModeList[NUM_CHROMA_MODE]; @@ -2337,6 +2344,23 @@ void CABACWriter::intra_chroma_lmc_mode(const PredictionUnit& pu) #endif } +#if JVET_AD0188_CCP_MERGE +void CABACWriter::nonLocalCCPIndex(const PredictionUnit &pu) +{ + if (PU::hasNonLocalCCP(pu)) + { + CHECK(pu.idxNonLocalCCP < 0 || pu.idxNonLocalCCP > MAX_CCP_CAND_LIST_SIZE, "Invalid idxNonLocalCCP"); + { + m_BinEncoder.encodeBin(pu.idxNonLocalCCP ? 1 : 0, Ctx::nonLocalCCP(0)); + if (pu.idxNonLocalCCP) + { + unary_max_eqprob(pu.idxNonLocalCCP - 1, MAX_CCP_CAND_LIST_SIZE - 1); + } + } + } +} +#endif + #if JVET_AA0057_CCCM void CABACWriter::cccmFlag(const PredictionUnit& pu) { diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index a188b852c..c240e7d3f 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -143,6 +143,9 @@ public: #endif #if JVET_AA0057_CCCM void cccmFlag ( const PredictionUnit& pu ); +#endif +#if JVET_AD0188_CCP_MERGE + void nonLocalCCPIndex ( const PredictionUnit& pu ); #endif void cu_residual ( const CodingUnit& cu, Partitioner& pm, CUCtx& cuCtx ); void rqt_root_cbf ( const CodingUnit& cu ); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 71aacf2e3..8e3f9de01 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -485,6 +485,9 @@ protected: #if JVET_AC0147_CCCM_NO_SUBSAMPLING int m_cccm; #endif +#if JVET_AD0188_CCP_MERGE + bool m_ccpMerge; +#endif #if ENABLE_OBMC bool m_OBMC; #endif @@ -1592,6 +1595,10 @@ public: void setUseCccm (int i) { m_cccm = i; } int getUseCccm () const { return m_cccm; } #endif +#if JVET_AD0188_CCP_MERGE + void setUseCcpMerge (bool i) { m_ccpMerge = i; } + bool getUseCcpMerge () const { return m_ccpMerge; } +#endif #if ENABLE_OBMC void setUseObmc ( bool b ) { m_OBMC = b; } bool getUseObmc () const { return m_OBMC; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 0c66ffa10..185bca903 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1558,6 +1558,20 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par bool isIbcSmallBlk = CU::isIBC(cu) && (cu.lwidth() * cu.lheight() <= 16); CU::saveMotionInHMVP( cu, isIbcSmallBlk ); } + +#if JVET_AD0188_CCP_MERGE + { + const CodingUnit &cu = *bestCS->cus.front(); + bool lumaUsesISP = !CS::isDualITree(*bestCS) && cu.ispMode; + if (!(cu.chromaFormat == CHROMA_400 || (CS::isDualITree(*bestCS) && cu.chType == CHANNEL_TYPE_LUMA)) + && CU::isIntra(cu) && !lumaUsesISP && bestCS->cus.size() == 1 + && bestCS->area.Cb() == (*bestCS->cus.back()).Cb()) + { + CU::saveModelsInHCCP(cu); + } + } +#endif + bestCS->picture->getPredBuf(currCsArea).copyFrom(bestCS->getPredBuf(currCsArea)); #if JVET_Z0118_GDR bestCS->updateReconMotIPM(currCsArea); // xcomrpessCU - need @@ -1842,6 +1856,9 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, const Slice &slice = *tempCS->slice; const int oldPrevQp = tempCS->prevQP[partitioner.chType]; const auto oldMotionLut = tempCS->motionLut; +#if JVET_AD0188_CCP_MERGE + const auto oldCCPLut = tempCS->ccpLut; +#endif #if ENABLE_QPA_SUB_CTU const PPS &pps = *tempCS->pps; const uint32_t currDepth = partitioner.currDepth; @@ -1981,6 +1998,9 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, #if JVET_Z0118_GDR tempCS->motionLut = oldMotionLut; +#if JVET_AD0188_CCP_MERGE + tempCS->ccpLut = oldCCPLut; +#endif tempCS->prevPLT = oldPLT; tempCS->releaseIntermediateData(); tempCS->prevQP[partitioner.chType] = oldPrevQp; @@ -2240,6 +2260,9 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, tempCS->motionLut = oldMotionLut; tempCS->prevPLT = oldPLT; +#if JVET_AD0188_CCP_MERGE + tempCS->ccpLut = oldCCPLut; +#endif tempCS->releaseIntermediateData(); diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 8201529c8..165280278 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -1854,6 +1854,9 @@ void EncLib::xInitSPS( SPS& sps ) #if JVET_AC0147_CCCM_NO_SUBSAMPLING sps.setUseCccm ( m_cccm ); #endif +#if JVET_AD0188_CCP_MERGE + sps.setUseCcpMerge ( m_ccpMerge ); +#endif #if ENABLE_OBMC sps.setUseOBMC ( m_OBMC ); #endif diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index 16aca5cd4..3c6964413 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -1842,6 +1842,12 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons } } #endif +#if JVET_AD0188_CCP_MERGE + if ((pCfg->getSwitchPOC() != pcPic->poc || -1 == pCfg->getDebugCTU())) + { + cs.ccpLut.lutCCP.resize(0); + } +#endif #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS if (pcSlice->getUseIBC() && m_pcCuEncoder->getEncCfg()->getIBCHashSearch() && m_pcCuEncoder->getEncCfg()->getIBCFracMode()) { @@ -1912,6 +1918,13 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons #endif } +#if JVET_AD0188_CCP_MERGE + if ((pCfg->getSwitchPOC() != pcPic->poc || -1 == pCfg->getDebugCTU()) && cs.pps->ctuIsTileColBd(ctuXPosInCtus)) + { + cs.ccpLut.lutCCP.resize(0); + } +#endif + const SubPic &curSubPic = pcSlice->getPPS()->getSubPicFromPos(pos); // padding/restore at slice level if (pcSlice->getPPS()->getNumSubPics() >= 2 && curSubPic.getTreatedAsPicFlag() && ctuIdx == 0) diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 8dbae2204..4989f9f43 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -2844,6 +2844,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #else bool isChromaFusion = false; #endif +#endif +#if JVET_AD0188_CCP_MERGE + int bestNonAdjCCCM = 0; + CCPModelCandidate ccpModelBest; #endif //----- init mode list ---- @@ -3473,12 +3477,21 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner distParamSadCr.applyWeight = false; distParamSatdCr.applyWeight = false; +#if JVET_AD0188_CCP_MERGE + pu.curCand = {}; +#endif #if JVET_AD0202_CCCM_MDF predIntraCCCM(pu, cccmStorage[sub][cccmBufferIdx].Cb(), cccmStorage[sub][cccmBufferIdx].Cr(), mode); #else predIntraCCCM(pu, cccmStorage[sub][idx].Cb(), cccmStorage[sub][idx].Cr(), mode); #endif - +#if JVET_AD0188_CCP_MERGE +#if JVET_AD0202_CCCM_MDF + m_ccmParamsStorage[sub][cccmBufferIdx] = pu.curCand; +#else + m_ccmParamsStorage[sub][idx] = pu.curCand; +#endif +#endif sadCb = distParamSadCb.distFunc(distParamSadCb) * 2; satdCb = distParamSatdCb.distFunc(distParamSatdCb); sad += std::min(sadCb, satdCb); @@ -3817,7 +3830,13 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner distParamSadCr.applyWeight = false; distParamSatdCr.applyWeight = false; +#if JVET_AD0188_CCP_MERGE + pu.curCand = {}; +#endif predIntraCCCM(pu, cccmStorage[idx].Cb(), cccmStorage[idx].Cr(), mode); +#if JVET_AD0188_CCP_MERGE + m_ccmParamsStorage[idx] = pu.curCand; +#endif sadCb = distParamSadCb.distFunc(distParamSadCb) * 2; satdCb = distParamSatdCb.distFunc(distParamSatdCb); @@ -3990,6 +4009,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #endif #endif #endif +#if JVET_AD0188_CCP_MERGE + pu.curCand = {}; +#endif #if JVET_AC0119_LM_CHROMA_FUSION int secondNonLmMode = -1; double dSecondNonLmCost = MAX_DOUBLE; @@ -4103,6 +4125,17 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner uiBestDist = uiDist; uiBestMode = chromaIntraMode; bestBDPCMMode = cu.bdpcmModeChroma; + +#if JVET_AD0188_CCP_MERGE + if (PU::isLMCMode(chromaIntraMode)) + { + ccpModelBest = pu.curCand; + } + else + { + ccpModelBest.type = CCP_TYPE_NONE; + } +#endif } #if JVET_Z0050_DIMD_CHROMA_FUSION #if JVET_AC0119_LM_CHROMA_FUSION @@ -4135,6 +4168,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #endif #endif } +#if JVET_AD0188_CCP_MERGE + pu.curCand = {}; +#endif #if JVET_AA0126_GLM for (int32_t uiMode = 0; uiMode < NUM_LMC_MODE; uiMode++) @@ -4206,6 +4242,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner uiBestMode = chromaIntraMode; bestBDPCMMode = cu.bdpcmModeChroma; bestGlmIdc = pu.glmIdc; + #if JVET_AD0188_CCP_MERGE + ccpModelBest = pu.curCand; + ccpModelBest.glmIdc = pu.glmIdc.cb0; +#endif } #if !JVET_AB0092_GLM_WITH_LUMA if ( chromaIntraMode == LM_CHROMA_IDX && !bestGlmIdc.isActive() ) @@ -4218,6 +4258,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner } pu.glmIdc.setAllZero(); +#if JVET_AD0188_CCP_MERGE + pu.curCand = {}; +#endif #endif #if JVET_Z0050_DIMD_CHROMA_FUSION @@ -4410,6 +4453,16 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner isChromaFusion = pu.isChromaFusion; #if JVET_AA0126_GLM bestGlmIdc = pu.glmIdc; +#endif + #if JVET_AD0188_CCP_MERGE + if (isChromaFusion == 1) + { + ccpModelBest = pu.curCand; + } + else + { + ccpModelBest.type = CCP_TYPE_NONE; + } #endif } #if !JVET_AC0119_LM_CHROMA_FUSION @@ -4421,6 +4474,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #else pu.isChromaFusion = false; #endif +#if JVET_AD0188_CCP_MERGE + pu.curCand = {}; +#endif #endif #if JVET_Z0050_CCLM_SLOPE @@ -4512,6 +4568,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #endif #if JVET_AA0126_GLM bestGlmIdc = pu.glmIdc; +#endif +#if JVET_AD0188_CCP_MERGE + ccpModelBest = pu.curCand; #endif } } @@ -4519,6 +4578,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner } pu.cclmOffsets.setAllZero(); +#if JVET_AD0188_CCP_MERGE + pu.curCand = {}; +#endif #endif #if JVET_AA0057_CCCM @@ -4648,6 +4710,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner continue; } pu.cccmMultiFilterIdx = filterIdx; +#if JVET_AD0188_CCP_MERGE + pu.curCand = {}; +#endif #endif pu.cccmNoSubFlag = sub; #if JVET_AC0054_GLCCCM @@ -4694,6 +4759,18 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_AC0147_CCCM_NO_SUBSAMPLING #if JVET_AD0202_CCCM_MDF const int cccmBufferIdx = filterIdx * CCCM_NUM_MODES + uiMode; +#endif +#if JVET_AD0188_CCP_MERGE + if (pu.cs->slice->isIntra() && CS::isDualITree(cs)) + { +#if JVET_AD0202_CCCM_MDF + pu.curCand = m_ccmParamsStorage[sub][cccmBufferIdx]; +#else + pu.curCand = m_ccmParamsStorage[sub][uiMode]; +#endif + } +#endif +#if JVET_AD0202_CCCM_MDF xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, cccmStorage[sub][cccmBufferIdx] #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS , pcInterPred @@ -4791,6 +4868,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_AD0202_CCCM_MDF cccmMultiFilterIdxBest = pu.cccmMultiFilterIdx; #endif +#if JVET_AD0188_CCP_MERGE + ccpModelBest = pu.curCand; +#endif #if JVET_AC0147_CCCM_NO_SUBSAMPLING cccmNoSubBest = pu.cccmNoSubFlag; } @@ -4806,6 +4886,196 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #if JVET_AD0202_CCCM_MDF pu.cccmMultiFilterIdx = 0; #endif +#if JVET_AD0188_CCP_MERGE + pu.curCand = {}; +#endif +#endif + +#if JVET_AD0188_CCP_MERGE + if (PU::hasNonLocalCCP(pu)) + { + pu.cccmFlag = 0; + pu.cccmNoSubFlag = 0; + pu.glCccmFlag = 0; + CCPModelCandidate candList[MAX_CCP_CAND_LIST_SIZE]; + double orderedCCPcost[MAX_CCP_CAND_LIST_SIZE]; + int orderedCCPCand[MAX_CCP_CAND_LIST_SIZE]; + PelUnitBuf ccpCandStorage[MAX_CCP_CAND_LIST_SIZE]; + int numPos = PU::getCCPModelCandidateList(pu, candList); + + reorderCCPCandidates(pu, candList, numPos); + + const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda() * FRAC_BITS_SCALE; + + for (int nonAdjCCCMCand = 0; nonAdjCCCMCand < numPos; nonAdjCCCMCand++) + { + pu.intraDir[1] = LM_CHROMA_IDX; // temporary assigned, for SATD checking. + pu.idxNonLocalCCP = nonAdjCCCMCand + 1; + + ccpCandStorage[nonAdjCCCMCand] = m_cccmStorage[0][nonAdjCCCMCand].getBuf(localUnitArea); // Borrow the CCCM storage + + uint64_t sad = 0; + uint64_t sadCb = 0; + uint64_t satdCb = 0; + uint64_t sadCr = 0; + uint64_t satdCr = 0; + CodingStructure &cs = *(pu.cs); + + CompArea areaCb = pu.Cb(); + PelBuf orgCb = cs.getOrgBuf(areaCb); + PelBuf predCb = ccpCandStorage[nonAdjCCCMCand].Cb(); + + CompArea areaCr = pu.Cr(); + PelBuf orgCr = cs.getOrgBuf(areaCr); + PelBuf predCr = ccpCandStorage[nonAdjCCCMCand].Cr(); + m_pcRdCost->setDistParam(distParamSad, orgCb, predCb, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, false); + m_pcRdCost->setDistParam(distParamSatd, orgCb, predCb, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, true); + distParamSad.applyWeight = false; + distParamSatd.applyWeight = false; + + pu.curCand = candList[nonAdjCCCMCand]; + predCCPCandidate(pu, predCb, predCr); + candList[nonAdjCCCMCand] = pu.curCand; + + sadCb = distParamSad.distFunc(distParamSad) * 2; + satdCb = distParamSatd.distFunc(distParamSatd); + sad += std::min(sadCb, satdCb); + + m_pcRdCost->setDistParam(distParamSad, orgCr, predCr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, false); + m_pcRdCost->setDistParam(distParamSatd, orgCr, predCr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, true); + distParamSad.applyWeight = false; + distParamSatd.applyWeight = false; + + sadCr = distParamSad.distFunc(distParamSad) * 2; + satdCr = distParamSatd.distFunc(distParamSatd); + sad += std::min(sadCr, satdCr); + + m_CABACEstimator->resetBits(); + m_CABACEstimator->nonLocalCCPIndex(pu); + uint64_t estbits = m_CABACEstimator->getEstFracBits(); + double curCost = (double) sad + sqrtLambdaForFirstPass * (double) estbits; + orderedCCPcost[nonAdjCCCMCand] = curCost; + orderedCCPCand[nonAdjCCCMCand] = nonAdjCCCMCand; + + for (int i = 0; i < nonAdjCCCMCand; i++) + { + if (curCost < orderedCCPcost[i]) + { + for (int j = nonAdjCCCMCand; j > i; j--) + { + orderedCCPcost[j] = orderedCCPcost[j - 1]; + orderedCCPCand[j] = orderedCCPCand[j - 1]; + } + orderedCCPcost[i] = curCost; + orderedCCPCand[i] = nonAdjCCCMCand; + break; + } + } + } + + const int numRDtest = std::min(2, numPos); + for (int rdIdx = 0; rdIdx < numRDtest; rdIdx++) + { + int chromaIntraMode = LM_CHROMA_IDX; + + pu.cccmFlag = 0; + pu.cccmNoSubFlag = 0; + pu.glCccmFlag = 0; + + int nonAdjCCCMCand = orderedCCPCand[rdIdx]; + + pu.idxNonLocalCCP = nonAdjCCCMCand + 1; + pu.curCand = candList[nonAdjCCCMCand]; + + // Original RD check code replicated from above + cs.setDecomp(pu.Cb(), false); + cs.dist = baseDist; + //----- restore context models ----- + m_CABACEstimator->getCtx() = ctxStart; + + //----- chroma coding ----- + pu.intraDir[1] = chromaIntraMode; +#if JVET_AB0143_CCCM_TS + xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, ccpCandStorage[nonAdjCCCMCand]); +#else + xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType); +#endif + if (lumaUsesISP && cs.dist == MAX_UINT) + { + continue; + } + + if (cs.sps->getTransformSkipEnabledFlag()) + { + m_CABACEstimator->getCtx() = ctxStart; + } + + uint64_t fracBits = xGetIntraFracBitsQT(cs, partitioner, false, true, -1, ispType); + Distortion uiDist = cs.dist; + double dCost = m_pcRdCost->calcRdCost(fracBits, uiDist - baseDist); + + //----- compare ----- + if (dCost < dBestCost) + { + if (lumaUsesISP && dCost < bestCostSoFar) + { + bestCostSoFar = dCost; + } + for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ ) + { + const CompArea &area = pu.blocks[i]; + + saveCS.getRecoBuf(area).copyFrom(cs.getRecoBuf(area)); +#if KEEP_PRED_AND_RESI_SIGNALS + saveCS.getPredBuf(area).copyFrom(cs.getPredBuf(area)); + saveCS.getResiBuf(area).copyFrom(cs.getResiBuf(area)); +#endif + saveCS.getPredBuf(area).copyFrom(cs.getPredBuf(area)); + cs.picture->getPredBuf(area).copyFrom(cs.getPredBuf(area)); +#if !JVET_AB0143_CCCM_TS + cs.picture->getRecoBuf(area).copyFrom(cs.getRecoBuf(area)); +#endif + + for (uint32_t j = 0; j < saveCS.tus.size(); j++) + { + saveCS.tus[j]->copyComponentFrom(*orgTUs[j], area.compID); + } + } + + dBestCost = dCost; + uiBestDist = uiDist; + + uiBestMode = chromaIntraMode; + + bestBDPCMMode = cu.bdpcmModeChroma; +#if JVET_Z0050_DIMD_CHROMA_FUSION + isChromaFusion = pu.isChromaFusion; +#endif +#if JVET_Z0050_CCLM_SLOPE + bestCclmOffsets = pu.cclmOffsets; +#endif + cccmModeBest = pu.cccmFlag; +#if JVET_AA0126_GLM + bestGlmIdc = pu.glmIdc; +#endif +#if JVET_AC0147_CCCM_NO_SUBSAMPLING + cccmNoSubBest = pu.cccmNoSubFlag; +#endif +#if JVET_AC0054_GLCCCM + glCccmBest = pu.glCccmFlag; +#endif +#if JVET_AD0202_CCCM_MDF + cccmMultiFilterIdxBest = pu.cccmMultiFilterIdx; +#endif + bestNonAdjCCCM = pu.idxNonLocalCCP; + ccpModelBest = pu.curCand; + } + } + } + pu.idxNonLocalCCP = 0; +#if JVET_AD0188_CCP_MERGE + pu.curCand = {}; +#endif #endif for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ ) { @@ -4855,6 +5125,10 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner #endif #if JVET_AA0126_GLM pu.glmIdc = bestGlmIdc; +#endif +#if JVET_AD0188_CCP_MERGE + pu.idxNonLocalCCP = bestNonAdjCCCM; + pu.curCand = ccpModelBest; #endif } @@ -9359,6 +9633,21 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio initIntraPatternChType( *currTU.cu, cbArea); initIntraPatternChType( *currTU.cu, crArea); + #if JVET_AD0188_CCP_MERGE + if (pu.idxNonLocalCCP) + { + if (!predStorage.bufs.empty()) + { + piPredCb.copyFrom(predStorage.Cb()); + piPredCr.copyFrom(predStorage.Cr()); + } + else + { + predCCPCandidate(pu, piPredCb, piPredCr); + } + } + else +#endif #if JVET_AA0057_CCCM if( pu.cccmFlag ) { diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 0806cc02d..4b1932cc1 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -553,6 +553,18 @@ private: #endif #endif +#if JVET_AD0188_CCP_MERGE +#if JVET_AC0147_CCCM_NO_SUBSAMPLING +#if JVET_AD0202_CCCM_MDF + CCPModelCandidate m_ccmParamsStorage[2][TOTAL_NUM_CCCM_MODES]; +#else + CCPModelCandidate m_ccmParamsStorage[2][CCCM_NUM_MODES]; +#endif +#else + CCPModelCandidate m_ccmParamsStorage[CCCM_NUM_MODES]; +#endif +#endif + #if JVET_AC0119_LM_CHROMA_FUSION PelStorage m_predStorage[2]; PelStorage m_fusionStorage[6]; diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 39cb0b9d4..7aee90c5c 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -1611,6 +1611,10 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) #if JVET_AC0147_CCCM_NO_SUBSAMPLING WRITE_UVLC(pcSPS->getUseCccm() , "sps_cccm_cand"); #endif +#if JVET_AD0188_CCP_MERGE + WRITE_UVLC(pcSPS->getUseCcpMerge(), "sps_ccp_merge"); +#endif + if( pcSPS->getChromaFormatIdc() != CHROMA_400) { WRITE_FLAG( pcSPS->getUseLMChroma() ? 1 : 0, "sps_cclm_enabled_flag"); -- GitLab