diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index a2881df31554040e244d372d2ca78c24a3912e29..434aaf98dacaefe5e82267bcd65bf04ff6dbc42b 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -833,6 +833,9 @@ void EncApp::xInitLibCfg() #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE m_cEncLib.setUseAltCost ( m_useAltCost ); #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + m_cEncLib.setUseExtAmvp ( m_useExtAmvp ); +#endif #if JVET_AF0163_TM_SUBBLOCK_REFINEMENT m_cEncLib.setUseAffineTM ( m_useAffineTM ); #if JVET_AG0276_NLIC diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 737460da0d59fcf4437eb1a11f688ece2af21650..8212b8ff8b9d5f1dee7205ce54f51b1147f085c9 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1054,6 +1054,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE ("AltCost", m_useAltCost, true, "Enable alternating cost function based on parity of merge index (0:off, 1:on) [default: on]") #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + ("ExtAmvp", m_useExtAmvp, true, "Enable extended amvp candidates (0:off, 1:on) [default: on]") +#endif #if JVET_AF0163_TM_SUBBLOCK_REFINEMENT ("AffineTM", m_useAffineTM, true, "Enable TM-based subblock motion refinement (0:off, 1:on) [default: on]") #if JVET_AG0276_NLIC diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 9a478c16a0901ac17536b60ee3dbf14f38c0769d..52930f736f79442d757adaf70364ffd6c9d2387a 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -418,6 +418,9 @@ protected: #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE bool m_useAltCost; #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + bool m_useExtAmvp; +#endif #if JVET_AF0163_TM_SUBBLOCK_REFINEMENT bool m_useAffineTM; #if JVET_AG0276_NLIC diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index a5a6c32fc81feba3cbfcafb07e19305a1a398b66..b15f94a5f9ceeb26a17a56e6d443dd832de11dfe 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -181,11 +181,20 @@ static const int MAX_NUM_REF = 16; ///< max. static const int MAX_QP = 63; static const int NOT_VALID = -1; +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT +static const int AFFINE_AMVP_MAX_CAND = 10; +#if TM_AMVP || (JVET_Z0084_IBC_TM && IBC_TM_AMVP) || JVET_AC0060_IBC_BVP_CLUSTER_RRIBC_BVD_SIGN_DERIV +static const int REGULAR_AMVP_MAX_NUM_CANDS = 10; ///< AMVP: advanced motion vector prediction - max number of final candidate for regular inter mode +#endif +static const int REGULAR_AMVP_MAX_NUM_CANDS_IBC = 5; +#else #if TM_AMVP || (JVET_Z0084_IBC_TM && IBC_TM_AMVP) || JVET_AC0060_IBC_BVP_CLUSTER_RRIBC_BVD_SIGN_DERIV static const int REGULAR_AMVP_MAX_NUM_CANDS = 5; ///< AMVP: advanced motion vector prediction - max number of final candidate for regular inter mode #endif +#endif static const int AMVP_MAX_NUM_CANDS = 2; ///< AMVP: advanced motion vector prediction - max number of final candidates static const int AMVP_MAX_NUM_CANDS_MEM = 3; ///< AMVP: advanced motion vector prediction - max number of candidates + #if INTER_RM_SIZE_CONSTRAINTS static const int AMVP_DECIMATION_FACTOR = 1; #else diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp index 506d65d77a62200abfba861f33c57e2a063ef84c..fe26e1d3eb948857470b96418f52ff8e755f0965 100644 --- a/source/Lib/CommonLib/InterPrediction.cpp +++ b/source/Lib/CommonLib/InterPrediction.cpp @@ -20292,6 +20292,193 @@ void InterPrediction::adjustIBCMergeCandidates(PredictionUnit &pu, MergeCtx& mr updateIBCCandInfo(pu, mrgCtx, rdCandList, startPos, endPos); } #endif + +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT +void InterPrediction::tmRefineAffineAMVPCandidates(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo, int extCond) +{ + if ((extCond >> 4 & 0x0f) == 0) + { + return; + } + + if (!(pu.cs->sps->getUseAffineTM() && pu.cs->sps->getTMToolsEnableFlag())) + { + return; + } + + int licStored = pu.cu->licFlag; + int refIdxL0Stored = pu.refIdx[0]; + int refIdxL1Stored = pu.refIdx[1]; + int affineTypeStored = pu.cu->affineType; + + PredictionUnit pu2 = pu; + pu2.cu->licFlag = false; + pu2.refIdx[eRefPicList] = refIdx; + pu2.refIdx[1-eRefPicList] = -1; + pu2.mergeFlag = true; + + for (int candIdx = 0; candIdx < affiAMVPInfo.numCand; ++candIdx) + { + pu2.cu->affineType = affineTypeStored; + + if (!(pu.cu->slice->getCheckLDB() && !pu.cu->slice->getExtAmvpLevel())) + { + if(candIdx % 2) + { + continue; + } + } + + pu2.mvAffi[eRefPicList][0] = affiAMVPInfo.mvCandLT[candIdx]; + pu2.mvAffi[eRefPicList][1] = affiAMVPInfo.mvCandRT[candIdx]; + pu2.mvAffi[eRefPicList][2] = affiAMVPInfo.mvCandLB[candIdx]; + + if(pu2.cu->affineType == AFFINEMODEL_6PARAM && pu2.mvAffi[eRefPicList][0] == Mv(0,0) && pu2.mvAffi[eRefPicList][1] == Mv(0,0) && pu2.mvAffi[eRefPicList][2] == Mv(0,0)) + { + break; + } + else if (pu2.cu->affineType == AFFINEMODEL_4PARAM && pu2.mvAffi[eRefPicList][0] == Mv(0,0) && pu2.mvAffi[eRefPicList][1] == Mv(0,0)) + { + break; + } + + Mv m_mvBufBDMVRAffine[2][MAX_NUM_SUBCU_DMVR]; + for (int i = 0; i < 3; i++) + { + m_mvBufBDMVRAffine[0][i].setZero(); + m_mvBufBDMVRAffine[1][i].setZero(); + } + setBdmvrSubPuMvBuf(m_mvBufBDMVRAffine[0], m_mvBufBDMVRAffine[1]); + pu2.bdmvrRefine = false; + + AffineMergeCtx AffineMergeCtxTmp = AffineMergeCtx(); + + processTM4Affine(pu2, AffineMergeCtxTmp, -1, false +#if JVET_AH0119_SUBBLOCK_TM + , false +#endif + , true + );//uni + + + affiAMVPInfo.mvCandLT[candIdx] += m_mvBufBDMVRAffine[eRefPicList][0]; + affiAMVPInfo.mvCandRT[candIdx] += m_mvBufBDMVRAffine[eRefPicList][1]; + if(affineTypeStored == AFFINEMODEL_6PARAM) + { + affiAMVPInfo.mvCandLB[candIdx] += m_mvBufBDMVRAffine[eRefPicList][2]; + } + else + { + affiAMVPInfo.mvCandLB[candIdx] = Mv(0,0); + } + + affiAMVPInfo.mvCandLT[candIdx].roundAffinePrecInternal2Amvr(pu.cu->imv); + affiAMVPInfo.mvCandRT[candIdx].roundAffinePrecInternal2Amvr(pu.cu->imv); + affiAMVPInfo.mvCandLB[candIdx].roundAffinePrecInternal2Amvr(pu.cu->imv); + } + pu.cu->licFlag = licStored; + pu.refIdx[0] = refIdxL0Stored; + pu.refIdx[1] = refIdxL1Stored; + pu.cu->affineType = affineTypeStored; +} + +void InterPrediction::adjustAffineAMVPCandidates(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo, int extCond) +{ + if((extCond >> 8 & 0x0f) == 0) + { + affiAMVPInfo.numCand = (affiAMVPInfo.numCand > AMVP_MAX_NUM_CANDS) ? AMVP_MAX_NUM_CANDS : affiAMVPInfo.numCand; + return; + } + + DistParam cDistParam; + cDistParam.applyWeight = false; + + int nWidth = pu.lumaSize().width; + int nHeight = pu.lumaSize().height; + + if (!xAMLGetCurBlkTemplate(pu, nWidth, nHeight)) + { + affiAMVPInfo.numCand = (affiAMVPInfo.numCand > AMVP_MAX_NUM_CANDS) ? AMVP_MAX_NUM_CANDS : affiAMVPInfo.numCand; + return; + } + + int licStored = pu.cu->licFlag; + int refIdxL0Stored = pu.refIdx[0]; + int refIdxL1Stored = pu.refIdx[1]; + + PredictionUnit pu2 = pu; + pu2.cu->licFlag = false; + pu2.refIdx[eRefPicList] = refIdx; + pu2.refIdx[1-eRefPicList] = -1; + + struct affineamvpSort + { + Mv mvCandLT; + Mv mvCandRT; + Mv mvCandLB; + Distortion cost; + }; + affineamvpSort temp; + std::vector<affineamvpSort> input; + const auto costIncSort = [](const affineamvpSort &x, const affineamvpSort &y) { return x.cost < y.cost; }; + Distortion tmCost[AFFINE_AMVP_MAX_CAND]; + for (int i = 0; i < AFFINE_AMVP_MAX_CAND; i++) + { + tmCost[i] = std::numeric_limits<Distortion>::max(); + } + for (int candIdx = 0; candIdx < affiAMVPInfo.numCand; ++candIdx) + { + pu2.mvAffi[eRefPicList][0] = affiAMVPInfo.mvCandLT[candIdx]; + pu2.mvAffi[eRefPicList][1] = affiAMVPInfo.mvCandRT[candIdx]; + pu2.mvAffi[eRefPicList][2] = affiAMVPInfo.mvCandLB[candIdx]; + + PelUnitBuf pcBufPredRefTop = (PelUnitBuf(pu2.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE))); + PelUnitBuf pcBufPredCurTop = (PelUnitBuf(pu2.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE))); + PelUnitBuf pcBufPredRefLeft = (PelUnitBuf(pu2.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight))); + PelUnitBuf pcBufPredCurLeft = (PelUnitBuf(pu2.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[1][0], nHeight, AML_MERGE_TEMPLATE_SIZE))); + getAffAMLRefTemplate(pu2, pcBufPredRefTop, pcBufPredRefLeft,true, AffineMergeCtx()); + + if (m_bAMLTemplateAvailabe[0]) + { + m_pcRdCost->setDistParam(cDistParam, pcBufPredCurTop.Y(), pcBufPredRefTop.Y(), pu2.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false); + + tmCost[candIdx] = cDistParam.distFunc(cDistParam); + } + + if (m_bAMLTemplateAvailabe[1]) + { + m_pcRdCost->setDistParam(cDistParam, pcBufPredCurLeft.Y(), pcBufPredRefLeft.Y(), pu2.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false); + + if(m_bAMLTemplateAvailabe[0]) + { + tmCost[candIdx] += cDistParam.distFunc(cDistParam); + } + else + { + tmCost[candIdx] = cDistParam.distFunc(cDistParam); + } + } + temp.mvCandLT = affiAMVPInfo.mvCandLT[candIdx]; + temp.mvCandRT = affiAMVPInfo.mvCandRT[candIdx]; + temp.mvCandLB = affiAMVPInfo.mvCandLB[candIdx]; + temp.cost = tmCost[candIdx]; + input.push_back(temp); + } + stable_sort(input.begin(), input.end(), costIncSort); + for (int candIdx = 0; candIdx < affiAMVPInfo.numCand; ++candIdx) + { + affiAMVPInfo.mvCandLT[candIdx] = input.at(candIdx).mvCandLT; + affiAMVPInfo.mvCandRT[candIdx] = input.at(candIdx).mvCandRT; + affiAMVPInfo.mvCandLB[candIdx] = input.at(candIdx).mvCandLB; + tmCost[candIdx] = input.at(candIdx).cost; + } + pu.cu->licFlag = licStored; + pu.refIdx[0] = refIdxL0Stored; + pu.refIdx[1] = refIdxL1Stored; + affiAMVPInfo.numCand = (affiAMVPInfo.numCand > AMVP_MAX_NUM_CANDS) ? AMVP_MAX_NUM_CANDS : affiAMVPInfo.numCand; +} +#endif + #if JVET_AA0107_RMVF_AFFINE_MERGE_DERIVATION void InterPrediction::adjustAffineMergeCandidatesOneGroup(PredictionUnit &pu, AffineMergeCtx& affMrgCtx, int listsize #if JVET_AD0182_AFFINE_DMVR_PLUS_EXTENSIONS @@ -24093,6 +24280,7 @@ Distortion InterPrediction::deriveTMMv(const PredictionUnit& pu, bool fillCurTpl { #endif tplCtrl.deriveMvUni<TM_TPL_SIZE>(); + #if TM_MRG && JVET_AA0093_REFINED_MOTION_FOR_ARMC } #endif @@ -25883,6 +26071,40 @@ bool InterPrediction::readTplAmvpBuffer(AMVPInfo& dst, const CodingUnit& cu, Ref } #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT +void InterPrediction::clearAffineAmvpBuffer() +{ + for (int affinetype = 0; affinetype < AFFINE_MODEL_NUM; ++affinetype) + { + for (int imv = 0; imv < NUM_IMV_MODES; ++imv) + { + for (int refIdx = 0; refIdx < MAX_NUM_REF; ++refIdx) + { + m_affineAmvpInfo [affinetype][imv][0][refIdx] = AffineAMVPInfo(); + m_affineAmvpInfo [affinetype][imv][1][refIdx] = AffineAMVPInfo(); + } + } + } +} + +void InterPrediction::writeAffineAmvpBuffer(const AffineAMVPInfo& src, const CodingUnit& cu, RefPicList eRefList, int refIdx) +{ + AffineAMVPInfo& dst = m_affineAmvpInfo[cu.affineType][cu.imv][eRefList][refIdx]; + dst = src; +} + +bool InterPrediction::readAffineAmvpBuffer(AffineAMVPInfo& dst, const CodingUnit& cu, RefPicList eRefList, int refIdx) +{ + AffineAMVPInfo& src = m_affineAmvpInfo[cu.affineType][cu.imv][eRefList][refIdx]; + if (src.numCand > 0) + { + dst = src; + return true; + } + return false; +} +#endif + #if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION void InterPrediction::writeMergeBuffer(const MergeCtx& srcList0, const MergeCtx& srcList1, const CodingUnit& cu) { @@ -27816,6 +28038,9 @@ bool InterPrediction::processTM4Affine(PredictionUnit& pu, AffineMergeCtx &affin #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE , int mergeIdx #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , bool isInt4PosRefine +#endif ) { if (!pu.cs->slice->getSPS()->getTMToolsEnableFlag()) @@ -27915,13 +28140,15 @@ bool InterPrediction::processTM4Affine(PredictionUnit& pu, AffineMergeCtx &affin continue; } - #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + processTM4AffineBaseMV(pu, affineMergeCtx, uiAffMergeCand, cpBestMVF, uiCostOri, uiCostBest, targetList, mergeIdx, isInt4PosRefine); +#else processTM4AffineBaseMV(pu, affineMergeCtx, uiAffMergeCand, cpBestMVF, uiCostOri, uiCostBest, targetList, mergeIdx); +#endif #else processTM4AffineBaseMV(pu, affineMergeCtx, uiAffMergeCand, cpBestMVF, uiCostOri, uiCostBest, targetList); #endif - if (pu.refIdx[0] < 0 || pu.refIdx[1] < 0) { if (isTmPara) @@ -28189,6 +28416,9 @@ bool InterPrediction::processTM4AffineBaseMV(PredictionUnit& pu, AffineMergeCtx #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE , int mergeIdx #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT +, bool isInt4PosRefine +#endif ) { Distortion uiCost = 0;; @@ -28201,13 +28431,30 @@ bool InterPrediction::processTM4AffineBaseMV(PredictionUnit& pu, AffineMergeCtx Mv cpBestMVI[2][3] = { { bestCPMV[0][0] , bestCPMV[0][1] ,bestCPMV[0][2] },{ bestCPMV[1][0] , bestCPMV[1][1] , bestCPMV[1][2] } }; Mv cpBestMVF[2][3] = { { bestCPMV[0][0] , bestCPMV[0][1] ,bestCPMV[0][2] },{ bestCPMV[1][0] , bestCPMV[1][1] , bestCPMV[1][2] } }; - +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + Mv cSearchOffset[8] = { Mv(-1 , 1) , Mv(0 , 1) , Mv(1 , 1) , Mv(1 , 0) , Mv(1 , -1) , Mv(0 , -1) , Mv(-1 , -1) , Mv(-1 , 0) }; + int nDirectStart = 0; + int nDirectEnd = 7; + int nDirectRounding = 8; + int nDirectMask = 0x07; + if(isInt4PosRefine) + { + cSearchOffset[0] = Mv(0 , 1); + cSearchOffset[1] = Mv(1 , 0); + cSearchOffset[2] = Mv(0 , -1); + cSearchOffset[3] = Mv(-1 , 0); + nDirectEnd = 3; + nDirectRounding = 4; + nDirectMask = 0x03; + } +#else static const Mv cSearchOffset[8] = { Mv(-1 , 1) , Mv(0 , 1) , Mv(1 , 1) , Mv(1 , 0) , Mv(1 , -1) , Mv(0 , -1) , Mv(-1 , -1) , Mv(-1 , 0) }; int nDirectStart = 0; int nDirectEnd = 7; const int nDirectRounding = 8; const int nDirectMask = 0x07; +#endif for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) @@ -28342,6 +28589,9 @@ bool InterPrediction::processTM4AffineBaseMV(PredictionUnit& pu, AffineMergeCtx nDirectStart = nBestDirect - nStep; nDirectEnd = nBestDirect + nStep; } +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if(!isInt4PosRefine) +#endif for (int searchIndex = 0; searchIndex < 8; searchIndex++) // fractional search { uiCost = 0; @@ -32092,7 +32342,6 @@ void InterPrediction::amvpMergeModeMvRefinement(PredictionUnit& pu, MvField* mvF } #endif - #if JVET_Z0054_BLK_REF_PIC_REORDER #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED #if JVET_AD0140_MVD_PREDICTION @@ -32666,8 +32915,11 @@ void InterPrediction::reorderRefCombList(PredictionUnit &pu, std::vector<RefList AffineAMVPInfo affineAMVPInfo; - PU::fillAffineMvpCand(tmpPU, eRefList, tmpPU.refIdx[eRefList], affineAMVPInfo); - + PU::fillAffineMvpCand(tmpPU, eRefList, tmpPU.refIdx[eRefList], affineAMVPInfo +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , this +#endif + ); const unsigned mvpIdx = tmpPU.mvpIdx[eRefList]; #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED @@ -33462,8 +33714,11 @@ void InterPrediction::reorderRefPairList(PredictionUnit &pu, std::vector<RefPicP RefPicList eRefList = (RefPicList)refList; - PU::fillAffineMvpCand(tmpPU, eRefList, tmpPU.refIdx[eRefList], affineAMVPInfo[eRefList][refIdx]); - + PU::fillAffineMvpCand(tmpPU, eRefList, tmpPU.refIdx[eRefList], affineAMVPInfo[eRefList][refIdx] +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , this +#endif + ); if (refIdx < 0) { continue; @@ -33531,11 +33786,13 @@ void InterPrediction::reorderRefPairList(PredictionUnit &pu, std::vector<RefPicP for (int refList = 0; refList < 2; refList++) { RefPicList eRefList = (RefPicList)refList; - PU::fillAffineMvpCand(tmpPU, eRefList, tmpPU.refIdx[eRefList], affineAMVPInfo[eRefList]); - -#if !JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED + PU::fillAffineMvpCand(tmpPU, eRefList, tmpPU.refIdx[eRefList], affineAMVPInfo[eRefList] +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , this +#endif + ); const unsigned mvpIdx = tmpPU.mvpIdx[eRefList]; - +#if !JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED Mv mvLT = affineAMVPInfo[eRefList].mvCandLT[mvpIdx] + tmpPU.mvdAffi[eRefList][0]; Mv mvRT = affineAMVPInfo[eRefList].mvCandRT[mvpIdx] + tmpPU.mvdAffi[eRefList][1]; mvRT += tmpPU.mvdAffi[eRefList][0]; @@ -36167,7 +36424,6 @@ void InterPrediction::defineSignHypMatchAffine(PredictionUnit& pu, const RefPicL #endif ); - DistParam cDistParam; cDistParam.applyWeight = false; Distortion uiCost; diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h index fd9e5139eb8bd2e96b68b6b5e775b4ab4c2edbca..b3863edc4e026a5813f87b9185dd54495cd7c74d 100644 --- a/source/Lib/CommonLib/InterPrediction.h +++ b/source/Lib/CommonLib/InterPrediction.h @@ -177,6 +177,10 @@ public: bool m_skipDoLic; #endif #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT +public: + AffineAMVPInfo m_affineAmvpInfo[AFFINE_MODEL_NUM][NUM_IMV_MODES][NUM_REF_PIC_LIST_01][MAX_NUM_REF]; +#endif #if JVET_AD0140_MVD_PREDICTION struct MvdDerivedInfo { @@ -251,6 +255,7 @@ public: AMVPInfo m_tplAmvpInfoLIC[NUM_IMV_MODES][NUM_REF_PIC_LIST_01][MAX_NUM_REF]; #endif #endif + #if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION MergeCtx m_pcMergeCtxList0; MergeCtx m_pcMergeCtxList1; @@ -980,6 +985,7 @@ public: int deriveMVSDIdxFromMVDTransSI(const Mv& cMvd, const std::vector<Mv>& cMvdDerived, const MvdSuffixInfo &si); Mv deriveMVDFromMVSDIdxTransSI(int mvsdIdx, const std::vector<Mv> &cMvdDerived, const MvdSuffixInfo &si); #endif + int deriveMVSDIdxFromMVDTrans(Mv cMvd, std::vector<Mv>& cMvdDerived); Mv deriveMVDFromMVSDIdxTrans(int mvsdIdx, std::vector<Mv>& cMvdDerived); void deriveMvdSignSMVD(const Mv& cMvPred, const Mv& cMvPred2, const Mv& cMvdKnownAtDecoder, PredictionUnit& pu, std::vector<Mv>& cMvdDerived); @@ -1249,6 +1255,10 @@ public: , int mrgCandIdx = -1); void updateAffineCandInfo2(PredictionUnit &pu, AffineMergeCtx& affMrgCtx, uint32_t(*rdCandList)[RMVF_AFFINE_MRG_MAX_CAND_LIST_SIZE], int listsize, int mrgCandIdx = -1); #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + void adjustAffineAMVPCandidates(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo, int extCond); + void tmRefineAffineAMVPCandidates(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo, int extCond); +#endif #if JVET_Y0058_IBC_LIST_MODIFY void adjustIBCMergeCandidates(PredictionUnit &pu, MergeCtx& mrgCtx, int mrgCandIdx = -1); void updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, uint32_t(*RdCandList)[IBC_MRG_MAX_NUM_CANDS], int mrgCandIdx = -1); @@ -1511,6 +1521,11 @@ public: void clearAmvpTmvpBuffer(); #endif #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + void clearAffineAmvpBuffer (); + void writeAffineAmvpBuffer (const AffineAMVPInfo& src, const CodingUnit& cu, RefPicList eRefList, int refIdx); + bool readAffineAmvpBuffer ( AffineAMVPInfo& dst, const CodingUnit& cu, RefPicList eRefList, int refIdx); +#endif #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR static Distortion getDecoderSideDerivedMvCost (const Mv& mvStart, const Mv& mvCur, int searchRangeInFullPel, int weight); #if MULTI_PASS_DMVR @@ -1576,6 +1591,7 @@ private: #endif Mv* m_bdmvrSubPuMvBuf[2]; + #if JVET_X0083_BM_AMVP_MERGE_MODE public: #if JVET_AD0213_LIC_IMP @@ -1586,6 +1602,7 @@ public: void amvpMergeModeMvRefinement(PredictionUnit& pu, MvField* mvFieldAmListCommon, const int mvFieldMergeIdx, const int mvFieldAmvpIdx); #endif #endif + #if JVET_AC0144_AFFINE_DMVR_REGRESSION #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE void bmAffineInit(const PredictionUnit& pu, int mergeIdx = -1); @@ -1665,6 +1682,9 @@ public: #endif #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE , int mergeIdx = -1 +#endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , bool isInt4PosRefine = false #endif ); #if JVET_AH0119_SUBBLOCK_TM @@ -1676,6 +1696,9 @@ public: bool processTM4AffineBaseMV(PredictionUnit& pu, AffineMergeCtx &affineMergeCtx, int uiAffMergeCand, Mv(&bestCPMV)[2][3], Distortion& uiCostOri, Distortion& uiCostBest, uint32_t targetList #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE , int mergeIdx = -1 +#endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , bool isInt4PosRefine = false #endif ); void xUpdateCPMV(PredictionUnit &pu, int32_t targetRefList, const Mv(&curCPMV)[2][3], const int deltaMvHorX, const int deltaMvHorY, const int deltaMvVerX, const int deltaMvVerY, const int baseCP); diff --git a/source/Lib/CommonLib/MotionInfo.h b/source/Lib/CommonLib/MotionInfo.h index 1e2a8c4bb7f991828eafea8810ec2f80a2df49f1..bf00c8abeb9be161aac5910e52dcc9035269b24f 100644 --- a/source/Lib/CommonLib/MotionInfo.h +++ b/source/Lib/CommonLib/MotionInfo.h @@ -126,9 +126,16 @@ struct AMVPInfo struct AffineAMVPInfo { +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + unsigned maxStorageSize; + Mv mvCandLT[ AFFINE_AMVP_MAX_CAND ]; ///< array of affine motion vector predictor candidates for left-top corner + Mv mvCandRT[ AFFINE_AMVP_MAX_CAND ]; ///< array of affine motion vector predictor candidates for right-top corner + Mv mvCandLB[ AFFINE_AMVP_MAX_CAND ]; ///< array of affine motion vector predictor candidates for left-bottom corner +#else Mv mvCandLT[ AMVP_MAX_NUM_CANDS_MEM ]; ///< array of affine motion vector predictor candidates for left-top corner Mv mvCandRT[ AMVP_MAX_NUM_CANDS_MEM ]; ///< array of affine motion vector predictor candidates for right-top corner Mv mvCandLB[ AMVP_MAX_NUM_CANDS_MEM ]; ///< array of affine motion vector predictor candidates for left-bottom corner +#endif unsigned numCand; ///< number of motion vector predictor candidates }; #if JVET_AA0107_RMVF_AFFINE_MERGE_DERIVATION diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 7bfe88ad40e95a43ea8488a6ea034ebe4fcf4fd2..26d549509a85f51715748da27ce2c92b7ffa20da 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -108,6 +108,9 @@ Slice::Slice() #if JVET_AG0098_AMVP_WITH_SBTMVP , m_amvpSbTmvpAmvrEnabledFlag (false) #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT +, m_extAmvpLevel (0) +#endif #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC , m_costForARMC ( MAX_UINT ) #endif @@ -2122,7 +2125,6 @@ void Slice::copySliceInfo(Slice *pSrc, bool cpyAlmostAll) #endif m_cabacInitFlag = pSrc->m_cabacInitFlag; - #if JVET_AG0196_CABAC_RETRAIN m_cabacInitSliceType = pSrc->m_cabacInitSliceType; #endif @@ -4295,6 +4297,9 @@ SPS::SPS() #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE , m_useAltCost ( true ) #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT +, m_useExtAmvp ( true ) +#endif #if JVET_AF0163_TM_SUBBLOCK_REFINEMENT , m_useAffineTM ( false ) #if JVET_AG0276_NLIC diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 4e132f78c0cf89d346a997752c0b1f695e89ea10..c4c4626fef7e8a2bbf9513b32006ab61297564b0 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -1805,6 +1805,9 @@ private: #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE bool m_useAltCost; #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + bool m_useExtAmvp; +#endif #if JVET_AF0163_TM_SUBBLOCK_REFINEMENT bool m_useAffineTM; #if JVET_AG0276_NLIC @@ -2708,6 +2711,10 @@ void setCCALFEnabledFlag( bool b ) void setUseFastSubTmvp ( bool b ) { m_fastSubTmvp = b; } bool getUseFastSubTmvp () const { return m_fastSubTmvp; } #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + void setUseExtAmvp ( bool b ) { m_useExtAmvp = b; } + bool getUseExtAmvp () const { return m_useExtAmvp; } +#endif #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE void setUseAltCost ( bool b ) { m_useAltCost = b; } bool getUseAltCost () const { return m_useAltCost; } @@ -3768,6 +3775,9 @@ private: bool m_amvpSbTmvpAmvrEnabledFlag; bool m_amvpSbTmvpEnabledFlag; #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + int m_extAmvpLevel; +#endif #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC uint32_t m_costForARMC; #endif @@ -3811,7 +3821,6 @@ private: uint32_t m_numSubstream; bool m_cabacInitFlag; - #if JVET_AG0196_CABAC_RETRAIN SliceType m_cabacInitSliceType; #endif @@ -4029,6 +4038,9 @@ public: uint8_t getAmvpSbTmvpNumColPic() const { return m_amvpSbTmvpNumColPic; } bool getAmvpSbTmvpAmvrEnabledFlag() const { return m_amvpSbTmvpAmvrEnabledFlag; } bool getAmvpSbTmvpEnabledFlag() const { return m_amvpSbTmvpEnabledFlag; } +#endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + int getExtAmvpLevel() const { return m_extAmvpLevel; } #endif void checkColRefIdx(uint32_t curSliceSegmentIdx, const Picture* pic); #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC @@ -4228,6 +4240,9 @@ public: void setAmvpSbTmvpNumColPic(uint8_t numPic) { m_amvpSbTmvpNumColPic = numPic; } void setAmvpSbTmvpAmvrEnabledFlag(bool b) { m_amvpSbTmvpAmvrEnabledFlag = b; } #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + void setExtAmvpLevel(int b) { m_extAmvpLevel = b; } +#endif #if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC void setCostForARMC(uint32_t cost) { m_costForARMC = cost; } #endif @@ -4364,7 +4379,6 @@ public: void setCabacInitFlag( bool val ) { m_cabacInitFlag = val; } //!< set CABAC initial flag bool getCabacInitFlag() const { return m_cabacInitFlag; } //!< get CABAC initial flag - #if JVET_AG0196_CABAC_RETRAIN void setCabacInitSliceType( SliceType val ) { m_cabacInitSliceType = val; } SliceType getCabacInitSliceType() const { return m_cabacInitSliceType; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index c2c5e192c06ced35c0536cd3819d17e6a412e109..b6d58953be033c1f68b140ebf45ef9df8b5a4b42 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -51,6 +51,7 @@ #include <cassert> #include <cstdint> + #define BASE_ENCODER 1 #define BASE_NORMATIVE 1 #define TOOLS 1 @@ -368,6 +369,7 @@ #define JVET_AI0094_SHARP_MC_FILTER_FOR_BIPRED 1 // JVET-AI0094: Sharp motion compensation filter for bi-prediction #define JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE 1 // JVET-AI0185 adaptive cost function selection in merge mode #define JVET_AI0183_MVP_EXTENSION 1 // JVET-AI0183 MVP extension +#define JVET_AJ0126_INTER_AMVP_ENHANCEMENT 1 // JVET-AJ0126: Enhanced inter AMVP (inter TM part is controlled by EnableTMTools) // Inter template matching tools #define JVET_AJ0096_SATD_REORDER_INTER 1 // JVET-AJ0096: SATD-based reordering for inter coding #define ENABLE_INTER_TEMPLATE_MATCHING 1 // It controls whether template matching is enabled for inter prediction diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index c44b9b1a3f1a687bd3a79aaa222718466ee90dab..20c845f7b38d3fb8d3c784b66b56bba51d296b3d 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -9803,6 +9803,7 @@ void PU::getInterMergeCandidatesSubTMVP(const PredictionUnit &pu, MergeCtx& mrgC #endif ); } + mrgCtx.numValidMergeCand = cnt; return; @@ -17967,6 +17968,124 @@ bool PU::checkAffineTMCondition(const PredictionUnit& pu) return (min > 1) || !pu.cu->slice->getCheckLDC(); } #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT +int PU::checkExtAffineAmvpCondition(const PredictionUnit& pu) +{ + if(pu.cu->cs->sps->getUseExtAmvp() == false) + { + return EXT_AFFINE_AMVP_TYPE_NONE; + } + + if(pu.cu->cs->sps->getTMToolsEnableFlag() == false) + { + return EXT_AFFINE_AMVP_TYPE_NA_TEMP; + } + + int clevel = pu.cu->slice->getExtAmvpLevel(); + int wxh = pu.lheight() * pu.lwidth(); + if(pu.cu->slice->getCheckLDB()) + { + if(clevel < 2 && wxh <= 4*4) + { + return EXT_AFFINE_AMVP_TYPE_NONE; + } + else if (!clevel && wxh > 64*64) + { + return EXT_AFFINE_AMVP_TYPE_NONE; + } + else if (clevel >= 2 && wxh <= 8*8) + { + return EXT_AFFINE_AMVP_TYPE_NONE; + } + else if (!clevel) + { + return EXT_AFFINE_AMVP_TYPE_LISTS4_REORDER_FIRST; + } + else + { + return EXT_AFFINE_AMVP_TYPE_LISTS10; + } + } + else + { + if (!clevel) + { + if(pu.cs->slice->getTLayer() > 4) + { + return EXT_AFFINE_AMVP_TYPE_NONE; + } + else if (wxh <= 4*4 || wxh > 64*64 || pu.lheight() >= 5* pu.lwidth() || pu.lwidth() >= 5* pu.lheight()) + { + return EXT_AFFINE_AMVP_TYPE_NONE; + } + else + { + return EXT_AFFINE_AMVP_TYPE_LISTS5; + } + } + else if (clevel <= 2 ) + { + if (pu.lheight() >= 4* pu.lwidth() || pu.lwidth() >= 4* pu.lheight()) + { + return EXT_AFFINE_AMVP_TYPE_NONE; + } + else + { + return EXT_AFFINE_AMVP_TYPE_LISTS4; + } + } + else + { + if(pu.cs->slice->getTLayer() > 3 || wxh <= 4*4) + { + return EXT_AFFINE_AMVP_TYPE_NONE; + } + else + { + return EXT_AFFINE_AMVP_TYPE_LISTS10; + } + } + } +} +int PU::checkExtRegularAmvpCondition(const PredictionUnit& pu) +{ + if(pu.cu->cs->sps->getUseExtAmvp() == false) + { + return EXT_REGULAR_AMVP_TYPE_NONE; + } + + int clevel = pu.cu->slice->getExtAmvpLevel(); + int wxh = pu.lheight() * pu.lwidth(); + if(pu.cu->slice->getCheckLDB()) + { + return EXT_REGULAR_AMVP_TYPE_NONE; + } + else if (clevel <= 2 && pu.cs->slice->getTLayer() > 4) + { + return EXT_REGULAR_AMVP_TYPE_NONE; + } + else if (!clevel) + { + if (pu.lheight() * pu.lwidth() > 64*64 || pu.lheight() >= 5* pu.lwidth() || pu.lwidth() >= 5* pu.lheight()) + { + return EXT_REGULAR_AMVP_TYPE_NONE; + } + else + { + return EXT_REGULAR_AMVP_TYPE_NA_SPATIAL; + } + } + else if (clevel > 2) + { + if(pu.cs->slice->getTLayer() > 4 || wxh <= 4*4 || wxh > 128*128) + { + return EXT_REGULAR_AMVP_TYPE_NONE; + } + } + return EXT_REGULAR_AMVP_TYPE_LISTS10; +} +#endif + #if MULTI_PASS_DMVR #if JVET_AE0046_BI_GPM bool PU::checkBDMVRCondition(const PredictionUnit& pu, bool disregardGpmFlag) @@ -19339,7 +19458,11 @@ inline void PU::getRribcBvpCand(PredictionUnit &pu, AMVPInfo *pInfo) inline void PU::clusterBvpCand(const int cbWidth, const int cbHeight, AMVPInfo *pInfo) { int numGroups = 0; +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + std::array<bool, (REGULAR_AMVP_MAX_NUM_CANDS_IBC + 1)> validCand; +#else std::array<bool, (REGULAR_AMVP_MAX_NUM_CANDS + 1)> validCand; +#endif validCand.fill(true); Mv bestCand; Distortion bestCost; @@ -19349,7 +19472,11 @@ inline void PU::clusterBvpCand(const int cbWidth, const int cbHeight, AMVPInfo * // Clustering of AMVP candidates into two groups if (pInfo->numCand > AMVP_MAX_NUM_CANDS) { +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + int numCand = std::min((int) pInfo->numCand, REGULAR_AMVP_MAX_NUM_CANDS_IBC + 1); +#else int numCand = std::min((int) pInfo->numCand, REGULAR_AMVP_MAX_NUM_CANDS + 1); +#endif for (int i = 0; i < numCand; i++) { if (validCand[i]) @@ -19444,7 +19571,11 @@ void PU::fillIBCMvpCand(PredictionUnit &pu, AMVPInfo &amvpInfo) AML_MERGE_TEMPLATE_SIZE, cbHeight); int candIdx = 0; +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + while ((pInfo->numCand < (REGULAR_AMVP_MAX_NUM_CANDS_IBC + 1)) && (candIdx < mergeCtx.numAMVPMergeCand)) +#else while ((pInfo->numCand < (REGULAR_AMVP_MAX_NUM_CANDS + 1)) && (candIdx < mergeCtx.numAMVPMergeCand)) +#endif { pInfo->mvCand[pInfo->numCand] = mergeCtx.mvFieldNeighbours[candIdx << 1].mv; pInfo->mvCost[pInfo->numCand] = @@ -19718,7 +19849,12 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in pInfo->numCand = 0; #if TM_AMVP +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + int extRegularAmvpCond = PU::checkExtRegularAmvpCondition(pu); + pInfo->maxStorageSize = interPred != nullptr ? ((extRegularAmvpCond & 0x0f) ? REGULAR_AMVP_MAX_NUM_CANDS : REGULAR_AMVP_MAX_NUM_CANDS_IBC) : AMVP_MAX_NUM_CANDS; +#else pInfo->maxStorageSize = interPred != nullptr ? REGULAR_AMVP_MAX_NUM_CANDS : AMVP_MAX_NUM_CANDS; +#endif pInfo->maxSimilarityThreshold = interPred != nullptr ? 1 : 0; #endif @@ -20055,8 +20191,174 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in } #endif + #if TM_AMVP // Non-adjacent candidates +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (extRegularAmvpCond & 0xff) + { + auto getNAcand = [&](Position pos) -> void + { + const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2; + const PredictionUnit *puNonAdjacent = cs.getPURestricted(pos, pu, pu.chType); + +#if JVET_Y0065_GPM_INTRA + bool isAvailableNonAdjacent = puNonAdjacent && isDiffMER(pu.lumaPos(), pos, plevel) + && CU::isInter(*puNonAdjacent->cu) && puNonAdjacent->getMotionInfo(pos).isInter; +#else + bool isAvailableNonAdjacent = + puNonAdjacent && isDiffMER(pu.lumaPos(), pos, plevel) && CU::isInter(*puNonAdjacent->cu); +#endif + + if (isAvailableNonAdjacent) + { + MotionInfo miNeighbor = puNonAdjacent->getMotionInfo(pos); + + 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; + int numDir = pu.cu->slice->getExtAmvpLevel() ? 2 : 1; + for (int predictorSource = 0; predictorSource < numDir; predictorSource++) + { + const RefPicList eRefPicListIndex = (predictorSource == 0) ? eRefPicList : eRefPicList2nd; + const int neibRefIdx = miNeighbor.refIdx[eRefPicListIndex]; + + if (neibRefIdx >= 0 && currRefPOC == cs.slice->getRefPOC(eRefPicListIndex, neibRefIdx)) + { + miNeighbor.mv[eRefPicListIndex].roundTransPrecInternal2Amvr(pu.cu->imv); + pInfo->mvCand[(pInfo->numCand)] = miNeighbor.mv[eRefPicListIndex]; + if (!pInfo->xCheckSimilarMotion(pInfo->numCand)) + { + pInfo->numCand++; + } + } + if (pInfo->numCand > pInfo->maxStorageSize) + { + pInfo->numCand = pInfo->maxStorageSize; + } + } + } + }; + + // Non-adjacent candidates + if (pInfo->numCand < pInfo->maxStorageSize && interPred != nullptr) + { + // Non-adjacent candidates round 1 + int offsetX = 0; + int offsetY = 0; + int offsetX0 = 0; + int offsetX1 = 0; + int offsetX2 = pu.Y().width >> 1; + int offsetY0 = 0; + int offsetY1 = 0; + int offsetY2 = pu.Y().height >> 1; + + const int horNAInterval = pu.Y().width; + const int verNAInterval = pu.Y().height; + const int numNACandidate01[7] = { 7, 9, 9, 9, 9, 9, 9 }; + const int idxMap01[7][9] = { { 0, 1, 2, 3, 4, 5, 6 }, { 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 && pInfo->numCand < pInfo->maxStorageSize; iDistanceIndex++) + { + const int iNADistanceHor = horNAInterval * (iDistanceIndex + 1); + const int iNADistanceVer = verNAInterval * (iDistanceIndex + 1); + + for (int naspIdx = 0; naspIdx < numNACandidate01[iDistanceIndex] && pInfo->numCand < pInfo->maxStorageSize; + naspIdx++) + { + switch (idxMap01[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: + CHECK(idxMap01[iDistanceIndex][naspIdx] > 8,"error!"); + exit(0); + break; + } + getNAcand(posLT.offset(offsetX, offsetY)); + } + } + + // 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 && pInfo->numCand < pInfo->maxStorageSize; iDistanceIndex++) + { + const int horNADistance = horNAInterval * (iDistanceIndex + 1); + const int verNADistance = verNAInterval * (iDistanceIndex + 1); + + for (int naspIdx = 0; naspIdx < numNACandidate2[iDistanceIndex] && pInfo->numCand < pInfo->maxStorageSize; + 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: + CHECK(idxMap2[iDistanceIndex][naspIdx] > 3, "error!"); + exit(0); + break; + } + + getNAcand(posLT.offset(offsetX, offsetY)); + } + } + } + } + else +#endif if (pInfo->numCand < pInfo->maxStorageSize && interPred != nullptr) { const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2; @@ -20137,6 +20439,7 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in const int currRefPOC = cs.slice->getRefPic(eRefPicList, refIdx)->getPOC(); addAMVPHMVPCand(pu, eRefPicList, currRefPOC, *pInfo); } + #if TM_AMVP if (pInfo->numCand > pInfo->maxStorageSize) { @@ -20188,6 +20491,7 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in input.push_back(temp); } stable_sort(input.begin(), input.end(), costIncSort); + for (int candIdx = 1; candIdx < pInfo->numCand; ++candIdx) { if (input.at(candIdx).cost > 5 * input.at(0).cost) @@ -20222,7 +20526,6 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in #if JVET_AA0093_REFINED_MOTION_FOR_ARMC pu.reduceTplSize = false; #endif - pInfo->numCand = 1; #if JVET_AA0093_REFINED_MOTION_FOR_ARMC if (!armcRefinedMotion) @@ -21377,7 +21680,11 @@ bool PU::addSpatialAffineMergeHMVPCand(const PredictionUnit& pu, AffineMergeCtx& bool PU::addSpatialAffineAMVPHMVPCand(PredictionUnit & pu, const RefPicList & eRefPicList, const int& refIdx, AffineAMVPInfo & affiAMVPInfo, static_vector<AffineMotionInfo, MAX_NUM_AFF_HMVP_CANDS>* lutAff, int iHMVPlistIdx, int neiIdx[], int iNeiNum, int aiNeibeInherited[], bool bFoundOne) { +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (affiAMVPInfo.numCand >= affiAMVPInfo.maxStorageSize) +#else if (affiAMVPInfo.numCand >= AMVP_MAX_NUM_CANDS) +#endif { return false; } @@ -21468,7 +21775,11 @@ bool PU::addSpatialAffineAMVPHMVPCand(PredictionUnit & pu, const RefPicList & eR affiAMVPInfo.numCand++; +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (affiAMVPInfo.numCand == affiAMVPInfo.maxStorageSize) +#else if (affiAMVPInfo.numCand == AMVP_MAX_NUM_CANDS) +#endif { return true; } @@ -21518,9 +21829,18 @@ bool PU::checkLastAffineAMVPCandRedundancy(const PredictionUnit& pu, AffineAMVPI return true; } #endif -void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo) +void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , InterPrediction* interPred +#endif +) { affiAMVPInfo.numCand = 0; +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + int extAffineAmvpCond = PU::checkExtAffineAmvpCondition(pu); + int extAffineAmvpVal = extAffineAmvpCond >> 8 & 0x0f; + affiAMVPInfo.maxStorageSize = (extAffineAmvpVal == 0) ? AMVP_MAX_NUM_CANDS : ((extAffineAmvpVal == 2) ? 4 : ((extAffineAmvpVal == 3) ? 5 : AFFINE_AMVP_MAX_CAND)); +#endif if (refIdx < 0) { @@ -21531,6 +21851,15 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co bool isClean = pu.cs->isClean(pu.cu->Y().bottomRight(), CHANNEL_TYPE_LUMA); #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (interPred != nullptr) + { + if(interPred->readAffineAmvpBuffer(affiAMVPInfo, *pu.cu, eRefPicList, refIdx)) + { + return; + } + } +#endif // insert inherited affine candidates Mv outputAffineMv[3]; Position posLT = pu.Y().topLeft(); @@ -21632,7 +21961,11 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co for (int affHMVPIdx = 0; affHMVPIdx < 1; affHMVPIdx++) { +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize && leftAffNeiNum > 0) +#else if (affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS && leftAffNeiNum > 0) +#endif { #if JVET_Z0118_GDR addSpatialAffineAMVPHMVPCand(pu, eRefPicList, refIdx, affiAMVPInfo, (isClean) ? pu.cs->motionLut.lutAff1 : pu.cs->motionLut.lutAff0, 0, leftNeiIdx, leftAffNeiNum, aiNeibeInherited, true); @@ -21640,7 +21973,11 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co addSpatialAffineAMVPHMVPCand(pu, eRefPicList, refIdx, affiAMVPInfo, pu.cs->motionLut.lutAff, 0, leftNeiIdx, leftAffNeiNum, aiNeibeInherited, true); #endif } +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize && aboveAffNeiNum > 0) +#else if (affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS && aboveAffNeiNum > 0) +#endif { #if JVET_Z0118_GDR addSpatialAffineAMVPHMVPCand(pu, eRefPicList, refIdx, affiAMVPInfo, (isClean) ? pu.cs->motionLut.lutAff1 : pu.cs->motionLut.lutAff0, 0, aboveNeiIdx, aboveAffNeiNum, aiNeibeInherited, true); @@ -21666,7 +22003,11 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co } #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if ( affiAMVPInfo.numCand >= affiAMVPInfo.maxStorageSize ) +#else if ( affiAMVPInfo.numCand >= AMVP_MAX_NUM_CANDS ) +#endif { for (int i = 0; i < affiAMVPInfo.numCand; i++) { @@ -21674,6 +22015,22 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co affiAMVPInfo.mvCandRT[i].roundAffinePrecInternal2Amvr(pu.cu->imv); affiAMVPInfo.mvCandLB[i].roundAffinePrecInternal2Amvr(pu.cu->imv); } +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (interPred != nullptr) + { + if ((extAffineAmvpCond >> 4 & 0x0f) == 1) + { + interPred->tmRefineAffineAMVPCandidates(pu, eRefPicList, refIdx, affiAMVPInfo, extAffineAmvpCond); + interPred->adjustAffineAMVPCandidates(pu, eRefPicList, refIdx, affiAMVPInfo, extAffineAmvpCond); + } + else + { + interPred->adjustAffineAMVPCandidates(pu, eRefPicList, refIdx, affiAMVPInfo, extAffineAmvpCond); + interPred->tmRefineAffineAMVPCandidates(pu, eRefPicList, refIdx, affiAMVPInfo, extAffineAmvpCond); + } + interPred->writeAffineAmvpBuffer(affiAMVPInfo, *pu.cu, eRefPicList, refIdx); + } +#endif return; } @@ -21743,7 +22100,11 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co #if JVET_Z0139_HIST_AFF for (int affHMVPIdx = 1; affHMVPIdx < MAX_NUM_AFF_HMVP_CANDS; affHMVPIdx++) { +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize && leftAffNeiNum > 0) +#else if (affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS && leftAffNeiNum > 0) +#endif { #if JVET_Z0118_GDR addSpatialAffineAMVPHMVPCand(pu, eRefPicList, refIdx, affiAMVPInfo, (isClean) ? pu.cs->motionLut.lutAff1 : pu.cs->motionLut.lutAff0, 0, leftNeiIdx, leftAffNeiNum, aiNeibeInherited, true); @@ -21751,7 +22112,11 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co addSpatialAffineAMVPHMVPCand(pu, eRefPicList, refIdx, affiAMVPInfo, pu.cs->motionLut.lutAff, 0, leftNeiIdx, leftAffNeiNum, aiNeibeInherited, true); #endif } +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize && aboveAffNeiNum > 0) +#else if (affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS && aboveAffNeiNum > 0) +#endif { #if JVET_Z0118_GDR addSpatialAffineAMVPHMVPCand(pu, eRefPicList, refIdx, affiAMVPInfo, (isClean) ? pu.cs->motionLut.lutAff1 : pu.cs->motionLut.lutAff0, 0, aboveNeiIdx, aboveAffNeiNum, aiNeibeInherited, true); @@ -21762,10 +22127,17 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co } #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if ( affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize ) + { + // check corner MVs + for ( int i = 2; i >= 0 && affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize; i-- ) +#else if ( affiAMVPInfo.numCand < 2 ) { // check corner MVs for ( int i = 2; i >= 0 && affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS; i-- ) +#endif { if ( cornerMVPattern & (1 << i) ) // MV i exist { @@ -21780,7 +22152,11 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co } // Get Temporal Motion Predictor +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if ( affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize && pu.cs->picHeader->getEnableTMVPFlag() ) +#else if ( affiAMVPInfo.numCand < 2 && pu.cs->picHeader->getEnableTMVPFlag() ) +#endif { const int refIdxCol = refIdx; @@ -21824,14 +22200,22 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co } #if JVET_Z0139_NA_AFF +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize) +#else if (affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS) +#endif { addNonAdjCstAffineMVPCandUnscaled(pu, eRefPicList, refIdx, affiAMVPInfo); } #endif #if JVET_Z0139_HIST_AFF +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize) +#else if (affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS) +#endif { for (int affHMVPIdx = 0; affHMVPIdx < MAX_NUM_AFF_HMVP_CANDS; affHMVPIdx++) { @@ -21843,6 +22227,158 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co } } #endif + +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + // Get Temporal Motion Predictor + if (((extAffineAmvpCond & 0x00f) == 1) && (affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize) + && pu.cs->picHeader->getEnableTMVPFlag()) + { + // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to + // const PreCalcValues &pcv = *cs.pcv; + bool isC0Avail; + bool isC1Avail; + bool boundaryCond; + const SubPic &curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos()); + Position posRB = pu.Y().bottomRight().offset(-3, -3); + const PreCalcValues &pcv = *pu.cs->pcv; + Position posCenter = pu.Y().center(); + Position posC0; + Position posC1; + + int iRefIdx = refIdx; + + bool bExistMV0; + Mv cColMv0[3]; + + int offsetX0 = 0, offsetX1 = 0, offsetX2 = 0, offsetX3 = pu.Y().width >> 1; + int offsetY0 = 0, offsetY1 = 0, offsetY2 = 0, offsetY3 = pu.Y().height >> 1; + + const int numNACandidate[5] = { 2, 2, 2, 2, 2 }; + const int idxMap[5][2] = { { 0, 1 }, { 0, 2 }, { 0, 2 }, { 0, 2 }, { 0, 2 } }; + + for (int iDistanceIndex = 0; + iDistanceIndex < TMVP_DISTANCE_LEVEL && affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize; iDistanceIndex++) + { + const int iNADistanceHor = pu.Y().width * iDistanceIndex; + const int iNADistanceVer = pu.Y().height * iDistanceIndex; + + for (int iNASPIdx = 0; + iNASPIdx < numNACandidate[iDistanceIndex] && affiAMVPInfo.numCand < affiAMVPInfo.maxStorageSize; + iNASPIdx++) + { + switch (idxMap[iDistanceIndex][iNASPIdx]) + { + case 0: + offsetX0 = offsetX2 = 4 + iNADistanceHor; + offsetY0 = offsetY2 = 4 + iNADistanceVer; + offsetX1 = iNADistanceHor; + offsetY1 = iNADistanceVer; + break; + case 1: + offsetX0 = 4; + offsetY0 = 0; + offsetX1 = 0; + offsetY1 = 4; + break; + case 2: + offsetX0 = offsetX2; + offsetY0 = 4 - offsetY3; + offsetX1 = 4 - offsetX3; + offsetY1 = offsetY2; + break; + default: + printf("error!"); + exit(0); + break; + } + isC0Avail = false; + if (curSubPic.getTreatedAsPicFlag()) + { + boundaryCond = ((posRB.x + offsetX0) <= curSubPic.getSubPicRight() + && (posRB.y + offsetY0) <= curSubPic.getSubPicBottom()); + } + else + { + boundaryCond = ((posRB.x + offsetX0) < pcv.lumaWidth) && ((posRB.y + offsetY0) < pcv.lumaHeight); + } + if (boundaryCond) + { + posC0 = posRB.offset(offsetX0, offsetY0); + isC0Avail = true; + } + + if (idxMap[iDistanceIndex][iNASPIdx] == 0) + { + isC1Avail = false; + if (curSubPic.getTreatedAsPicFlag()) + { + boundaryCond = ((posCenter.x + offsetX1) <= curSubPic.getSubPicRight() + && (posCenter.y + offsetY1) <= curSubPic.getSubPicBottom()); + } + else + { + boundaryCond = ((posCenter.x + offsetX1) < pcv.lumaWidth) && ((posCenter.y + offsetY1) < pcv.lumaHeight); + } + if (boundaryCond) + { + posC1 = posCenter.offset(offsetX1, offsetY1); + isC1Avail = true; + } + } + else + { + isC1Avail = false; + if (curSubPic.getTreatedAsPicFlag()) + { + boundaryCond = ((posRB.x + offsetX1) <= curSubPic.getSubPicRight() + && (posRB.y + offsetY1) <= curSubPic.getSubPicBottom()); + } + else + { + boundaryCond = ((posRB.x + offsetX1) < pcv.lumaWidth) && ((posRB.y + offsetY1) < pcv.lumaHeight); + } + if (boundaryCond) + { + posC1 = posRB.offset(offsetX1, offsetY1); + isC1Avail = true; + } + } + bExistMV0 = false; + + EAffineModel affineType = (EAffineModel) (pu.cu->affineType); + bExistMV0 = (isC0Avail + && getColocatedAffineCMVP(pu, eRefPicList, posC0, cColMv0, iRefIdx, false, +#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION + pu.cu->slice->isInterB(), +#endif + NULL, &affineType)) + || (isC1Avail + && getColocatedAffineCMVP(pu, eRefPicList, posC1, cColMv0, iRefIdx, false, +#if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION + pu.cu->slice->isInterB(), +#endif + NULL, &affineType)); + + if (bExistMV0) + { + cColMv0[0].roundAffinePrecInternal2Amvr(pu.cu->imv); + affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = cColMv0[0]; + cColMv0[1].roundAffinePrecInternal2Amvr(pu.cu->imv); + affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = cColMv0[1]; + cColMv0[2].roundAffinePrecInternal2Amvr(pu.cu->imv); + affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = cColMv0[2]; +#if JVET_Z0139_HIST_AFF + if (checkLastAffineAMVPCandRedundancy(pu, affiAMVPInfo)) +#endif + { + affiAMVPInfo.numCand++; + } + } + } + } + } +#endif + #if JVET_Z0139_HIST_AFF if (affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS) #else @@ -21866,8 +22402,23 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co affiAMVPInfo.mvCandRT[i].roundAffinePrecInternal2Amvr(pu.cu->imv); affiAMVPInfo.mvCandLB[i].roundAffinePrecInternal2Amvr(pu.cu->imv); } +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (interPred != nullptr) + { + if ((extAffineAmvpCond >> 4 & 0x0f) == 1) + { + interPred->tmRefineAffineAMVPCandidates(pu, eRefPicList, refIdx, affiAMVPInfo, extAffineAmvpCond); + interPred->adjustAffineAMVPCandidates(pu, eRefPicList, refIdx, affiAMVPInfo, extAffineAmvpCond); + } + else + { + interPred->adjustAffineAMVPCandidates(pu, eRefPicList, refIdx, affiAMVPInfo, extAffineAmvpCond); + interPred->tmRefineAffineAMVPCandidates(pu, eRefPicList, refIdx, affiAMVPInfo, extAffineAmvpCond); + } + interPred->writeAffineAmvpBuffer(affiAMVPInfo, *pu.cu, eRefPicList, refIdx); + } +#endif } - bool PU::addMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &info ) { CodingStructure &cs = *pu.cs; @@ -22511,7 +23062,11 @@ bool PU::addNonAdjCstAffineMVPCandUnscaled(const PredictionUnit &pu, const RefPi if (addNonAdjCstAffineMVPConstructedCPMV(pu, miNew, isAvailableNew, posNew, refPicList, refIdx, affiAmvpInfo)) { +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (affiAmvpInfo.numCand >= affiAmvpInfo.maxStorageSize) +#else if (affiAmvpInfo.numCand >= AMVP_MAX_NUM_CANDS) +#endif { return true; } @@ -22673,7 +23228,11 @@ bool PU::addNonAdjCstAffineMVPConstructedCPMV( const PredictionUnit &pu, MotionI } affiAmvpInfo.numCand++; isConverted = true; +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (affiAmvpInfo.numCand >= affiAmvpInfo.maxStorageSize) +#else if (affiAmvpInfo.numCand >= AMVP_MAX_NUM_CANDS) +#endif { return true; } @@ -31213,8 +31772,16 @@ AMVPInfo PU::getMultiHypMVPCandsAMVP(PredictionUnit &pu, const RefPicList eRefPi { AffineAMVPInfo affineAMVPInfo; PU::fillAffineMvpCand(pu, RefPicList(refListForAMVP), refIdxForAMVP, affineAMVPInfo); +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + amvpInfo.numCand = (affineAMVPInfo.numCand <= AMVP_MAX_NUM_CANDS) ? affineAMVPInfo.numCand : AMVP_MAX_NUM_CANDS; + for (int i = 0; i < amvpInfo.numCand; i++) + { + amvpInfo.mvCand[i] = affineAMVPInfo.mvCandLT[i]; + } +#else amvpInfo.numCand = affineAMVPInfo.numCand; memcpy(amvpInfo.mvCand, affineAMVPInfo.mvCandLT, sizeof(amvpInfo.mvCand)); +#endif } else { @@ -31232,7 +31799,6 @@ AMVPInfo PU::getMultiHypMVPCands(PredictionUnit &pu, const MultiHypPredictionDat CHECK(MHRefPics.empty(), "Multi Hyp: MHRefPics.empty()"); const auto eRefPicList = RefPicList(MHRefPics[mhRefIdxForAMVPList].refList); const int iRefIdx = MHRefPics[mhRefIdxForAMVPList].refIdx; - return (pu.mergeFlag ? PU::getMultiHypMVPCandsMerge : PU::getMultiHypMVPCandsAMVP)(pu, eRefPicList, iRefIdx); } diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index cee2761cc416394ccd0ec33fb7f2cfe96fc753f0..981d4e0e615f1ab634f1b94ee6a80afe1549cea6 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -493,7 +493,11 @@ namespace PU #else void fillIBCMvpCand (PredictionUnit &pu, AMVPInfo &amvpInfo); #endif - void fillAffineMvpCand ( PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo); + void fillAffineMvpCand ( PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , InterPrediction* interPred = nullptr +#endif + ); bool addMVPCandUnscaled (const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &amvpInfo); void xInheritedAffineMv ( const PredictionUnit &pu, const PredictionUnit* puNeighbour, RefPicList eRefPicList, Mv rcMv[3] ); #if JVET_AA0107_RMVF_AFFINE_MERGE_DERIVATION @@ -929,6 +933,26 @@ namespace PU #if JVET_AF0163_TM_SUBBLOCK_REFINEMENT bool checkAffineTMCondition(const PredictionUnit& pu); #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + enum ExtAffineAmvpType + { + EXT_AFFINE_AMVP_TYPE_NONE = 0, + EXT_AFFINE_AMVP_TYPE_NA_TEMP = 1, + EXT_AFFINE_AMVP_TYPE_LISTS10 = (1 << 8) + (1 << 4) + 1, + EXT_AFFINE_AMVP_TYPE_LISTS4 = (2 << 8) + (1 << 4) + 1, + EXT_AFFINE_AMVP_TYPE_LISTS5 = (3 << 8) + (1 << 4) + 1, + EXT_AFFINE_AMVP_TYPE_LISTS4_REORDER_FIRST = (2 << 8) + (2 << 4) + 1 + }; + enum ExtRegularAmvpType + { + EXT_REGULAR_AMVP_TYPE_NONE = 0, + EXT_REGULAR_AMVP_TYPE_NA_SPATIAL = (1 << 4), + EXT_REGULAR_AMVP_TYPE_LISTS10 = (1 << 4) + 1 + }; + int checkExtAffineAmvpCondition(const PredictionUnit& pu); + int checkExtRegularAmvpCondition(const PredictionUnit& pu); +#endif + #if INTER_LIC void spanLicFlags(PredictionUnit &pu, const bool LICFlag); #endif diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 920b902b64ad4ef254b8913d4ab439144bc97ebd..2481c9f29523ee404850ab9d3ec24d235fe6ea08 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -2184,7 +2184,6 @@ void CABACReader::cu_pred_data( CodingUnit &cu ) return; } MergeCtx mrgCtx; - for( auto &pu : CU::traversePUs( cu ) ) { #if JVET_AD0140_MVD_PREDICTION diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index b6d14b321e96f237a5feec76e86a2e88f3bd8d24..27abad62dd791be910b9fea1cad801e59f1707bb 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -5247,6 +5247,9 @@ void DecCu::xDeriveCUMV(CodingUnit &cu) #endif #if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION m_pcInterPred->clearAmvpTmvpBuffer(); +#endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + m_pcInterPred->clearAffineAmvpBuffer(); #endif if (pu.cu->affine) { @@ -5374,7 +5377,6 @@ void DecCu::xDeriveCUMV(CodingUnit &cu) pu.refIdx[refListAmvp] = orgRefIdxAMVP; } #endif - if( pu.cu->affine ) { for ( uint32_t uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ ) @@ -5383,8 +5385,11 @@ void DecCu::xDeriveCUMV(CodingUnit &cu) if ( pu.cs->slice->getNumRefIdx( eRefList ) > 0 && ( pu.interDir & ( 1 << uiRefListIdx ) ) ) { AffineAMVPInfo affineAMVPInfo; - PU::fillAffineMvpCand( pu, eRefList, pu.refIdx[eRefList], affineAMVPInfo ); - + PU::fillAffineMvpCand( pu, eRefList, pu.refIdx[eRefList], affineAMVPInfo +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , m_pcInterPred +#endif + ); const unsigned mvpIdx = pu.mvpIdx[eRefList]; pu.mvpNum[eRefList] = affineAMVPInfo.numCand; diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp index e7808d117be586970ebb895481261e369cb1c4c9..69db99fb37d50587ae613116b1f5a0790fcb9684 100644 --- a/source/Lib/DecoderLib/DecSlice.cpp +++ b/source/Lib/DecoderLib/DecSlice.cpp @@ -520,6 +520,14 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb #endif #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (!slice->isIntra()) + { + int picH = slice->getPic()->getPicHeightInLumaSamples(); + slice->setExtAmvpLevel(picH >= 2160 ? 3 : (picH >= 1080 ? 2 : (picH >= 720 ? 1 : 0))); + } +#endif + // for every CTU in the slice segment... #if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index f974db44538cd4898d9ee7e5f2a9a49e3424a7e4..99ce96ca89cb0b9b8998a778595a0ebba4b4deff 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -2625,7 +2625,9 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE READ_FLAG( uiCode, "sps_alt_cost_enabled_flag"); pcSPS->setUseAltCost(uiCode != 0); #endif - +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + READ_FLAG( uiCode, "sps_ext_amvp_enabled_flag"); pcSPS->setUseExtAmvp(uiCode != 0); +#endif READ_FLAG( uiCode, "sps_bcw_enabled_flag" ); pcSPS->setUseBcw( uiCode != 0 ); READ_FLAG( uiCode, "sps_ciip_enabled_flag" ); pcSPS->setUseCiip ( uiCode != 0 ); #if JVET_X0141_CIIP_TIMD_TM && TM_MRG @@ -5432,7 +5434,6 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par pcSlice->setCabacInitFlag( uiCode ? true : false ); pcSlice->setEncCABACTableIdx( pcSlice->getSliceType() == B_SLICE ? ( uiCode ? P_SLICE : B_SLICE ) : ( uiCode ? B_SLICE : P_SLICE ) ); } - if ( picHeader->getEnableTMVPFlag() ) { if( pcSlice->getSliceType() == P_SLICE ) diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 616369020a22ab7bf9eddaa436d81378558df2ae..8658c980a5ab96a85e1220b1cf7fc5ef4a95a3a1 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -430,6 +430,9 @@ protected: #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE bool m_useAltCost; #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + bool m_useExtAmvp; +#endif #if JVET_AF0163_TM_SUBBLOCK_REFINEMENT bool m_useAffineTM; #if JVET_AG0276_NLIC @@ -1618,6 +1621,10 @@ public: void setUseAltCost(bool b) { m_useAltCost = b; } bool getUseAltCost() const { return m_useAltCost; } #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + void setUseExtAmvp(bool b) { m_useExtAmvp = b; } + bool getUseExtAmvp() const { return m_useExtAmvp; } +#endif #if JVET_AF0163_TM_SUBBLOCK_REFINEMENT void setUseAffineTM( bool b ) { m_useAffineTM = b; } bool getUseAffineTM() const { return m_useAffineTM; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 4b27948fbd737786ae9a2356c6f0043142b9d13e..a9a7b41a57eba12102bad3053724958e8e519dd7 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1348,6 +1348,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par m_pcInterSearch->resetSavedAffineMotion(); +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + m_pcInterSearch->clearAffineAmvpBuffer(); +#endif #if TM_AMVP if (!slice.isIntra()) { @@ -1492,7 +1495,6 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par } #endif #endif - if( ( currTestMode.opts & ETO_IMV ) != 0 ) { const bool skipAltHpelIF = ( int( ( currTestMode.opts & ETO_IMV ) >> ETO_IMV_SHIFT ) == 4 ) && ( bestIntPelCost > 1.25 * bestCS->cost ); @@ -22753,10 +22755,10 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC #endif tempCS->initStructData( encTestMode.qp ); m_pcInterSearch->setAffineModeSelected(false); + #if JVET_AD0213_LIC_IMP m_pcInterSearch->setDoAffineLic(true); #endif - m_pcInterSearch->resetBufferedUniMotions(); int bcwLoopNum = (tempCS->slice->isInterB() ? BCW_NUM : 1); bcwLoopNum = (tempCS->sps->getUseBcw() ? bcwLoopNum : 1); @@ -22925,6 +22927,7 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC #else m_pcInterSearch->predInterSearch( cu, partitioner ); #endif + #if INTER_LIC if (cu.slice->getUseLIC() && lic) { m_pcInterSearch->swapUniMvBuffer(); } #endif @@ -23433,10 +23436,10 @@ bool EncCu::xCheckRDCostInterIMV(CodingStructure *&tempCS, CodingStructure *&bes #else m_pcInterSearch->predInterSearch( cu, partitioner ); #endif + #if INTER_LIC if (cu.slice->getUseLIC() && lic) { m_pcInterSearch->swapUniMvBuffer(); } #endif - if ( cu.firstPU->interDir <= 3 ) { bcwIdx = CU::getValidBcwIdx(cu); diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index d3209d48c5d0393c47f9c28c089ee38f79578fb2..7d7f97fab6e56e20674996fdba490e9c399739cb 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -1904,6 +1904,9 @@ void EncLib::xInitSPS( SPS& sps ) } } #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + sps.setUseExtAmvp ( m_useExtAmvp ); +#endif #if JVET_AF0163_TM_SUBBLOCK_REFINEMENT sps.setUseAffineTM ( m_useAffineTM ); #if JVET_AG0276_NLIC diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index b61088704df6c3edfa2c90cd38390d6d0b9791fc..ff5ae80e52c6129405eaca997552d08bcac115de 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -1719,6 +1719,13 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c pcSlice->setAmvpSbTmvpEnabledFlag(false); } #endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + if (!pcSlice->isIntra()) + { + int picH = pcSlice->getPic()->getPicHeightInLumaSamples(); + pcSlice->setExtAmvpLevel(picH >= 2160 ? 3 : (picH >= 1080 ? 2 : (picH >= 720 ? 1 : 0))); + } +#endif if ( bWp_explicit ) { diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 05a4785072ddc40780d1d0bf356826b210d270f1..e05a6c3e57db0b65980a0b6deb3ec90fae020cc0 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -6042,7 +6042,6 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) #if JVET_AD0213_LIC_IMP && TM_AMVP resetLicEncCtrlPara(); #endif - #if MULTI_HYP_PRED const bool saveMeResultsForMHP = cs.sps->getUseInterMultiHyp() && bcwIdx != BCW_DEFAULT @@ -6333,7 +6332,6 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) uiMotBits[1] = uiBits[1] - uiMbBits[1]; uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1]; } - if( doBiPred ) { // 4-times iteration (default) @@ -6344,6 +6342,8 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) { iNumIter = 1; } + + #if JVET_X0083_BM_AMVP_MERGE_MODE if (amvpMergeModeFlag) { @@ -6404,7 +6404,6 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } bool bChanged = false; - iRefStart = 0; iRefEnd = cs.slice->getNumRefIdx(eRefPicList)-1; for (int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++) @@ -6429,6 +6428,7 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) xCopyAMVPInfo( &amvp[refListAmvp], &aacAMVPInfo[refListAmvp][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE ) numberBestMvpIdxLoop = amvp[eRefPicList].numCand; } + for (int bestMvpIdxLoop = 0; bestMvpIdxLoop < numberBestMvpIdxLoop; bestMvpIdxLoop++) { if (amvpMergeModeFlag) @@ -6680,7 +6680,6 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } cu.refIdxBi[0] = iRefIdxBi[0]; cu.refIdxBi[1] = iRefIdxBi[1]; - if ( cs.slice->getBiDirPred() && trySmvd ) { Distortion symCost; @@ -6889,7 +6888,6 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } } } // if (B_SLICE) - #if JVET_AG0098_AMVP_WITH_SBTMVP bool useAmvpSbTmvpBuf = false; int amvpSbTmvpMvdIdx = -1; @@ -7419,6 +7417,7 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } #endif #if INTER_LIC + #if JVET_X0083_BM_AMVP_MERGE_MODE && JVET_AD0213_LIC_IMP #if JVET_AG0098_AMVP_WITH_SBTMVP if (cu.licFlag && !amvpMergeModeFlag && !pu.amvpSbTmvpFlag) @@ -7696,7 +7695,12 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) && (pu.interDir & (1 << uiRefListIdx)) && (absMvd[0] != Mv(0, 0) || absMvd[1] != Mv(0, 0) || absMvd[2] != Mv(0, 0)) && pu.isMvdPredApplicable()) { AffineAMVPInfo affineAMVPInfo; - PU::fillAffineMvpCand(pu, eRefPicList, pu.refIdx[uiRefListIdx], affineAMVPInfo); + PU::fillAffineMvpCand(pu, eRefPicList, pu.refIdx[uiRefListIdx], affineAMVPInfo +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , this +#endif + ); + const unsigned mvpIdx = pu.mvpIdx[eRefPicList]; #if JVET_AD0140_MVD_PREDICTION @@ -7760,7 +7764,6 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } } #endif - for (uint32_t uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++) { RefPicList eRefPicList = RefPicList(uiRefListIdx); @@ -7778,6 +7781,7 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) { PU::fillMvpCand(pu, RefPicList(uiRefListIdx), iRefIdx, *amvpCand, this); } + Mv cMvPred2 = amvpCand->mvCand[pu.mvpIdx[uiRefListIdx]]; #else auto aMvPred = bi ? cMvPredBi : cMvPred; @@ -10446,6 +10450,7 @@ void InterSearch::xPatternSearchIntRefine(PredictionUnit& pu, IntTZSearchStruct& cBaseMvd[0] = (rcMv - amvpInfo.mvCand[0]); cBaseMvd[1] = (rcMv - amvpInfo.mvCand[1]); + CHECK( (cBaseMvd[0].getHor() & 0x03) != 0 || (cBaseMvd[0].getVer() & 0x03) != 0 , "xPatternSearchIntRefine(): AMVP cand 0 Mvd issue."); CHECK( (cBaseMvd[1].getHor() & 0x03) != 0 || (cBaseMvd[1].getVer() & 0x03) != 0 , "xPatternSearchIntRefine(): AMVP cand 1 Mvd issue."); @@ -11259,6 +11264,7 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, { // 4-times iteration (default) int iNumIter = 4; + // fast encoder setting or GPB: only one iteration if ( m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE2 || slice.getPicHeader()->getMvdL1ZeroFlag() ) { @@ -11724,9 +11730,7 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin { return; } - int mvNum = pu.cu->affineType ? 3 : 2; - m_pcRdCost->selectMotionLambda( ); m_pcRdCost->setCostScale ( 0 ); @@ -12293,7 +12297,12 @@ void InterSearch::xEstimateAffineAMVP( PredictionUnit& pu, Distortion uiBestCost = std::numeric_limits<Distortion>::max(); // Fill the MV Candidates - PU::fillAffineMvpCand( pu, eRefPicList, iRefIdx, affineAMVPInfo ); + PU::fillAffineMvpCand( pu, eRefPicList, iRefIdx, affineAMVPInfo +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + , this +#endif + ); + CHECK( affineAMVPInfo.numCand == 0, "Assertion failed." ); PelUnitBuf predBuf = m_tmpStorageLCU.getBuf( UnitAreaRelative(*pu.cu, pu) ); @@ -12324,6 +12333,7 @@ void InterSearch::xEstimateAffineAMVP( PredictionUnit& pu, pu.mvpIdx[eRefPicList] = iBestIdx; pu.mvpNum[eRefPicList] = affineAMVPInfo.numCand; + DTRACE( g_trace_ctx, D_COMMON, "#estAffi=%d \n", affineAMVPInfo.numCand ); } @@ -16367,7 +16377,6 @@ void InterSearch::setEncCtrlParaLicOff(CodingUnit& cu) { CodingStructure& cs = *cu.cs; PredictionUnit& pu = *cu.firstPU; - isBDOFNotNeeded = (pu.interDir == 1 || pu.interDir == 2 || pu.cu->bcwIdx != BCW_DEFAULT || pu.cu->affine || pu.cu->smvdMode); amvpCand0 = &(m_tplAmvpInfo[cu.imv][REF_PIC_LIST_0][pu.refIdx[REF_PIC_LIST_0]]); amvpCand1 = &(m_tplAmvpInfo[cu.imv][REF_PIC_LIST_1][pu.refIdx[REF_PIC_LIST_1]]); @@ -16375,6 +16384,7 @@ void InterSearch::setEncCtrlParaLicOff(CodingUnit& cu) amvpCand1Lic = &(m_tplAmvpInfoLIC[cu.imv][REF_PIC_LIST_1][pu.refIdx[REF_PIC_LIST_1]]); mvpIdx0 = pu.mvpIdx[REF_PIC_LIST_0]; mvpIdx1 = pu.mvpIdx[REF_PIC_LIST_1]; + if (!cu.affine) { for (int refList = 0; refList < NUM_REF_PIC_LIST_01; refList++) @@ -16399,7 +16409,6 @@ void InterSearch::setEncCtrlParaLicOff(CodingUnit& cu) pu.cu->licFlag = true; } } - if (cs.picHeader->getMvdL1ZeroFlag() && pu.interDir == 3) { if (amvpCand1Lic->mvCand[mvpIdx1] != amvpCand1->mvCand[mvpIdx1]) diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index bdb2d71d23654628a9d1001ee3451c316293773d..102e0f83a46eee5fac4eebb66634f9b9699ec1d1 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -1666,6 +1666,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) #if JVET_AI0185_ADAPTIVE_COST_IN_MERGE_MODE WRITE_FLAG(pcSPS->getUseAltCost() ? 1 : 0, "sps_alt_cost_enabled_flag"); +#endif +#if JVET_AJ0126_INTER_AMVP_ENHANCEMENT + WRITE_FLAG(pcSPS->getUseExtAmvp() ? 1 : 0, "sps_ext_amvp_enabled_flag"); #endif WRITE_FLAG(pcSPS->getUseBcw() ? 1 : 0, "sps_bcw_enabled_flag");