diff --git a/source/Lib/CommonLib/MotionInfo.h b/source/Lib/CommonLib/MotionInfo.h index 26fcb5a712797ddf09b3b2b262617542e8c8269d..4b89dade0c12af8e8e1a0bebb8036f13ffa639bf 100644 --- a/source/Lib/CommonLib/MotionInfo.h +++ b/source/Lib/CommonLib/MotionInfo.h @@ -208,5 +208,11 @@ public: } }; #endif - +#if JVET_L0266_HMVP +struct LuTMotionCand +{ + MotionInfo* m_MotionCand; + int currCnt; +}; +#endif #endif // __MOTIONINFO__ diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 6023e01bc877a3e7a47d9a804bb897eb9b9e5323..f51ef38985416363b46350c3eb6e346dfd764305 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -41,6 +41,9 @@ #include "Picture.h" #include "dtrace_next.h" +#if JVET_L0266_HMVP +#include "UnitTools.h" +#endif //! \ingroup CommonLib //! \{ @@ -125,6 +128,9 @@ Slice::Slice() , m_iProcessingStartTime ( 0 ) , m_dProcessingTime ( 0 ) , m_uiMaxBTSize ( 0 ) +#if JVET_L0266_HMVP +, m_MotionCandLuTs (NULL) +#endif { for(uint32_t i=0; i<NUM_REF_PIC_LIST_01; i++) { @@ -161,11 +167,16 @@ Slice::Slice() m_saoEnabledFlag[ch] = false; } +#if JVET_L0266_HMVP + initMotionLUTs(); +#endif } Slice::~Slice() { - +#if JVET_L0266_HMVP + destroyMotionLUTs(); +#endif } @@ -197,6 +208,9 @@ void Slice::initSlice() m_enableTMVPFlag = true; m_subPuMvpSubBlkSizeSliceEnable = false; m_subPuMvpSubBlkLog2Size = 2; +#if JVET_L0266_HMVP + resetMotionLUTs(); +#endif } void Slice::setDefaultClpRng( const SPS& sps ) @@ -1550,7 +1564,75 @@ void Slice::stopProcessingTimer() m_dProcessingTime += (double)(clock()-m_iProcessingStartTime) / CLOCKS_PER_SEC; m_iProcessingStartTime = 0; } +#if JVET_L0266_HMVP +void Slice::initMotionLUTs() +{ + m_MotionCandLuTs = new LuTMotionCand; + m_MotionCandLuTs->currCnt = 0; + m_MotionCandLuTs->m_MotionCand = nullptr; + m_MotionCandLuTs->m_MotionCand = new MotionInfo[MAX_NUM_HMVP_CANDS]; +} +void Slice::destroyMotionLUTs() +{ + delete[] m_MotionCandLuTs->m_MotionCand; + m_MotionCandLuTs->m_MotionCand = nullptr; + delete[] m_MotionCandLuTs; + m_MotionCandLuTs = NULL; +} +void Slice::resetMotionLUTs() +{ + m_MotionCandLuTs->currCnt = 0; +} + +MotionInfo Slice::getMotionInfoFromLUTs(int MotCandIdx) const +{ + return m_MotionCandLuTs->m_MotionCand[MotCandIdx]; +} + + + +void Slice::addMotionInfoToLUTs(LuTMotionCand* lutMC, MotionInfo newMi) +{ + int currCnt = lutMC->currCnt ; + + bool bPruned = false; + int sameCandIdx = -1; + for (int idx = 0; idx < currCnt; idx++) + { + if (lutMC->m_MotionCand[idx] == newMi) + { + sameCandIdx = idx; + bPruned = true; + break; + } + } + if (bPruned || lutMC->currCnt == MAX_NUM_HMVP_CANDS) + { + int startIdx = bPruned ? sameCandIdx : 0; + memmove(&lutMC->m_MotionCand[startIdx], &lutMC->m_MotionCand[startIdx+1], sizeof(MotionInfo)*(currCnt - sameCandIdx - 1)); + memcpy(&lutMC->m_MotionCand[lutMC->currCnt-1], &newMi, sizeof(MotionInfo)); + } + else + { + memcpy(&lutMC->m_MotionCand[lutMC->currCnt++], &newMi, sizeof(MotionInfo)); + } +} +void Slice::updateMotionLUTs(LuTMotionCand* lutMC, CodingUnit & cu) +{ + PredictionUnit *selectedPU = cu.firstPU; + if (cu.affine) { return; } + + MotionInfo newMi = selectedPU->getMotionInfo(); + addMotionInfoToLUTs(lutMC, newMi); +} + +void Slice::copyMotionLUTs(LuTMotionCand* Src, LuTMotionCand* Dst) +{ + memcpy(Dst->m_MotionCand, Src->m_MotionCand, sizeof(MotionInfo)*(std::min(Src->currCnt, MAX_NUM_HMVP_CANDS))); + Dst->currCnt = Src->currCnt; +} +#endif unsigned Slice::getMinPictureDistance() const { diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index d6ef610c7304e8361981d2524201642290e29fd9..f66d5f5a7bdd1e2b50452c25dda856630a1c18bf 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -49,7 +49,10 @@ //! \ingroup CommonLib //! \{ - +#if JVET_L0266_HMVP +#include "CommonLib/MotionInfo.h" +struct MotionInfo; +#endif struct Picture; @@ -1553,6 +1556,9 @@ private: uint32_t m_uiMaxBTSize; AlfSliceParam m_alfSliceParam; +#if JVET_L0266_HMVP + LuTMotionCand* m_MotionCandLuTs; +#endif public: Slice(); @@ -1810,6 +1816,20 @@ public: void setAlfSliceParam( AlfSliceParam& alfSliceParam ) { m_alfSliceParam = alfSliceParam; } AlfSliceParam& getAlfSliceParam() { return m_alfSliceParam; } +#if JVET_L0266_HMVP + void initMotionLUTs (); + void destroyMotionLUTs (); + void resetMotionLUTs(); + int getAvailableLUTMrgNum() const { return m_MotionCandLuTs->currCnt; } + MotionInfo getMotionInfoFromLUTs(int MotCandIdx) const; + LuTMotionCand* getMotionLUTs() { return m_MotionCandLuTs; } + + + void addMotionInfoToLUTs(LuTMotionCand* lutMC, MotionInfo newMi); + + void updateMotionLUTs(LuTMotionCand* lutMC, CodingUnit & cu); + void copyMotionLUTs(LuTMotionCand* Src, LuTMotionCand* Dst); +#endif protected: Picture* xGetRefPic (PicList& rcListPic, int poc); diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 1c7469a6d0fad7564d5a4457b6fd423e700bce30..56026e5456505714d7dbc1443cf12c038631da04 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,8 @@ #include <assert.h> #include <cassert> +#define JVET_L0266_HMVP 1 //History-based MVP + #define JVET_L0553_FIX_INITQP 1 #define JVET_L0147_ALF_SUBSAMPLED_LAPLACIAN 1 // Subsampled Laplacian calculation @@ -307,6 +309,10 @@ #define DISTORTION_ESTIMATION_BITS 8 #define DISTORTION_PRECISION_ADJUSTMENT(x) ((x>DISTORTION_ESTIMATION_BITS)? ((x)-DISTORTION_ESTIMATION_BITS) : 0) #endif +#if JVET_L0266_HMVP +#define MAX_NUM_HMVP_CANDS 6 +#define MAX_NUM_HMVP_AVMPCANDS 4 //should NOT be larger than MAX_NUM_HMVP_CANDS +#endif // ==================================================================================================================== // Error checks diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 50a027e071af64297cd7c24ed9ea49e4c8c4366e..68f916b0e0e74710b89193fe9e7b3a19e7011de5 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -494,7 +494,90 @@ uint32_t PU::getFinalIntraMode( const PredictionUnit &pu, const ChannelType &chT return uiIntraMode; } +#if JVET_L0266_HMVP +bool PU::xCheckSimilarMotion(const int mergeCandIndex, const int prevCnt, const MergeCtx mergeCandList, bool hasPruned[MRG_MAX_NUM_CANDS]) +{ + for (uint32_t ui = 0; ui < prevCnt; ui++) + { + if (hasPruned[ui]) + { + continue; + } + if ( (mergeCandList.interDirNeighbours[ui] == mergeCandList.interDirNeighbours[mergeCandIndex])) + { + if (mergeCandList.interDirNeighbours[ui] == 3) + { + int offset0 = (ui << 1); + int offset1 = (mergeCandIndex << 1); + if (mergeCandList.mvFieldNeighbours[offset0].refIdx == mergeCandList.mvFieldNeighbours[offset1].refIdx && + mergeCandList.mvFieldNeighbours[offset0 + 1].refIdx == mergeCandList.mvFieldNeighbours[offset1 + 1].refIdx && + mergeCandList.mvFieldNeighbours[offset0].mv == mergeCandList.mvFieldNeighbours[offset1].mv && + mergeCandList.mvFieldNeighbours[offset0 + 1].mv == mergeCandList.mvFieldNeighbours[offset1 + 1].mv + ) + { + hasPruned[ui] = true; + return true; + } + } + else + { + int offset0 = (ui << 1) + mergeCandList.interDirNeighbours[ui] - 1; + int offset1 = (mergeCandIndex << 1) + mergeCandList.interDirNeighbours[ui] - 1; + if (mergeCandList.mvFieldNeighbours[offset0].refIdx == mergeCandList.mvFieldNeighbours[offset1].refIdx && + mergeCandList.mvFieldNeighbours[offset0].mv == mergeCandList.mvFieldNeighbours[offset1].mv + ) + { + hasPruned[ui] = true; + return true; + } + } + } + } + return false; +} +#if JVET_L0090_PAIR_AVG +bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool canFastExit, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const int prevCnt, bool isAvailableSubPu, unsigned subPuMvpPos) +#else +bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter[MRG_MAX_NUM_CANDS], bool canFastExit, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const int prevCnt, bool isAvailableSubPu, unsigned subPuMvpPos) +#endif +{ + MotionInfo miNeighbor; + bool hasPruned[MRG_MAX_NUM_CANDS]; + memset(hasPruned, false, MRG_MAX_NUM_CANDS * sizeof(bool)); + if (isAvailableSubPu) + { + hasPruned[subPuMvpPos] = true; + } + int num_avai_candInLUT = slice.getAvailableLUTMrgNum(); + for (int mrgIdx = 1; mrgIdx <= num_avai_candInLUT; mrgIdx++) + { + miNeighbor = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx); + mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir; + mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]); + if (slice.isInterB()) + { + mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[1], miNeighbor.refIdx[1]); + } + if (!xCheckSimilarMotion(cnt, prevCnt, mrgCtx, hasPruned)) + { +#if !JVET_L0090_PAIR_AVG + isCandInter[cnt] = true; +#endif + if (mrgCandIdx == cnt && canFastExit) + { + return true; + } + cnt ++; + if (cnt == maxNumMergeCandMin1) + { + break; + } + } + } + return false; +} +#endif void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx ) { const CodingStructure &cs = *pu.cs; @@ -923,7 +1006,21 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, co { return; } - +#if JVET_L0266_HMVP + int maxNumMergeCandMin1 = maxNumMergeCand - 1; + if (cnt != maxNumMergeCandMin1) + { +#if JVET_L0090_PAIR_AVG + bool bFound = addMergeHMVPCand(slice, mrgCtx, canFastExit, mrgCandIdx, maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos); +#else + bool bFound = addMergeHMVPCand(slice, mrgCtx, isCandInter, canFastExit, mrgCandIdx, maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos); +#endif + if (bFound) + { + return; + } + } +#endif #if JVET_L0090_PAIR_AVG // pairwise-average candidates { @@ -1015,8 +1112,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, co uint32_t uiArrayAddr = cnt; #if !JVET_L0090_PAIR_AVG +#if JVET_L0266_HMVP + uint32_t uiCutoff = std::min( uiArrayAddr, 3u ); +#else uint32_t uiCutoff = std::min( uiArrayAddr, 4u ); - +#endif if (slice.isInterB()) { static const uint32_t NUM_PRIORITY_LIST = 12; @@ -1391,9 +1491,37 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in if ((C0Avail && getColocatedMVP(pu, eRefPicList, posC0, cColMv, refIdx_Col)) || getColocatedMVP(pu, eRefPicList, posC1, cColMv, refIdx_Col)) { +#if JVET_L0266_HMVP + if (pu.cu->imv != 0) + { + unsigned imvShift = pu.cu->imv << 1; + roundMV(cColMv, imvShift); + } + int i = 0; + for (i = 0; i < pInfo->numCand; i++) + { + if (cColMv == pInfo->mvCand[i]) + { + break; + } + } + if (i == pInfo->numCand) + { + pInfo->mvCand[pInfo->numCand++] = cColMv; + } +#else pInfo->mvCand[pInfo->numCand++] = cColMv; +#endif } } +#if JVET_L0266_HMVP + if (pInfo->numCand < AMVP_MAX_NUM_CANDS) + { + const int currRefPOC = cs.slice->getRefPic(eRefPicList, refIdx)->getPOC(); + const RefPicList eRefPicList2nd = (eRefPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0; + addAMVPHMVPCand(pu, eRefPicList, eRefPicList2nd, currRefPOC, *pInfo, pu.cu->imv); + } +#endif if (pInfo->numCand > AMVP_MAX_NUM_CANDS) { pInfo->numCand = AMVP_MAX_NUM_CANDS; @@ -1952,6 +2080,58 @@ bool PU::addMVPCandWithScaling( const PredictionUnit &pu, const RefPicList &eRef return false; } +#if JVET_L0266_HMVP +void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, const RefPicList eRefPicList2nd, const int currRefPOC, AMVPInfo &info, uint8_t imv) +{ + const Slice &slice = *(*pu.cs).slice; + + MotionInfo neibMi; + int i = 0; + unsigned imvShift = imv << 1; + + int num_avai_candInLUT = slice.getAvailableLUTMrgNum(); + int num_allowedCand = std::min(MAX_NUM_HMVP_AVMPCANDS, num_avai_candInLUT); + + for (int mrgIdx = 1; mrgIdx <= num_allowedCand; mrgIdx++) + { + if (info.numCand >= AMVP_MAX_NUM_CANDS) + { + return; + } + neibMi = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx); + + for (int predictorSource = 0; predictorSource < 2; predictorSource++) // examine the indicated reference picture list, then if not available, examine the other list. + { + const RefPicList eRefPicListIndex = (predictorSource == 0) ? eRefPicList : eRefPicList2nd; + const int neibRefIdx = neibMi.refIdx[eRefPicListIndex]; + + if (neibRefIdx >= 0 && currRefPOC == slice.getRefPOC(eRefPicListIndex, neibRefIdx)) + { + Mv pmv = neibMi.mv[eRefPicListIndex]; + if (imv != 0) + { + roundMV(pmv, imvShift); + } + for (i = 0; i < info.numCand; i++) + { + if (pmv == info.mvCand[i]) + { + break; + } + } + if (i == info.numCand) + { + info.mvCand[info.numCand++] = pmv; + if (info.numCand >= AMVP_MAX_NUM_CANDS) + { + return; + } + } + } + } + } +} +#endif bool PU::isBipredRestriction(const PredictionUnit &pu) { const SPSNext &spsNext = pu.cs->sps->getSpsNext(); diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 3247170c6f357a977fdc39d16be213adee1a28ee..24ac8613dfa77fefc71444d3259dc400383b352b 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -118,6 +118,15 @@ namespace PU bool addMVPCandUnscaled (const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &amvpInfo, bool affine = false); bool addMVPCandWithScaling (const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &amvpInfo, bool affine = false); void xInheritedAffineMv ( const PredictionUnit &pu, const PredictionUnit* puNeighbour, RefPicList eRefPicList, Mv rcMv[3] ); +#if JVET_L0266_HMVP + bool xCheckSimilarMotion(const int mergeCandIndex, const int prevCnt, const MergeCtx mergeCandList, bool hasPruned[MRG_MAX_NUM_CANDS]); +#if JVET_L0090_PAIR_AVG + bool addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool canFastExit, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const int prevCnt, bool isAvailableSubPu, unsigned subPuMvpPos); +#else + bool addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter[MRG_MAX_NUM_CANDS], bool canFastExit, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const int prevCnt, bool isAvailableSubPu, unsigned subPuMvpPos); +#endif + void addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, const RefPicList eRefPicList2nd, const int currRefPOC, AMVPInfo &info, uint8_t imv); +#endif bool isBipredRestriction (const PredictionUnit &pu); void spanMotionInfo ( PredictionUnit &pu, const MergeCtx &mrgCtx = MergeCtx() ); void applyImv ( PredictionUnit &pu, MergeCtx &mrgCtx, InterPrediction *interPred = NULL ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 8fb1c75ba89f278c1a621440ce9e8fd16f45bade..19a8c333be7a94f264fae385d01f72b380b5e6cd 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -316,6 +316,9 @@ void DecCu::xReconInter(CodingUnit &cu) { // inter prediction m_pcInterPred->motionCompensation( cu ); +#if JVET_L0266_HMVP + cu.slice->updateMotionLUTs(cu.slice->getMotionLUTs(), cu); +#endif DTRACE ( g_trace_ctx, D_TMP, "pred " ); DTRACE_CRC( g_trace_ctx, D_TMP, *cu.cs, cu.cs->getPredBuf( cu ), &cu.Y() ); diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 926841c1057fb2740c447752eab355c7ab3f2bc3..1030f4050aa563fe1f37c6959aa860946fd3faa5 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -78,10 +78,21 @@ void EncCu::create( EncCfg* encCfg ) m_pTempCS = new CodingStructure** [numWidths]; m_pBestCS = new CodingStructure** [numWidths]; +#if JVET_L0266_HMVP + m_pTempMotLUTs = new LuTMotionCand**[numWidths]; + m_pBestMotLUTs = new LuTMotionCand**[numWidths]; + m_pSplitTempMotLUTs = new LuTMotionCand**[numWidths]; +#endif + for( unsigned w = 0; w < numWidths; w++ ) { m_pTempCS[w] = new CodingStructure* [numHeights]; m_pBestCS[w] = new CodingStructure* [numHeights]; +#if JVET_L0266_HMVP + m_pTempMotLUTs[w] = new LuTMotionCand*[numHeights]; + m_pBestMotLUTs[w] = new LuTMotionCand*[numHeights]; + m_pSplitTempMotLUTs[w] = new LuTMotionCand*[numHeights]; +#endif for( unsigned h = 0; h < numHeights; h++ ) { @@ -95,11 +106,32 @@ void EncCu::create( EncCfg* encCfg ) m_pTempCS[w][h]->create( chromaFormat, Area( 0, 0, width, height ), false ); m_pBestCS[w][h]->create( chromaFormat, Area( 0, 0, width, height ), false ); +#if JVET_L0266_HMVP + m_pTempMotLUTs[w][h] = new LuTMotionCand ; + m_pBestMotLUTs[w][h] = new LuTMotionCand ; + m_pSplitTempMotLUTs[w][h] = new LuTMotionCand; + m_pSplitTempMotLUTs[w][h]->currCnt = 0; + m_pSplitTempMotLUTs[w][h]->m_MotionCand = nullptr; + m_pSplitTempMotLUTs[w][h]->m_MotionCand = new MotionInfo[MAX_NUM_HMVP_CANDS]; + + m_pTempMotLUTs[w][h]->currCnt = 0; + m_pTempMotLUTs[w][h]->m_MotionCand = nullptr; + m_pTempMotLUTs[w][h]->m_MotionCand = new MotionInfo[MAX_NUM_HMVP_CANDS]; + + m_pBestMotLUTs[w][h]->currCnt = 0; + m_pBestMotLUTs[w][h]->m_MotionCand = nullptr; + m_pBestMotLUTs[w][h]->m_MotionCand = new MotionInfo[MAX_NUM_HMVP_CANDS]; +#endif } else { m_pTempCS[w][h] = nullptr; m_pBestCS[w][h] = nullptr; +#if JVET_L0266_HMVP + m_pTempMotLUTs[w][h] = nullptr; + m_pBestMotLUTs[w][h] = nullptr; + m_pSplitTempMotLUTs[w][h] = nullptr; +#endif } } } @@ -180,15 +212,46 @@ void EncCu::destroy() delete m_pBestCS[w][h]; delete m_pTempCS[w][h]; +#if JVET_L0266_HMVP + if (m_pTempMotLUTs[w][h]) + { + delete[] m_pTempMotLUTs[w][h]->m_MotionCand; + m_pTempMotLUTs[w][h]->m_MotionCand = nullptr; + delete[] m_pTempMotLUTs[w][h]; + } + if (m_pBestMotLUTs[w][h]) + { + delete[] m_pBestMotLUTs[w][h]->m_MotionCand; + m_pBestMotLUTs[w][h]->m_MotionCand = nullptr; + delete[] m_pBestMotLUTs[w][h]; + } + + if (m_pSplitTempMotLUTs[w][h]) + { + delete[] m_pSplitTempMotLUTs[w][h]->m_MotionCand; + m_pSplitTempMotLUTs[w][h]->m_MotionCand = nullptr; + delete[] m_pSplitTempMotLUTs[w][h]; + } +#endif } } delete[] m_pTempCS[w]; delete[] m_pBestCS[w]; +#if JVET_L0266_HMVP + delete[] m_pBestMotLUTs[w]; + delete[] m_pTempMotLUTs[w]; + delete[] m_pSplitTempMotLUTs[w]; +#endif } delete[] m_pBestCS; m_pBestCS = nullptr; delete[] m_pTempCS; m_pTempCS = nullptr; +#if JVET_L0266_HMVP + delete[] m_pSplitTempMotLUTs; m_pSplitTempMotLUTs = nullptr; + delete[] m_pBestMotLUTs; m_pBestMotLUTs = nullptr; + delete[] m_pTempMotLUTs; m_pTempMotLUTs = nullptr; +#endif #if REUSE_CU_RESULTS m_modeCtrl->destroy(); @@ -292,6 +355,12 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign CodingStructure *tempCS = m_pTempCS[gp_sizeIdxInfo->idxFrom( area.lumaSize().width )][gp_sizeIdxInfo->idxFrom( area.lumaSize().height )]; CodingStructure *bestCS = m_pBestCS[gp_sizeIdxInfo->idxFrom( area.lumaSize().width )][gp_sizeIdxInfo->idxFrom( area.lumaSize().height )]; +#if JVET_L0266_HMVP + LuTMotionCand *tempMotCandLUTs = m_pTempMotLUTs[gp_sizeIdxInfo->idxFrom(area.lumaSize().width)][gp_sizeIdxInfo->idxFrom(area.lumaSize().height)]; + LuTMotionCand *bestMotCandLUTs = m_pBestMotLUTs[gp_sizeIdxInfo->idxFrom(area.lumaSize().width)][gp_sizeIdxInfo->idxFrom(area.lumaSize().height)]; + cs.slice->copyMotionLUTs(cs.slice->getMotionLUTs(), tempMotCandLUTs); + cs.slice->copyMotionLUTs(cs.slice->getMotionLUTs(), bestMotCandLUTs); +#endif cs.initSubStructure( *tempCS, partitioner->chType, partitioner->currArea(), false ); cs.initSubStructure( *bestCS, partitioner->chType, partitioner->currArea(), false ); @@ -299,12 +368,20 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign tempCS->baseQP = bestCS->baseQP = currQP[CH_L]; tempCS->prevQP[CH_L] = bestCS->prevQP[CH_L] = prevQP[CH_L]; - xCompressCU( tempCS, bestCS, *partitioner ); + xCompressCU( tempCS, bestCS, *partitioner +#if JVET_L0266_HMVP + , tempMotCandLUTs + , bestMotCandLUTs +#endif + ); // all signals were already copied during compression if the CTU was split - at this point only the structures are copied to the top level CS const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1 && KEEP_PRED_AND_RESI_SIGNALS; cs.useSubStructure( *bestCS, partitioner->chType, CS::getArea( *bestCS, area, partitioner->chType ), copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals ); +#if JVET_L0266_HMVP + cs.slice->copyMotionLUTs(bestMotCandLUTs, cs.slice->getMotionLUTs()); +#endif if( !cs.pcv->ISingleTree && cs.slice->isIRAP() && cs.pcv->chrFormat != CHROMA_400 ) { @@ -318,7 +395,12 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign tempCS->baseQP = bestCS->baseQP = currQP[CH_C]; tempCS->prevQP[CH_C] = bestCS->prevQP[CH_C] = prevQP[CH_C]; - xCompressCU( tempCS, bestCS, *partitioner ); + xCompressCU( tempCS, bestCS, *partitioner +#if JVET_L0266_HMVP + , tempMotCandLUTs + , bestMotCandLUTs +#endif + ); const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1 && KEEP_PRED_AND_RESI_SIGNALS; cs.useSubStructure( *bestCS, partitioner->chType, CS::getArea( *bestCS, area, partitioner->chType ), copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals ); @@ -465,8 +547,16 @@ int EncCu::updateCtuDataISlice(const CPelBuf buf) return( iSumHad ); } +#if JVET_L0266_HMVP +bool EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) +#else void EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) +#endif { +#if JVET_L0266_HMVP + bool bSwitch = false; +#endif + if( !tempCS->cus.empty() ) { if( tempCS->cus.size() == 1 ) @@ -497,14 +587,26 @@ void EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS, std::swap( tempCS, bestCS ); // store temp best CI for next CU coding m_CurrCtx->best = m_CABACEstimator->getCtx(); +#if JVET_L0266_HMVP + bSwitch = true; +#endif } } // reset context states m_CABACEstimator->getCtx() = m_CurrCtx->start; +#if JVET_L0266_HMVP + return bSwitch; +#endif + } -void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner ) +void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner +#if JVET_L0266_HMVP + , LuTMotionCand* &tempMotCandLUTs + , LuTMotionCand* &bestMotCandLUTs +#endif +) { #if ENABLE_SPLIT_PARALLELISM CHECK( m_dataId != tempCS->picture->scheduler.getDataId(), "Working in the wrong dataId!" ); @@ -557,6 +659,12 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par m_modeCtrl->finishCULevel( partitioner ); return; } +#if JVET_L0266_HMVP + if (!slice.isIntra()) + { + tempCS->slice->copyMotionLUTs(tempMotCandLUTs, tempCS->slice->getMotionLUTs()); + } +#endif DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cux", uiLPelX ) ); DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cuy", uiTPelY ) ); @@ -618,7 +726,13 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par else if( isModeSplit( currTestMode ) ) { - xCheckModeSplit( tempCS, bestCS, partitioner, currTestMode ); + xCheckModeSplit( tempCS, bestCS, partitioner, currTestMode +#if JVET_L0266_HMVP + , tempMotCandLUTs + , bestMotCandLUTs + , partitioner.currArea() +#endif + ); } else { @@ -644,7 +758,12 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par // QP from last processed CU for further processing bestCS->prevQP[partitioner.chType] = bestCS->cus.back()->qp; - +#if JVET_L0266_HMVP + if (!slice.isIntra() && bestCS->cus.size() == 1 && bestCS->cus.back()->predMode == MODE_INTER && bestCS->area == *bestCS->cus.back()) + { + bestCS->slice->updateMotionLUTs(bestMotCandLUTs, (*bestCS->cus.back())); + } +#endif bestCS->picture->getRecoBuf( currCsArea ).copyFrom( bestCS->getRecoBuf( currCsArea ) ); m_modeCtrl->finishCULevel( partitioner ); @@ -892,7 +1011,13 @@ void EncCu::copyState( EncCu* other, Partitioner& partitioner, const UnitArea& c } #endif -void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode) +void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode +#if JVET_L0266_HMVP + , LuTMotionCand* &tempMotCandLUTs + , LuTMotionCand* &bestMotCandLUTs + , UnitArea parArea +#endif +) { const int qp = encTestMode.qp; const PPS &pps = *tempCS->pps; @@ -901,6 +1026,13 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, const int oldPrevQp = tempCS->prevQP[partitioner.chType]; const uint32_t currDepth = partitioner.currDepth; +#if JVET_L0266_HMVP + const unsigned wParIdx = gp_sizeIdxInfo->idxFrom(parArea.lwidth()); + const unsigned hParIdx = gp_sizeIdxInfo->idxFrom(parArea.lheight()); + + tempCS->slice->copyMotionLUTs(tempMotCandLUTs, m_pSplitTempMotLUTs[wParIdx][hParIdx]); +#endif + const PartSplit split = getPartSplit( encTestMode ); CHECK( split == CU_DONT_SPLIT, "No proper split provided!" ); @@ -961,8 +1093,19 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, tempCS->initSubStructure( *tempSubCS, partitioner.chType, subCUArea, false ); tempCS->initSubStructure( *bestSubCS, partitioner.chType, subCUArea, false ); +#if JVET_L0266_HMVP + LuTMotionCand *tempSubMotCandLUTs = m_pTempMotLUTs[wIdx][hIdx]; + LuTMotionCand *bestSubMotCandLUTs = m_pBestMotLUTs[wIdx][hIdx]; + tempCS->slice->copyMotionLUTs(tempMotCandLUTs, tempSubMotCandLUTs); + tempCS->slice->copyMotionLUTs(tempMotCandLUTs, bestSubMotCandLUTs); +#endif - xCompressCU( tempSubCS, bestSubCS, partitioner ); + xCompressCU( tempSubCS, bestSubCS, partitioner +#if JVET_L0266_HMVP + , tempSubMotCandLUTs + , bestSubMotCandLUTs +#endif + ); if( bestSubCS->cost == MAX_DOUBLE ) { @@ -970,12 +1113,25 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, tempCS->cost = MAX_DOUBLE; m_CurrCtx--; partitioner.exitCurrSplit(); +#if JVET_L0266_HMVP + bool bUpdate = +#endif xCheckBestMode( tempCS, bestCS, partitioner, encTestMode ); + +#if JVET_L0266_HMVP + if (bUpdate) + { + std::swap(tempMotCandLUTs, bestMotCandLUTs); + } +#endif return; } bool keepResi = KEEP_PRED_AND_RESI_SIGNALS; tempCS->useSubStructure( *bestSubCS, partitioner.chType, CS::getArea( *tempCS, subCUArea, partitioner.chType ), KEEP_PRED_AND_RESI_SIGNALS, true, keepResi, keepResi ); +#if JVET_L0266_HMVP + tempCS->slice->copyMotionLUTs(bestSubMotCandLUTs, tempMotCandLUTs); +#endif if(currDepth < pps.getMaxCuDQPDepth()) { @@ -1079,8 +1235,22 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, // RD check for sub partitioned coding structure. +#if JVET_L0266_HMVP + bool bUpdate = +#endif xCheckBestMode( tempCS, bestCS, partitioner, encTestMode ); +#if JVET_L0266_HMVP + if (!slice.isIntra()) + { + if (bUpdate) + { + std::swap(tempMotCandLUTs, bestMotCandLUTs); + } + tempCS->slice->copyMotionLUTs(m_pSplitTempMotLUTs[wParIdx][hParIdx], tempMotCandLUTs); + } +#endif + tempCS->releaseIntermediateData(); tempCS->prevQP[partitioner.chType] = oldPrevQp; diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index d8131f4532a7f5b5e278e8284af1d8cf9275b42c..8269b83611d264ea6699558dec19556dd9cd5671 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -95,6 +95,11 @@ private: CodingStructure ***m_pTempCS; CodingStructure ***m_pBestCS; +#if JVET_L0266_HMVP + LuTMotionCand ***m_pTempMotLUTs; + LuTMotionCand ***m_pBestMotLUTs; + LuTMotionCand ***m_pSplitTempMotLUTs; +#endif // Access channel EncCfg* m_pcEncCfg; IntraSearch* m_pcIntraSearch; @@ -167,15 +172,31 @@ public: protected: - void xCompressCU ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm ); + void xCompressCU ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm +#if JVET_L0266_HMVP + , LuTMotionCand* &tempMotCandLUTs + , LuTMotionCand* &bestMotCandLUTs +#endif + ); #if ENABLE_SPLIT_PARALLELISM void xCompressCUParallel ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm ); void copyState ( EncCu* other, Partitioner& pm, const UnitArea& currArea, const bool isDist ); #endif - void xCheckBestMode ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestmode ); +#if JVET_L0266_HMVP + bool +#else + void +#endif + xCheckBestMode ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestmode ); - void xCheckModeSplit ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode ); + void xCheckModeSplit ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode +#if JVET_L0266_HMVP + , LuTMotionCand* &tempMotCandLUTs + , LuTMotionCand* &bestMotCandLUTs + , UnitArea parArea +#endif + ); void xCheckRDCostIntra ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode ); void xCheckIntraPCM ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );