diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 830fc4bf4fb6c05537ba28249664864f9b42e981..fa49d881ed4604a2f3560f9c37831ea72429f3b7 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -294,6 +294,16 @@ static const int AFFINE_MAX_NUM_V2 = 2; ///< max static const int AFFINE_MAX_NUM_COMB = 12; ///< max number of combined motion candidates static const int AFFINE_MIN_BLOCK_SIZE = 4; ///< Minimum affine MC block size + +#if JVET_L0054_MMVD +static const int MMVD_REFINE_STEP = 8; ///< max number of distance step +static const int MMVD_MAX_REFINE_NUM = (MMVD_REFINE_STEP * 4); ///< max number of candidate from a base candidate +static const int MMVD_BASE_MV_NUM = 2; ///< max number of base candidate +static const int MMVD_ADD_NUM = (MMVD_MAX_REFINE_NUM * MMVD_BASE_MV_NUM);///< total number of mmvd candidate +static const int MMVD_MRG_MAX_RD_NUM = MRG_MAX_NUM_CANDS; +static const int MMVD_MRG_MAX_RD_BUF_NUM = (MMVD_MRG_MAX_RD_NUM + 1);///< increase buffer size by 1 +#endif + #if JVET_L0274 static const int MAX_NUM_REG_BINS_4x4SUBBLOCK = 32; ///< max number of context-coded bins (incl. gt2 bins) per 4x4 subblock static const int MAX_NUM_GT2_BINS_4x4SUBBLOCK = 4; ///< max number of gt2 bins per 4x4 subblock diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index 9f41baa2f13ebd3fb2c9912b3ec24a1ba834bde7..bbdc6f2ed935169ad7e1581664170a3c3d7bbd88 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -365,6 +365,9 @@ void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx ) CHECK( candIdx >= numValidMergeCand, "Merge candidate does not exist" ); pu.mergeFlag = true; +#if JVET_L0054_MMVD + pu.mmvdMergeFlag = false; +#endif pu.interDir = interDirNeighbours[candIdx]; pu.mergeIdx = candIdx; pu.mergeType = mrgTypeNeighbours[candIdx]; @@ -384,3 +387,209 @@ void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx ) #endif } +#if JVET_L0054_MMVD +void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx) +{ + const Slice &slice = *pu.cs->slice; + const int mvShift = VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE; + const int refMvdCands[8] = { 1 << mvShift , 2 << mvShift , 4 << mvShift , 8 << mvShift , 16 << mvShift , 32 << mvShift, 64 << mvShift , 128 << mvShift }; + int fPosGroup = 0; + int fPosBaseIdx = 0; + int fPosStep = 0; + int tempIdx = 0; + int fPosPosition = 0; + Mv tempMv[2]; + + tempIdx = candIdx; + fPosGroup = tempIdx / (MMVD_BASE_MV_NUM * MMVD_MAX_REFINE_NUM); + tempIdx = tempIdx - fPosGroup * (MMVD_BASE_MV_NUM * MMVD_MAX_REFINE_NUM); + fPosBaseIdx = tempIdx / MMVD_MAX_REFINE_NUM; + tempIdx = tempIdx - fPosBaseIdx * (MMVD_MAX_REFINE_NUM); + fPosStep = tempIdx / 4; + fPosPosition = tempIdx - fPosStep * (4); + + const int offset = refMvdCands[fPosStep]; +#if !REMOVE_MV_ADAPT_PREC + const int highPrecList0 = mmvdBaseMv[fPosBaseIdx][0].mv.highPrec; + const int highPrecList1 = mmvdBaseMv[fPosBaseIdx][1].mv.highPrec; +#endif + const int refList0 = mmvdBaseMv[fPosBaseIdx][0].refIdx; + const int refList1 = mmvdBaseMv[fPosBaseIdx][1].refIdx; + + if ((refList0 != -1) && (refList1 != -1)) + { + const int poc0 = slice.getRefPOC(REF_PIC_LIST_0, refList0); + const int poc1 = slice.getRefPOC(REF_PIC_LIST_1, refList1); + const int currPoc = slice.getPOC(); + int refSign = 1; + + if ((poc0 - currPoc) * (currPoc - poc1) > 0) + { + refSign = -1; + } +#if REMOVE_MV_ADAPT_PREC + if (fPosPosition == 0) + { + tempMv[0] = Mv(offset, 0); + tempMv[1] = Mv(offset * refSign, 0); + } + else if (fPosPosition == 1) + { + tempMv[0] = Mv(-offset, 0); + tempMv[1] = Mv(-offset * refSign, 0); + } + else if (fPosPosition == 2) + { + tempMv[0] = Mv(0, offset); + tempMv[1] = Mv(0, offset * refSign); + } + else + { + tempMv[0] = Mv(0, -offset); + tempMv[1] = Mv(0, -offset * refSign); + } +#else + if (fPosPosition == 0) + { + tempMv[0] = Mv(offset, 0, highPrecList0); + tempMv[1] = Mv(offset * refSign, 0, highPrecList1); + } + else if (fPosPosition == 1) + { + tempMv[0] = Mv(-offset, 0, highPrecList0); + tempMv[1] = Mv(-offset * refSign, 0, highPrecList1); + } + else if (fPosPosition == 2) + { + tempMv[0] = Mv(0, offset, highPrecList0); + tempMv[1] = Mv(0, offset * refSign, highPrecList1); + } + else + { + tempMv[0] = Mv(0, -offset, highPrecList0); + tempMv[1] = Mv(0, -offset * refSign, highPrecList1); + } +#endif + if (abs(poc1 - currPoc) > abs(poc0 - currPoc)) + { + const int scale = PU::getDistScaleFactor(currPoc, poc0, currPoc, poc1); + if (scale != 4096) + { + tempMv[0] = tempMv[0].scaleMv(scale); + } + } + else if (abs(poc1 - currPoc) < abs(poc0 - currPoc)) + { + const int scale = PU::getDistScaleFactor(currPoc, poc1, currPoc, poc0); + if (scale != 4096) + { + tempMv[1] = tempMv[1].scaleMv(scale); + } + } + + pu.interDir = 3; + pu.mv[REF_PIC_LIST_0] = mmvdBaseMv[fPosBaseIdx][0].mv + tempMv[0]; + pu.refIdx[REF_PIC_LIST_0] = refList0; + pu.mv[REF_PIC_LIST_1] = mmvdBaseMv[fPosBaseIdx][1].mv + tempMv[1]; + pu.refIdx[REF_PIC_LIST_1] = refList1; + } + else if (refList0 != -1) + { +#if REMOVE_MV_ADAPT_PREC + if (fPosPosition == 0) + { + tempMv[0] = Mv(offset, 0); + } + else if (fPosPosition == 1) + { + tempMv[0] = Mv(-offset, 0); + } + else if (fPosPosition == 2) + { + tempMv[0] = Mv(0, offset); + } + else + { + tempMv[0] = Mv(0, -offset); + } +#else + if (fPosPosition == 0) + { + tempMv[0] = Mv(offset, 0, highPrecList0); + } + else if (fPosPosition == 1) + { + tempMv[0] = Mv(-offset, 0, highPrecList0); + } + else if (fPosPosition == 2) + { + tempMv[0] = Mv(0, offset, highPrecList0); + } + else + { + tempMv[0] = Mv(0, -offset, highPrecList0); + } +#endif + pu.interDir = 1; + pu.mv[REF_PIC_LIST_0] = mmvdBaseMv[fPosBaseIdx][0].mv + tempMv[0]; + pu.refIdx[REF_PIC_LIST_0] = refList0; + pu.mv[REF_PIC_LIST_1] = Mv(0, 0); + pu.refIdx[REF_PIC_LIST_1] = -1; + } + else if (refList1 != -1) + { +#if REMOVE_MV_ADAPT_PREC + if (fPosPosition == 0) + { + tempMv[1] = Mv(offset, 0); + } + else if (fPosPosition == 1) + { + tempMv[1] = Mv(-offset, 0); + } + else if (fPosPosition == 2) + { + tempMv[1] = Mv(0, offset); + } + else + { + tempMv[1] = Mv(0, -offset); + } +#else + if (fPosPosition == 0) + { + tempMv[1] = Mv(offset, 0, highPrecList1); + } + else if (fPosPosition == 1) + { + tempMv[1] = Mv(-offset, 0, highPrecList1); + } + else if (fPosPosition == 2) + { + tempMv[1] = Mv(0, offset, highPrecList1); + } + else + { + tempMv[1] = Mv(0, -offset, highPrecList1); + } +#endif + pu.interDir = 2; + pu.mv[REF_PIC_LIST_0] = Mv(0, 0); + pu.refIdx[REF_PIC_LIST_0] = -1; + pu.mv[REF_PIC_LIST_1] = mmvdBaseMv[fPosBaseIdx][1].mv + tempMv[1]; + pu.refIdx[REF_PIC_LIST_1] = refList1; + } + + pu.mmvdMergeFlag = true; + pu.mmvdMergeIdx = candIdx; + pu.mergeFlag = true; + pu.mergeIdx = candIdx; + pu.mergeType = MRG_TYPE_DEFAULT_N; + pu.mvd[REF_PIC_LIST_0] = Mv(); + pu.mvd[REF_PIC_LIST_1] = Mv(); + pu.mvpIdx[REF_PIC_LIST_0] = NOT_VALID; + pu.mvpIdx[REF_PIC_LIST_1] = NOT_VALID; + pu.mvpNum[REF_PIC_LIST_0] = NOT_VALID; + pu.mvpNum[REF_PIC_LIST_1] = NOT_VALID; +} +#endif \ No newline at end of file diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index 58c8d8e5898b9222b1fa7529b6654b597c06ffed..f98d40a0190883c0de652daa87671730f511eef7 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -309,6 +309,10 @@ public: MotionBuf subPuMvpMiBuf; MotionBuf subPuMvpExtMiBuf; +#if JVET_L0054_MMVD + MvField mmvdBaseMv[MMVD_BASE_MV_NUM][2]; + void setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx); +#endif void setMergeInfo( PredictionUnit& pu, int candIdx ); }; diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 434e66e89c9de59b81126a4def2fbfdc28370c46..36f6118eaf38ddb98d48e980b40da6665321ee1c 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -313,7 +313,28 @@ const CtxSet ContextSetCfg::MergeIdx = ContextSetCfg::addCtxSet { CNU, CNU, CNU, CNU, CNU,}, #endif }); +#if JVET_L0054_MMVD +const CtxSet ContextSetCfg::MmvdFlag = ContextSetCfg::addCtxSet +({ + { 151, }, + { CNU, }, + { CNU, }, + }); +const CtxSet ContextSetCfg::MmvdMergeIdx = ContextSetCfg::addCtxSet +({ + { CNU, }, + { CNU, }, + { CNU, }, + }); + +const CtxSet ContextSetCfg::MmvdStepMvpIdx = ContextSetCfg::addCtxSet +({ + { 184, }, + { CNU, }, + { CNU, }, + }); +#endif const CtxSet ContextSetCfg::PartSize = ContextSetCfg::addCtxSet ({ { 154, 139, 154, 154,}, diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 3e4679c06bd64c00f0f7611e8ca52e739902a135..3e08409e3475ef600e486ccfed9c35e40144ed1b 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -166,6 +166,11 @@ public: static const CtxSet DeltaQP; static const CtxSet InterDir; static const CtxSet RefPic; +#if JVET_L0054_MMVD + static const CtxSet MmvdFlag; + static const CtxSet MmvdMergeIdx; + static const CtxSet MmvdStepMvpIdx; +#endif static const CtxSet AffineFlag; static const CtxSet AffineType; static const CtxSet Mvd; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 2fbbae285a1e3412f81905c1fca0711294f72b51..556890451adf06f598e58442291034d6b267c3f8 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -61,6 +61,7 @@ #define JVET_L0191_LM_WO_LMS 1 // NO LMS regression. min/max are used instead #define JVET_L0090_PAIR_AVG 1 // Add pairwise average candidates, replace HEVC combined candidates +#define JVET_L0054_MMVD 1 #define JVET_L0392_ALF_INIT_STATE 1 diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 3c21d11bcce7c067ba06c957b8eaa08bc5b18272..e81e2170b05dc2fff3268b1370cf4ae7a49cde36 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -253,6 +253,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other ) mtDepth = other.mtDepth; splitSeries = other.splitSeries; skip = other.skip; +#if JVET_L0054_MMVD + mmvdSkip = other.mmvdSkip; +#endif affine = other.affine; affineType = other.affineType; transQuantBypass = other.transQuantBypass; @@ -284,6 +287,9 @@ void CodingUnit::initData() mtDepth = 0; splitSeries = 0; skip = false; +#if JVET_L0054_MMVD + mmvdSkip = false; +#endif affine = false; affineType = 0; transQuantBypass = false; @@ -321,6 +327,10 @@ void PredictionUnit::initData() // inter data mergeFlag = false; mergeIdx = MAX_UCHAR; +#if JVET_L0054_MMVD + mmvdMergeFlag = false; + mmvdMergeIdx = MAX_UINT; +#endif interDir = MAX_UCHAR; mergeType = MRG_TYPE_DEFAULT_N; for (uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++) @@ -351,6 +361,10 @@ PredictionUnit& PredictionUnit::operator=(const InterPredictionData& predData) { mergeFlag = predData.mergeFlag; mergeIdx = predData.mergeIdx; +#if JVET_L0054_MMVD + mmvdMergeFlag = predData.mmvdMergeFlag; + mmvdMergeIdx = predData.mmvdMergeIdx; +#endif interDir = predData.interDir; mergeType = predData.mergeType; for (uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++) @@ -378,6 +392,10 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other ) mergeFlag = other.mergeFlag; mergeIdx = other.mergeIdx; +#if JVET_L0054_MMVD + mmvdMergeFlag = other.mmvdMergeFlag; + mmvdMergeIdx = other.mmvdMergeIdx; +#endif interDir = other.interDir; mergeType = other.mergeType; for (uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++) diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 93924a20065a649ddfe4e80adaf1b4553766616c..083a2e36eefe2257e9b01c77f96670b4ff5ed906 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -295,6 +295,9 @@ struct CodingUnit : public UnitArea int8_t qp; SplitSeries splitSeries; bool skip; +#if JVET_L0054_MMVD + bool mmvdSkip; +#endif bool affine; int affineType; bool transQuantBypass; @@ -349,6 +352,10 @@ struct InterPredictionData { bool mergeFlag; uint8_t mergeIdx; +#if JVET_L0054_MMVD + bool mmvdMergeFlag; + uint32_t mmvdMergeIdx; +#endif uint8_t interDir; uint8_t mvpIdx [NUM_REF_PIC_LIST_01]; uint8_t mvpNum [NUM_REF_PIC_LIST_01]; diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index ad55e2ec379c61087bbfd6a9fdb37ad57391b434..a511f85701136115f5055e4cf660a21aaf97c571 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -494,8 +494,11 @@ uint32_t PU::getFinalIntraMode( const PredictionUnit &pu, const ChannelType &chT return uiIntraMode; } - -void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx ) +void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, +#if JVET_L0054_MMVD + int mmvdList, +#endif + const int& mrgCandIdx ) { const CodingStructure &cs = *pu.cs; const Slice &slice = *pu.cs->slice; @@ -723,7 +726,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, co bool bMrgIdxMatchATMVPCan = ( mrgCandIdx == cnt ); bool tmpLICFlag = false; - isAvailableSubPu = cs.sps->getSpsNext().getUseATMVP() && getInterMergeSubPuMvpCand( pu, mrgCtx, tmpLICFlag, cnt + isAvailableSubPu = cs.sps->getSpsNext().getUseATMVP() && + getInterMergeSubPuMvpCand( pu, mrgCtx, tmpLICFlag, cnt +#if JVET_L0054_MMVD + , mmvdList +#endif ); if( isAvailableSubPu ) @@ -1117,7 +1124,78 @@ static int xGetDistScaleFactor(const int &iCurrPOC, const int &iCurrRefPOC, cons return iScale; } } +#if JVET_L0054_MMVD +int PU::getDistScaleFactor(const int &currPOC, const int &currRefPOC, const int &colPOC, const int &colRefPOC) +{ + return xGetDistScaleFactor(currPOC, currRefPOC, colPOC, colRefPOC); +} + +void PU::getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx) +{ + int refIdxList0, refIdxList1; + int k; + int currBaseNum = 0; + const uint16_t maxNumMergeCand = mrgCtx.numValidMergeCand; + +#if !REMOVE_MV_ADAPT_PREC + if (pu.cu->slice->getSPS()->getSpsNext().getUseHighPrecMv()) + { + for (k = 0; k < maxNumMergeCand; k++) + { + if (mrgCtx.mrgTypeNeighbours[k] == MRG_TYPE_DEFAULT_N) + { + if ((mrgCtx.mvFieldNeighbours[(k << 1)].mv.highPrec == false) && (mrgCtx.mvFieldNeighbours[(k << 1)].refIdx >= 0)) + { + mrgCtx.mvFieldNeighbours[(k << 1)].mv.setHighPrec(); + } + if ((mrgCtx.mvFieldNeighbours[(k << 1) + 1].mv.highPrec == false) && (mrgCtx.mvFieldNeighbours[(k << 1) + 1].refIdx >= 0)) + { + mrgCtx.mvFieldNeighbours[(k << 1) + 1].mv.setHighPrec(); + } + } + } + } +#endif + for (k = 0; k < maxNumMergeCand; k++) + { + if (mrgCtx.mrgTypeNeighbours[k] == MRG_TYPE_DEFAULT_N) + { + refIdxList0 = mrgCtx.mvFieldNeighbours[(k << 1)].refIdx; + refIdxList1 = mrgCtx.mvFieldNeighbours[(k << 1) + 1].refIdx; + + if ((refIdxList0 >= 0) && (refIdxList1 >= 0)) + { + mrgCtx.mmvdBaseMv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[(k << 1)]; + mrgCtx.mmvdBaseMv[currBaseNum][1] = mrgCtx.mvFieldNeighbours[(k << 1) + 1]; + } + else if (refIdxList0 >= 0) + { + mrgCtx.mmvdBaseMv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[(k << 1)]; + mrgCtx.mmvdBaseMv[currBaseNum][1] = MvField(Mv(0, 0), -1); + } + else if (refIdxList1 >= 0) + { + mrgCtx.mmvdBaseMv[currBaseNum][0] = MvField(Mv(0, 0), -1); + mrgCtx.mmvdBaseMv[currBaseNum][1] = mrgCtx.mvFieldNeighbours[(k << 1) + 1]; + } + currBaseNum++; + + if (currBaseNum == MMVD_BASE_MV_NUM) + break; + } + } + + if (currBaseNum < MMVD_BASE_MV_NUM) + { + for (k = currBaseNum; k < MMVD_BASE_MV_NUM; k++) + { + mrgCtx.mmvdBaseMv[k][0] = MvField(Mv(0, 0), 0); + mrgCtx.mmvdBaseMv[k][0] = MvField(Mv(0, 0), 0); + } + } +} +#endif bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList, const Position &_pos, Mv& rcMv, const int &refIdx ) { // don't perform MV compression when generally disabled or subPuMvp is used @@ -2287,6 +2365,9 @@ void clipColBlkMv(int& mvX, int& mvY, const PredictionUnit& pu) #endif bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, bool& LICFlag, const int count +#if JVET_L0054_MMVD + , int mmvdList +#endif ) { const Slice &slice = *pu.cs->slice; @@ -2412,7 +2493,10 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b { return false; } - +#if JVET_L0054_MMVD + if (mmvdList != 1) + { +#endif #if JVET_L0257_ATMVP_COLBLK_CLIP int xOff = (puWidth >> 1) + tempX; int yOff = (puHeight >> 1) + tempY; @@ -2487,7 +2571,9 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b mb.subBuf(g_miScaling.scale(Position{ x, y } -pu.lumaPos()), g_miScaling.scale(Size(puWidth, puHeight))).fill(mi); } } - +#if JVET_L0054_MMVD + } +#endif return true; } @@ -2617,7 +2703,11 @@ void PU::applyImv( PredictionUnit& pu, MergeCtx &mrgCtx, InterPrediction *interP { // this function is never called for merge THROW("unexpected"); - PU::getInterMergeCandidates ( pu, mrgCtx ); + PU::getInterMergeCandidates ( pu, mrgCtx +#if JVET_L0054_MMVD + , 0 +#endif + ); PU::restrictBiPredMergeCands( pu, mrgCtx ); mrgCtx.setMergeInfo( pu, pu.mergeIdx ); @@ -2710,7 +2800,11 @@ void CU::resetMVDandMV2Int( CodingUnit& cu, InterPrediction *interPred ) } else { - PU::getInterMergeCandidates ( pu, mrgCtx ); + PU::getInterMergeCandidates ( pu, mrgCtx +#if JVET_L0054_MMVD + , 0 +#endif + ); PU::restrictBiPredMergeCands( pu, mrgCtx ); mrgCtx.setMergeInfo( pu, pu.mergeIdx ); diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 3247170c6f357a977fdc39d16be213adee1a28ee..84a6e3992f44a1832f9772fddb285c0438948748 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -109,8 +109,15 @@ namespace PU int getIntraMPMs(const PredictionUnit &pu, unsigned *mpm, const ChannelType &channelType = CHANNEL_TYPE_LUMA); void getIntraChromaCandModes (const PredictionUnit &pu, unsigned modeList[NUM_CHROMA_MODE]); uint32_t getFinalIntraMode (const PredictionUnit &pu, const ChannelType &chType); - - void getInterMergeCandidates (const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx = -1 ); + void getInterMergeCandidates (const PredictionUnit &pu, MergeCtx& mrgCtx, +#if JVET_L0054_MMVD + int mmvdList, +#endif + const int& mrgCandIdx = -1 ); +#if JVET_L0054_MMVD + void getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx = -1); + int getDistScaleFactor(const int &currPOC, const int &currRefPOC, const int &colPOC, const int &colRefPOC); +#endif bool isDiffMER (const PredictionUnit &pu, const PredictionUnit &pu2); bool getColocatedMVP (const PredictionUnit &pu, const RefPicList &eRefPicList, const Position &pos, Mv& rcMv, const int &refIdx); void fillMvpCand ( PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AMVPInfo &amvpInfo ); @@ -135,6 +142,9 @@ namespace PU #endif ); bool getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx &mrgCtx, bool& LICFlag, const int count +#if JVET_L0054_MMVD + , int mmvdList +#endif ); bool getInterMergeSubPuRecurCand(const PredictionUnit &pu, MergeCtx &mrgCtx, const int count); bool isBiPredFromDifferentDir (const PredictionUnit &pu); @@ -178,7 +188,11 @@ namespace TU uint32_t getCtuAddr (const Position& pos, const PreCalcValues &pcv); template<typename T, size_t N> +#if JVET_L0054_MMVD +uint32_t updateCandList(T uiMode, double uiCost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, size_t uiFastCandNum = N, int* iserttPos = nullptr) +#else uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, size_t uiFastCandNum = N ) +#endif { CHECK( std::min( uiFastCandNum, candModeList.size() ) != std::min( uiFastCandNum, candCostList.size() ), "Sizes do not match!" ); CHECK( uiFastCandNum > candModeList.capacity(), "The vector is to small to hold all the candidates!" ); @@ -201,15 +215,32 @@ uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeL } candModeList[currSize - shift] = uiMode; candCostList[currSize - shift] = uiCost; +#if JVET_L0054_MMVD + if (iserttPos != nullptr) + { + *iserttPos = int(currSize - shift); + } +#endif return 1; } else if( currSize < uiFastCandNum ) { candModeList.insert( candModeList.end() - shift, uiMode ); candCostList.insert( candCostList.end() - shift, uiCost ); +#if JVET_L0054_MMVD + if (iserttPos != nullptr) + { + *iserttPos = int(candModeList.size() - shift - 1); + } +#endif return 1; } - +#if JVET_L0054_MMVD + if (iserttPos != nullptr) + { + *iserttPos = -1; + } +#endif return 0; } diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index f6c572efa44731ca674f93ba6942086e9b755c45..b58966e8de83e770f99d1db2bf36c9c2bbb01419 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -757,6 +757,11 @@ void CABACReader::cu_skip_flag( CodingUnit& cu ) if( skip ) { +#if JVET_L0054_MMVD + unsigned mmvdSkip = m_BinDecoder.decodeBin(Ctx::MmvdFlag(0)); + cu.mmvdSkip = mmvdSkip; + DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_cu_skip_flag() ctx=%d mmvd_skip=%d\n", 0, mmvdSkip ? 1 : 0); +#endif cu.skip = true; cu.rootCbf = false; cu.predMode = MODE_INTER; @@ -1155,6 +1160,13 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx ) if( pu.mergeFlag ) { affine_flag ( *pu.cu ); +#if JVET_L0054_MMVD + if (pu.mmvdMergeFlag) + { + mmvd_merge_idx(pu); + } + else +#endif merge_data ( pu ); } else @@ -1236,6 +1248,12 @@ void CABACReader::affine_flag( CodingUnit& cu ) { return; } +#if JVET_L0054_MMVD + if (cu.firstPU->mergeFlag && (cu.firstPU->mmvdMergeFlag || cu.mmvdSkip)) + { + return; + } +#endif CHECK( !cu.cs->pcv->rectCUs && cu.lumaSize().width != cu.lumaSize().height, "CU width and height are not equal for QTBT off." ); @@ -1265,6 +1283,13 @@ void CABACReader::merge_flag( PredictionUnit& pu ) pu.mergeFlag = ( m_BinDecoder.decodeBin( Ctx::MergeFlag() ) ); DTRACE( g_trace_ctx, D_SYNTAX, "merge_flag() merge=%d pos=(%d,%d) size=%dx%d\n", pu.mergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height ); +#if JVET_L0054_MMVD + if (pu.mergeFlag) + { + pu.mmvdMergeFlag = (m_BinDecoder.decodeBin(Ctx::MmvdFlag(0))); + DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_flag() mmvd_merge=%d pos=(%d,%d) size=%dx%d\n", pu.mmvdMergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height); + } +#endif } @@ -1274,7 +1299,13 @@ void CABACReader::merge_data( PredictionUnit& pu ) { return; } - +#if JVET_L0054_MMVD + if (pu.cu->mmvdSkip) + { + mmvd_merge_idx(pu); + } + else +#endif merge_idx( pu ); } @@ -1319,6 +1350,76 @@ void CABACReader::merge_idx( PredictionUnit& pu ) DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() merge_idx=%d\n", pu.mergeIdx ); } +#if JVET_L0054_MMVD +void CABACReader::mmvd_merge_idx(PredictionUnit& pu) +{ + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET(STATS__CABAC_BITS__MERGE_INDEX); + int var0, var1, var2; + int dir0 = 0; + int var = 0; + int mvpIdx = 0; + + pu.mmvdMergeIdx = 0; + + mvpIdx = (var + dir0)*(MMVD_MAX_REFINE_NUM*MMVD_BASE_MV_NUM); + + int numCandminus1_base = MMVD_BASE_MV_NUM - 1; + var0 = 0; + if (numCandminus1_base > 0) + { + if (m_BinDecoder.decodeBin(Ctx::MmvdMergeIdx())) + { + var0++; + for (; var0 < numCandminus1_base; var0++) + { + if (!m_BinDecoder.decodeBinEP()) + { + break; + } + } + } + } + DTRACE(g_trace_ctx, D_SYNTAX, "base_mvp_idx() base_mvp_idx=%d\n", var0); + int numCandminus1_step = MMVD_REFINE_STEP - 1; + var1 = 0; + if (numCandminus1_step > 0) + { + if (m_BinDecoder.decodeBin(Ctx::MmvdStepMvpIdx())) + { + var1++; + for (; var1 < numCandminus1_step; var1++) + { + if (!m_BinDecoder.decodeBinEP()) + { + break; + } + } + } + } + DTRACE(g_trace_ctx, D_SYNTAX, "MmvdStepMvpIdx() MmvdStepMvpIdx=%d\n", var1); + var2 = 0; + if (m_BinDecoder.decodeBinEP()) + { + var2 += 2; + if (m_BinDecoder.decodeBinEP()) + { + var2 += 1; + } + } + else + { + var2 += 0; + if (m_BinDecoder.decodeBinEP()) + { + var2 += 1; + } + } + DTRACE(g_trace_ctx, D_SYNTAX, "pos() pos=%d\n", var2); + mvpIdx += (var0 * MMVD_MAX_REFINE_NUM + var1 * 4 + var2); + pu.mmvdMergeIdx = mvpIdx; + DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_idx() mmvd_merge_idx=%d\n", pu.mmvdMergeIdx); +} +#endif void CABACReader::inter_pred_idc( PredictionUnit& pu ) { diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index fd194650c2275ac547e9cff453b7c7f04d167b64..fa5236476e45f3ebea59d0f230602df17a3a83bd 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -97,6 +97,9 @@ public: void merge_data ( PredictionUnit& pu ); void affine_flag ( CodingUnit& cu ); void merge_idx ( PredictionUnit& pu ); +#if JVET_L0054_MMVD + void mmvd_merge_idx(PredictionUnit& pu); +#endif void imv_mode ( CodingUnit& cu, MergeCtx& mrgCtx ); void inter_pred_idc ( PredictionUnit& pu ); void ref_idx ( PredictionUnit& pu, RefPicList eRefList ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 8fb1c75ba89f278c1a621440ce9e8fd16f45bade..3b2672079e57eff9c93d995b4fb601d9f0352b97 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -414,6 +414,63 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) if( pu.mergeFlag ) { +#if JVET_L0054_MMVD + if (pu.mmvdMergeFlag || pu.cu->mmvdSkip) + { + if (pu.cs->sps->getSpsNext().getUseSubPuMvp()) + { + Size bufSize = g_miScaling.scale(pu.lumaSize()); + mrgCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize); + } + + if (cu.cs->pps->getLog2ParallelMergeLevelMinus2() && cu.partSize != SIZE_2Nx2N && cu.lumaSize().width <= 8) + { + if (!mrgCtx.hasMergedCandList) + { + // temporarily set size to 2Nx2N + PartSize tmpPS = SIZE_2Nx2N; + PredictionUnit tmpPU = pu; + static_cast<UnitArea&> (tmpPU) = cu; + std::swap(tmpPS, cu.partSize); +#if JVET_L0054_MMVD + int fPosBaseIdx = pu.mmvdMergeIdx / MMVD_MAX_REFINE_NUM; + PU::getInterMergeCandidates(tmpPU, mrgCtx, 1, fPosBaseIdx + 1); +#else + PU::getInterMergeCandidates(tmpPU, mrgCtx, 255); +#endif + PU::getInterMMVDMergeCandidates(tmpPU, mrgCtx, + pu.mmvdMergeIdx + ); + std::swap(tmpPS, cu.partSize); + mrgCtx.hasMergedCandList = true; + } + } + else + { +#if JVET_L0054_MMVD + int fPosBaseIdx = pu.mmvdMergeIdx / MMVD_MAX_REFINE_NUM; + PU::getInterMergeCandidates(pu, mrgCtx, 1, fPosBaseIdx + 1); +#else + PU::getInterMergeCandidates(pu, mrgCtx, 255); +#endif + PU::getInterMMVDMergeCandidates(pu, mrgCtx, + pu.mmvdMergeIdx + ); + } + mrgCtx.setMmvdMergeCandiInfo(pu, pu.mmvdMergeIdx); + + if (pu.interDir == 3 /* PRED_BI */ && PU::isBipredRestriction(pu)) + { + pu.mv[REF_PIC_LIST_1] = Mv(0, 0); + pu.refIdx[REF_PIC_LIST_1] = -1; + pu.interDir = 1; + } + + PU::spanMotionInfo(pu, mrgCtx); + } + else + { +#endif { if( pu.cu->affine ) { @@ -461,14 +518,22 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) PredictionUnit tmpPU = pu; static_cast<UnitArea&> ( tmpPU ) = cu; std::swap( tmpPS, cu.partSize ); +#if JVET_L0054_MMVD + PU::getInterMergeCandidates(tmpPU, mrgCtx, 0, pu.mergeIdx); +#else PU::getInterMergeCandidates( tmpPU, mrgCtx, pu.mergeIdx ); +#endif std::swap( tmpPS, cu.partSize ); mrgCtx.hasMergedCandList = true; } } else { +#if JVET_L0054_MMVD + PU::getInterMergeCandidates(pu, mrgCtx, 0, pu.mergeIdx); +#else PU::getInterMergeCandidates( pu, mrgCtx, pu.mergeIdx ); +#endif } mrgCtx.setMergeInfo( pu, pu.mergeIdx ); @@ -486,6 +551,9 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) PU::spanMotionInfo( pu, mrgCtx ); } } +#if JVET_L0054_MMVD + } +#endif } else { diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 03d4197ea3e76b0331654aaa8e8fa39971d8dbb3..7636c2b34f332af8b0c695fa3854eb66ccde4002 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -666,6 +666,13 @@ void CABACWriter::cu_skip_flag( const CodingUnit& cu ) m_BinEncoder.encodeBin( ( cu.skip ), Ctx::SkipFlag( ctxId ) ); DTRACE( g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, cu.skip ? 1 : 0 ); +#if JVET_L0054_MMVD + if (cu.skip) + { + m_BinEncoder.encodeBin(cu.mmvdSkip, Ctx::MmvdFlag(0)); + DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_cu_skip_flag() ctx=%d mmvd_skip=%d\n", 0, cu.mmvdSkip ? 1 : 0); + } +#endif } @@ -1114,6 +1121,13 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu ) if( pu.mergeFlag ) { affine_flag ( *pu.cu ); +#if JVET_L0054_MMVD + if (pu.mmvdMergeFlag) + { + mmvd_merge_idx(pu); + } + else +#endif merge_idx ( pu ); } else @@ -1180,7 +1194,12 @@ void CABACWriter::affine_flag( const CodingUnit& cu ) } CHECK( !cu.cs->pcv->rectCUs && cu.lumaSize().width != cu.lumaSize().height, "CU width and height are not equal for QTBT off." ); - +#if JVET_L0054_MMVD + if (cu.firstPU->mergeFlag && (cu.firstPU->mmvdMergeFlag || cu.mmvdSkip)) + { + return; + } +#endif unsigned ctxId = DeriveCtx::CtxAffineFlag( cu ); m_BinEncoder.encodeBin( cu.affine, Ctx::AffineFlag( ctxId ) ); DTRACE( g_trace_ctx, D_COMMON, " (%d) affine_flag() affine=%d\n", DTRACE_GET_COUNTER(g_trace_ctx, D_COMMON), cu.affine ? 1 : 0 ); @@ -1202,6 +1221,13 @@ void CABACWriter::merge_flag( const PredictionUnit& pu ) m_BinEncoder.encodeBin( pu.mergeFlag, Ctx::MergeFlag() ); DTRACE( g_trace_ctx, D_SYNTAX, "merge_flag() merge=%d pos=(%d,%d) size=%dx%d\n", pu.mergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height ); +#if JVET_L0054_MMVD + if (pu.mergeFlag) + { + m_BinEncoder.encodeBin(pu.mmvdMergeFlag, Ctx::MmvdFlag(0)); + DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_flag() mmvd_merge=%d pos=(%d,%d) size=%dx%d\n", pu.mmvdMergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height); + } +#endif } void CABACWriter::imv_mode( const CodingUnit& cu ) @@ -1277,7 +1303,65 @@ void CABACWriter::merge_idx( const PredictionUnit& pu ) } DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() merge_idx=%d\n", pu.mergeIdx ); } +#if JVET_L0054_MMVD +void CABACWriter::mmvd_merge_idx(const PredictionUnit& pu) +{ + int var0, var1, var2; + int mvpIdx = pu.mmvdMergeIdx; + var0 = mvpIdx / MMVD_MAX_REFINE_NUM; + var1 = (mvpIdx - (var0 * MMVD_MAX_REFINE_NUM)) / 4; + var2 = mvpIdx - (var0 * MMVD_MAX_REFINE_NUM) - var1 * 4; + int numCandminus1_base = MMVD_BASE_MV_NUM - 1; + if (numCandminus1_base > 0) + { + if (var0 == 0) + { + m_BinEncoder.encodeBin(0, Ctx::MmvdMergeIdx()); + } + else + { + m_BinEncoder.encodeBin(1, Ctx::MmvdMergeIdx()); + for (unsigned idx = 1; idx < numCandminus1_base; idx++) + { + m_BinEncoder.encodeBinEP(var0 == idx ? 0 : 1); + if (var0 == idx) + { + break; + } + } + } + } + DTRACE(g_trace_ctx, D_SYNTAX, "base_mvp_idx() base_mvp_idx=%d\n", var0); + + int numCandminus1_step = MMVD_REFINE_STEP - 1; + if (numCandminus1_step > 0) + { + if (var1 == 0) + { + m_BinEncoder.encodeBin(0, Ctx::MmvdStepMvpIdx()); + } + else + { + m_BinEncoder.encodeBin(1, Ctx::MmvdStepMvpIdx()); + for (unsigned idx = 1; idx < numCandminus1_step; idx++) + { + m_BinEncoder.encodeBinEP(var1 == idx ? 0 : 1); + if (var1 == idx) + { + break; + } + } + } + } + DTRACE(g_trace_ctx, D_SYNTAX, "MmvdStepMvpIdx() MmvdStepMvpIdx=%d\n", var1); + + m_BinEncoder.encodeBinsEP(var2, 2); + + DTRACE(g_trace_ctx, D_SYNTAX, "pos() pos=%d\n", var2); + DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_idx() mmvd_merge_idx=%d\n", pu.mmvdMergeIdx); +} +#endif void CABACWriter::inter_pred_idc( const PredictionUnit& pu ) { if( !pu.cs->slice->isInterB() ) diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index b17bfadeef0a8c6034921de77b5838e451e51257..b597aa474d329e7271ebff05054f4df528db5fb5 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -110,6 +110,9 @@ public: void merge_flag ( const PredictionUnit& pu ); void affine_flag ( const CodingUnit& cu ); void merge_idx ( const PredictionUnit& pu ); +#if JVET_L0054_MMVD + void mmvd_merge_idx(const PredictionUnit& pu); +#endif void imv_mode ( const CodingUnit& cu ); void inter_pred_idc ( const PredictionUnit& pu ); void ref_idx ( const PredictionUnit& pu, RefPicList eRefList ); diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 60b08917056def793fde1fd21b93894c8a99b258..8295455e5237eb70e7d7e8a08ff4076c9f2c3b3a 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -151,7 +151,11 @@ void EncCu::create( EncCfg* encCfg ) m_modeCtrl->create( *encCfg ); #endif +#if JVET_L0054_MMVD + for (unsigned ui = 0; ui < MMVD_MRG_MAX_RD_BUF_NUM; ui++) +#else for( unsigned ui = 0; ui < MRG_MAX_NUM_CANDS; ui++ ) +#endif { m_acMergeBuffer[ui].create( chromaFormat, Area( 0, 0, uiMaxWidth, uiMaxHeight ) ); } @@ -606,6 +610,10 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par else if( currTestMode.type == ETM_MERGE_SKIP ) { xCheckRDCostMerge2Nx2N( tempCS, bestCS, partitioner, currTestMode ); +#if JVET_L0054_MMVD + CodingUnit* cu = bestCS->getCU(partitioner.chType); + cu->mmvdSkip = cu->skip == false ? false : cu->mmvdSkip; +#endif } else if( currTestMode.type == ETM_INTRA ) { @@ -1131,6 +1139,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); #endif cu.skip = false; +#if JVET_L0054_MMVD + cu.mmvdSkip = false; +#endif cu.partSize = encTestMode.partSize; cu.predMode = MODE_INTRA; cu.transQuantBypass = encTestMode.lossless; @@ -1244,6 +1255,9 @@ void EncCu::xCheckIntraPCM(CodingStructure *&tempCS, CodingStructure *&bestCS, P cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); #endif cu.skip = false; +#if JVET_L0054_MMVD + cu.mmvdSkip = false; +#endif cu.partSize = SIZE_2Nx2N; cu.predMode = MODE_INTRA; cu.transQuantBypass = encTestMode.lossless; @@ -1413,8 +1427,14 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& PredictionUnit pu( tempCS->area ); pu.cu = &cu; pu.cs = tempCS; - - PU::getInterMergeCandidates(pu, mergeCtx); + PU::getInterMergeCandidates(pu, mergeCtx +#if JVET_L0054_MMVD + , 0 +#endif + ); +#if JVET_L0054_MMVD + PU::getInterMMVDMergeCandidates(pu, mergeCtx); +#endif #if JVET_L0104_NO_4x4BI_INTER_CU if (PU::isBipredRestriction(pu)) { @@ -1432,8 +1452,43 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& } #endif } +#if JVET_L0054_MMVD + bool candHasNoResidual[MRG_MAX_NUM_CANDS + MMVD_ADD_NUM]; + for (uint32_t ui = 0; ui < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; ui++) + { + candHasNoResidual[ui] = false; + } + bool bestIsSkip = false; + bool bestIsMMVDSkip = true; + PelUnitBuf acMergeRealBuffer[MMVD_MRG_MAX_RD_BUF_NUM]; + PelUnitBuf * acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM]; + PelUnitBuf * singleMergeTempBuffer; + int insertPos; + unsigned uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM; + + static_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> RdModeList; + bool mrgTempBufSet = false; + + for (unsigned i = 0; i < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; i++) + { + RdModeList.push_back(i); + } + const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height)); + for (unsigned i = 0; i < MMVD_MRG_MAX_RD_BUF_NUM; i++) + { + acMergeRealBuffer[i] = m_acMergeBuffer[i].getBuf(localUnitArea); + if (i < MMVD_MRG_MAX_RD_NUM) + { + acMergeTempBuffer[i] = acMergeRealBuffer + i; + } + else + { + singleMergeTempBuffer = acMergeRealBuffer + i; + } + } +#else bool candHasNoResidual[MRG_MAX_NUM_CANDS]; for (uint32_t ui = 0; ui < mergeCtx.numValidMergeCand; ui++) { @@ -1454,7 +1509,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& { RdModeList.push_back( i ); } - +#endif if( m_pcEncCfg->getUseFastMerge() ) { uiNumMrgSATDCand = NUM_MRG_SATD_CAND; @@ -1463,10 +1518,15 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) ) { bestIsSkip = blkCache->isSkip( tempCS->area ); +#if JVET_L0054_MMVD + bestIsMMVDSkip = blkCache->isMMVDSkip(tempCS->area); +#endif } - +#if JVET_L0054_MMVD + static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> candCostList; +#else static_vector<double, MRG_MAX_NUM_CANDS> candCostList; - +#endif // 1. Pass: get SATD-cost for selected candidates and reduce their count if( !bestIsSkip ) { @@ -1482,6 +1542,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); #endif cu.skip = false; +#if JVET_L0054_MMVD + cu.mmvdSkip = false; +#endif cu.partSize = SIZE_2Nx2N; //cu.affine cu.predMode = MODE_INTER; @@ -1500,16 +1563,20 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& const UnitArea localUnitArea( tempCS->area.chromaFormat, Area( 0, 0, tempCS->area.Y().width, tempCS->area.Y().height) ); for( uint32_t uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ ) { +#if !JVET_L0054_MMVD acMergeBuffer[uiMergeCand] = m_acMergeBuffer[uiMergeCand].getBuf( localUnitArea ); - +#endif mergeCtx.setMergeInfo( pu, uiMergeCand ); PU::spanMotionInfo( pu, mergeCtx ); - +#if JVET_L0054_MMVD + distParam.cur = singleMergeTempBuffer->Y(); + m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer); +#else distParam.cur = acMergeBuffer[uiMergeCand].Y(); m_pcInterSearch->motionCompensation( pu, acMergeBuffer[uiMergeCand] ); - +#endif if( mergeCtx.interDirNeighbours[uiMergeCand] == 3 && mergeCtx.mrgTypeNeighbours[uiMergeCand] == MRG_TYPE_DEFAULT_N ) { mergeCtx.mvFieldNeighbours[2*uiMergeCand].mv = pu.mv[0]; @@ -1525,11 +1592,121 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& { uiBitsCand--; } +#if JVET_L0054_MMVD + uiBitsCand++; // for mmvd_flag +#endif double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass; - +#if JVET_L0054_MMVD + insertPos = -1; + updateCandList(uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos); + if (insertPos != -1) + { + if (insertPos == RdModeList.size() - 1) + { + swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]); + } + else + { + for (uint32_t i = uint32_t(RdModeList.size()) - 1; i > insertPos; i--) + { + swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]); + } + swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]); + } + } +#else updateCandList( uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand ); +#endif CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" ); } +#if JVET_L0054_MMVD + cu.mmvdSkip = true; + int tempNum = 0; + tempNum = MMVD_ADD_NUM; + bool allowDirection[4] = { true, true, true, true }; + for (uint32_t mergeCand = mergeCtx.numValidMergeCand; mergeCand < mergeCtx.numValidMergeCand + tempNum; mergeCand++) + { + const int mmvdMergeCand = mergeCand - mergeCtx.numValidMergeCand; + int bitsBaseIdx = 0; + int bitsRefineStep = 0; + int bitsDirection = 2; + int bitsCand = 0; + int baseIdx; + int refineStep; + int direction; + baseIdx = mmvdMergeCand / MMVD_MAX_REFINE_NUM; + refineStep = (mmvdMergeCand - (baseIdx * MMVD_MAX_REFINE_NUM)) / 4; + direction = (mmvdMergeCand - baseIdx * MMVD_MAX_REFINE_NUM - refineStep * 4) % 4; + if (refineStep == 0) + { + allowDirection[direction] = true; + } + if (allowDirection[direction] == false) + { + continue; + } + bitsBaseIdx = baseIdx + 1; + if (baseIdx == MMVD_BASE_MV_NUM - 1) + { + bitsBaseIdx--; + } + + bitsRefineStep = refineStep + 1; + if (refineStep == MMVD_REFINE_STEP - 1) + { + bitsRefineStep--; + } + + bitsCand = bitsBaseIdx + bitsRefineStep + bitsDirection; + bitsCand++; // for mmvd_flag + +#if !JVET_L0054_MMVD + acMergeBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea); +#endif + mergeCtx.setMmvdMergeCandiInfo(pu, mmvdMergeCand); + + PU::spanMotionInfo(pu, mergeCtx); +#if JVET_L0054_MMVD + distParam.cur = singleMergeTempBuffer->Y(); + m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer); +#else + distParam.cur = acMergeBuffer[mergeCand].Y(); + m_pcInterSearch->motionCompensation(pu, acMergeBuffer[mergeCand]); +#endif + + Distortion uiSad = distParam.distFunc(distParam); + + +#if !JVET_L0054_MMVD + uint32_t bitsCand = mergeCand + 1; + if (mergeCand == tempCS->slice->getMaxNumMergeCand() - 1) + { + bitsCand--; + } +#endif + double cost = (double)uiSad + (double)bitsCand * sqrtLambdaForFirstPass; +#if JVET_L0054_MMVD + allowDirection[direction] = cost > 1.3 * candCostList[0] ? 0 : 1; +#endif +#if JVET_L0054_MMVD + insertPos = -1; + updateCandList(mergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos); + if (insertPos != -1) + { + for (int i = int(RdModeList.size()) - 1; i > insertPos; i--) + { + swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]); + } + swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]); + } +#else + updateCandList(mergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand); +#endif +#if !JVET_L0054_MMVD + CHECK(std::min(mergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), ""); +#endif + } +#endif // Try to limit number of candidates using SATD-costs for( uint32_t i = 1; i < uiNumMrgSATDCand; i++ ) { @@ -1544,7 +1721,18 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& } else { +#if JVET_L0054_MMVD + if (bestIsMMVDSkip) + { + uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM; + } + else + { + uiNumMrgSATDCand = mergeCtx.numValidMergeCand; + } +#else uiNumMrgSATDCand = mergeCtx.numValidMergeCand; +#endif } } @@ -1556,7 +1744,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ ) { uint32_t uiMergeCand = RdModeList[uiMrgHADIdx]; +#if JVET_L0054_MMVD + if (((uiNoResidualPass != 0) && candHasNoResidual[uiMrgHADIdx]) +#else if( ( (uiNoResidualPass != 0) && candHasNoResidual[uiMergeCand] ) +#endif || ( (uiNoResidualPass == 0) && bestIsSkip ) ) { continue; @@ -1571,6 +1763,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); #endif cu.skip = false; +#if JVET_L0054_MMVD + cu.mmvdSkip = false; +#endif cu.partSize = SIZE_2Nx2N; //cu.affine cu.predMode = MODE_INTER; @@ -1579,8 +1774,20 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1; cu.qp = encTestMode.qp; PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType ); - +#if JVET_L0054_MMVD + if (uiMergeCand >= mergeCtx.numValidMergeCand) + { + cu.mmvdSkip = true; + mergeCtx.setMmvdMergeCandiInfo(pu, uiMergeCand - mergeCtx.numValidMergeCand); + } + else + { + cu.mmvdSkip = false; + mergeCtx.setMergeInfo(pu, uiMergeCand); + } +#else mergeCtx.setMergeInfo( pu, uiMergeCand ); +#endif PU::spanMotionInfo( pu, mergeCtx ); if( mrgTempBufSet ) @@ -1588,18 +1795,28 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& #if DMVR_JVET_LOW_LATENCY_K0217 pu.mvd[0] = refinedMvdL0[uiMergeCand]; #endif +#if JVET_L0054_MMVD + tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]); +#else tempCS->getPredBuf().copyFrom( acMergeBuffer[ uiMergeCand ]); +#endif } else { m_pcInterSearch->motionCompensation( pu ); } - +#if JVET_L0054_MMVD + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass + , NULL + , 1 + , uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL); +#else xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass , NULL , 1 , uiNoResidualPass == 0 ? &candHasNoResidual[uiMergeCand] : NULL ); +#endif if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip ) { @@ -1672,6 +1889,9 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); #endif cu.skip = false; +#if JVET_L0054_MMVD + cu.mmvdSkip = false; +#endif cu.partSize = encTestMode.partSize; cu.affine = true; cu.predMode = MODE_INTER; @@ -1781,6 +2001,9 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); #endif cu.skip = false; +#if JVET_L0054_MMVD + cu.mmvdSkip = false; +#endif cu.partSize = encTestMode.partSize; //cu.affine cu.predMode = MODE_INTER; @@ -1948,6 +2171,9 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); #endif cu.skip = false; +#if JVET_L0054_MMVD + cu.mmvdSkip = false; +#endif cu.partSize = encTestMode.partSize; //cu.affine cu.predMode = MODE_INTER; diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index e5df1314e452666f2b3512a7fda92c328ff00dac..7e0512e3c3d5d81c84c87e23507e557896566afd 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -107,9 +107,11 @@ private: RateCtrl* m_pcRateCtrl; CodingStructure ***m_pImvTempCS; EncModeCtrl *m_modeCtrl; - +#if JVET_L0054_MMVD + PelStorage m_acMergeBuffer[MMVD_MRG_MAX_RD_BUF_NUM]; +#else PelStorage m_acMergeBuffer[MRG_MAX_NUM_CANDS]; - +#endif MotionInfo m_SubPuMiBuf [( MAX_CU_SIZE * MAX_CU_SIZE ) >> ( MIN_CU_LOG2 << 1 )]; unsigned int m_subMergeBlkSize[10]; unsigned int m_subMergeBlkNum[10]; diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index 115f532997460397c273eed0e5998111110ea8c7..784903a0135979e42ac875ca516869e70f05bf61 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -473,6 +473,16 @@ bool CacheBlkInfoCtrl::isSkip( const UnitArea& area ) return m_codedCUInfo[idx1][idx2][idx3][idx4]->isSkip; } +#if JVET_L0054_MMVD +bool CacheBlkInfoCtrl::isMMVDSkip(const UnitArea& area) +{ + unsigned idx1, idx2, idx3, idx4; + getAreaIdx(area.Y(), *m_slice_chblk->getPPS()->pcv, idx1, idx2, idx3, idx4); + + return m_codedCUInfo[idx1][idx2][idx3][idx4]->isMMVDSkip; +} +#endif + void CacheBlkInfoCtrl::setMv( const UnitArea& area, const RefPicList refPicList, const int iRefIdx, const Mv& rMv ) { if( iRefIdx >= MAX_STORED_CU_INFO_REFS ) return; @@ -1509,6 +1519,9 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt relatedCU.isInter = true; #if HM_CODED_CU_INFO relatedCU.isSkip |= bestCU->skip; +#if JVET_L0054_MMVD + relatedCU.isMMVDSkip |= bestCU->mmvdSkip; +#endif #else relatedCU.isSkip = bestCU->skip; #endif diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h index 987c6a6750dc5ff2fb66ab023c83c529c5324bdd..f56fceb06b1435025bced67fcf32150c1a4c7253 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.h +++ b/source/Lib/EncoderLib/EncModeCtrl.h @@ -317,7 +317,9 @@ struct CodedCUInfo bool isInter; bool isIntra; bool isSkip; - +#if JVET_L0054_MMVD + bool isMMVDSkip; +#endif bool validMv[NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS]; Mv saveMv [NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS]; @@ -368,7 +370,9 @@ public: virtual ~CacheBlkInfoCtrl() {} bool isSkip ( const UnitArea& area ); - +#if JVET_L0054_MMVD + bool isMMVDSkip(const UnitArea& area); +#endif bool getMv ( const UnitArea& area, const RefPicList refPicList, const int iRefIdx, Mv& rMv ) const; void setMv ( const UnitArea& area, const RefPicList refPicList, const int iRefIdx, const Mv& rMv ); diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 8e01532c7e6012e760088d6b3fd92d1d1924d7c9..c3267fac82b983c0178909aeadf0aa5f69dfa548 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -692,16 +692,54 @@ void InterSearch::xMergeEstimation( PredictionUnit& pu, PelUnitBuf& origBuf, int pu.UnitArea::operator=( *pu.cu ); pu.cu->partSize = SIZE_2Nx2N; - +#if JVET_L0054_MMVD + if(pu.mmvdMergeFlag) + { + PU::getInterMergeCandidates( pu, mergeCtx +#if JVET_L0054_MMVD + , 0 +#endif + ); + PU::getInterMMVDMergeCandidates(pu, mergeCtx); + } + else + { + PU::getInterMergeCandidates(pu, mergeCtx +#if JVET_L0054_MMVD + , 0 +#endif + ); + } +#else PU::getInterMergeCandidates( pu, mergeCtx ); - +#endif pu.UnitArea::operator=( unitArea ); pu.cu->partSize = partSize; } } else { +#if JVET_L0054_MMVD + if(pu.mmvdMergeFlag) + { + PU::getInterMergeCandidates( pu, mergeCtx +#if JVET_L0054_MMVD + , 0 +#endif + ); + PU::getInterMMVDMergeCandidates(pu, mergeCtx); + } + else + { + PU::getInterMergeCandidates(pu, mergeCtx +#if JVET_L0054_MMVD + , 0 +#endif + ); + } +#else PU::getInterMergeCandidates( pu, mergeCtx ); +#endif } PU::restrictBiPredMergeCands( pu, mergeCtx ); @@ -4565,6 +4603,13 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa m_CABACEstimator->cu_skip_flag ( cu ); m_CABACEstimator->affine_flag( cu ); +#if JVET_L0054_MMVD + if (cu.mmvdSkip) + { + m_CABACEstimator->mmvd_merge_idx(pu); + } + else +#endif m_CABACEstimator->merge_idx ( pu ); @@ -4689,6 +4734,13 @@ uint64_t InterSearch::xGetSymbolFracBitsInter(CodingStructure &cs, Partitioner & m_CABACEstimator->cu_skip_flag ( cu ); m_CABACEstimator->affine_flag ( cu ); +#if JVET_L0054_MMVD + if (cu.mmvdSkip) + { + m_CABACEstimator->mmvd_merge_idx(*cu.firstPU); + } + else +#endif m_CABACEstimator->merge_idx ( *cu.firstPU ); fracBits += m_CABACEstimator->getEstFracBits(); }