diff --git a/cfg/encoder_intra_vtm.cfg b/cfg/encoder_intra_vtm.cfg index e3cc0a9ad25e16106211814f797f69a40551b340..041ade27fedf5422edd41dd3a888a607f05f737b 100644 --- a/cfg/encoder_intra_vtm.cfg +++ b/cfg/encoder_intra_vtm.cfg @@ -120,6 +120,9 @@ PBIntraFast : 1 FastMrg : 1 AMaxBT : 1 +# Encoder optimization tools +AffineAmvrEncOpt : 0 + ### DO NOT ADD ANYTHING BELOW THIS LINE ### ### DO NOT DELETE THE EMPTY LINE BELOW ### diff --git a/cfg/encoder_lowdelay_P_vtm.cfg b/cfg/encoder_lowdelay_P_vtm.cfg index 9c2f8ece3e201df90b0200240d366f634222ae48..e9aa837f2171481534ac8592c269c6dc83b6a682 100644 --- a/cfg/encoder_lowdelay_P_vtm.cfg +++ b/cfg/encoder_lowdelay_P_vtm.cfg @@ -137,6 +137,9 @@ PBIntraFast : 1 FastMrg : 1 AMaxBT : 1 +# Encoder optimization tools +AffineAmvrEncOpt : 0 + ### DO NOT ADD ANYTHING BELOW THIS LINE ### ### DO NOT DELETE THE EMPTY LINE BELOW ### diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg index 324320970afffe7c5a042636337590cdb55b0c94..0922ffc13b62dab779cd616704db7945e19d3feb 100644 --- a/cfg/encoder_lowdelay_vtm.cfg +++ b/cfg/encoder_lowdelay_vtm.cfg @@ -140,6 +140,9 @@ PBIntraFast : 1 FastMrg : 1 AMaxBT : 1 +# Encoder optimization tools +AffineAmvrEncOpt : 0 + ### DO NOT ADD ANYTHING BELOW THIS LINE ### ### DO NOT DELETE THE EMPTY LINE BELOW ### diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index ab7c99c0cb22fc888ec9da541acde853d45ecc60..7ca088122f6b1439b67870bb4c2adbcc64c56038 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -155,6 +155,9 @@ PBIntraFast : 1 FastMrg : 1 AMaxBT : 1 +# Encoder optimization tools +AffineAmvrEncOpt : 1 + ### DO NOT ADD ANYTHING BELOW THIS LINE ### ### DO NOT DELETE THE EMPTY LINE BELOW ### diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 611f6f82f6b5ca37a2b62ac3108be0f98d9380bc..54cfe178e2cfab8cf953d86c3f2a5ab06c59bc3b 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -262,6 +262,9 @@ void EncApp::xInitLibCfg() #endif #if JVET_M0246_AFFINE_AMVR m_cEncLib.setUseAffineAmvr ( m_AffineAmvr ); +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + m_cEncLib.setUseAffineAmvrEncOpt ( m_AffineAmvrEncOpt ); #endif m_cEncLib.setIBCMode ( m_IBCMode ); m_cEncLib.setIBCLocalSearchRangeX ( m_IBCLocalSearchRangeX ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index ea91679e6aa8ba27564bce3f45a20baadae298ba..f31fad8636275253c227ef20c31d5251b929fa5e 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -869,6 +869,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #endif #if JVET_M0246_AFFINE_AMVR ("AffineAmvr", m_AffineAmvr, false, "Eanble AMVR for affine inter mode") +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + ("AffineAmvrEncOpt", m_AffineAmvrEncOpt, false, "Enable encoder optimization of affine AMVR") #endif ( "IBC", m_IBCMode, 0u, "IBCMode (0x1:enabled, 0x0:disabled) [default: disabled]") ( "IBCLocalSearchRangeX", m_IBCLocalSearchRangeX, 128u, "Search range of IBC local search in x direction") @@ -3155,6 +3158,10 @@ void EncAppCfg::xPrintParameter() #endif #if JVET_M0246_AFFINE_AMVR msg( VERBOSE, "AffineAmvr:%d ", m_AffineAmvr ); +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + m_AffineAmvrEncOpt = m_AffineAmvr ? m_AffineAmvrEncOpt : false; + msg( VERBOSE, "AffineAmvrEncOpt:%d ", m_AffineAmvrEncOpt ); #endif } msg(VERBOSE, "IBC:%d ", m_IBCMode); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 9d7b9a62ca4abd2a412fdf2c4546995ad7303a04..c91c7ec580402ba1b0a7941bb7222fb0e4404b7f 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -243,6 +243,9 @@ protected: #if JVET_M0246_AFFINE_AMVR bool m_AffineAmvr; #endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + bool m_AffineAmvrEncOpt; +#endif unsigned m_IBCMode; unsigned m_IBCLocalSearchRangeX; diff --git a/source/Lib/CommonLib/MotionInfo.h b/source/Lib/CommonLib/MotionInfo.h index 43acd88f1ca37ff7be0488afd9133ee92bf765fe..c193228a79b0c9523180c969f7199c7e18a2fb8e 100644 --- a/source/Lib/CommonLib/MotionInfo.h +++ b/source/Lib/CommonLib/MotionInfo.h @@ -161,6 +161,9 @@ class GBiMotionParam bool m_readOnlyAffine[2][2][33]; Mv m_mvAffine[2][2][33][3]; Distortion m_distAffine[2][2][33]; +#if JVET_M0247_AFFINE_AMVR_ENCOPT + int m_mvpIdx[2][2][33]; +#endif public: @@ -182,6 +185,9 @@ public: memset(m_dist, -1, 2 * 33 * sizeof(Distortion)); memset(m_readOnlyAffine, false, 2 * 2 * 33 * sizeof(bool)); memset(m_distAffine, -1, 2 * 2 * 33 * sizeof(Distortion)); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + memset( m_mvpIdx, 0, 2 * 2 * 33 * sizeof( int ) ); +#endif } void setReadMode(bool b, uint32_t uiRefList, uint32_t uiRefIdx) { m_readOnly[uiRefList][uiRefIdx] = b; } @@ -206,16 +212,30 @@ public: Mv& getAffineMv(uint32_t uiRefList, uint32_t uiRefIdx, uint32_t uiAffineMvIdx, int bP4) { return m_mvAffine[bP4][uiRefList][uiRefIdx][uiAffineMvIdx]; } - void copyAffineMvFrom(Mv(&racAffineMvs)[3], Distortion uiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4) + void copyAffineMvFrom(Mv(&racAffineMvs)[3], Distortion uiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4 +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , const int mvpIdx +#endif + ) { memcpy(m_mvAffine[bP4][uiRefList][uiRefIdx], racAffineMvs, 3 * sizeof(Mv)); m_distAffine[bP4][uiRefList][uiRefIdx] = uiDist; +#if JVET_M0247_AFFINE_AMVR_ENCOPT + m_mvpIdx[bP4][uiRefList][uiRefIdx] = mvpIdx; +#endif } - void copyAffineMvTo(Mv acAffineMvs[3], Distortion& ruiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4) + void copyAffineMvTo(Mv acAffineMvs[3], Distortion& ruiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4 +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , int& mvpIdx +#endif + ) { memcpy(acAffineMvs, m_mvAffine[bP4][uiRefList][uiRefIdx], 3 * sizeof(Mv)); ruiDist = m_distAffine[bP4][uiRefList][uiRefIdx]; +#if JVET_M0247_AFFINE_AMVR_ENCOPT + mvpIdx = m_mvpIdx[bP4][uiRefList][uiRefIdx]; +#endif } }; struct LutMotionCand diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index e0dfe4779d6d787859714e1b12467df7b4b07818..cb1dc56721259efdd479c56284673317f95b2bfc 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -115,6 +115,9 @@ typedef std::pair<int, int> TrCost; #endif #define JVET_M0246_AFFINE_AMVR 1 +#if JVET_M0246_AFFINE_AMVR +#define JVET_M0247_AFFINE_AMVR_ENCOPT 1 +#endif #define JVET_M0421_SPLIT_SIG 1 #define JVET_M0173_MOVE_GT2_TO_FIRST_PASS 1 // Moving the gtr2 flag to the first coding pass diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index a34fdac1aa7579b157ad0bf5ce8ff5338ff848f0..bbfd74821a63dea93ca14b8dec8a7450abc75930 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -243,6 +243,9 @@ protected: #endif #if JVET_M0246_AFFINE_AMVR bool m_AffineAmvr; +#endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + bool m_AffineAmvrEncOpt; #endif unsigned m_IBCMode; unsigned m_IBCLocalSearchRangeX; @@ -767,6 +770,10 @@ public: void setUseAffineAmvr ( bool b ) { m_AffineAmvr = b; } bool getUseAffineAmvr () const { return m_AffineAmvr; } #endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + void setUseAffineAmvrEncOpt ( bool b ) { m_AffineAmvrEncOpt = b; } + bool getUseAffineAmvrEncOpt () const { return m_AffineAmvrEncOpt; } +#endif void setIBCMode (unsigned n) { m_IBCMode = n; } unsigned getIBCMode () const { return m_IBCMode; } diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 1b5559dff1c59e6f5298d1f710ecffc744f132ad..65d35faf49c6580fbe3c340ae2ce1b958e9ae45e 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -3950,20 +3950,35 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, } else { - xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); + xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , aaiMvpIdx[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList] +#endif + ); } } else { - xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); + xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , aaiMvpIdx[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList] +#endif + ); } if(pu.cu->cs->sps->getSpsNext().getUseGBi() && pu.cu->GBiIdx == GBI_DEFAULT && pu.cu->slice->isInterB()) { m_uniMotions.setReadModeAffine(true, (uint8_t)iRefList, (uint8_t)iRefIdxTemp, pu.cu->affineType); - m_uniMotions.copyAffineMvFrom(cMvTemp[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint8_t)iRefList, (uint8_t)iRefIdxTemp, pu.cu->affineType); + m_uniMotions.copyAffineMvFrom(cMvTemp[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint8_t)iRefList, (uint8_t)iRefIdxTemp, pu.cu->affineType +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , aaiMvpIdx[iRefList][iRefIdxTemp] +#endif + ); } // Set best AMVP Index xCopyAffineAMVPInfo( affiAMVPInfoTemp[eRefPicList], aacAffineAMVPInfo[iRefList][iRefIdxTemp] ); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( pu.cu->imv != 2 || !m_pcEncCfg->getUseAffineAmvrEncOpt() ) +#endif xCheckBestAffineMVP( pu, affiAMVPInfoTemp[eRefPicList], eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); if ( iRefList == 0 ) @@ -4185,8 +4200,15 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdxBi[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS]; // call Affine ME - xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, true ); + xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, +#if JVET_M0247_AFFINE_AMVR_ENCOPT + aaiMvpIdxBi[iRefList][iRefIdxTemp], aacAffineAMVPInfo[iRefList][iRefIdxTemp], +#endif + true ); xCopyAffineAMVPInfo( aacAffineAMVPInfo[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList] ); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( pu.cu->imv != 2 || !m_pcEncCfg->getUseAffineAmvrEncOpt() ) +#endif xCheckBestAffineMVP( pu, affiAMVPInfoTemp[eRefPicList], eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); if ( uiCostTemp < uiCostBi ) @@ -4532,13 +4554,25 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost, +#if JVET_M0247_AFFINE_AMVR_ENCOPT + int& mvpIdx, + const AffineAMVPInfo& aamvpi, +#endif bool bBi) { - if( pu.cu->cs->sps->getSpsNext().getUseGBi() && pu.cu->GBiIdx != GBI_DEFAULT && !bBi && xReadBufferedAffineUniMv(pu, eRefPicList, iRefIdxPred, acMvPred, acMv, ruiBits, ruiCost) ) + if( pu.cu->cs->sps->getSpsNext().getUseGBi() && pu.cu->GBiIdx != GBI_DEFAULT && !bBi && xReadBufferedAffineUniMv(pu, eRefPicList, iRefIdxPred, acMvPred, acMv, ruiBits, ruiCost +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , mvpIdx, aamvpi +#endif + ) ) { return; } +#if JVET_M0247_AFFINE_AMVR_ENCOPT + uint32_t dirBits = ruiBits - m_auiMVPIdxCost[mvpIdx][aamvpi.numCand]; + int bestMvpIdx = mvpIdx; +#endif const int width = pu.Y().width; const int height = pu.Y().height; @@ -4634,10 +4668,24 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, // get cost with mv m_pcRdCost->setCostScale(0); uiBitsBest = ruiBits; - DTRACE( g_trace_ctx, D_COMMON, " (%d) xx uiBitsBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest ); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( pu.cu->imv == 2 && m_pcEncCfg->getUseAffineAmvrEncOpt() ) + { + uiBitsBest = dirBits + xDetermineBestMvp( pu, acMvTemp, mvpIdx, aamvpi ); + acMvPred[0] = aamvpi.mvCandLT[mvpIdx]; + acMvPred[1] = aamvpi.mvCandRT[mvpIdx]; + acMvPred[2] = aamvpi.mvCandLB[mvpIdx]; + } + else + { +#endif + DTRACE( g_trace_ctx, D_COMMON, " (%d) xx uiBitsBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest ); #if JVET_M0246_AFFINE_AMVR - uiBitsBest += xCalcAffineMVBits( pu, acMvTemp, acMvPred, pu.cu->imv != 1 ); - DTRACE( g_trace_ctx, D_COMMON, " (%d) yy uiBitsBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest ); + uiBitsBest += xCalcAffineMVBits( pu, acMvTemp, acMvPred, pu.cu->imv != 1 ); + DTRACE( g_trace_ctx, D_COMMON, " (%d) yy uiBitsBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest ); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + } +#endif #else for ( int i = 0; i < mvNum; i++ ) { @@ -4666,7 +4714,9 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, const int bufStride = pBuf->Y().stride; const int predBufStride = predBuf.Y().stride; - +#if JVET_M0247_AFFINE_AMVR_ENCOPT + Mv prevIterMv[7][3]; +#endif int iIterTime; if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { @@ -4683,6 +4733,9 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, } for ( int iter=0; iter<iIterTime; iter++ ) // iterate loop { +#if JVET_M0247_AFFINE_AMVR_ENCOPT + memcpy( prevIterMv[iter], acMvTemp, sizeof( Mv ) * 3 ); +#endif /********************************************************************************* * use gradient to update mv *********************************************************************************/ @@ -4774,29 +4827,35 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, ); } #endif - bool bAllZero = false; - for ( int i = 0; i < mvNum; i++ ) +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( !m_pcEncCfg->getUseAffineAmvrEncOpt() ) { -#if JVET_M0246_AFFINE_AMVR - Mv deltaMv = acDeltaMv[i]; - if ( pu.cu->imv == 2 ) +#endif + bool bAllZero = false; + for ( int i = 0; i < mvNum; i++ ) { - deltaMv.roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_HALF ); - } - if ( deltaMv.getHor() != 0 || deltaMv.getVer() != 0 ) +#if JVET_M0246_AFFINE_AMVR + Mv deltaMv = acDeltaMv[i]; + if ( pu.cu->imv == 2 ) + { + deltaMv.roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_HALF ); + } + if ( deltaMv.getHor() != 0 || deltaMv.getVer() != 0 ) #else - if ( acDeltaMv[i].getHor() != 0 || acDeltaMv[i].getVer() != 0 ) + if ( acDeltaMv[i].getHor() != 0 || acDeltaMv[i].getVer() != 0 ) #endif - { - bAllZero = false; - break; + { + bAllZero = false; + break; + } + bAllZero = true; } - bAllZero = true; - } - - if ( bAllZero ) - break; + if ( bAllZero ) + break; +#if JVET_M0247_AFFINE_AMVR_ENCOPT + } +#endif // do motion compensation with updated mv for ( int i = 0; i < mvNum; i++ ) { @@ -4824,6 +4883,29 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, pu.cu->lumaSize(), *pu.cs->sps); } + +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( m_pcEncCfg->getUseAffineAmvrEncOpt() ) + { + bool identical = false; + for ( int k = iter; k >= 0; k-- ) + { + if ( acMvTemp[0] == prevIterMv[k][0] && acMvTemp[1] == prevIterMv[k][1] ) + { + identical = pu.cu->affineType ? acMvTemp[2] == prevIterMv[k][2] : true; + if ( identical ) + { + break; + } + } + } + if ( identical ) + { + break; + } + } +#endif + xPredAffineBlk( COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cu->slice->clpRng( COMPONENT_Y ) ); // get error @@ -4834,7 +4916,21 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, m_pcRdCost->setCostScale(0); uint32_t uiBitsTemp = ruiBits; #if JVET_M0246_AFFINE_AMVR +#if JVET_M0247_AFFINE_AMVR_ENCOPT + if ( pu.cu->imv == 2 && m_pcEncCfg->getUseAffineAmvrEncOpt() ) + { + uiBitsTemp = dirBits + xDetermineBestMvp( pu, acMvTemp, bestMvpIdx, aamvpi ); + acMvPred[0] = aamvpi.mvCandLT[bestMvpIdx]; + acMvPred[1] = aamvpi.mvCandRT[bestMvpIdx]; + acMvPred[2] = aamvpi.mvCandLB[bestMvpIdx]; + } + else + { + uiBitsTemp += xCalcAffineMVBits( pu, acMvTemp, acMvPred, pu.cu->imv != 1 ); + } +#else uiBitsTemp += xCalcAffineMVBits( pu, acMvTemp, acMvPred, pu.cu->imv != 1 ); +#endif #else for ( int i = 0; i < mvNum; i++ ) { @@ -4860,6 +4956,9 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, uiCostBest = uiCostTemp; uiBitsBest = uiBitsTemp; memcpy( acMv, acMvTemp, sizeof(Mv) * 3 ); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + mvpIdx = bestMvpIdx; +#endif } } @@ -4902,6 +5001,56 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, if (uiCostBest <= AFFINE_ME_LIST_MVP_TH*m_hevcCost) { +#if JVET_M0247_AFFINE_AMVR_ENCOPT + //search 8 nearest neighbors; integer distance + int testPos[8][2] = { { -1, 0 },{ 0, -1 },{ 0, 1 },{ 1, 0 },{ -1, -1 },{ -1, 1 },{ 1, 1 },{ 1, -1 } }; + const uint32_t mvShift = pu.cu->imv == 1 ? 0 : ( pu.cu->imv == 2 ? ( MV_FRACTIONAL_BITS_DIFF << 1 ) : MV_FRACTIONAL_BITS_DIFF ); + const int maxSearchRound = 3; + + if ( m_pcEncCfg->getUseAffineAmvrEncOpt() && m_pcEncCfg->getIntraPeriod() != ( uint32_t ) -1 && pu.cu->imv ) + { + for ( int rnd = 0; rnd < ( pu.cu->slice->getTLayer() <= 2 ? maxSearchRound : maxSearchRound - 1 ); rnd++ ) + { + bool modelChange = false; + //search the model parameters with finear granularity; + for ( int j = 0; j < mvNum; j++ ) + { + for ( int iter = 0; iter < 2; iter++ ) + { + Mv centerMv[3]; + memcpy( centerMv, acMv, sizeof( Mv ) * 3 ); + memcpy( acMvTemp, acMv, sizeof( Mv ) * 3 ); + for ( int i = ( iter ? 0: 4 ); i < ( iter ? 4 : 8 ); i++ ) + { + acMvTemp[j].set( centerMv[j].getHor() + ( testPos[i][0] << mvShift ), centerMv[j].getVer() + ( testPos[i][1] << mvShift ) ); + + clipMv( acMvTemp[j], pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps ); + xPredAffineBlk( COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cu->slice->clpRng( COMPONENT_Y ) ); + + Distortion costTemp = m_pcRdCost->getDistPart( predBuf.Y(), pBuf->Y(), pu.cs->sps->getBitDepth( CHANNEL_TYPE_LUMA ), COMPONENT_Y, DF_HAD ); + uint32_t bitsTemp = ruiBits; + bitsTemp += xCalcAffineMVBits( pu, acMvTemp, acMvPred, pu.cu->imv != 1 ); + costTemp = ( Distortion ) ( floor( fWeight * ( double ) costTemp ) + ( double ) m_pcRdCost->getCost( bitsTemp ) ); + + if ( costTemp < uiCostBest ) + { + uiCostBest = costTemp; + uiBitsBest = bitsTemp; + ::memcpy( acMv, acMvTemp, sizeof( Mv ) * 3 ); + modelChange = true; + } + } + } + } + + if ( !modelChange ) + { + break; + } + } + } +#endif + Mv mvPredTmp[3] = { acMvPred[0], acMvPred[1], acMvPred[2] }; #if JVET_M0246_AFFINE_AMVR if ( pu.cu->imv != 1 ) @@ -4988,6 +5137,11 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, #if JVET_M0246_AFFINE_AMVR } #endif +#if JVET_M0247_AFFINE_AMVR_ENCOPT + acMvPred[0] = aamvpi.mvCandLT[mvpIdx]; + acMvPred[1] = aamvpi.mvCandRT[mvpIdx]; + acMvPred[2] = aamvpi.mvCandLB[mvpIdx]; +#endif // free buffer for (int i = 0; i<iParaNum; i++) @@ -6207,12 +6361,25 @@ bool InterSearch::xReadBufferedUniMv(PredictionUnit& pu, RefPicList eRefPicList, return false; } -bool InterSearch::xReadBufferedAffineUniMv(PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost) +bool InterSearch::xReadBufferedAffineUniMv(PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , int& mvpIdx, const AffineAMVPInfo& aamvpi +#endif +) { if (m_uniMotions.isReadModeAffine((uint32_t)eRefPicList, (uint32_t)iRefIdx, pu.cu->affineType)) { - m_uniMotions.copyAffineMvTo(acMv, ruiCost, (uint32_t)eRefPicList, (uint32_t)iRefIdx, pu.cu->affineType); + m_uniMotions.copyAffineMvTo(acMv, ruiCost, (uint32_t)eRefPicList, (uint32_t)iRefIdx, pu.cu->affineType +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , mvpIdx +#endif + ); m_pcRdCost->setCostScale(0); +#if JVET_M0247_AFFINE_AMVR_ENCOPT + acMvPred[0] = aamvpi.mvCandLT[mvpIdx]; + acMvPred[1] = aamvpi.mvCandRT[mvpIdx]; + acMvPred[2] = aamvpi.mvCandLB[mvpIdx]; +#endif uint32_t uiMvBits = 0; for (int iVerIdx = 0; iVerIdx<(pu.cu->affineType ? 3 : 2); iVerIdx++) @@ -6264,6 +6431,29 @@ void InterSearch::xClipMv( Mv& rcMv, const Position& pos, const struct Size& siz rcMv.setVer( std::min( verMax, std::max( verMin, rcMv.getVer() ) ) ); } +#if JVET_M0247_AFFINE_AMVR_ENCOPT +uint32_t InterSearch::xDetermineBestMvp( PredictionUnit& pu, Mv acMvTemp[3], int& mvpIdx, const AffineAMVPInfo& aamvpi ) +{ + bool mvpUpdated = false; + uint32_t minBits = std::numeric_limits<uint32_t>::max(); + for ( int i = 0; i < aamvpi.numCand; i++ ) + { + Mv mvPred[3] = { aamvpi.mvCandLT[i], aamvpi.mvCandRT[i], aamvpi.mvCandLB[i] }; + uint32_t candBits = m_auiMVPIdxCost[i][aamvpi.numCand]; + candBits += xCalcAffineMVBits( pu, acMvTemp, mvPred, pu.cu->imv != 1 ); + + if ( candBits < minBits ) + { + minBits = candBits; + mvpIdx = i; + mvpUpdated = true; + } + } + CHECK( !mvpUpdated, "xDetermineBestMvp() error" ); + return minBits; +} +#endif + #if JVET_M0444_SMVD void InterSearch::symmvdCheckBestMvp( PredictionUnit& pu, diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h index 27030ab31ec24eddb4085f35b4a0f7ba54efb931..da9abdf1bea40095271e8b8f1c0eede5da81fddc 100644 --- a/source/Lib/EncoderLib/InterSearch.h +++ b/source/Lib/EncoderLib/InterSearch.h @@ -404,6 +404,10 @@ protected: Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost, +#if JVET_M0247_AFFINE_AMVR_ENCOPT + int& mvpIdx, + const AffineAMVPInfo& aamvpi, +#endif bool bBi = false ); @@ -430,7 +434,11 @@ protected: void xSymmetricMotionEstimation( PredictionUnit& pu, PelUnitBuf& origBuf, Mv& rcMvCurPred, Mv& rcMvTarPred, RefPicList eRefPicList, MvField& rCurMvField, MvField& rTarMvField, Distortion& ruiCost, int gbiIdx ); #endif - bool xReadBufferedAffineUniMv ( PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost); + bool xReadBufferedAffineUniMv ( PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost +#if JVET_M0247_AFFINE_AMVR_ENCOPT + , int& mvpIdx, const AffineAMVPInfo& aamvpi +#endif + ); double xGetMEDistortionWeight ( uint8_t gbiIdx, RefPicList eRefPicList); bool xReadBufferedUniMv ( PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv& pcMvPred, Mv& rcMv, uint32_t& ruiBits, Distortion& ruiCost); @@ -458,7 +466,9 @@ protected: void xExtDIFUpSamplingH ( CPelBuf* pcPattern ); void xExtDIFUpSamplingQ ( CPelBuf* pcPatternKey, Mv halfPelRef ); - +#if JVET_M0247_AFFINE_AMVR_ENCOPT + uint32_t xDetermineBestMvp ( PredictionUnit& pu, Mv acMvTemp[3], int& mvpIdx, const AffineAMVPInfo& aamvpi ); +#endif // ------------------------------------------------------------------------------------------------------------------- // compute symbol bits // -------------------------------------------------------------------------------------------------------------------