diff --git a/cfg/encoder_intra_vtm.cfg b/cfg/encoder_intra_vtm.cfg index 59ccd79d22efd033933d0a3887c8d8aec4fc088f..e3cc0a9ad25e16106211814f797f69a40551b340 100644 --- a/cfg/encoder_intra_vtm.cfg +++ b/cfg/encoder_intra_vtm.cfg @@ -113,6 +113,7 @@ IMV : 2 ALF : 1 IBC : 0 # turned off in CTC AllowDisFracMMVD : 1 +AffineAmvr : 0 # Fast tools PBIntraFast : 1 diff --git a/cfg/encoder_lowdelay_P_vtm.cfg b/cfg/encoder_lowdelay_P_vtm.cfg index 7b36027e2da7f6636732156674d3e943531772a8..9c2f8ece3e201df90b0200240d366f634222ae48 100644 --- a/cfg/encoder_lowdelay_P_vtm.cfg +++ b/cfg/encoder_lowdelay_P_vtm.cfg @@ -130,6 +130,7 @@ ALF : 1 MHIntra : 1 IBC : 0 # turned off in CTC AllowDisFracMMVD : 1 +AffineAmvr : 0 # Fast tools PBIntraFast : 1 diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg index 53ba9df9aa8936b3b66b71ffc92870bc4705938b..324320970afffe7c5a042636337590cdb55b0c94 100644 --- a/cfg/encoder_lowdelay_vtm.cfg +++ b/cfg/encoder_lowdelay_vtm.cfg @@ -133,6 +133,7 @@ MHIntra : 1 Triangle : 1 IBC : 0 # turned off in CTC AllowDisFracMMVD : 1 +AffineAmvr : 0 # Fast tools PBIntraFast : 1 diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index ba6baf1c44fd5ac1d5563d58fa5124960bd51740..ab7c99c0cb22fc888ec9da541acde853d45ecc60 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -148,6 +148,7 @@ MHIntra : 1 Triangle : 1 IBC : 0 # turned off in CTC AllowDisFracMMVD : 1 +AffineAmvr : 1 # Fast tools PBIntraFast : 1 diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index eee3ac2643a8777165bdd46364510553426a9530..611f6f82f6b5ca37a2b62ac3108be0f98d9380bc 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -259,6 +259,9 @@ void EncApp::xInitLibCfg() m_cEncLib.setUseTriangle ( m_Triangle ); #if JVET_M0255_FRACMMVD_SWITCH m_cEncLib.setAllowDisFracMMVD ( m_allowDisFracMMVD ); +#endif +#if JVET_M0246_AFFINE_AMVR + m_cEncLib.setUseAffineAmvr ( m_AffineAmvr ); #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 a1709b0d3f6099610091ce32df39da172126e7a3..ea91679e6aa8ba27564bce3f45a20baadae298ba 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -866,6 +866,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("Triangle", m_Triangle, false, "Enable triangular shape motion vector prediction (0:off, 1:on)") #if JVET_M0255_FRACMMVD_SWITCH ("AllowDisFracMMVD", m_allowDisFracMMVD, false, "Disable fractional MVD in MMVD mode adaptively") +#endif +#if JVET_M0246_AFFINE_AMVR + ("AffineAmvr", m_AffineAmvr, false, "Eanble AMVR for affine inter mode") #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") @@ -3149,6 +3152,9 @@ void EncAppCfg::xPrintParameter() msg( VERBOSE, "Triangle:%d ", m_Triangle ); #if JVET_M0255_FRACMMVD_SWITCH msg( VERBOSE, "AllowDisFracMMVD:%d ", m_allowDisFracMMVD ); +#endif +#if JVET_M0246_AFFINE_AMVR + msg( VERBOSE, "AffineAmvr:%d ", m_AffineAmvr ); #endif } msg(VERBOSE, "IBC:%d ", m_IBCMode); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index b1910b56b7d52708154d3272acf7a6739145fa81..9d7b9a62ca4abd2a412fdf2c4546995ad7303a04 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -240,6 +240,9 @@ protected: #if JVET_M0255_FRACMMVD_SWITCH bool m_allowDisFracMMVD; #endif +#if JVET_M0246_AFFINE_AMVR + bool m_AffineAmvr; +#endif unsigned m_IBCMode; unsigned m_IBCLocalSearchRangeX; @@ -248,7 +251,7 @@ protected: unsigned m_IBCHashSearchMaxCand; unsigned m_IBCHashSearchRange4SmallBlk; unsigned m_IBCFastMethod; - + bool m_wrapAround; unsigned m_wrapAroundOffset; diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index 8d5013fcc154824f7131c04f8dc76f23b3576441..e420621c35aab284ab7afd0f88fd0cd530a1c568 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -62,6 +62,9 @@ CodingStructure::CodingStructure(CUCache& cuCache, PUCache& puCache, TUCache& tu : area () , picture ( nullptr ) , parent ( nullptr ) +#if JVET_M0246_AFFINE_AMVR + , bestCS ( nullptr ) +#endif , m_isTuEnc ( false ) , m_cuCache ( cuCache ) , m_puCache ( puCache ) diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index 3727cc1fd33e8af22c8d7a44362b79ba00a14524..1b57a771f386821023747359a4293cb0ca3f95a1 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -79,7 +79,9 @@ public: Picture *picture; CodingStructure *parent; - +#if JVET_M0246_AFFINE_AMVR + CodingStructure *bestCS; +#endif Slice *slice; UnitScale unitScale[MAX_NUM_COMPONENT]; diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 5dd621fe0adb07058edc9aa00b65d844eb063e52..924ebb8a185020584551c76be9e9b3630d327ad6 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -1241,15 +1241,28 @@ const CtxSet ContextSetCfg::ChromaQpAdjIdc = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::ImvFlag = ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE +#if JVET_M0246_AFFINE_AMVR + { 227, 214, 230, 195, 227, 214, }, + { 213, 229, 230, 166, 213, 229, }, + { CNU, CNU, CNU, CNU, CNU, CNU, }, + { 1, 4, 4, 5, 1, 4, }, +#else { 227, 214, 230, 195,}, { 213, 229, 230, 166,}, { CNU, CNU, CNU, CNU,}, { 1, 4, 4, 5,}, +#endif +#else +#if BD_AFFINE_AMVR + { 212, 214, 230, 182, 212, 214 }, + { 212, 214, 230, 182, 212, 214 }, + { CNU, CNU, CNU, CNU, CNU, CNU }, #else { 212, 214, 230, 182, }, { 212, 214, 230, 182, }, { CNU, CNU, CNU, CNU, }, #endif +#endif }); const CtxSet ContextSetCfg::ctbAlfFlag = diff --git a/source/Lib/CommonLib/Mv.h b/source/Lib/CommonLib/Mv.h index 15326e1fdae504d253546284ceb163fd983f326e..8204a0b92d90c6832ce0917f087f0a7c26fdd583 100644 --- a/source/Lib/CommonLib/Mv.h +++ b/source/Lib/CommonLib/Mv.h @@ -51,6 +51,9 @@ enum MvPrecision { MV_PRECISION_4PEL = 0, // 4-pel MV_PRECISION_INT = 2, // 1-pel, shift 2 bits from 4-pel +#if JVET_M0246_AFFINE_AMVR + MV_PRECISION_HALF = 3, // 1/2-pel +#endif MV_PRECISION_QUARTER = 4, // 1/4-pel (the precision of regular MV difference signaling), shift 4 bits from 4-pel MV_PRECISION_INTERNAL = 6, // 1/16-pel (the precision of internal MV), shift 6 bits from 4-pel }; diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index eafa690993ea9e0f292e2ca43912712e9ad12f3f..fe1541e008a14867e3b0faad4cff4c47f894fd1f 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1840,6 +1840,9 @@ SPS::SPS() , m_bNoLadfConstraintFlag (false) , m_bNoDepQuantConstraintFlag (false) , m_bNoSignDataHidingConstraintFlag(false) +#if JVET_M0246_AFFINE_AMVR +, m_affineAmvrEnabledFlag ( false ) +#endif #if HEVC_VPS , m_VPSId ( 0) #endif diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index d28d9ebfb635362568ecd2ef11e9b3b07a2884f5..a4e2a209321b741c791666ac36898188b21a160b 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -942,6 +942,9 @@ private: bool m_bNoDepQuantConstraintFlag; bool m_bNoSignDataHidingConstraintFlag; +#if JVET_M0246_AFFINE_AMVR + bool m_affineAmvrEnabledFlag; +#endif #if HEVC_VPS int m_VPSId; #endif @@ -1227,6 +1230,10 @@ public: void setUseStrongIntraSmoothing(bool bVal) { m_useStrongIntraSmoothing = bVal; } bool getUseStrongIntraSmoothing() const { return m_useStrongIntraSmoothing; } +#endif +#if JVET_M0246_AFFINE_AMVR + void setAffineAmvrEnabledFlag( bool val ) { m_affineAmvrEnabledFlag = val; } + bool getAffineAmvrEnabledFlag() const { return m_affineAmvrEnabledFlag; } #endif bool getVuiParametersPresentFlag() const { return m_vuiParametersPresentFlag; } void setVuiParametersPresentFlag(bool b) { m_vuiParametersPresentFlag = b; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 7b97b11dc40fb3457264d82a503b98e152f154b3..f88f4350765e4d1fce240eb222552111824a2288 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -107,6 +107,7 @@ typedef std::pair<int, bool> TrMode; typedef std::pair<int, int> TrCost; #endif +#define JVET_M0246_AFFINE_AMVR 1 #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/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index c997743d28bb1a2ecbc822daa5269f517b7de351..68790ed5d474d132fa41923de14f009ebcd27da4 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -2104,14 +2104,36 @@ bool PU::addAffineMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &r } xInheritedAffineMv( pu, neibPU, eRefPicListIndex, outputAffineMv ); - - outputAffineMv[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - outputAffineMv[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { +#endif + outputAffineMv[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + outputAffineMv[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } + else if ( pu.cu->imv == 2 ) + { + outputAffineMv[0].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + outputAffineMv[1].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } +#endif affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0]; affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1]; if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { - outputAffineMv[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { +#endif + outputAffineMv[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } + else if ( pu.cu->imv == 2 ) + { + outputAffineMv[2].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } +#endif affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2]; } affiAMVPInfo.numCand++; @@ -2240,9 +2262,16 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co { for (int i = 0; i < affiAMVPInfo.numCand; i++) { - affiAMVPInfo.mvCandLT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - affiAMVPInfo.mvCandRT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - affiAMVPInfo.mvCandLB[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + affiAMVPInfo.mvCandLT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + affiAMVPInfo.mvCandRT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + affiAMVPInfo.mvCandLB[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } +#endif } return; } @@ -2294,10 +2323,22 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co outputAffineMv[1] = amvpInfo1.mvCand[0]; outputAffineMv[2] = amvpInfo2.mvCand[0]; - - outputAffineMv[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - outputAffineMv[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - outputAffineMv[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { +#endif + outputAffineMv[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + outputAffineMv[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + outputAffineMv[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } + else if ( pu.cu->imv == 2 ) + { + outputAffineMv[0].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + outputAffineMv[1].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + outputAffineMv[2].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } +#endif if ( cornerMVPattern == 7 || (cornerMVPattern == 3 && pu.cu->affineType == AFFINEMODEL_4PARAM) ) { @@ -2372,7 +2413,18 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co if ( (C0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdxCol )) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdxCol ) ) #endif { - cColMv.roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { +#endif + cColMv.roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } + else if ( pu.cu->imv == 2 ) + { + cColMv.roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } +#endif affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = cColMv; affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = cColMv; affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = cColMv; @@ -2395,9 +2447,16 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co for (int i = 0; i < affiAMVPInfo.numCand; i++) { - affiAMVPInfo.mvCandLT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - affiAMVPInfo.mvCandRT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - affiAMVPInfo.mvCandLB[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + affiAMVPInfo.mvCandLT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + affiAMVPInfo.mvCandRT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + affiAMVPInfo.mvCandLB[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } +#endif } @@ -4367,6 +4426,47 @@ bool CU::hasSubCUNonZeroMVd( const CodingUnit& cu ) return bNonZeroMvd; } +#if JVET_M0246_AFFINE_AMVR +bool CU::hasSubCUNonZeroAffineMVd( const CodingUnit& cu ) +{ + bool nonZeroAffineMvd = false; + + if ( !cu.affine || cu.firstPU->mergeFlag ) + { + return false; + } + + for ( const auto &pu : CU::traversePUs( cu ) ) + { + if ( ( !pu.mergeFlag ) && ( !cu.skip ) ) + { + if ( pu.interDir != 2 /* PRED_L1 */ ) + { + for ( int i = 0; i < ( cu.affineType == AFFINEMODEL_6PARAM ? 3 : 2 ); i++ ) + { + nonZeroAffineMvd |= pu.mvdAffi[REF_PIC_LIST_0][i].getHor() != 0; + nonZeroAffineMvd |= pu.mvdAffi[REF_PIC_LIST_0][i].getVer() != 0; + } + } + + if ( pu.interDir != 1 /* PRED_L0 */ ) + { + if ( !pu.cu->cs->slice->getMvdL1ZeroFlag() || pu.interDir != 3 /* PRED_BI */ ) + { + for ( int i = 0; i < ( cu.affineType == AFFINEMODEL_6PARAM ? 3 : 2 ); i++ ) + { + nonZeroAffineMvd |= pu.mvdAffi[REF_PIC_LIST_1][i].getHor() != 0; + nonZeroAffineMvd |= pu.mvdAffi[REF_PIC_LIST_1][i].getVer() != 0; + } + } + } + } + } + + return nonZeroAffineMvd; +} +#endif + int CU::getMaxNeighboriMVCandNum( const CodingStructure& cs, const Position& pos ) { const int numDefault = 0; diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 3795ed91c9decc2c1068c12130746a8b73bac5af..5bbf165cae5329d9d182bc57c23661fff01f1ff7 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -92,6 +92,9 @@ namespace CU cTUTraverser traverseTUs (const CodingUnit& cu); bool hasSubCUNonZeroMVd (const CodingUnit& cu); +#if JVET_M0246_AFFINE_AMVR + bool hasSubCUNonZeroAffineMVd ( const CodingUnit& cu ); +#endif int getMaxNeighboriMVCandNum (const CodingStructure& cs, const Position& pos); void resetMVDandMV2Int ( CodingUnit& cu, InterPrediction *interPred ); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 265d98ded7b171f372acf87b64cbba858c489921..bd9ff0f130a4937cb1945d5b3de3e3da4c9648b2 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -979,6 +979,13 @@ void CABACReader::imv_mode( CodingUnit& cu, MergeCtx& mrgCtx ) return; } +#if JVET_M0246_AFFINE_AMVR + if ( cu.affine ) + { + return; + } +#endif + const SPSNext& spsNext = cu.cs->sps->getSpsNext(); unsigned value = 0; @@ -1000,6 +1007,39 @@ void CABACReader::imv_mode( CodingUnit& cu, MergeCtx& mrgCtx ) DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() IMVFlag=%d\n", cu.imv ); } +#if JVET_M0246_AFFINE_AMVR +void CABACReader::affine_amvr_mode( CodingUnit& cu, MergeCtx& mrgCtx ) +{ + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__OTHER ); + + const SPS* sps = cu.slice->getSPS(); + + if( !sps->getAffineAmvrEnabledFlag() || !cu.affine ) + { + return; + } + + if ( !CU::hasSubCUNonZeroAffineMVd( cu ) ) + { + return; + } + + unsigned value = 0; + value = m_BinDecoder.decodeBin( Ctx::ImvFlag( 4 ) ); + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", value, 4 ); + + if( value ) + { + value = m_BinDecoder.decodeBin( Ctx::ImvFlag( 5 ) ); + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", value, 5 ); + value++; + } + + cu.imv = value; + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() IMVFlag=%d\n", cu.imv ); +} +#endif + void CABACReader::pred_mode( CodingUnit& cu ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__PRED_MODE ); @@ -1057,7 +1097,9 @@ void CABACReader::cu_pred_data( CodingUnit &cu ) } imv_mode ( cu, mrgCtx ); - +#if JVET_M0246_AFFINE_AMVR + affine_amvr_mode( cu, mrgCtx ); +#endif cu_gbi_flag( cu ); } diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 8e5586e5007f95e5575812bfd5fbe899116e6aca..29e463caafb6d2e4ee3a6cb904c156e50601c4e8 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -107,6 +107,9 @@ public: void merge_idx ( PredictionUnit& pu ); void mmvd_merge_idx(PredictionUnit& pu); void imv_mode ( CodingUnit& cu, MergeCtx& mrgCtx ); +#if JVET_M0246_AFFINE_AMVR + void affine_amvr_mode ( CodingUnit& cu, MergeCtx& mrgCtx ); +#endif void inter_pred_idc ( PredictionUnit& pu ); void ref_idx ( PredictionUnit& pu, RefPicList eRefList ); void mvp_flag ( PredictionUnit& pu, RefPicList eRefList ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index b36cb3207e8d2c10913f78b4826506b09c758e22..3c2730c0098acc41af8431a03d9c05c203991190 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -583,7 +583,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) else { #if REUSE_CU_RESULTS +#if JVET_M0246_AFFINE_AMVR + if ( cu.imv && !pu.cu->affine && !cu.cs->pcv->isEncoder ) +#else if (cu.imv && !cu.cs->pcv->isEncoder) +#endif #else if (cu.imv) #endif @@ -608,7 +612,35 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) // Mv mv[3]; CHECK( pu.refIdx[eRefList] < 0, "Unexpected negative refIdx." ); +#if JVET_M0246_AFFINE_AMVR + Mv tmpMvd[3]; + memcpy( tmpMvd, pu.mvdAffi[eRefList], 3 * sizeof( Mv ) ); + const int imvShift = ( !cu.cs->pcv->isEncoder && pu.cu->imv == 2 ) ? MV_FRACTIONAL_BITS_DIFF : 0; + pu.mvdAffi[eRefList][0] <<= imvShift; + pu.mvdAffi[eRefList][1] <<= imvShift; + + Mv mvLT = affineAMVPInfo.mvCandLT[mvp_idx] + pu.mvdAffi[eRefList][0]; + Mv mvRT = affineAMVPInfo.mvCandRT[mvp_idx] + pu.mvdAffi[eRefList][1]; + mvRT += pu.mvdAffi[eRefList][0]; + if ( pu.cu->imv != 1 ) + { + mvLT.changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL ); + mvRT.changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL ); + } + Mv mvLB; + if ( cu.affineType == AFFINEMODEL_6PARAM ) + { + pu.mvdAffi[eRefList][2] <<= imvShift; + mvLB = affineAMVPInfo.mvCandLB[mvp_idx] + pu.mvdAffi[eRefList][2]; + mvLB += pu.mvdAffi[eRefList][0]; + if ( pu.cu->imv != 1 ) + { + mvLB.changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL ); + } + } + memcpy( pu.mvdAffi[eRefList], tmpMvd, 3 * sizeof( Mv ) ); +#else Mv mvLT = affineAMVPInfo.mvCandLT[mvp_idx] + pu.mvdAffi[eRefList][0]; Mv mvRT = affineAMVPInfo.mvCandRT[mvp_idx] + pu.mvdAffi[eRefList][1]; mvRT += pu.mvdAffi[eRefList][0]; @@ -622,6 +654,7 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) mvLB += pu.mvdAffi[eRefList][0]; mvLB.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); } +#endif PU::setAllAffineMv( pu, mvLT, mvRT, mvLB, eRefList ); } } diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 94b555869904b70a7f95e1705f277fa1c903028a..94c056f8825fc470e949b7f7f9adbba23d19af54 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -1050,7 +1050,9 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) #if JVET_M0255_FRACMMVD_SWITCH READ_FLAG( uiCode, "sps_fracmmvd_disabled_flag" ); pcSPS->setDisFracMmvdEnabledFlag ( uiCode != 0 ); #endif - +#if JVET_M0246_AFFINE_AMVR + READ_FLAG( uiCode, "sps_affine_amvr_enabled_flag" ); pcSPS->setAffineAmvrEnabledFlag ( uiCode != 0 ); +#endif #if HEVC_USE_SCALING_LISTS READ_FLAG( uiCode, "scaling_list_enabled_flag" ); pcSPS->setScalingListFlag ( uiCode ); if(pcSPS->getScalingListFlag()) diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 010808ea87a76da78ca9084ce4e34f4690cf7a86..0c5ca538c96f879290883445226651cc5e6b8f07 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -830,6 +830,9 @@ void CABACWriter::cu_pred_data( const CodingUnit& cu ) } imv_mode ( cu ); +#if JVET_M0246_AFFINE_AMVR + affine_amvr_mode( cu ); +#endif cu_gbi_flag( cu ); @@ -1326,6 +1329,9 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu ) } else { +#if JVET_M0246_AFFINE_AMVR + int8_t affineMvdShift = pu.cu->imv ? ( pu.cu->imv == 1 ? -1 : 1 ) : 0; +#endif inter_pred_idc( pu ); affine_flag ( *pu.cu ); #if JVET_M0444_SMVD @@ -1336,12 +1342,21 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu ) ref_idx ( pu, REF_PIC_LIST_0 ); if ( pu.cu->affine ) { +#if JVET_M0246_AFFINE_AMVR + mvd_coding( pu.mvdAffi[REF_PIC_LIST_0][0], affineMvdShift ); + mvd_coding( pu.mvdAffi[REF_PIC_LIST_0][1], affineMvdShift ); + if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) + { + mvd_coding( pu.mvdAffi[REF_PIC_LIST_0][2], affineMvdShift ); + } +#else mvd_coding(pu.mvdAffi[REF_PIC_LIST_0][0], 0); mvd_coding(pu.mvdAffi[REF_PIC_LIST_0][1], 0); if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { mvd_coding(pu.mvdAffi[REF_PIC_LIST_0][2], 0); } +#endif } else { @@ -1360,12 +1375,21 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu ) { if ( pu.cu->affine ) { +#if JVET_M0246_AFFINE_AMVR + mvd_coding( pu.mvdAffi[REF_PIC_LIST_1][0], affineMvdShift ); + mvd_coding( pu.mvdAffi[REF_PIC_LIST_1][1], affineMvdShift ); + if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) + { + mvd_coding( pu.mvdAffi[REF_PIC_LIST_1][2], affineMvdShift ); + } +#else mvd_coding(pu.mvdAffi[REF_PIC_LIST_1][0], 0); mvd_coding(pu.mvdAffi[REF_PIC_LIST_1][1], 0); if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { mvd_coding(pu.mvdAffi[REF_PIC_LIST_1][2], 0); } +#endif } else { @@ -1451,6 +1475,12 @@ void CABACWriter::imv_mode( const CodingUnit& cu ) { return; } +#if JVET_M0246_AFFINE_AMVR + if ( cu.affine ) + { + return; + } +#endif bool bNonZeroMvd = CU::hasSubCUNonZeroMVd( cu ); if( !bNonZeroMvd ) @@ -1472,6 +1502,33 @@ void CABACWriter::imv_mode( const CodingUnit& cu ) DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() IMVFlag=%d\n", cu.imv ); } +#if JVET_M0246_AFFINE_AMVR +void CABACWriter::affine_amvr_mode( const CodingUnit& cu ) +{ + const SPS* sps = cu.slice->getSPS(); + + if( !sps->getAffineAmvrEnabledFlag() || !cu.affine ) + { + return; + } + + if ( !CU::hasSubCUNonZeroAffineMVd( cu ) ) + { + return; + } + + m_BinEncoder.encodeBin( ( cu.imv > 0 ), Ctx::ImvFlag( 4 ) ); + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", ( cu.imv > 0 ), 4 ); + + if( cu.imv > 0 ) + { + m_BinEncoder.encodeBin( ( cu.imv > 1 ), Ctx::ImvFlag( 5 ) ); + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", ( cu.imv > 1 ), 5 ); + } + DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() IMVFlag=%d\n", cu.imv ); +} +#endif + void CABACWriter::merge_idx( const PredictionUnit& pu ) { @@ -2001,12 +2058,19 @@ void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& //-------------------------------------------------------------------------------- // void mvd_coding( pu, refList ) //================================================================================ - +#if JVET_M0246_AFFINE_AMVR +void CABACWriter::mvd_coding( const Mv &rMvd, int8_t imv ) +#else void CABACWriter::mvd_coding( const Mv &rMvd, uint8_t imv ) +#endif { int horMvd = rMvd.getHor(); int verMvd = rMvd.getVer(); +#if JVET_M0246_AFFINE_AMVR + if ( imv > 0 ) +#else if( imv ) +#endif { CHECK( (horMvd % 4) != 0 && (verMvd % 4) != 0, "IMV: MVD is not a multiple of 4" ); horMvd >>= 2; diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 10c97e26f7796ea71d546d39521533b9f4fa2c19..51fbd8ddd98eb5705e26d18101e03cac957d3264 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -117,6 +117,9 @@ public: void merge_idx ( const PredictionUnit& pu ); void mmvd_merge_idx(const PredictionUnit& pu); void imv_mode ( const CodingUnit& cu ); +#if JVET_M0246_AFFINE_AMVR + void affine_amvr_mode ( const CodingUnit& cu ); +#endif void inter_pred_idc ( const PredictionUnit& pu ); void ref_idx ( const PredictionUnit& pu, RefPicList eRefList ); void mvp_flag ( const PredictionUnit& pu, RefPicList eRefList ); @@ -136,8 +139,11 @@ public: void cbf_comp ( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf = false ); // mvd coding (clause 7.3.8.9) +#if JVET_M0246_AFFINE_AMVR + void mvd_coding ( const Mv &rMvd, int8_t imv ); +#else void mvd_coding ( const Mv &rMvd, uint8_t imv ); - +#endif // transform unit (clause 7.3.8.10) void transform_unit ( const TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& chromaCbfs ); void cu_qp_delta ( const CodingUnit& cu, int predQP, const int8_t qp ); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 24561541aaaba574191f431cc60803309ef2c966..a34fdac1aa7579b157ad0bf5ce8ff5338ff848f0 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -240,6 +240,9 @@ protected: bool m_Triangle; #if JVET_M0255_FRACMMVD_SWITCH bool m_allowDisFracMMVD; +#endif +#if JVET_M0246_AFFINE_AMVR + bool m_AffineAmvr; #endif unsigned m_IBCMode; unsigned m_IBCLocalSearchRangeX; @@ -248,7 +251,7 @@ protected: unsigned m_IBCHashSearchMaxCand; unsigned m_IBCHashSearchRange4SmallBlk; unsigned m_IBCFastMethod; - + bool m_wrapAround; unsigned m_wrapAroundOffset; @@ -760,6 +763,10 @@ public: void setAllowDisFracMMVD ( bool b ) { m_allowDisFracMMVD = b; } bool getAllowDisFracMMVD () const { return m_allowDisFracMMVD; } #endif +#if JVET_M0246_AFFINE_AMVR + void setUseAffineAmvr ( bool b ) { m_AffineAmvr = b; } + bool getUseAffineAmvr () const { return m_AffineAmvr; } +#endif void setIBCMode (unsigned n) { m_IBCMode = n; } unsigned getIBCMode () const { return m_IBCMode; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 1500c9a368c1b8924a0aec9ef59c8b4bcb54b1e6..32639339932f9997b2656b341fd10f747d5831a7 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -695,6 +695,9 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par #if JVET_M0170_MRG_SHARELIST int startShareThisLevel = 0; #endif +#if JVET_M0246_AFFINE_AMVR + m_pcInterSearch->resetSavedAffineMotion(); +#endif do { @@ -731,11 +734,23 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par { if( ( currTestMode.opts & ETO_IMV ) != 0 ) { +#if JVET_M0246_AFFINE_AMVR + tempCS->bestCS = bestCS; + xCheckRDCostInterIMV( tempCS, bestCS, partitioner, currTestMode ); + tempCS->bestCS = nullptr; +#else xCheckRDCostInterIMV(tempCS, bestCS, partitioner, currTestMode); +#endif } else { +#if JVET_M0246_AFFINE_AMVR + tempCS->bestCS = bestCS; xCheckRDCostInter( tempCS, bestCS, partitioner, currTestMode ); + tempCS->bestCS = nullptr; +#else + xCheckRDCostInter( tempCS, bestCS, partitioner, currTestMode ); +#endif } } @@ -3489,6 +3504,9 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be gbiLoopNum = 1; } +#if JVET_M0246_AFFINE_AMVR + bool validMode = false; +#endif double curBestCost = bestCS->cost; double equGBiCost = MAX_DOUBLE; @@ -3560,6 +3578,9 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be bool testGbi; uint8_t gbiIdx; +#if JVET_M0246_AFFINE_AMVR + bool affineAmvrEanbledFlag = cu.slice->getSPS()->getAffineAmvrEnabledFlag(); +#endif if( pcCUInfo2Reuse != nullptr ) { @@ -3570,7 +3591,11 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be gbiIdx = CU::getValidGbiIdx(cu); testGbi = (gbiIdx != GBI_DEFAULT); +#if JVET_M0246_AFFINE_AMVR + if ( !CU::hasSubCUNonZeroMVd( cu ) && !CU::hasSubCUNonZeroAffineMVd( cu ) ) +#else if( !CU::hasSubCUNonZeroMVd( cu ) ) +#endif { if (m_modeCtrl->useModeResult(encTestModeBase, tempCS, partitioner)) { @@ -3578,7 +3603,19 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be // store temp best CI for next CU coding m_CurrCtx->best = m_CABACEstimator->getCtx(); } +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEanbledFlag ) + { + tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); + continue; + } + else + { + return false; + } +#else return false; +#endif } else { @@ -3591,9 +3628,24 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be gbiIdx = cu.GBiIdx; testGbi = (gbiIdx != GBI_DEFAULT); +#if JVET_M0246_AFFINE_AMVR + cu.firstPU->interDir = 10; +#endif + m_pcInterSearch->predInterSearch( cu, partitioner ); +#if JVET_M0246_AFFINE_AMVR + if ( cu.firstPU->interDir <= 3 ) + { + gbiIdx = CU::getValidGbiIdx(cu); + } + else + { + return false; + } +#else gbiIdx = CU::getValidGbiIdx(cu); +#endif } if( testGbi && gbiIdx == GBI_DEFAULT ) // Enabled GBi but the search results is uni. @@ -3612,7 +3664,11 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be } } +#if JVET_M0246_AFFINE_AMVR + if ( !CU::hasSubCUNonZeroMVd( cu ) && !CU::hasSubCUNonZeroAffineMVd( cu ) ) +#else if( !CU::hasSubCUNonZeroMVd( cu ) ) +#endif { if (m_modeCtrl->useModeResult(encTestModeBase, tempCS, partitioner)) { @@ -3620,7 +3676,19 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be // store temp best CI for next CU coding m_CurrCtx->best = m_CABACEstimator->getCtx(); } +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEanbledFlag ) + { + tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); + continue; + } + else + { + return false; + } +#else return false; +#endif } #if JVET_M0464_UNI_MTS @@ -3657,9 +3725,16 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be { break; } +#if JVET_M0246_AFFINE_AMVR + validMode = true; +#endif } // for( UChar gbiLoopIdx = 0; gbiLoopIdx < gbiLoopNum; gbiLoopIdx++ ) +#if JVET_M0246_AFFINE_AMVR + return tempCS->slice->getSPS()->getAffineAmvrEnabledFlag() ? validMode : true; +#else return true; +#endif } #if JVET_M0464_UNI_MTS diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index e3fa09d81e87633dda9bc6cd79bc73259dda47cf..4d8506f0217d3292f6c752caf591887c6d7e76a7 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -893,6 +893,9 @@ void EncLib::xInitSPS(SPS &sps) sps.getSpsNext().setUseTriangle ( m_Triangle ); #if JVET_M0255_FRACMMVD_SWITCH sps.setDisFracMmvdEnabledFlag ( m_allowDisFracMMVD ); +#endif +#if JVET_M0246_AFFINE_AMVR + sps.setAffineAmvrEnabledFlag ( m_AffineAmvr ); #endif sps.getSpsNext().setIBCMode ( m_IBCMode ); diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index 5c9aeb9b77dd60bc8c0de2c323d85552d96052e8..ecd823301016b267b8f0fe099da56a9820289c67 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -1139,10 +1139,17 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru { const int qp = std::max( qpLoop, lowestQP ); const bool lossless = useLossless && qpLoop == minQP; - +#if JVET_M0246_AFFINE_AMVR + if( m_pcEncCfg->getIMV() || m_pcEncCfg->getUseAffineAmvr() ) +#else if( m_pcEncCfg->getIMV() ) +#endif { +#if JVET_M0246_AFFINE_AMVR + if( m_pcEncCfg->getIMV() == IMV_4PEL || m_pcEncCfg->getUseAffineAmvr() ) +#else if( m_pcEncCfg->getIMV() == IMV_4PEL ) +#endif { int imv = m_pcEncCfg->getIMV4PelFast() ? 3 : 2; m_ComprCUCtxList.back().testModes.push_back( { ETM_INTER_ME, EncTestModeOpts( imv << ETO_IMV_SHIFT ), qp, lossless } ); @@ -1384,6 +1391,9 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt if (imvOpt == 3 && cuECtx.get<double>(BEST_NO_IMV_COST) * 1.06 < cuECtx.get<double>(BEST_IMV_COST)) { +#if JVET_M0246_AFFINE_AMVR + if ( !m_pcEncCfg->getUseAffineAmvr() ) +#endif return false; } } diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 233d90017647044e9c6019f8cfa234262263dffa..1b5559dff1c59e6f5298d1f710ecffc744f132ad 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -251,6 +251,58 @@ void InterSearch::init( EncCfg* pcEncCfg, m_isInitialized = true; } +#if JVET_M0246_AFFINE_AMVR +void InterSearch::resetSavedAffineMotion() +{ + for ( int i = 0; i < 2; i++ ) + { + for ( int j = 0; j < 2; j++ ) + { + m_affineMotion.acMvAffine4Para[i][j] = Mv( 0, 0 ); + m_affineMotion.acMvAffine6Para[i][j] = Mv( 0, 0 ); + } + m_affineMotion.acMvAffine6Para[i][2] = Mv( 0, 0 ); + + m_affineMotion.affine4ParaRefIdx[i] = -1; + m_affineMotion.affine6ParaRefIdx[i] = -1; + } + for ( int i = 0; i < 3; i++ ) + { + m_affineMotion.hevcCost[i] = std::numeric_limits<Distortion>::max(); + } + m_affineMotion.affine4ParaAvail = false; + m_affineMotion.affine6ParaAvail = false; +} + +void InterSearch::storeAffineMotion( Mv acAffineMv[2][3], int16_t affineRefIdx[2], EAffineModel affineType, int gbiIdx ) +{ + if ( ( gbiIdx == GBI_DEFAULT || !m_affineMotion.affine6ParaAvail ) && affineType == AFFINEMODEL_6PARAM ) + { + for ( int i = 0; i < 2; i++ ) + { + for ( int j = 0; j < 3; j++ ) + { + m_affineMotion.acMvAffine6Para[i][j] = acAffineMv[i][j]; + } + m_affineMotion.affine6ParaRefIdx[i] = affineRefIdx[i]; + } + m_affineMotion.affine6ParaAvail = true; + } + + if ( ( gbiIdx == GBI_DEFAULT || !m_affineMotion.affine4ParaAvail ) && affineType == AFFINEMODEL_4PARAM ) + { + for ( int i = 0; i < 2; i++ ) + { + for ( int j = 0; j < 2; j++ ) + { + m_affineMotion.acMvAffine4Para[i][j] = acAffineMv[i][j]; + } + m_affineMotion.affine4ParaRefIdx[i] = affineRefIdx[i]; + } + m_affineMotion.affine4ParaAvail = true; + } +} +#endif inline void InterSearch::xTZSearchHelp( IntTZSearchStruct& rcStruct, const int iSearchX, const int iSearchY, const uint8_t ucPointNr, const uint32_t uiDistance ) { @@ -1540,6 +1592,25 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) uint32_t puIdx = 0; auto &pu = *cu.firstPU; +#if JVET_M0246_AFFINE_AMVR + bool checkAffine = pu.cu->imv == 0 || pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag(); + bool checkNonAffine = pu.cu->imv == 0 || ( pu.cu->slice->getSPS()->getSpsNext().getUseIMV() && + pu.cu->imv <= pu.cu->slice->getSPS()->getSpsNext().getImvMode() ); + CodingUnit *bestCU = pu.cu->cs->bestCS != nullptr ? pu.cu->cs->bestCS->getCU( CHANNEL_TYPE_LUMA ) : nullptr; +#if JVET_M0444_SMVD + bool trySmvd = ( bestCU != nullptr && pu.cu->imv == 2 && checkAffine ) ? ( !bestCU->firstPU->mergeFlag && !bestCU->affine ) : true; +#endif + if ( pu.cu->imv && bestCU != nullptr && checkAffine ) + { + checkAffine = !( bestCU->firstPU->mergeFlag || !bestCU->affine ); + } + + if ( pu.cu->imv == 2 && checkNonAffine && pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag() ) + { + checkNonAffine = m_affineMotion.hevcCost[1] < m_affineMotion.hevcCost[0] * 1.06f; + } +#endif + { // motion estimation only evaluates luma component m_maxCompIDToPred = MAX_NUM_COMPONENT; @@ -1583,6 +1654,10 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) m_pcRdCost->selectMotionLambda( cu.transQuantBypass ); unsigned imvShift = pu.cu->imv << 1; +#if JVET_M0246_AFFINE_AMVR + if ( checkNonAffine ) + { +#endif // Uni-directional prediction for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ ) { @@ -1677,7 +1752,11 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getSpsNext().getUseAffine() +#if JVET_M0246_AFFINE_AMVR + && checkAffine +#else && cu.imv == 0 +#endif && (gbiIdx == GBI_DEFAULT || m_affineModeSelected || !m_pcEncCfg->getUseGBiFast()) ) { @@ -1871,7 +1950,11 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) cu.refIdxBi[1] = iRefIdxBi[1]; #if JVET_M0444_SMVD +#if JVET_M0246_AFFINE_AMVR + if ( cs.slice->getBiDirPred() && trySmvd ) +#else if ( cs.slice->getBiDirPred() ) +#endif { Distortion symCost; Mv cMvPredSym[2]; @@ -2056,7 +2139,15 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } uiHevcCost = ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1] ) ? uiCostBi : ( ( uiCost[0] <= uiCost[1] ) ? uiCost[0] : uiCost[1] ); - if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getSpsNext().getUseAffine() && cu.imv == 0 +#if JVET_M0246_AFFINE_AMVR + } +#endif + if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getSpsNext().getUseAffine() +#if JVET_M0246_AFFINE_AMVR + && checkAffine +#else + && cu.imv == 0 +#endif && (gbiIdx == GBI_DEFAULT || m_affineModeSelected || !m_pcEncCfg->getUseGBiFast()) ) { @@ -2089,6 +2180,14 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffineCost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, gbiIdx, enforceGBiPred, ((cu.slice->getSPS()->getSpsNext().getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0)); + +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { + storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_4PARAM, gbiIdx ); + } +#endif + if ( cu.slice->getSPS()->getSpsNext().getUseAffineType() ) { if ( uiAffineCost < uiHevcCost * 1.05 ) ///< condition for 6 parameter affine ME @@ -2124,6 +2223,13 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffine6Cost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, gbiIdx, enforceGBiPred, ((cu.slice->getSPS()->getSpsNext().getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0)); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { + storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_6PARAM, gbiIdx ); + } +#endif + // reset to 4 parameter affine inter mode if ( uiAffineCost <= uiAffine6Cost ) { @@ -2204,6 +2310,12 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) // MC PelUnitBuf predBuf = pu.cs->getPredBuf(pu); +#if JVET_M0246_AFFINE_AMVR + if ( gbiIdx == GBI_DEFAULT || !m_affineMotion.affine4ParaAvail || !m_affineMotion.affine6ParaAvail ) + { + m_affineMotion.hevcCost[pu.cu->imv] = uiHevcCost; + } +#endif motionCompensation( pu, predBuf, REF_PIC_LIST_X ); puIdx++; } @@ -2213,8 +2325,39 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) return; } +#if JVET_M0246_AFFINE_AMVR +uint32_t InterSearch::xCalcAffineMVBits( PredictionUnit& pu, Mv acMvTemp[3], Mv acMvPred[3], bool mvHighPrec ) +{ + int mvNum = pu.cu->affineType ? 3 : 2; + Mv tempMv0 = acMvTemp[0]; + const int shift = mvHighPrec ? MV_FRACTIONAL_BITS_DIFF : 0; + const unsigned int mvdShift = pu.cu->imv == 2 ? MV_FRACTIONAL_BITS_DIFF : 0; + Mv secondPred; + + if ( mvHighPrec ) + { + tempMv0.changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER ); + } + + m_pcRdCost->setCostScale( 0 ); + uint32_t bitsTemp = 0; + + for ( int verIdx = 0; verIdx < mvNum; verIdx++ ) + { + m_pcRdCost->setPredictor( acMvPred[verIdx] ); + + if ( verIdx != 0 ) + { + secondPred = acMvPred[verIdx] + ( tempMv0 - acMvPred[0] ); + m_pcRdCost->setPredictor( secondPred ); + } + bitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor( acMvTemp[verIdx].getHor() >> shift, acMvTemp[verIdx].getVer() >> shift, mvdShift ); + } + return bitsTemp; +} +#endif // AMVP void InterSearch::xEstimateMvPredAMVP( PredictionUnit& pu, PelUnitBuf& origBuf, RefPicList eRefPicList, int iRefIdx, Mv& rcMvPred, AMVPInfo& rAMVPInfo, bool bFilled, Distortion* puiDistBiP ) @@ -2410,9 +2553,16 @@ Distortion InterSearch::xGetAffineTemplateCost( PredictionUnit& pu, PelUnitBuf& const bool bi = pu.cu->slice->testWeightPred() && pu.cu->slice->getSliceType()==P_SLICE; Mv mv[3]; memcpy(mv, acMvCand, sizeof(mv)); - mv[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - mv[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - mv[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + mv[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + mv[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + mv[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + } +#endif xPredAffineBlk(COMPONENT_Y, pu, picRef, mv, predBuf, bi, pu.cu->slice->clpRng(COMPONENT_Y)); if( bi ) { @@ -3478,6 +3628,10 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, uint32_t bitsValidList1 = MAX_UINT; Distortion costValidList1 = std::numeric_limits<Distortion>::max(); Mv mvHevc[3]; +#if JVET_M0246_AFFINE_AMVR + const bool changeToHighPrec = pu.cu->imv != 1; + const bool affineAmvrEnabled = pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag(); +#endif xGetBlkBits( slice.isInterP(), puIdx, lastMode, uiMbBits); @@ -3513,6 +3667,12 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, // Do Affine AMVP xEstimateAffineAMVP( pu, affiAMVPInfoTemp[eRefPicList], origBuf, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], &biPDistTemp ); +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEnabled ) + { + biPDistTemp += m_pcRdCost->getCost( xCalcAffineMVBits( pu, cMvPred[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp] ) ); + } +#endif aaiMvpIdx[iRefList][iRefIdxTemp] = pu.mvpIdx[eRefPicList]; aaiMvpNum[iRefList][iRefIdxTemp] = pu.mvpNum[eRefPicList];; if ( pu.cu->affineType == AFFINEMODEL_6PARAM && refIdx4Para[iRefList] != iRefIdxTemp ) @@ -3525,11 +3685,57 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, for ( int i=0; i<3; i++ ) { mvHevc[i] = hevcMv[iRefList][iRefIdxTemp]; +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 1 ) + { + mvHevc[i].changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL ); + } + else if ( pu.cu->imv == 2 ) + { + mvHevc[i].roundToPrecision( MV_PRECISION_QUARTER, MV_PRECISION_INT ); + } +#endif } PelUnitBuf predBuf = m_tmpStorageLCU.getBuf( UnitAreaRelative(*pu.cu, pu) ); Distortion uiCandCost = xGetAffineTemplateCost(pu, origBuf, predBuf, mvHevc, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp); + +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEnabled ) + { + uiCandCost += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvHevc, cMvPred[iRefList][iRefIdxTemp] ) ); + } + + //check stored affine motion + bool affine4Para = pu.cu->affineType == AFFINEMODEL_4PARAM; + bool savedParaAvail = pu.cu->imv && ( ( m_affineMotion.affine4ParaRefIdx[iRefList] == iRefIdxTemp && affine4Para && m_affineMotion.affine4ParaAvail ) || + ( m_affineMotion.affine6ParaRefIdx[iRefList] == iRefIdxTemp && !affine4Para && m_affineMotion.affine6ParaAvail ) ); + + if ( savedParaAvail ) + { + Mv mvFour[3]; + for ( int i = 0; i < mvNum; i++ ) + { + mvFour[i] = affine4Para ? m_affineMotion.acMvAffine4Para[iRefList][i] : m_affineMotion.acMvAffine6Para[iRefList][i]; + if ( pu.cu->imv != 1 ) + { + mvFour[i].roundToPrecision( MV_PRECISION_INTERNAL, pu.cu->imv == 2 ? MV_PRECISION_INT : MV_PRECISION_QUARTER ); + mvFour[i].changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER ); + } + } + + Distortion candCostInherit = xGetAffineTemplateCost( pu, origBuf, predBuf, mvFour, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp ); + candCostInherit += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvFour, cMvPred[iRefList][iRefIdxTemp] ) ); + + if ( candCostInherit < uiCandCost ) + { + uiCandCost = candCostInherit; + memcpy( mvHevc, mvFour, 3 * sizeof( Mv ) ); + } + } +#endif + if (pu.cu->affineType == AFFINEMODEL_4PARAM && m_affMVListSize && (!pu.cu->cs->sps->getSpsNext().getUseGBi() || gbiIdx == GBI_DEFAULT) ) @@ -3578,6 +3784,13 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, clipMv(mvTmp[0], pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 2 ) + { + mvTmp[0].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } + else if ( pu.cu->imv == 0 ) +#endif mvTmp[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); vx = mvScaleHor + dMvHorX * (pu.Y().x + pu.Y().width - mvInfo->x) + dMvVerX * (pu.Y().y - mvInfo->y); vy = mvScaleVer + dMvHorY * (pu.Y().x + pu.Y().width - mvInfo->x) + dMvVerY * (pu.Y().y - mvInfo->y); @@ -3589,10 +3802,25 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, clipMv(mvTmp[1], pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { + mvTmp[1].roundToPrecision( MV_PRECISION_INTERNAL, pu.cu->imv == 2 ? MV_PRECISION_INT : MV_PRECISION_QUARTER ); + mvTmp[0].changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER ); + mvTmp[1].changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER ); + } +#else mvTmp[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); mvTmp[0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); mvTmp[1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#endif Distortion tmpCost = xGetAffineTemplateCost(pu, origBuf, predBuf, mvTmp, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp); +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEnabled ) + { + tmpCost += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvTmp, cMvPred[iRefList][iRefIdxTemp] ) ); + } +#endif if (tmpCost < uiCandCost) { uiCandCost = tmpCost; @@ -3603,13 +3831,26 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { Mv mvFour[3]; - mvAffine4Para[iRefList][iRefIdxTemp][0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - mvAffine4Para[iRefList][iRefIdxTemp][1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + mvAffine4Para[iRefList][iRefIdxTemp][0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + mvAffine4Para[iRefList][iRefIdxTemp][1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + } +#endif mvFour[0] = mvAffine4Para[iRefList][iRefIdxTemp][0]; mvFour[1] = mvAffine4Para[iRefList][iRefIdxTemp][1]; - mvAffine4Para[iRefList][iRefIdxTemp][0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - mvAffine4Para[iRefList][iRefIdxTemp][1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + mvAffine4Para[iRefList][iRefIdxTemp][0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + mvAffine4Para[iRefList][iRefIdxTemp][1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } +#endif int shift = MAX_CU_DEPTH; int vx2 = (mvFour[0].getHor() << shift) - ((mvFour[1].getVer() - mvFour[0].getVer()) << (shift + g_aucLog2[pu.lheight()] - g_aucLog2[pu.lwidth()])); int vy2 = (mvFour[0].getVer() << shift) + ((mvFour[1].getHor() - mvFour[0].getHor()) << (shift + g_aucLog2[pu.lheight()] - g_aucLog2[pu.lwidth()])); @@ -3620,12 +3861,34 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, #if JVET_M0145_AFFINE_MV_CLIP mvFour[2].clipToStorageBitDepth(); #endif +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { + mvFour[0].roundToPrecision( MV_PRECISION_INTERNAL, pu.cu->imv == 2 ? MV_PRECISION_INT : MV_PRECISION_QUARTER ); + mvFour[1].roundToPrecision( MV_PRECISION_INTERNAL, pu.cu->imv == 2 ? MV_PRECISION_INT : MV_PRECISION_QUARTER ); + mvFour[2].roundToPrecision( MV_PRECISION_INTERNAL, pu.cu->imv == 2 ? MV_PRECISION_INT : MV_PRECISION_QUARTER ); + } +#else mvFour[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#endif for (int i = 0; i < 3; i++) { +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { + mvFour[i].changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER ); + } +#else mvFour[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#endif } Distortion uiCandCostInherit = xGetAffineTemplateCost( pu, origBuf, predBuf, mvFour, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp ); +#if JVET_M0246_AFFINE_AMVR + if ( affineAmvrEnabled ) + { + uiCandCostInherit += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvFour, cMvPred[iRefList][iRefIdxTemp] ) ); + } +#endif if ( uiCandCostInherit < uiCandCost ) { uiCandCost = uiCandCostInherit; @@ -3665,6 +3928,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, uiCostTemp = uiCostTempL0[iList1ToList0Idx]; uiCostTemp -= m_pcRdCost->getCost( uiBitsTempL0[iList1ToList0Idx] ); +#if JVET_M0246_AFFINE_AMVR + uiBitsTemp += xCalcAffineMVBits( pu, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp] ); +#else for (int iVerIdx = 0; iVerIdx < mvNum; iVerIdx++) { m_pcRdCost->setPredictor( cMvPred[iRefList][iRefIdxTemp][iVerIdx] ); @@ -3677,6 +3943,7 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, } uiBitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor( cMvTemp[1][iRefIdxTemp][iVerIdx].getHor()>>shift, cMvTemp[1][iRefIdxTemp][iVerIdx].getVer()>>shift, 0 ); } +#endif /*calculate the correct cost*/ uiCostTemp += m_pcRdCost->getCost( uiBitsTemp ); DTRACE( g_trace_ctx, D_COMMON, " (%d) uiCostTemp=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiCostTemp ); @@ -3730,7 +3997,11 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, if ( pu.cu->affineType == AFFINEMODEL_4PARAM ) { ::memcpy( mvAffine4Para, cMvTemp, sizeof( cMvTemp ) ); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 && ( !pu.cu->cs->sps->getSpsNext().getUseGBi() || gbiIdx == GBI_DEFAULT ) ) +#else if (!pu.cu->cs->sps->getSpsNext().getUseGBi() || gbiIdx == GBI_DEFAULT) +#endif { AffineMVInfo *affMVInfo = m_affMVList + m_affMVListIdx; @@ -3791,7 +4062,11 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, // Get list1 prediction block PU::setAllAffineMv( pu, cMvBi[1][0], cMvBi[1][1], cMvBi[1][2], REF_PIC_LIST_1 +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1]; @@ -3856,7 +4131,11 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, if( iIter == 0 && !slice.getMvdL1ZeroFlag() ) { PU::setAllAffineMv( pu, aacMv[1-iRefList][0], aacMv[1-iRefList][1], aacMv[1-iRefList][2], RefPicList(1-iRefList) +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[1-iRefList] = iRefIdx[1-iRefList]; @@ -3925,7 +4204,11 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, { // Set motion PU::setAllAffineMv( pu, cMvBi[iRefList][0], cMvBi[iRefList][1], cMvBi[iRefList][2], eRefPicList +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[eRefPicList] = iRefIdxBi[eRefPicList]; PelUnitBuf predBufTmp = m_tmpPredStorage[iRefList].getBuf( UnitAreaRelative(*pu.cu, pu) ); @@ -3987,10 +4270,18 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, affineCost = uiCostBi; PU::setAllAffineMv( pu, cMvBi[0][0], cMvBi[0][1], cMvBi[0][2], REF_PIC_LIST_0 +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); PU::setAllAffineMv( pu, cMvBi[1][0], cMvBi[1][1], cMvBi[1][2], REF_PIC_LIST_1 +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[REF_PIC_LIST_0] = iRefIdxBi[0]; pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1]; @@ -4019,7 +4310,11 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, affineCost = uiCost[0]; PU::setAllAffineMv( pu, aacMv[0][0], aacMv[0][1], aacMv[0][2], REF_PIC_LIST_0 +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[REF_PIC_LIST_0] = iRefIdx[0]; @@ -4042,7 +4337,11 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, affineCost = uiCost[1]; PU::setAllAffineMv( pu, aacMv[1][0], aacMv[1][1], aacMv[1][2], REF_PIC_LIST_1 +#if JVET_M0246_AFFINE_AMVR + , changeToHighPrec +#else , true +#endif ); pu.refIdx[REF_PIC_LIST_1] = iRefIdx[1]; @@ -4151,6 +4450,10 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin int iBestMVPIdx = riMVPIdx; // Get origin MV bits +#if JVET_M0246_AFFINE_AMVR + Mv tmpPredMv[3]; + int iOrgMvBits = xCalcAffineMVBits( pu, acMv, acMvPred ); +#else int iOrgMvBits = 0; for ( int iVerIdx = 0; iVerIdx < mvNum; iVerIdx++ ) { @@ -4165,6 +4468,7 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin } iOrgMvBits += m_pcRdCost->getBitsOfVectorWithPredictor( acMv[iVerIdx].getHor()>>shift, acMv[iVerIdx].getVer()>>shift, 0 ); } +#endif iOrgMvBits += m_auiMVPIdxCost[riMVPIdx][AMVP_MAX_NUM_CANDS]; int iBestMvBits = iOrgMvBits; @@ -4174,7 +4478,15 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin { continue; } - +#if JVET_M0246_AFFINE_AMVR + tmpPredMv[0] = affineAMVPInfo.mvCandLT[iMVPIdx]; + tmpPredMv[1] = affineAMVPInfo.mvCandRT[iMVPIdx]; + if ( mvNum == 3 ) + { + tmpPredMv[2] = affineAMVPInfo.mvCandLB[iMVPIdx]; + } + int iMvBits = xCalcAffineMVBits( pu, acMv, tmpPredMv ); +#else int iMvBits = 0; for ( int iVerIdx = 0; iVerIdx < mvNum; iVerIdx++ ) { @@ -4190,6 +4502,7 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin } iMvBits += m_pcRdCost->getBitsOfVectorWithPredictor( acMv[iVerIdx].getHor()>>shift, acMv[iVerIdx].getVer()>>shift, 0 ); } +#endif iMvBits += m_auiMVPIdxCost[iMVPIdx][AMVP_MAX_NUM_CANDS]; if (iMvBits < iBestMvBits) @@ -4257,10 +4570,16 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, // Set start Mv position, use input mv as started search mv Mv acMvTemp[3]; ::memcpy( acMvTemp, acMv, sizeof(Mv)*3 ); - acMvTemp[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - acMvTemp[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - acMvTemp[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + acMvTemp[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + acMvTemp[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + acMvTemp[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + } +#endif // Set delta mv // malloc buffer int iParaNum = pu.cu->affineType ? 7 : 5; @@ -4295,6 +4614,18 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, pu.cu->lumaSize(), *pu.cs->sps ); } +#if JVET_M0246_AFFINE_AMVR + int mvdPrecision = ( pu.cu->imv == 1 ) ? 2 : 0; + if ( pu.cu->imv == 2 ) + { + acMvTemp[0].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + acMvTemp[1].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) + { + acMvTemp[2].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } + } +#endif xPredAffineBlk( COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cs->slice->clpRng( COMPONENT_Y ) ); // get error @@ -4304,6 +4635,10 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, 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_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 ); +#else for ( int i = 0; i < mvNum; i++ ) { DTRACE( g_trace_ctx, D_COMMON, "#mvPredForBits=(%d,%d) \n", acMvPred[i].getHor(), acMvPred[i].getVer() ); @@ -4322,6 +4657,7 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, uiBitsBest += m_pcRdCost->getBitsOfVectorWithPredictor( acMvTemp[i].getHor()>>shift, acMvTemp[i].getVer()>>shift, 0 ); DTRACE( g_trace_ctx, D_COMMON, " (%d) yy uiBitsBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest ); } +#endif uiCostBest = (Distortion)( floor( fWeight * (double)uiCostBest ) + (double)m_pcRdCost->getCost( uiBitsBest ) ); DTRACE( g_trace_ctx, D_COMMON, " (%d) uiBitsBest=%d, uiCostBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest, uiCostBest ); @@ -4415,7 +4751,18 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, dDeltaMv[1] = dAffinePara[1] * width + dAffinePara[0]; dDeltaMv[3] = -dAffinePara[3] * width + dAffinePara[2]; } +#if JVET_M0246_AFFINE_AMVR + int mvShift = MV_FRACTIONAL_BITS_DIFF - mvdPrecision; + int multiShift = 1 << ( MV_FRACTIONAL_BITS_DIFF + mvdPrecision ); + acDeltaMv[0] = Mv( ( int ) ( dDeltaMv[0] * multiShift + SIGN( dDeltaMv[0] ) * 0.5 ) << mvShift, ( int ) ( dDeltaMv[2] * multiShift + SIGN( dDeltaMv[2] ) * 0.5 ) << mvShift ); + acDeltaMv[1] = Mv( ( int ) ( dDeltaMv[1] * multiShift + SIGN( dDeltaMv[1] ) * 0.5 ) << mvShift, ( int ) ( dDeltaMv[3] * multiShift + SIGN( dDeltaMv[3] ) * 0.5 ) << mvShift ); + + if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) + { + acDeltaMv[2] = Mv( ( int ) ( dDeltaMv[4] * multiShift + SIGN( dDeltaMv[4] ) * 0.5 ) << mvShift, ( int ) ( dDeltaMv[5] * multiShift + SIGN( dDeltaMv[5] ) * 0.5 ) << mvShift ); + } +#else acDeltaMv[0] = Mv( (int)(dDeltaMv[0] * 4 + SIGN( dDeltaMv[0] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF, (int)(dDeltaMv[2] * 4 + SIGN( dDeltaMv[2] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF ); acDeltaMv[1] = Mv( (int)(dDeltaMv[1] * 4 + SIGN( dDeltaMv[1] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF, (int)(dDeltaMv[3] * 4 + SIGN( dDeltaMv[3] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF @@ -4426,11 +4773,20 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, acDeltaMv[2] = Mv( (int)(dDeltaMv[4] * 4 + SIGN( dDeltaMv[4] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF, (int)(dDeltaMv[5] * 4 + SIGN( dDeltaMv[5] ) * 0.5) << MV_FRACTIONAL_BITS_DIFF ); } - +#endif bool bAllZero = false; for ( int i = 0; i < mvNum; i++ ) { +#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 ) +#endif { bAllZero = false; break; @@ -4452,7 +4808,18 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, acMvTemp[i].hor = Clip3( -32768, 32767, acMvTemp[i].hor ); acMvTemp[i].ver = Clip3( -32768, 32767, acMvTemp[i].ver ); #endif - acMvTemp[i].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv == 0 ) + { +#endif + acMvTemp[i].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } + else if ( pu.cu->imv == 2 ) + { + acMvTemp[i].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT ); + } +#endif clipMv(acMvTemp[i], pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps); @@ -4466,6 +4833,9 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, // get cost with mv m_pcRdCost->setCostScale(0); uint32_t uiBitsTemp = ruiBits; +#if JVET_M0246_AFFINE_AMVR + uiBitsTemp += xCalcAffineMVBits( pu, acMvTemp, acMvPred, pu.cu->imv != 1 ); +#else for ( int i = 0; i < mvNum; i++ ) { m_pcRdCost->setPredictor( acMvPred[i] ); @@ -4481,7 +4851,7 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, } uiBitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor( acMvTemp[i].getHor()>>shift, acMvTemp[i].getVer()>>shift, 0 ); } - +#endif uiCostTemp = (Distortion)( floor( fWeight * (double)uiCostTemp ) + (double)m_pcRdCost->getCost( uiBitsTemp ) ); // store best cost and mv @@ -4501,6 +4871,9 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, // get cost with mv m_pcRdCost->setCostScale(0); uint32_t bitsTemp = ruiBits; +#if JVET_M0246_AFFINE_AMVR + bitsTemp += xCalcAffineMVBits( pu, ctrlPtMv, acMvPred, pu.cu->imv != 1 ); +#else for (int i = 0; i < mvNum; i++) { m_pcRdCost->setPredictor(acMvPred[i]); @@ -4516,6 +4889,7 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, } bitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor(ctrlPtMv[i].getHor() >> shift, ctrlPtMv[i].getVer() >> shift, 0); } +#endif costTemp = (Distortion)(floor(fWeight * (double)costTemp) + (double)m_pcRdCost->getCost(bitsTemp)); // store best cost and mv if (costTemp < uiCostBest) @@ -4529,9 +4903,16 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, if (uiCostBest <= AFFINE_ME_LIST_MVP_TH*m_hevcCost) { Mv mvPredTmp[3] = { acMvPred[0], acMvPred[1], acMvPred[2] }; - mvPredTmp[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - mvPredTmp[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); - mvPredTmp[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + mvPredTmp[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + mvPredTmp[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + mvPredTmp[2].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); +#if JVET_M0246_AFFINE_AMVR + } +#endif Mv mvME[3]; ::memcpy(mvME, acMv, sizeof(Mv) * 3); Mv dMv = mvME[0] - mvPredTmp[0]; @@ -4580,20 +4961,33 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, { int testPos[4][2] = { { -1, 0 },{ 0, -1 },{ 0, 1 },{ 1, 0 } }; Mv centerMv[3]; +#if JVET_M0246_AFFINE_AMVR + const uint32_t mvShift = pu.cu->imv == 1 ? 0 : ( pu.cu->imv == 2 ? ( MV_FRACTIONAL_BITS_DIFF << 1 ) : MV_FRACTIONAL_BITS_DIFF ); +#endif ::memcpy(centerMv, acMv, sizeof(Mv) * 3); acMvTemp[0] = centerMv[0]; for (int i = 0; i < 4; i++) { +#if JVET_M0246_AFFINE_AMVR + acMvTemp[1].set( centerMv[1].getHor() + ( testPos[i][0] << mvShift ), centerMv[1].getVer() + ( testPos[i][1] << mvShift ) ); +#else acMvTemp[1].set(centerMv[1].getHor() + (testPos[i][0] << MV_FRACTIONAL_BITS_DIFF), centerMv[1].getVer() + (testPos[i][1] << MV_FRACTIONAL_BITS_DIFF)); +#endif checkCPMVRdCost(acMvTemp); } } } } - - acMv[0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - acMv[1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); - acMv[2].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + if ( pu.cu->imv != 1 ) + { +#endif + acMv[0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + acMv[1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); + acMv[2].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER); +#if JVET_M0246_AFFINE_AMVR + } +#endif // free buffer for (int i = 0; i<iParaNum; i++) diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h index 6d63e96515f0889023b0448e805007d766c5a185..27030ab31ec24eddb4085f35b4a0f7ba54efb931 100644 --- a/source/Lib/EncoderLib/InterSearch.h +++ b/source/Lib/EncoderLib/InterSearch.h @@ -76,6 +76,20 @@ struct AffineMVInfo int x, y, w, h; }; +#if JVET_M0246_AFFINE_AMVR +typedef struct +{ + Mv acMvAffine4Para[2][2]; + Mv acMvAffine6Para[2][3]; + int16_t affine4ParaRefIdx[2]; + int16_t affine6ParaRefIdx[2]; + Distortion hevcCost[3]; + Distortion affineCost[3]; + bool affine4ParaAvail; + bool affine6ParaAvail; +} EncAffineMotion; +#endif + /// encoder search class class InterSearch : public InterPrediction, CrossComponentPrediction, AffineGradientSearch { @@ -103,7 +117,9 @@ private: int m_affMVListSize; int m_affMVListMaxSize; Distortion m_hevcCost; - +#if JVET_M0246_AFFINE_AMVR + EncAffineMotion m_affineMotion; +#endif protected: // interface to option EncCfg* m_pcEncCfg; @@ -190,6 +206,10 @@ public: m_affMVListSize = std::min(m_affMVListSize + 1, m_affMVListMaxSize); } } +#if JVET_M0246_AFFINE_AMVR + void resetSavedAffineMotion(); + void storeAffineMotion( Mv acAffineMv[2][3], int16_t affineRefIdx[2], EAffineModel affineType, int gbiIdx ); +#endif protected: /// sub-function for motion vector refinement used in fractional-pel accuracy @@ -280,7 +300,9 @@ protected: RefPicList eRefPicList, int iRefIdx ); - +#if JVET_M0246_AFFINE_AMVR + uint32_t xCalcAffineMVBits ( PredictionUnit& pu, Mv mvCand[3], Mv mvPred[3], bool mvHighPrec = false ); +#endif void xCopyAMVPInfo ( AMVPInfo* pSrc, AMVPInfo* pDst ); uint32_t xGetMvpIdxBits ( int iIdx, int iNum ); diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 5d4ea024ffd108d353f9f38b3971d13b22eff878..82300aae2c1bd65753949587c2561789de66badc 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -724,7 +724,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) #if JVET_M0255_FRACMMVD_SWITCH WRITE_FLAG( pcSPS->getDisFracMmvdEnabledFlag() ? 1 : 0, "sps_fracmmvd_disabled_flag" ); #endif - +#if JVET_M0246_AFFINE_AMVR + WRITE_FLAG( pcSPS->getAffineAmvrEnabledFlag() ? 1 : 0, "sps_affine_amvr_enabled_flag" ); +#endif #if HEVC_USE_SCALING_LISTS WRITE_FLAG( pcSPS->getScalingListFlag() ? 1 : 0, "scaling_list_enabled_flag" ); if(pcSPS->getScalingListFlag())