From 3fdc7d65efe18b73ca5cba129e04f28a23b43a84 Mon Sep 17 00:00:00 2001 From: rlliao <ruling.liao@sg.panasonic.com> Date: Thu, 1 Nov 2018 13:57:07 +0800 Subject: [PATCH] L0124 & L0208 Triangular shape prediction unit with the bug fix --- cfg/encoder_lowdelay_vtm.cfg | 1 + cfg/encoder_randomaccess_vtm.cfg | 1 + source/App/EncoderApp/EncApp.cpp | 3 + source/App/EncoderApp/EncAppCfg.cpp | 9 + source/App/EncoderApp/EncAppCfg.h | 3 + source/Lib/CommonLib/CodingStatistics.h | 8 + source/Lib/CommonLib/CommonDef.h | 8 + source/Lib/CommonLib/ContextModelling.cpp | 16 + source/Lib/CommonLib/ContextModelling.h | 3 + source/Lib/CommonLib/Contexts.cpp | 16 + source/Lib/CommonLib/Contexts.h | 4 + source/Lib/CommonLib/InterPrediction.cpp | 684 ++++++++++++++++++++++ source/Lib/CommonLib/InterPrediction.h | 8 + source/Lib/CommonLib/Rom.cpp | 84 +++ source/Lib/CommonLib/Rom.h | 10 + source/Lib/CommonLib/Slice.cpp | 6 + source/Lib/CommonLib/Slice.h | 7 + source/Lib/CommonLib/TypeDef.h | 10 + source/Lib/CommonLib/Unit.cpp | 6 + source/Lib/CommonLib/Unit.h | 3 + source/Lib/CommonLib/UnitTools.cpp | 489 ++++++++++++++++ source/Lib/CommonLib/UnitTools.h | 7 + source/Lib/DecoderLib/CABACReader.cpp | 39 ++ source/Lib/DecoderLib/CABACReader.h | 3 + source/Lib/DecoderLib/DecCu.cpp | 27 + source/Lib/DecoderLib/DecCu.h | 4 + source/Lib/DecoderLib/VLCReader.cpp | 3 + source/Lib/EncoderLib/CABACWriter.cpp | 37 ++ source/Lib/EncoderLib/CABACWriter.h | 3 + source/Lib/EncoderLib/EncCfg.h | 7 + source/Lib/EncoderLib/EncCu.cpp | 260 ++++++++ source/Lib/EncoderLib/EncCu.h | 13 + source/Lib/EncoderLib/EncLib.cpp | 3 + source/Lib/EncoderLib/EncModeCtrl.cpp | 19 +- source/Lib/EncoderLib/EncModeCtrl.h | 6 + source/Lib/EncoderLib/InterSearch.cpp | 6 + source/Lib/EncoderLib/VLCWriter.cpp | 3 + 37 files changed, 1818 insertions(+), 1 deletion(-) diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg index 2e9644e55..04f5162bb 100644 --- a/cfg/encoder_lowdelay_vtm.cfg +++ b/cfg/encoder_lowdelay_vtm.cfg @@ -130,6 +130,7 @@ ALF : 1 GBi : 1 GBiFast : 1 MHIntra : 1 +Triangle : 1 # Fast tools PBIntraFast : 1 diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg index 0bce50263..7e8715098 100644 --- a/cfg/encoder_randomaccess_vtm.cfg +++ b/cfg/encoder_randomaccess_vtm.cfg @@ -145,6 +145,7 @@ GBi : 1 GBiFast : 1 BIO : 1 MHIntra : 1 +Triangle : 1 # Fast tools PBIntraFast : 1 diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 13cfd5424..c4fb670b0 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -263,6 +263,9 @@ void EncApp::xInitLibCfg() #endif #if JVET_L0100_MULTI_HYPOTHESIS_INTRA m_cEncLib.setUseMHIntra ( m_MHIntra ); +#endif +#if JVET_L0124_L0208_TRIANGLE + m_cEncLib.setUseTriangle ( m_Triangle ); #endif // ADD_NEW_TOOL : (encoder app) add setting of tool enabling flags and associated parameters here diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 93ba95291..14ea3f1e3 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -868,6 +868,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #endif #if JVET_L0100_MULTI_HYPOTHESIS_INTRA ("MHIntra", m_MHIntra, false, "Enable MHIntra mode") +#endif +#if JVET_L0124_L0208_TRIANGLE + ("Triangle", m_Triangle, false, "Enable triangular shape motion vector prediction (0:off, 1:on) [default: on]") #endif // ADD_NEW_TOOL : (encoder app) add parsing parameters here @@ -1966,6 +1969,9 @@ bool EncAppCfg::xCheckParameter() #if JVET_L0646_GBI xConfirmPara( m_GBi, "GBi is only allowed with NEXT profile" ); xConfirmPara( m_GBiFast, "GBiFast is only allowed with NEXT profile" ); +#endif +#if JVET_L0124_L0208_TRIANGLE + xConfirmPara( m_Triangle, "Triangle is only allowed with NEXT profile" ); #endif // ADD_NEW_TOOL : (parameter check) add a check for next tools here } @@ -3191,6 +3197,9 @@ void EncAppCfg::xPrintParameter() #endif #if JVET_L0100_MULTI_HYPOTHESIS_INTRA msg(VERBOSE, "MHIntra:%d ", m_MHIntra); +#endif +#if JVET_L0124_L0208_TRIANGLE + msg( VERBOSE, "Triangle:%d ", m_Triangle ); #endif } // ADD_NEW_TOOL (add some output indicating the usage of tools) diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 27b243101..0bc0a2446 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -240,6 +240,9 @@ protected: #if JVET_L0100_MULTI_HYPOTHESIS_INTRA bool m_MHIntra; +#endif +#if JVET_L0124_L0208_TRIANGLE + bool m_Triangle; #endif // ADD_NEW_TOOL : (encoder app) add tool enabling flags and associated parameters here diff --git a/source/Lib/CommonLib/CodingStatistics.h b/source/Lib/CommonLib/CodingStatistics.h index 3c82f4abe..a00a49b10 100644 --- a/source/Lib/CommonLib/CodingStatistics.h +++ b/source/Lib/CommonLib/CodingStatistics.h @@ -108,6 +108,10 @@ enum CodingStatisticsType STATS__TOOL_EMT, #if JVET_L0100_MULTI_HYPOTHESIS_INTRA STATS__CABAC_BITS__MH_INTRA_FLAG, +#endif +#if JVET_L0124_L0208_TRIANGLE + STATS__CABAC_BITS__TRIANGLE_FLAG, + STATS__CABAC_BITS__TRIANGLE_INDEX, #endif STATS__TOOL_TOTAL, STATS__NUM_STATS @@ -183,6 +187,10 @@ static inline const char* getName(CodingStatisticsType name) "CABAC_BITS__EMT_TU_INDX", #if JVET_L0100_MULTI_HYPOTHESIS_INTRA "CABAC_BITS__MH_INTRA_FLAG", +#endif +#if JVET_L0124_L0208_TRIANGLE + "CABAC_BITS__TRIANGLE_FLAG", + "CABAC_BITS__TRIANGLE_INDEX", #endif "CABAC_BITS__OTHER", "CABAC_BITS__INVALID", diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 59fa2e336..f21d96a90 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -415,6 +415,14 @@ static const int MAX_LADF_INTERVALS = 5; /// max n static const int NTAPS_BILINEAR = 2; ///< Number of taps for bilinear filter #endif +#if JVET_L0124_L0208_TRIANGLE +static const int TRIANGLE_MAX_NUM_UNI_CANDS = 5; +static const int TRIANGLE_MAX_NUM_CANDS_MEM = 7; +static const int TRIANGLE_MAX_NUM_CANDS = 40; +static const int TRIANGLE_MAX_NUM_SATD_CANDS = 3; +static const int TRIANGLE_MIN_SIZE = 8 * 8; +#endif + // ==================================================================================================================== // Macro functions // ==================================================================================================================== diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index 300e861c3..f2787ae42 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -359,6 +359,22 @@ unsigned DeriveCtx::CtxBTsplit(const CodingStructure& cs, Partitioner& partition return ctx; } +#if JVET_L0124_L0208_TRIANGLE +unsigned DeriveCtx::CtxTriangleFlag( const CodingUnit& cu ) +{ + const CodingStructure *cs = cu.cs; + unsigned ctxId = 0; + + const CodingUnit *cuLeft = cs->getCURestricted( cu.lumaPos().offset( -1, 0 ), cu, CH_L ); + ctxId = ( cuLeft && cuLeft->triangle ) ? 1 : 0; + + const CodingUnit *cuAbove = cs->getCURestricted( cu.lumaPos().offset( 0, -1 ), cu, CH_L ); + ctxId += ( cuAbove && cuAbove->triangle ) ? 1 : 0; + + return ctxId; +} +#endif + void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx ) { diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index 2e03bc1b4..806b6cc57 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -353,6 +353,9 @@ unsigned CtxInterDir ( const PredictionUnit& pu ); unsigned CtxSkipFlag ( const CodingUnit& cu ); unsigned CtxIMVFlag ( const CodingUnit& cu ); unsigned CtxAffineFlag( const CodingUnit& cu ); +#if JVET_L0124_L0208_TRIANGLE +unsigned CtxTriangleFlag( const CodingUnit& cu ); +#endif } #endif // __CONTEXTMODELLING__ diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 7fd0d1de7..4130a6462 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -823,6 +823,22 @@ const CtxSet ContextSetCfg::MHIntraPredMode = ContextSetCfg::addCtxSet }); #endif +#if JVET_L0124_L0208_TRIANGLE +const CtxSet ContextSetCfg::TriangleFlag = ContextSetCfg::addCtxSet +({ + { 151, 137, 154, }, + { 151, 137, 154, }, + { CNU, CNU, CNU, }, +}); + +const CtxSet ContextSetCfg::TriangleIdx = ContextSetCfg::addCtxSet +({ + { 140, }, + { 140, }, + { CNU, }, +}); +#endif + const unsigned ContextSetCfg::NumberOfContexts = (unsigned)ContextSetCfg::sm_InitTables[0].size(); diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 31b4bafe1..718a8b234 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -206,6 +206,10 @@ public: #if JVET_L0100_MULTI_HYPOTHESIS_INTRA static const CtxSet MHIntraFlag; static const CtxSet MHIntraPredMode; +#endif +#if JVET_L0124_L0208_TRIANGLE + static const CtxSet TriangleFlag; + static const CtxSet TriangleIdx; #endif static const unsigned NumberOfContexts; diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp index 7a7979567..410cf1eee 100644 --- a/source/Lib/CommonLib/InterPrediction.cpp +++ b/source/Lib/CommonLib/InterPrediction.cpp @@ -120,6 +120,10 @@ void InterPrediction::destroy() } } +#if JVET_L0124_L0208_TRIANGLE + m_tmpTriangleBuf.destroy(); +#endif + #if JVET_L0265_AFF_MINIMUM4X4 if (m_storedMv != nullptr) { @@ -175,6 +179,9 @@ void InterPrediction::init( RdCost* pcRdCost, ChromaFormat chromaFormatIDC ) } } +#if JVET_L0124_L0208_TRIANGLE + m_tmpTriangleBuf.create(UnitArea(chromaFormatIDC, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE))); +#endif m_iRefListIdx = -1; @@ -481,7 +488,11 @@ void InterPrediction::xPredInterBi(PredictionUnit& pu, PelUnitBuf &pcYuvPred) } else { +#if JVET_L0124_L0208_TRIANGLE + xPredInterUni ( pu, eRefPicList, pcMbBuf, pu.cu->triangle, false ); +#else xPredInterUni ( pu, eRefPicList, pcMbBuf, false ); +#endif } } } @@ -1069,10 +1080,24 @@ void InterPrediction::xWeightedAverage( const PredictionUnit& pu, const CPelUnit } else if( iRefIdx0 >= 0 && iRefIdx1 < 0 ) { +#if JVET_L0124_L0208_TRIANGLE + if( pu.cu->triangle ) + { + pcYuvDst.copyFrom( pcYuvSrc0 ); + } + else +#endif pcYuvDst.copyClip( pcYuvSrc0, clpRngs ); } else if( iRefIdx0 < 0 && iRefIdx1 >= 0 ) { +#if JVET_L0124_L0208_TRIANGLE + if( pu.cu->triangle ) + { + pcYuvDst.copyFrom( pcYuvSrc1 ); + } + else +#endif pcYuvDst.copyClip( pcYuvSrc1, clpRngs ); } } @@ -1152,6 +1177,665 @@ int InterPrediction::rightShiftMSB(int numer, int denom) } #endif +#if JVET_L0124_L0208_TRIANGLE +void InterPrediction::motionCompensation4Triangle( CodingUnit &cu, MergeCtx &TriangleMrgCtx, const bool SplitDir, const uint8_t CandIdx0, const uint8_t CandIdx1 ) +{ + for( auto &pu : CU::traversePUs( cu ) ) + { + const UnitArea localUnitArea( cu.cs->area.chromaFormat, Area( 0, 0, pu.lwidth(), pu.lheight() ) ); + PelUnitBuf tmpTriangleBuf = m_tmpTriangleBuf.getBuf( localUnitArea ); + PelUnitBuf predBuf = cu.cs->getPredBuf( pu ); + + TriangleMrgCtx.setMergeInfo( pu, CandIdx0 ); + PU::spanMotionInfo( pu ); + motionCompensation( pu, tmpTriangleBuf ); + + TriangleMrgCtx.setMergeInfo( pu, CandIdx1 ); + PU::spanMotionInfo( pu ); + motionCompensation( pu, predBuf ); + + TriangleWeighting( pu, PU::isTriangleEhancedWeight(pu, TriangleMrgCtx, CandIdx0, CandIdx1), SplitDir, MAX_NUM_CHANNEL_TYPE, predBuf, tmpTriangleBuf, predBuf ); + } +} + +void InterPrediction::TriangleWeighting( PredictionUnit &pu, bool ehanced, const bool SplitDir, int32_t channel, PelUnitBuf& PredDst, PelUnitBuf& PredSrc0, PelUnitBuf& PredSrc1 ) +{ + const uint32_t WidthY = pu.lumaSize() .width; + const uint32_t HeightY = pu.lumaSize() .height; + const uint32_t WidthUV = pu.chromaSize().width; + const uint32_t HeightUV = pu.chromaSize().height; + + Pel* DstY = PredDst .get(COMPONENT_Y).buf; + Pel* Src0Y = PredSrc0.get(COMPONENT_Y).buf; + Pel* Src1Y = PredSrc1.get(COMPONENT_Y).buf; + Pel* DstU = PredDst .get(COMPONENT_Cb).buf; + Pel* Src0U = PredSrc0.get(COMPONENT_Cb).buf; + Pel* Src1U = PredSrc1.get(COMPONENT_Cb).buf; + Pel* DstV = PredDst .get(COMPONENT_Cr).buf; + Pel* Src0V = PredSrc0.get(COMPONENT_Cr).buf; + Pel* Src1V = PredSrc1.get(COMPONENT_Cr).buf; + + int strideY = PredDst .get(COMPONENT_Y).stride - WidthY; + int stride0Y = PredSrc0.get(COMPONENT_Y).stride - WidthY; + int stride1Y = PredSrc1.get(COMPONENT_Y).stride - WidthY; + int strideU = PredDst .get(COMPONENT_Cb).stride - WidthUV; + int stride0U = PredSrc0.get(COMPONENT_Cb).stride - WidthUV; + int stride1U = PredSrc1.get(COMPONENT_Cb).stride - WidthUV; + + const bool format = PredDst.chromaFormat == CHROMA_444 ? 0 : 1; + + const int32_t BlendLengthY = g_TriangleWeightLengthLuma[ehanced]; + const int32_t BlendLengthUV = g_TriangleWeightLengthChroma[format][ehanced]; + + const char log2WeightBase = 3; + const ClpRng clipRngY = pu.cu->slice->clpRngs().comp[0]; + const ClpRng clipRngU = pu.cu->slice->clpRngs().comp[1]; + const ClpRng clipRngV = pu.cu->slice->clpRngs().comp[2]; + const int clipbdY = clipRngY.bd; + const int clipbdU = clipRngU.bd; + const int clipbdV = clipRngV.bd; + const int shiftNumY = std::max<int>(2, (IF_INTERNAL_PREC - clipbdY)) + log2WeightBase; + const int offsetY = (1 << (shiftNumY - 1)) + (IF_INTERNAL_OFFS << log2WeightBase); + const int shiftNumU = std::max<int>(2, (IF_INTERNAL_PREC - clipbdU)) + log2WeightBase; + const int offsetU = (1 << (shiftNumU - 1)) + (IF_INTERNAL_OFFS << log2WeightBase); + const int shiftNumV = std::max<int>(2, (IF_INTERNAL_PREC - clipbdV)) + log2WeightBase; + const int offsetV = (1 << (shiftNumV - 1)) + (IF_INTERNAL_OFFS << log2WeightBase); + + const int shiftDefault = std::max<int>(2, (IF_INTERNAL_PREC - clipbdY)); + const int offsetDefault = (1<<(shiftDefault-1)) + IF_INTERNAL_OFFS; + + const Pel* TmpPelWeighted; + + if( channel == CHANNEL_TYPE_LUMA || channel == MAX_NUM_CHANNEL_TYPE ) + { + if( SplitDir == TRIANGLE_DIR_135 && WidthY == HeightY ) + { + int32_t BlendStart = 0 - (BlendLengthY >> 1); + int32_t BlendEnd = 0 + (BlendLengthY >> 1); + for( int32_t y = 0; y < HeightY; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src1Y++ + offsetDefault, shiftDefault ), clipRngY ); + } + Src0Y += x; + + int32_t TmpBlendStart = std::max( (int32_t)0, BlendStart ); + int32_t TmpBlendEnd = std::min( BlendEnd, (int32_t)(WidthY - 1) ); + TmpPelWeighted = g_TrianglePelWeightedLuma[SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs( BlendStart ); + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x++ ) + { + *DstY++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0Y++) + ((8 - (*TmpPelWeighted)) * (*Src1Y++)) + offsetY), shiftNumY ), clipRngY ); + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthY; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src0Y++ + offsetDefault, shiftDefault ), clipRngY ); + Src1Y++; + } + + BlendStart++; + BlendEnd++; + + DstY += strideY; + Src0Y += stride0Y; + Src1Y += stride1Y; + } + } + else if( SplitDir == TRIANGLE_DIR_135 && WidthY > HeightY ) + { + int32_t RatioWH = WidthY / HeightY; + int32_t BlendStart = 0 - (BlendLengthY >> 1) * RatioWH; + int32_t BlendEnd = BlendStart + BlendLengthY * RatioWH - 1; + for( int32_t y = 0; y < HeightY; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src1Y++ + offsetDefault, shiftDefault ), clipRngY ); + } + Src0Y += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthY - 1) ); + TmpPelWeighted = g_TrianglePelWeightedLuma[SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart) / RatioWH; + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x += RatioWH ) + { + for( int32_t Cnt = 0; Cnt < RatioWH; Cnt++ ) + { + *DstY++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0Y++) + ((8 - (*TmpPelWeighted)) * (*Src1Y++)) + offsetY), shiftNumY ), clipRngY ); + } + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthY; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src0Y++ + offsetDefault, shiftDefault ), clipRngY ); + Src1Y++; + } + + BlendStart += RatioWH; + BlendEnd += RatioWH; + + DstY += strideY; + Src0Y += stride0Y; + Src1Y += stride1Y; + } + } + else if( SplitDir == TRIANGLE_DIR_135 && WidthY < HeightY ) + { + int32_t RatioHW = HeightY / WidthY; + int32_t BlendStart = 0 - (BlendLengthY >> 1); + int32_t BlendEnd = BlendStart + BlendLengthY - 1; + int32_t Cnt = RatioHW; + for( int32_t y = 0; y < HeightY; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src1Y++ + offsetDefault, shiftDefault ), clipRngY ); + } + Src0Y += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthY - 1)); + TmpPelWeighted = g_TrianglePelWeightedLuma[SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart); + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x++ ) + { + *DstY++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0Y++) + ((8 - (*TmpPelWeighted)) * (*Src1Y++)) + offsetY), shiftNumY ), clipRngY ); + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthY; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src0Y++ + offsetDefault, shiftDefault ), clipRngY ); + Src1Y++; + } + + Cnt--; + if( Cnt <= 0 ) + { + BlendStart++; + BlendEnd++; + Cnt = RatioHW; + } + + DstY += strideY; + Src0Y += stride0Y; + Src1Y += stride1Y; + } + } + else if( SplitDir == TRIANGLE_DIR_45 && WidthY == HeightY ) + { + int32_t BlendStart = (WidthY - 1) - (BlendLengthY >> 1); + int32_t BlendEnd = (WidthY - 1) + (BlendLengthY >> 1); + for( int32_t y = 0; y < HeightY; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src0Y++ + offsetDefault, shiftDefault ), clipRngY ); + } + Src1Y += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthY - 1)); + TmpPelWeighted = g_TrianglePelWeightedLuma[SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart); + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x++ ) + { + *DstY++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0Y++) + ((8 - (*TmpPelWeighted)) * (*Src1Y++)) + offsetY), shiftNumY ), clipRngY ); + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthY; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src1Y++ + offsetDefault, shiftDefault ), clipRngY ); + Src0Y++; + } + + BlendStart--; + BlendEnd--; + + DstY += strideY; + Src0Y += stride0Y; + Src1Y += stride1Y; + } + } + else if( SplitDir == TRIANGLE_DIR_45 && WidthY > HeightY ) + { + int32_t RatioWH = WidthY / HeightY; + int32_t BlendStart = WidthY - ((BlendLengthY + 1) >> 1) * RatioWH; + int32_t BlendEnd = BlendStart + BlendLengthY * RatioWH - 1; + for( int32_t y = 0; y < HeightY; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src0Y++ + offsetDefault, shiftDefault ), clipRngY ); + } + Src1Y += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthY - 1)); + TmpPelWeighted = g_TrianglePelWeightedLuma[SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart) / RatioWH; + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x += RatioWH ) + { + for( int32_t Cnt = 0; Cnt < RatioWH; Cnt++ ) + { + *DstY++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0Y++) + ((8 - (*TmpPelWeighted)) * (*Src1Y++)) + offsetY), shiftNumY ), clipRngY ); + } + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthY; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src1Y++ + offsetDefault, shiftDefault ), clipRngY ); + Src0Y++; + } + + BlendStart -= RatioWH; + BlendEnd -= RatioWH; + + DstY += strideY; + Src0Y += stride0Y; + Src1Y += stride1Y; + } + } + else if( SplitDir == TRIANGLE_DIR_45 && WidthY < HeightY ) + { + int32_t RatioHW = HeightY / WidthY; + int32_t BlendStart = WidthY - ((BlendLengthY + 1) >> 1); + int32_t BlendEnd = BlendStart + BlendLengthY - 1; + int32_t Cnt = RatioHW; + for( int32_t y = 0; y < HeightY; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src0Y++ + offsetDefault, shiftDefault ), clipRngY ); + } + Src1Y += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthY - 1)); + TmpPelWeighted = g_TrianglePelWeightedLuma[SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart); + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x++ ) + { + *DstY++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0Y++) + ((8 - (*TmpPelWeighted)) * (*Src1Y++)) + offsetY), shiftNumY ), clipRngY ); + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthY; x++ ) + { + *DstY++ = ClipPel( rightShift( *Src1Y++ + offsetDefault, shiftDefault ), clipRngY ); + Src0Y++; + } + + Cnt--; + if( Cnt <= 0 ) + { + BlendStart--; + BlendEnd--; + Cnt = RatioHW; + } + + DstY += strideY; + Src0Y += stride0Y; + Src1Y += stride1Y; + } + } + else + { + assert(0); + } + } + + if( channel == CHANNEL_TYPE_CHROMA || channel == MAX_NUM_CHANNEL_TYPE ) + { + if( SplitDir == TRIANGLE_DIR_135 && WidthY == HeightY ) + { + int32_t BlendStart = 0 - (BlendLengthUV >> 1); + int32_t BlendEnd = 0 + (BlendLengthUV >> 1); + for( int32_t y = 0; y < HeightUV; y++ ) + { + int x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src1U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src1V++ + offsetDefault, shiftDefault ), clipRngV ); + } + Src0U += x; + Src0V += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthUV - 1)); + TmpPelWeighted = g_TrianglePelWeightedChroma[format][SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart); + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x++ ) + { + *DstU++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0U++) + ((8 - (*TmpPelWeighted)) * (*Src1U++)) + offsetU), shiftNumU ), clipRngU ); + *DstV++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0V++) + ((8 - (*TmpPelWeighted)) * (*Src1V++)) + offsetV), shiftNumV ), clipRngV ); + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthUV; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src0U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src0V++ + offsetDefault, shiftDefault ), clipRngV ); + Src1U++; + Src1V++; + } + + BlendStart++; + BlendEnd++; + + DstU += strideU; + Src0U += stride0U; + Src1U += stride1U; + DstV += strideU; + Src0V += stride0U; + Src1V += stride1U; + } + } + else if( SplitDir == TRIANGLE_DIR_135 && WidthY > HeightY ) + { + int32_t RatioWH = WidthY / HeightY; + int32_t BlendStart = 0 - (BlendLengthUV >> 1) * RatioWH; + int32_t BlendEnd = BlendStart + BlendLengthUV * RatioWH - 1; + for( int32_t y = 0; y < HeightUV; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src1U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src1V++ + offsetDefault, shiftDefault ), clipRngV ); + } + Src0U += x; + Src0V += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthUV - 1)); + TmpPelWeighted = g_TrianglePelWeightedChroma[format][SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart) / RatioWH; + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x += RatioWH ) + { + for( int32_t Cnt = 0; Cnt < RatioWH; Cnt++ ) + { + *DstU++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0U++) + ((8 - (*TmpPelWeighted)) * (*Src1U++)) + offsetU), shiftNumU ), clipRngU ); + *DstV++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0V++) + ((8 - (*TmpPelWeighted)) * (*Src1V++)) + offsetV), shiftNumV ), clipRngV ); + } + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthUV; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src0U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src0V++ + offsetDefault, shiftDefault ), clipRngV ); + Src1U++; + Src1V++; + } + + BlendStart += RatioWH; + BlendEnd += RatioWH; + + DstU += strideU; + Src0U += stride0U; + Src1U += stride1U; + DstV += strideU; + Src0V += stride0U; + Src1V += stride1U; + } + } + else if( SplitDir == TRIANGLE_DIR_135 && WidthY < HeightY ) + { + int32_t RatioHW = HeightY / WidthY; + int32_t Cnt = RatioHW; + int32_t BlendStart = 0 - (BlendLengthUV >> 1); + int32_t BlendEnd = BlendStart + BlendLengthUV - 1; + for( int32_t y = 0; y < HeightUV; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src1U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src1V++ + offsetDefault, shiftDefault ), clipRngV ); + } + Src0U += x; + Src0V += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthUV - 1)); + TmpPelWeighted = g_TrianglePelWeightedChroma[format][SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart); + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x++ ) + { + *DstU++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0U++) + ((8 - (*TmpPelWeighted)) * (*Src1U++)) + offsetU), shiftNumU ), clipRngU ); + *DstV++ = ClipPel( rightShift( ((*TmpPelWeighted)*(*Src0V++) + ((8 - (*TmpPelWeighted)) * (*Src1V++)) + offsetV), shiftNumV ), clipRngV ); + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthUV; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src0U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src0V++ + offsetDefault, shiftDefault ), clipRngV ); + Src1U++; + Src1V++; + } + + Cnt--; + if( Cnt <= 0 ) + { + BlendStart++; + BlendEnd++; + Cnt = RatioHW; + } + + DstU += strideU; + Src0U += stride0U; + Src1U += stride1U; + DstV += strideU; + Src0V += stride0U; + Src1V += stride1U; + } + } + else if( SplitDir == TRIANGLE_DIR_45 && WidthY == HeightY ) + { + int32_t BlendStart = (WidthUV - 1) - (BlendLengthUV >> 1); + int32_t BlendEnd = (WidthUV - 1) + (BlendLengthUV >> 1); + for( int32_t y = 0; y < HeightUV; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src0U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src0V++ + offsetDefault, shiftDefault ), clipRngV ); + } + Src1U += x; + Src1V += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthUV - 1)); + TmpPelWeighted = g_TrianglePelWeightedChroma[format][SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart); + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x++ ) + { + *DstU++ = ClipPel( rightShift(((*TmpPelWeighted)*(*Src0U++) + ((8 - (*TmpPelWeighted)) * (*Src1U++)) + offsetU), shiftNumU ), clipRngU ); + *DstV++ = ClipPel( rightShift(((*TmpPelWeighted)*(*Src0V++) + ((8 - (*TmpPelWeighted)) * (*Src1V++)) + offsetV), shiftNumV ), clipRngV ); + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthUV; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src1U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src1V++ + offsetDefault, shiftDefault ), clipRngV ); + Src0U++; + Src0V++; + } + + BlendStart--; + BlendEnd--; + + DstU += strideU; + Src0U += stride0U; + Src1U += stride1U; + DstV += strideU; + Src0V += stride0U; + Src1V += stride1U; + } + } + else if( SplitDir == TRIANGLE_DIR_45 && WidthY > HeightY ) + { + int32_t RatioWH = WidthY / HeightY; + int32_t BlendStart = WidthUV - ((BlendLengthUV + 1) >> 1) * RatioWH; + int32_t BlendEnd = BlendStart + BlendLengthUV * RatioWH - 1; + for( int32_t y = 0; y < HeightUV; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src0U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src0V++ + offsetDefault, shiftDefault ), clipRngV ); + } + Src1U += x; + Src1V += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthUV - 1)); + TmpPelWeighted = g_TrianglePelWeightedChroma[format][SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart) / RatioWH; + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x += RatioWH ) + { + for( int32_t Cnt = 0; Cnt < RatioWH; Cnt++ ) + { + *DstU++ = ClipPel( rightShift(((*TmpPelWeighted)*(*Src0U++) + ((8 - (*TmpPelWeighted)) * (*Src1U++)) + offsetU), shiftNumU ), clipRngU ); + *DstV++ = ClipPel( rightShift(((*TmpPelWeighted)*(*Src0V++) + ((8 - (*TmpPelWeighted)) * (*Src1V++)) + offsetV), shiftNumV ), clipRngV ); + } + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthUV; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src1U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src1V++ + offsetDefault, shiftDefault ), clipRngV ); + Src0U++; + Src0V++; + } + + BlendStart -= RatioWH; + BlendEnd -= RatioWH; + + DstU += strideU; + Src0U += stride0U; + Src1U += stride1U; + DstV += strideU; + Src0V += stride0U; + Src1V += stride1U; + } + } + else if( SplitDir == TRIANGLE_DIR_45 && WidthY < HeightY ) + { + int32_t RatioHW = HeightY / WidthY; + int32_t BlendStart = WidthUV - ((BlendLengthUV + 1) >> 1); + int32_t BlendEnd = BlendStart + BlendLengthUV - 1; + int32_t Cnt = RatioHW; + for( int32_t y = 0; y < HeightUV; y++ ) + { + int32_t x = 0; + for( x = 0; x < BlendStart; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src0U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src0V++ + offsetDefault, shiftDefault ), clipRngV ); + } + Src1U += x; + Src1V += x; + + int32_t TmpBlendStart = std::max((int32_t)0, BlendStart); + int32_t TmpBlendEnd = std::min(BlendEnd, (int32_t)(WidthUV - 1)); + TmpPelWeighted = g_TrianglePelWeightedChroma[format][SplitDir][ehanced]; + if( BlendStart < 0 ) + { + TmpPelWeighted += abs(BlendStart); + } + for( x = TmpBlendStart; x <= TmpBlendEnd; x++ ) + { + *DstU++ = ClipPel( rightShift(((*TmpPelWeighted)*(*Src0U++) + ((8 - (*TmpPelWeighted)) * (*Src1U++)) + offsetU), shiftNumU ), clipRngU ); + *DstV++ = ClipPel( rightShift(((*TmpPelWeighted)*(*Src0V++) + ((8 - (*TmpPelWeighted)) * (*Src1V++)) + offsetV), shiftNumV ), clipRngV ); + TmpPelWeighted++; + } + + for( x = BlendEnd + 1; x < WidthUV; x++ ) + { + *DstU++ = ClipPel( rightShift( *Src1U++ + offsetDefault, shiftDefault ), clipRngU ); + *DstV++ = ClipPel( rightShift( *Src1V++ + offsetDefault, shiftDefault ), clipRngV ); + Src0U++; + Src0V++; + } + + Cnt--; + if( Cnt <= 0 ) + { + BlendStart--; + BlendEnd--; + Cnt = RatioHW; + } + + DstU += strideU; + Src0U += stride0U; + Src1U += stride1U; + DstV += strideU; + Src0V += stride0U; + Src1V += stride1U; + } + } + else + { + assert(0); + } + } +} +#endif + #if JVET_J0090_MEMORY_BANDWITH_MEASURE void InterPrediction::cacheAssign( CacheModel *cache ) { diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h index eb7cf48dd..4f13cb9c8 100644 --- a/source/Lib/CommonLib/InterPrediction.h +++ b/source/Lib/CommonLib/InterPrediction.h @@ -91,6 +91,9 @@ protected: RdCost* m_pcRdCost; int m_iRefListIdx; +#if JVET_L0124_L0208_TRIANGLE + PelStorage m_tmpTriangleBuf; +#endif #if JVET_L0265_AFF_MINIMUM4X4 Mv* m_storedMv; #endif @@ -149,6 +152,11 @@ public: void motionCompensation (CodingUnit &cu, const RefPicList &eRefPicList = REF_PIC_LIST_X ); +#if JVET_L0124_L0208_TRIANGLE + void motionCompensation4Triangle( CodingUnit &cu, MergeCtx &TriangleMrgCtx, const bool SplitDir, const uint8_t CandIdx0, const uint8_t CandIdx1 ); + void TriangleWeighting ( PredictionUnit &pu, bool ehanced, const bool SplitDir, int32_t channel, PelUnitBuf& PredDst, PelUnitBuf& PredSrc0, PelUnitBuf& PredSrc1 ); +#endif + #if JVET_J0090_MEMORY_BANDWITH_MEASURE void cacheAssign( CacheModel *cache ); #endif diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp index e9972bf93..1ff35211c 100644 --- a/source/Lib/CommonLib/Rom.cpp +++ b/source/Lib/CommonLib/Rom.cpp @@ -528,6 +528,30 @@ void initROM() //-------------------------------------------------------------------------------------------------- } } + +#if JVET_L0124_L0208_TRIANGLE + for( int IdxH = MAX_CU_DEPTH - MIN_CU_LOG2; IdxH >= 0; --IdxH ) + { + for( int IdxW = MAX_CU_DEPTH - MIN_CU_LOG2; IdxW >= 0; --IdxW ) + { + int numW = 1 << IdxW; + int numH = 1 << IdxH; + int ratioW = std::max( 0, IdxW - IdxH ); + int ratioH = std::max( 0, IdxH - IdxW ); + int sum = std::max( (numW >> ratioW), (numH >> ratioH) ) - 1; + for( int y = 0; y < numH; y++ ) + { + int IdxY = y >> ratioH; + for( int x = 0; x < numW; x++ ) + { + int IdxX = x >> ratioW; + g_TriangleMvStorage[TRIANGLE_DIR_135][IdxH][IdxW][y][x] = (IdxX == IdxY) ? 2 : (IdxX > IdxY ? 0 : 1); + g_TriangleMvStorage[TRIANGLE_DIR_45][IdxH][IdxW][y][x] = (IdxX + IdxY == sum) ? 2 : (IdxX + IdxY > sum ? 1 : 0); + } + } + } + } +#endif } void destroyROM() @@ -883,5 +907,65 @@ const uint8_t g_NonMPM[257] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8 }; +#if JVET_L0124_L0208_TRIANGLE +const Pel g_TrianglePelWeightedLuma[TRIANGLE_DIR_NUM][2][7] = +{ + { // TRIANGLE_DIR_135 + { 1, 2, 4, 6, 7, 0, 0 }, + { 1, 2, 3, 4, 5, 6, 7 } + }, + { // TRIANGLE_DIR_45 + { 7, 6, 4, 2, 1, 0, 0 }, + { 7, 6, 5, 4, 3, 2, 1 } + } +}; +const Pel g_TrianglePelWeightedChroma[2][TRIANGLE_DIR_NUM][2][7] = +{ + { // 444 format + { // TRIANGLE_DIR_135 + { 1, 2, 4, 6, 7, 0, 0 }, + { 1, 2, 3, 4, 5, 6, 7 } + }, + { // TRIANGLE_DIR_45 + { 7, 6, 4, 2, 1, 0, 0 }, + { 7, 6, 5, 4, 3, 2, 1 } + } + }, + { // 420 format + { // TRIANGLE_DIR_135 + { 1, 4, 7, 0, 0, 0, 0 }, + { 2, 4, 6, 0, 0, 0, 0 } + }, + { // TRIANGLE_DIR_45 + { 7, 4, 1, 0, 0, 0, 0 }, + { 6, 4, 2, 0, 0, 0, 0 } + } + } +}; + +const uint8_t g_TriangleWeightLengthLuma[2] = { 5, 7 }; +const uint8_t g_TriangleWeightLengthChroma[2][2] = { { 5, 7 }, { 3, 3 } }; + + uint8_t g_TriangleMvStorage[TRIANGLE_DIR_NUM][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_SIZE >> MIN_CU_LOG2][MAX_CU_SIZE >> MIN_CU_LOG2]; +const uint8_t g_TriangleCombination[TRIANGLE_MAX_NUM_CANDS][3] = +{ + { 0, 1, 0 }, { 1, 0, 1 }, { 1, 0, 2 }, { 0, 0, 1 }, { 0, 2, 0 }, + { 1, 0, 3 }, { 1, 0, 4 }, { 1, 1, 0 }, { 0, 3, 0 }, { 0, 4, 0 }, + { 0, 0, 2 }, { 0, 1, 2 }, { 1, 1, 2 }, { 0, 0, 4 }, { 0, 0, 3 }, + { 0, 1, 3 }, { 0, 1, 4 }, { 1, 1, 4 }, { 1, 1, 3 }, { 1, 2, 1 }, + { 1, 2, 0 }, { 0, 2, 1 }, { 0, 4, 3 }, { 1, 3, 0 }, { 1, 3, 2 }, + { 1, 3, 4 }, { 1, 4, 0 }, { 1, 3, 1 }, { 1, 2, 3 }, { 1, 4, 1 }, + { 0, 4, 1 }, { 0, 2, 3 }, { 1, 4, 2 }, { 0, 3, 2 }, { 1, 4, 3 }, + { 0, 3, 1 }, { 0, 2, 4 }, { 1, 2, 4 }, { 0, 4, 2 }, { 0, 3, 4 }, +}; + +const uint8_t g_TriangleIdxBins[TRIANGLE_MAX_NUM_CANDS] = +{ + 2, 2, 4, 4, 4, 4, 6, 6, 6, 6, + 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 +}; +#endif //! \} diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h index ba99b1608..56e2f392e 100644 --- a/source/Lib/CommonLib/Rom.h +++ b/source/Lib/CommonLib/Rom.h @@ -270,5 +270,15 @@ constexpr uint8_t g_tbMax[257] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, //! \} +#if JVET_L0124_L0208_TRIANGLE +extern const Pel g_TrianglePelWeightedLuma[TRIANGLE_DIR_NUM][2][7]; +extern const Pel g_TrianglePelWeightedChroma[2][TRIANGLE_DIR_NUM][2][7]; +extern const uint8_t g_TriangleWeightLengthLuma[2]; +extern const uint8_t g_TriangleWeightLengthChroma[2][2]; +extern uint8_t g_TriangleMvStorage[TRIANGLE_DIR_NUM][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_DEPTH - MIN_CU_LOG2 + 1][MAX_CU_SIZE >> MIN_CU_LOG2][MAX_CU_SIZE >> MIN_CU_LOG2]; +extern const uint8_t g_TriangleCombination[TRIANGLE_MAX_NUM_CANDS][3]; +extern const uint8_t g_TriangleIdxBins[TRIANGLE_MAX_NUM_CANDS]; +#endif + #endif //__TCOMROM__ diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 366b4ae30..af439fd99 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1651,6 +1651,9 @@ void Slice::updateMotionLUTs(LutMotionCand* lutMC, CodingUnit & cu) { PredictionUnit *selectedPU = cu.firstPU; if (cu.affine) { return; } +#if JVET_L0124_L0208_TRIANGLE + if (cu.triangle) { return; } +#endif MotionInfo newMi = selectedPU->getMotionInfo(); addMotionInfoToLUTs(lutMC, newMi); @@ -1757,6 +1760,9 @@ SPSNext::SPSNext( SPS& sps ) #if JVET_L0100_MULTI_HYPOTHESIS_INTRA , m_MHIntra ( false ) #endif +#if JVET_L0124_L0208_TRIANGLE + , m_Triangle ( false ) +#endif #if ENABLE_WPP_PARALLELISM , m_NextDQP ( false ) #endif diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 617855753..d7adc7576 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -823,6 +823,9 @@ private: #if JVET_L0100_MULTI_HYPOTHESIS_INTRA bool m_MHIntra; #endif +#if JVET_L0124_L0208_TRIANGLE + bool m_Triangle; +#endif #if ENABLE_WPP_PARALLELISM bool m_NextDQP; #endif @@ -972,6 +975,10 @@ public: #if JVET_L0100_MULTI_HYPOTHESIS_INTRA void setUseMHIntra ( bool b ) { m_MHIntra = b; } bool getUseMHIntra () const { return m_MHIntra; } +#endif +#if JVET_L0124_L0208_TRIANGLE + void setUseTriangle ( bool b ) { m_Triangle = b; } + bool getUseTriangle () const { return m_Triangle; } #endif // ADD_NEW_TOOL : (sps extension) add access functions for tool enabling flags and associated parameters here diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 97e4a94be..913436f9b 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,8 @@ #include <assert.h> #include <cassert> +#define JVET_L0124_L0208_TRIANGLE 1 // triangular shape prediction unit + #define JVET_L0059_MTS_SIMP 1 // Simpification on MTS signaling #define JVET_L0100_MULTI_HYPOTHESIS_INTRA 1 // Combine intra mode with an extra merge indexed prediction @@ -942,6 +944,14 @@ enum MergeType NUM_MRG_TYPE // 5 }; +#if JVET_L0124_L0208_TRIANGLE +enum TriangleSplit +{ + TRIANGLE_DIR_135 = 0, + TRIANGLE_DIR_45, + TRIANGLE_DIR_NUM +}; +#endif ////////////////////////////////////////////////////////////////////////// // Encoder modes to try out diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 710868551..098732295 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -258,6 +258,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other ) #endif affine = other.affine; affineType = other.affineType; +#if JVET_L0124_L0208_TRIANGLE + triangle = other.triangle; +#endif transQuantBypass = other.transQuantBypass; ipcm = other.ipcm; qp = other.qp; @@ -292,6 +295,9 @@ void CodingUnit::initData() #endif affine = false; affineType = 0; +#if JVET_L0124_L0208_TRIANGLE + triangle = false; +#endif transQuantBypass = false; ipcm = false; qp = 0; diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 48496a8e6..976dfdf1f 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -300,6 +300,9 @@ struct CodingUnit : public UnitArea #endif bool affine; int affineType; +#if JVET_L0124_L0208_TRIANGLE + bool triangle; +#endif bool transQuantBypass; bool ipcm; uint8_t imv; diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 5d866f823..f7bb9c977 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -3973,6 +3973,495 @@ void PU::restrictBiPredMergeCands( const PredictionUnit &pu, MergeCtx& mergeCtx } } +#if JVET_L0124_L0208_TRIANGLE +void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& TriangleMrgCtx ) +{ + const CodingStructure &cs = *pu.cs; + const Slice &slice = *pu.cs->slice; + const int32_t maxNumMergeCand = TRIANGLE_MAX_NUM_UNI_CANDS; + TriangleMrgCtx.numValidMergeCand = 0; + + for( int32_t i = 0; i < maxNumMergeCand; i++ ) + { + TriangleMrgCtx.interDirNeighbours[i] = 0; + TriangleMrgCtx.mrgTypeNeighbours [i] = MRG_TYPE_DEFAULT_N; + TriangleMrgCtx.mvFieldNeighbours[(i << 1) ].refIdx = NOT_VALID; + TriangleMrgCtx.mvFieldNeighbours[(i << 1) + 1].refIdx = NOT_VALID; + TriangleMrgCtx.mvFieldNeighbours[(i << 1) ].mv = Mv(); + TriangleMrgCtx.mvFieldNeighbours[(i << 1) + 1].mv = Mv(); + } + + MotionInfo Candidate[TRIANGLE_MAX_NUM_CANDS_MEM]; + int32_t CandCount = 0; + + const Position posLT = pu.Y().topLeft(); + const Position posRT = pu.Y().topRight(); + const Position posLB = pu.Y().bottomLeft(); + + MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft; + + //left + const PredictionUnit* puLeft = cs.getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType ); + const bool isAvailableA1 = puLeft && isDiffMER( pu, *puLeft ) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu ); + if( isAvailableA1 ) + { + miLeft = puLeft->getMotionInfo( posLB.offset(-1, 0) ); + Candidate[CandCount].isInter = true; + Candidate[CandCount].interDir = miLeft.interDir; + Candidate[CandCount].mv[0] = miLeft.mv[0]; + Candidate[CandCount].mv[1] = miLeft.mv[1]; + Candidate[CandCount].refIdx[0] = miLeft.refIdx[0]; + Candidate[CandCount].refIdx[1] = miLeft.refIdx[1]; + CandCount++; + } + + // above + const PredictionUnit *puAbove = cs.getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType ); + bool isAvailableB1 = puAbove && isDiffMER( pu, *puAbove ) && pu.cu != puAbove->cu && CU::isInter( *puAbove->cu ); + if( isAvailableB1 ) + { + miAbove = puAbove->getMotionInfo( posRT.offset( 0, -1 ) ); + + if( !isAvailableA1 || ( miAbove != miLeft ) ) + { + Candidate[CandCount].isInter = true; + Candidate[CandCount].interDir = miAbove.interDir; + Candidate[CandCount].mv[0] = miAbove.mv[0]; + Candidate[CandCount].mv[1] = miAbove.mv[1]; + Candidate[CandCount].refIdx[0] = miAbove.refIdx[0]; + Candidate[CandCount].refIdx[1] = miAbove.refIdx[1]; + CandCount++; + } + } + + // above right + const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType ); + bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu ); + + if( isAvailableB0 ) + { + miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) ); + + if( ( !isAvailableB1 || ( miAbove != miAboveRight ) ) && ( !isAvailableA1 || ( miLeft != miAboveRight ) ) ) + { + Candidate[CandCount].isInter = true; + Candidate[CandCount].interDir = miAboveRight.interDir; + Candidate[CandCount].mv[0] = miAboveRight.mv[0]; + Candidate[CandCount].mv[1] = miAboveRight.mv[1]; + Candidate[CandCount].refIdx[0] = miAboveRight.refIdx[0]; + Candidate[CandCount].refIdx[1] = miAboveRight.refIdx[1]; + CandCount++; + } + } + + //left bottom + const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType ); + bool isAvailableA0 = puLeftBottom && isDiffMER( pu, *puLeftBottom ) && CU::isInter( *puLeftBottom->cu ); + if( isAvailableA0 ) + { + miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) ); + + if( ( !isAvailableA1 || ( miBelowLeft != miLeft ) ) && ( !isAvailableB1 || ( miBelowLeft != miAbove ) ) && ( !isAvailableB0 || ( miBelowLeft != miAboveRight ) ) ) + { + Candidate[CandCount].isInter = true; + Candidate[CandCount].interDir = miBelowLeft.interDir; + Candidate[CandCount].mv[0] = miBelowLeft.mv[0]; + Candidate[CandCount].mv[1] = miBelowLeft.mv[1]; + Candidate[CandCount].refIdx[0] = miBelowLeft.refIdx[0]; + Candidate[CandCount].refIdx[1] = miBelowLeft.refIdx[1]; + CandCount++; + } + } + + // above left + const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType ); + bool isAvailableB2 = puAboveLeft && isDiffMER( pu, *puAboveLeft ) && CU::isInter( *puAboveLeft->cu ); + + if( isAvailableB2 ) + { + miAboveLeft = puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) ); + + if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) && ( !isAvailableA0 || ( miBelowLeft != miAboveLeft ) ) && ( !isAvailableB0 || ( miAboveRight != miAboveLeft ) ) ) + { + Candidate[CandCount].isInter = true; + Candidate[CandCount].interDir = miAboveLeft.interDir; + Candidate[CandCount].mv[0] = miAboveLeft.mv[0]; + Candidate[CandCount].mv[1] = miAboveLeft.mv[1]; + Candidate[CandCount].refIdx[0] = miAboveLeft.refIdx[0]; + Candidate[CandCount].refIdx[1] = miAboveLeft.refIdx[1]; + CandCount++; + } + } + + if( slice.getEnableTMVPFlag() ) + { + Position posRB = pu.Y().bottomRight().offset(-3, -3); + + const PreCalcValues& pcv = *cs.pcv; + + Position posC0; + Position posC1 = pu.Y().center(); + bool C0Avail = false; + + if (((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight)) + { + Position posInCtu( posRB.x & pcv.maxCUWidthMask, posRB.y & pcv.maxCUHeightMask ); + + if( ( posInCtu.x + 4 < pcv.maxCUWidth ) && // is not at the last column of CTU + ( posInCtu.y + 4 < pcv.maxCUHeight ) ) // is not at the last row of CTU + { + posC0 = posRB.offset( 4, 4 ); + C0Avail = true; + } + else if( posInCtu.x + 4 < pcv.maxCUWidth ) // is not at the last column of CTU But is last row of CTU + { + posC0 = posRB.offset( 4, 4 ); + // in the reference the CTU address is not set - thus probably resulting in no using this C0 possibility + } + else if( posInCtu.y + 4 < pcv.maxCUHeight ) // is not at the last row of CTU But is last column of CTU + { + posC0 = posRB.offset( 4, 4 ); + C0Avail = true; + } + else //is the right bottom corner of CTU + { + posC0 = posRB.offset( 4, 4 ); + // same as for last column but not last row + } + } + + // C0 + Mv cColMv; + int32_t RefIdx = 0; + bool ExistMV = ( C0Avail && getColocatedMVP( pu, REF_PIC_LIST_0, posC0, cColMv, RefIdx ) ); + MotionInfo MvTemporal; + MvTemporal.interDir = 0; + if( ExistMV ) + { + MvTemporal.isInter = true; + MvTemporal.interDir |= 1; + MvTemporal.mv[0] = cColMv; + MvTemporal.refIdx[0] = RefIdx; + } + ExistMV = ( C0Avail && getColocatedMVP( pu, REF_PIC_LIST_1, posC0, cColMv, RefIdx ) ); + if( ExistMV ) + { + MvTemporal.interDir |= 2; + MvTemporal.mv[1] = cColMv; + MvTemporal.refIdx[1] = RefIdx; + } + + if( MvTemporal.interDir != 0 ) + { + Candidate[CandCount].isInter = true; + Candidate[CandCount].interDir = MvTemporal.interDir; + Candidate[CandCount].mv[0] = MvTemporal.mv[0]; + Candidate[CandCount].mv[1] = MvTemporal.mv[1]; + Candidate[CandCount].refIdx[0] = MvTemporal.refIdx[0]; + Candidate[CandCount].refIdx[1] = MvTemporal.refIdx[1]; + CandCount++; + } + + // C1 + MvTemporal.interDir = 0; + ExistMV = getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv, RefIdx ); + if( ExistMV ) + { + MvTemporal.isInter = true; + MvTemporal.interDir |= 1; + MvTemporal.mv[0] = cColMv; + MvTemporal.refIdx[0] = RefIdx; + } + ExistMV = getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv, RefIdx ); + if( ExistMV ) + { + MvTemporal.interDir |= 2; + MvTemporal.mv[1] = cColMv; + MvTemporal.refIdx[1] = RefIdx; + } + + if( MvTemporal.interDir != 0 ) + { + Candidate[CandCount].isInter = true; + Candidate[CandCount].interDir = MvTemporal.interDir; + Candidate[CandCount].mv[0] = MvTemporal.mv[0]; + Candidate[CandCount].mv[1] = MvTemporal.mv[1]; + Candidate[CandCount].refIdx[0] = MvTemporal.refIdx[0]; + Candidate[CandCount].refIdx[1] = MvTemporal.refIdx[1]; + CandCount++; + } + } // if( slice.getEnableTMVPFlag() ) + + // uni-pred + for( int32_t i = 0; i < CandCount; i++ ) + { + if( Candidate[i].interDir != 3 ) + { + TriangleMrgCtx.interDirNeighbours[TriangleMrgCtx.numValidMergeCand] = Candidate[i].interDir; + TriangleMrgCtx.mrgTypeNeighbours [TriangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) ].mv = Candidate[i].mv[0]; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) + 1].mv = Candidate[i].mv[1]; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) ].refIdx = Candidate[i].refIdx[0]; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = Candidate[i].refIdx[1]; + TriangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, TriangleMrgCtx); + if( TriangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS ) + { + return; + } + } + } + + // L0 of bi-pred + for( int32_t i = 0; i < CandCount; i++ ) + { + if( Candidate[i].interDir == 3 ) + { + TriangleMrgCtx.interDirNeighbours[TriangleMrgCtx.numValidMergeCand] = 1; + TriangleMrgCtx.mrgTypeNeighbours [TriangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) ].mv = Candidate[i].mv[0]; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) + 1].mv = Mv(0, 0); + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) ].refIdx = Candidate[i].refIdx[0]; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = -1; + TriangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, TriangleMrgCtx); + if( TriangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS ) + { + return; + } + } + } + + // L1 of bi-pred + for( int32_t i = 0; i < CandCount; i++ ) + { + if( Candidate[i].interDir == 3 ) + { + TriangleMrgCtx.interDirNeighbours[TriangleMrgCtx.numValidMergeCand] = 2; + TriangleMrgCtx.mrgTypeNeighbours [TriangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) ].mv = Mv(0, 0); + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) + 1].mv = Candidate[i].mv[1]; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) ].refIdx = -1; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = Candidate[i].refIdx[1]; + TriangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, TriangleMrgCtx); + if( TriangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS ) + { + return; + } + } + } + + // averaging two uni-pred of bi-pred + for( int32_t i = 0; i < CandCount; i++ ) + { + if( Candidate[i].interDir == 3 ) + { + int32_t currPOC = slice.getPOC(); + int32_t L0RefPOC = slice.getRefPOC(REF_PIC_LIST_0, Candidate[i].refIdx[0]); + int32_t L1RefPOC = slice.getRefPOC(REF_PIC_LIST_1, Candidate[i].refIdx[1]); + Mv aveMv = Candidate[i].mv[1]; + aveMv = aveMv.scaleMv( xGetDistScaleFactor( currPOC, L0RefPOC, currPOC, L1RefPOC ) ); // scaling to L0 + aveMv.setHor( ( aveMv.getHor() + Candidate[i].mv[0].getHor() + 1 ) >> 1 ); + aveMv.setVer( ( aveMv.getVer() + Candidate[i].mv[0].getVer() + 1 ) >> 1 ); + + TriangleMrgCtx.interDirNeighbours[TriangleMrgCtx.numValidMergeCand] = 1; + TriangleMrgCtx.mrgTypeNeighbours [TriangleMrgCtx.numValidMergeCand] = MRG_TYPE_DEFAULT_N; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) ].mv = aveMv; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) + 1].mv = Mv(0, 0); + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) ].refIdx = Candidate[i].refIdx[0]; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) + 1].refIdx = -1; + TriangleMrgCtx.numValidMergeCand += isUniqueTriangleCandidates(pu, TriangleMrgCtx); + if( TriangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS ) + { + return; + } + } + } + + // fill with Mv(0, 0) + int32_t NumRefIdx = std::min( slice.getNumRefIdx(REF_PIC_LIST_0), slice.getNumRefIdx(REF_PIC_LIST_1) ); + int32_t Cnt = 0; + while( TriangleMrgCtx.numValidMergeCand < TRIANGLE_MAX_NUM_UNI_CANDS ) + { + if( Cnt < NumRefIdx ) + { + TriangleMrgCtx.interDirNeighbours[TriangleMrgCtx.numValidMergeCand] = 1; + TriangleMrgCtx.mvFieldNeighbours[TriangleMrgCtx.numValidMergeCand << 1].setMvField(Mv(0, 0), Cnt); + TriangleMrgCtx.numValidMergeCand++; + + if( TriangleMrgCtx.numValidMergeCand == TRIANGLE_MAX_NUM_UNI_CANDS ) + { + return; + } + + TriangleMrgCtx.interDirNeighbours[TriangleMrgCtx.numValidMergeCand] = 2; + TriangleMrgCtx.mvFieldNeighbours [(TriangleMrgCtx.numValidMergeCand << 1) + 1 ].setMvField(Mv(0, 0), Cnt); + TriangleMrgCtx.numValidMergeCand++; + + Cnt = (Cnt + 1) % NumRefIdx; + } + } +} + +bool PU::isUniqueTriangleCandidates( const PredictionUnit &pu, MergeCtx& TriangleMrgCtx ) +{ + int newCand = TriangleMrgCtx.numValidMergeCand; + for( int32_t i = 0; i < newCand; i++ ) + { + int32_t predFlagCur = TriangleMrgCtx.interDirNeighbours[i] == 1 ? 0 : 1; + int32_t predFlagNew = TriangleMrgCtx.interDirNeighbours[newCand] == 1 ? 0 : 1; + int32_t refPicPocCur = pu.cs->slice->getRefPOC( (RefPicList)predFlagCur, TriangleMrgCtx.mvFieldNeighbours[(i << 1) + predFlagCur].refIdx ); + int32_t refPicPocNew = pu.cs->slice->getRefPOC( (RefPicList)predFlagNew, TriangleMrgCtx.mvFieldNeighbours[(newCand << 1) + predFlagNew].refIdx); + if( refPicPocCur == refPicPocNew && TriangleMrgCtx.mvFieldNeighbours[(i << 1) + predFlagCur].mv == TriangleMrgCtx.mvFieldNeighbours[(newCand << 1) + predFlagNew].mv ) + { + return false; + } + } + return true; +} + +bool PU::isTriangleEhancedWeight( const PredictionUnit& pu, MergeCtx &TriangleMrgCtx, const uint8_t CandIdx0, const uint8_t CandIdx1 ) +{ + RefPicList RefPicListCand0 = TriangleMrgCtx.interDirNeighbours[CandIdx0] == 1 ? REF_PIC_LIST_0 : REF_PIC_LIST_1; + RefPicList RefPicListCand1 = TriangleMrgCtx.interDirNeighbours[CandIdx1] == 1 ? REF_PIC_LIST_0 : REF_PIC_LIST_1; + int32_t RefPicPoc0 = pu.cs->slice->getRefPOC( RefPicListCand0, TriangleMrgCtx.mvFieldNeighbours[ (CandIdx0 << 1) + RefPicListCand0 ].refIdx ); + int32_t RefPicPoc1 = pu.cs->slice->getRefPOC( RefPicListCand1, TriangleMrgCtx.mvFieldNeighbours[ (CandIdx1 << 1) + RefPicListCand1 ].refIdx ); + + if( RefPicPoc0 != RefPicPoc1 ) + { + // different reference picture + return true; + } + + // same reference picture, but mv difference is larger than 16 pel + int32_t threshold = 16 << 4; + Mv DiffMv = TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + RefPicListCand0].mv - TriangleMrgCtx.mvFieldNeighbours[(CandIdx1 << 1) + RefPicListCand1].mv; + + if( DiffMv.getAbsHor() > threshold || DiffMv.getAbsVer() > threshold ) + { + return true; + } + + return false; +} + +void PU::spanTriangleMotionInfo( PredictionUnit &pu, MergeCtx &TriangleMrgCtx, const uint8_t MergeIdx, const bool SplitDir, const uint8_t CandIdx0, const uint8_t CandIdx1 ) +{ + pu.mergeIdx = MergeIdx; + MotionBuf mb = pu.getMotionBuf(); + + MotionInfo BiMv; + BiMv.isInter = true; + + if( TriangleMrgCtx.interDirNeighbours[CandIdx0] == 1 && TriangleMrgCtx.interDirNeighbours[CandIdx1] == 2 ) + { + BiMv.interDir = 3; + BiMv.mv[0] = TriangleMrgCtx.mvFieldNeighbours[ CandIdx0 << 1 ].mv; + BiMv.mv[1] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx1 << 1) + 1].mv; + BiMv.refIdx[0] = TriangleMrgCtx.mvFieldNeighbours[ CandIdx0 << 1 ].refIdx; + BiMv.refIdx[1] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx1 << 1) + 1].refIdx; + } + else if( TriangleMrgCtx.interDirNeighbours[CandIdx0] == 2 && TriangleMrgCtx.interDirNeighbours[CandIdx1] == 1 ) + { + BiMv.interDir = 3; + BiMv.mv[0] = TriangleMrgCtx.mvFieldNeighbours[ CandIdx1 << 1 ].mv; + BiMv.mv[1] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + 1].mv; + BiMv.refIdx[0] = TriangleMrgCtx.mvFieldNeighbours[ CandIdx1 << 1 ].refIdx; + BiMv.refIdx[1] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + 1].refIdx; + } + else if( TriangleMrgCtx.interDirNeighbours[CandIdx0] == 1 && TriangleMrgCtx.interDirNeighbours[CandIdx1] == 1 ) + { + int32_t refIdx = mappingRefPic( pu, pu.cs->slice->getRefPOC( REF_PIC_LIST_0, TriangleMrgCtx.mvFieldNeighbours[CandIdx1 << 1].refIdx ), REF_PIC_LIST_1 ); + if( refIdx != -1 ) + { + BiMv.interDir = 3; + BiMv.mv[0] = TriangleMrgCtx.mvFieldNeighbours[CandIdx0 << 1].mv; + BiMv.mv[1] = TriangleMrgCtx.mvFieldNeighbours[CandIdx1 << 1].mv; + BiMv.refIdx[0] = TriangleMrgCtx.mvFieldNeighbours[CandIdx0 << 1].refIdx; + BiMv.refIdx[1] = refIdx; + } + else + { + refIdx = mappingRefPic( pu, pu.cs->slice->getRefPOC( REF_PIC_LIST_0, TriangleMrgCtx.mvFieldNeighbours[CandIdx0 << 1].refIdx), REF_PIC_LIST_1 ); + BiMv.interDir = ( refIdx != -1 ) ? 3 : 1; + BiMv.mv[0] = ( refIdx != -1 ) ? TriangleMrgCtx.mvFieldNeighbours[CandIdx1 << 1].mv : TriangleMrgCtx.mvFieldNeighbours[CandIdx0 << 1].mv; + BiMv.mv[1] = ( refIdx != -1 ) ? TriangleMrgCtx.mvFieldNeighbours[CandIdx0 << 1].mv : Mv(0, 0); + BiMv.refIdx[0] = ( refIdx != -1 ) ? TriangleMrgCtx.mvFieldNeighbours[CandIdx1 << 1].refIdx : TriangleMrgCtx.mvFieldNeighbours[CandIdx0 << 1].refIdx; + BiMv.refIdx[1] = ( refIdx != -1 ) ? refIdx : -1; + } + } + else if( TriangleMrgCtx.interDirNeighbours[CandIdx0] == 2 && TriangleMrgCtx.interDirNeighbours[CandIdx1] == 2 ) + { + int32_t refIdx = mappingRefPic( pu, pu.cs->slice->getRefPOC( REF_PIC_LIST_1, TriangleMrgCtx.mvFieldNeighbours[(CandIdx1 << 1) + 1].refIdx ), REF_PIC_LIST_0 ); + if( refIdx != -1 ) + { + BiMv.interDir = 3; + BiMv.mv[0] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx1 << 1) + 1].mv; + BiMv.mv[1] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + 1].mv; + BiMv.refIdx[0] = refIdx; + BiMv.refIdx[1] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + 1].refIdx; + } + else + { + refIdx = mappingRefPic( pu, pu.cs->slice->getRefPOC( REF_PIC_LIST_1, TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + 1].refIdx ), REF_PIC_LIST_0 ); + BiMv.interDir = ( refIdx != -1 ) ? 3 : 2; + BiMv.mv[0] = ( refIdx != -1 ) ? TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + 1].mv : Mv(0, 0); + BiMv.mv[1] = ( refIdx != -1 ) ? TriangleMrgCtx.mvFieldNeighbours[(CandIdx1 << 1) + 1].mv : TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + 1].mv; + BiMv.refIdx[0] = ( refIdx != -1 ) ? refIdx : -1; + BiMv.refIdx[1] = ( refIdx != -1 ) ? TriangleMrgCtx.mvFieldNeighbours[(CandIdx1 << 1) + 1].refIdx : TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + 1].refIdx; + } + } + + int32_t IdxW = (int32_t)g_aucLog2[pu.lwidth() ] - MIN_CU_LOG2; + int32_t IdxH = (int32_t)g_aucLog2[pu.lheight()] - MIN_CU_LOG2; + for( int32_t y = 0; y < mb.height; y++ ) + { + for( int32_t x = 0; x < mb.width; x++ ) + { + if( g_TriangleMvStorage[SplitDir][IdxH][IdxW][y][x] == 2 ) + { + mb.at( x, y ).isInter = true; + mb.at( x, y ).interDir = BiMv.interDir; + mb.at( x, y ).refIdx[0] = BiMv.refIdx[0]; + mb.at( x, y ).refIdx[1] = BiMv.refIdx[1]; + mb.at( x, y ).mv [0] = BiMv.mv [0]; + mb.at( x, y ).mv [1] = BiMv.mv [1]; + } + else if( g_TriangleMvStorage[SplitDir][IdxH][IdxW][y][x] == 0 ) + { + mb.at( x, y ).isInter = true; + mb.at( x, y ).interDir = TriangleMrgCtx.interDirNeighbours[CandIdx0]; + mb.at( x, y ).refIdx[0] = TriangleMrgCtx.mvFieldNeighbours[ CandIdx0 << 1 ].refIdx; + mb.at( x, y ).refIdx[1] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + 1].refIdx; + mb.at( x, y ).mv [0] = TriangleMrgCtx.mvFieldNeighbours[ CandIdx0 << 1 ].mv; + mb.at( x, y ).mv [1] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx0 << 1) + 1].mv; + } + else + { + mb.at( x, y ).isInter = true; + mb.at( x, y ).interDir = TriangleMrgCtx.interDirNeighbours[CandIdx1]; + mb.at( x, y ).refIdx[0] = TriangleMrgCtx.mvFieldNeighbours[ CandIdx1 << 1 ].refIdx; + mb.at( x, y ).refIdx[1] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx1 << 1) + 1].refIdx; + mb.at( x, y ).mv [0] = TriangleMrgCtx.mvFieldNeighbours[ CandIdx1 << 1 ].mv; + mb.at( x, y ).mv [1] = TriangleMrgCtx.mvFieldNeighbours[(CandIdx1 << 1) + 1].mv; + } + } + } +} + +int32_t PU::mappingRefPic( const PredictionUnit &pu, int32_t refPicPoc, bool targetRefPicList ) +{ + int32_t numRefIdx = pu.cs->slice->getNumRefIdx( (RefPicList)targetRefPicList ); + + for( int32_t i = 0; i < numRefIdx; i++ ) + { + if( pu.cs->slice->getRefPOC( (RefPicList)targetRefPicList, i ) == refPicPoc ) + { + return i; + } + } + return -1; +} +#endif + void CU::resetMVDandMV2Int( CodingUnit& cu, InterPrediction *interPred ) { for( auto &pu : CU::traversePUs( cu ) ) diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 9645cd773..445c86de6 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -173,6 +173,13 @@ namespace PU int getMHIntraMPMs (const PredictionUnit &pu, unsigned *mpm, const ChannelType &channelType = CHANNEL_TYPE_LUMA, const bool isChromaMDMS = false, const unsigned startIdx = 0); int getNarrowShape (const int width, const int height); #endif +#if JVET_L0124_L0208_TRIANGLE + void getTriangleMergeCandidates (const PredictionUnit &pu, MergeCtx& TriangleMrgCtx); + bool isUniqueTriangleCandidates (const PredictionUnit &pu, MergeCtx& TriangleMrgCtx); + bool isTriangleEhancedWeight (const PredictionUnit &pu, MergeCtx &TriangleMrgCtx, const uint8_t CandIdx0, const uint8_t CandIdx1); + void spanTriangleMotionInfo ( PredictionUnit &pu, MergeCtx &TriangleMrgCtx, const uint8_t MergeIdx, const bool SplitDir, const uint8_t CandIdx0, const uint8_t CandIdx1); + int32_t mappingRefPic (const PredictionUnit &pu, int32_t refPicPoc, bool targetRefPicList); +#endif } // TU tools diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 271eb5713..3c709ba3b 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -1172,6 +1172,9 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx ) pu.intraDir[1] = DM_CHROMA_IDX; } #endif +#if JVET_L0124_L0208_TRIANGLE + triangle_mode( *pu.cu ); +#endif #if JVET_L0054_MMVD if (pu.mmvdMergeFlag) { @@ -1413,6 +1416,25 @@ void CABACReader::merge_idx( PredictionUnit& pu ) #endif int numCandminus1 = int( pu.cs->slice->getMaxNumMergeCand() ) - 1; pu.mergeIdx = 0; + +#if JVET_L0124_L0208_TRIANGLE + if( pu.cu->triangle ) + { + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__TRIANGLE_INDEX ); + if( m_BinDecoder.decodeBin( Ctx::TriangleIdx() ) == 0 ) + { + pu.mergeIdx += m_BinDecoder.decodeBinEP(); + } + else + { + pu.mergeIdx += exp_golomb_eqprob( 2 ) + 2; + } + + DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx=%d\n", pu.mergeIdx ); + return; + } +#endif + if( numCandminus1 > 0 ) { if( m_BinDecoder.decodeBin( Ctx::MergeIdx() ) ) @@ -1728,6 +1750,23 @@ void CABACReader::MHIntra_luma_pred_modes(CodingUnit &cu) } #endif +#if JVET_L0124_L0208_TRIANGLE +void CABACReader::triangle_mode( CodingUnit& cu ) +{ + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__TRIANGLE_FLAG ); + + if( !cu.cs->slice->getSPS()->getSpsNext().getUseTriangle() || !cu.cs->slice->isInterB() || cu.lwidth() * cu.lheight() < TRIANGLE_MIN_SIZE || cu.affine ) + { + return; + } + + unsigned flag_idx = DeriveCtx::CtxTriangleFlag( cu ); + cu.triangle = m_BinDecoder.decodeBin( Ctx::TriangleFlag(flag_idx) ); + + + DTRACE( g_trace_ctx, D_SYNTAX, "triangle_mode() triangle_mode=%d pos=(%d,%d) size: %dx%d\n", cu.triangle, cu.Y().x, cu.Y().y, cu.lumaSize().width, cu.lumaSize().height ); +} +#endif //================================================================================ // clause 7.3.8.7 diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 046c3b7ae..0ec81a5fa 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -111,6 +111,9 @@ public: void MHIntra_flag ( PredictionUnit& pu ); void MHIntra_luma_pred_modes ( CodingUnit& cu ); #endif +#if JVET_L0124_L0208_TRIANGLE + void triangle_mode ( CodingUnit& cu ); +#endif // pcm samples (clause 7.3.8.7) void pcm_samples ( TransformUnit& tu ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 7cfd907ef..2ea919792 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -314,12 +314,28 @@ void DecCu::xFillPCMBuffer(CodingUnit &cu) void DecCu::xReconInter(CodingUnit &cu) { +#if JVET_L0124_L0208_TRIANGLE + if( cu.triangle ) + { + const uint8_t mergeIdx = cu.firstPU->mergeIdx; + const bool SplitDir = g_TriangleCombination[mergeIdx][0]; + const uint8_t CandIdx0 = g_TriangleCombination[mergeIdx][1]; + const uint8_t CandIdx1 = g_TriangleCombination[mergeIdx][2]; + m_pcInterPred->motionCompensation4Triangle( cu, m_TriangleMrgCtx, SplitDir, CandIdx0, CandIdx1 ); + PU::spanTriangleMotionInfo( *cu.firstPU, m_TriangleMrgCtx, mergeIdx, SplitDir, CandIdx0, CandIdx1 ); + } + else + { +#endif #if JVET_L0100_MULTI_HYPOTHESIS_INTRA m_pcIntraPred->geneIntrainterPred(cu); #endif // inter prediction m_pcInterPred->motionCompensation( cu ); +#if JVET_L0124_L0208_TRIANGLE + } +#endif #if JVET_L0266_HMVP cu.slice->updateMotionLUTs(cu.slice->getMotionLUTs(), cu); #endif @@ -486,6 +502,14 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) { #endif { +#if JVET_L0124_L0208_TRIANGLE + if( pu.cu->triangle ) + { + PU::getTriangleMergeCandidates( pu, m_TriangleMrgCtx ); + } + else + { +#endif if( pu.cu->affine ) { #if JVET_L0632_AFFINE_MERGE @@ -593,6 +617,9 @@ void DecCu::xDeriveCUMV( CodingUnit &cu ) PU::spanMotionInfo( pu, mrgCtx ); } +#if JVET_L0124_L0208_TRIANGLE + } +#endif } #if JVET_L0054_MMVD } diff --git a/source/Lib/DecoderLib/DecCu.h b/source/Lib/DecoderLib/DecCu.h index 2a61f26cc..4e98da082 100644 --- a/source/Lib/DecoderLib/DecCu.h +++ b/source/Lib/DecoderLib/DecCu.h @@ -92,6 +92,10 @@ private: MotionInfo m_SubPuMiBuf[(MAX_CU_SIZE * MAX_CU_SIZE) >> (MIN_CU_LOG2 << 1)]; + +#if JVET_L0124_L0208_TRIANGLE + MergeCtx m_TriangleMrgCtx; +#endif }; //! \} diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 9113f8ec2..2858f2b6e 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -818,6 +818,9 @@ void HLSyntaxReader::parseSPSNext( SPSNext& spsNext, const bool usePCM ) #if JVET_L0100_MULTI_HYPOTHESIS_INTRA READ_FLAG( symbol, "mhintra_flag" ); spsNext.setUseMHIntra ( symbol != 0 ); #endif +#if JVET_L0124_L0208_TRIANGLE + READ_FLAG( symbol, "triangle_flag" ); spsNext.setUseTriangle ( symbol != 0 ); +#endif #if ENABLE_WPP_PARALLELISM READ_FLAG( symbol, "next_dqp_enabled_flag" ); spsNext.setUseNextDQP ( symbol != 0 ); #else diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 5e9177706..fbdbf1f53 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -1132,6 +1132,9 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu ) MHIntra_luma_pred_modes( *pu.cu ); } #endif +#if JVET_L0124_L0208_TRIANGLE + triangle_mode( *pu.cu ); +#endif #if JVET_L0054_MMVD if (pu.mmvdMergeFlag) { @@ -1354,6 +1357,24 @@ void CABACWriter::merge_idx( const PredictionUnit& pu ) } else { +#endif +#if JVET_L0124_L0208_TRIANGLE + if( pu.cu->triangle ) + { + if( pu.mergeIdx < 2 ) + { + m_BinEncoder.encodeBin( 0, Ctx::TriangleIdx() ); + m_BinEncoder.encodeBinEP( pu.mergeIdx ); + } + else + { + m_BinEncoder.encodeBin( 1, Ctx::TriangleIdx() ); + exp_golomb_eqprob( pu.mergeIdx - 2, 2 ); + } + + DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx=%d\n", pu.mergeIdx ); + return; + } #endif int numCandminus1 = int( pu.cs->slice->getMaxNumMergeCand() ) - 1; if( numCandminus1 > 0 ) @@ -1618,6 +1639,22 @@ void CABACWriter::MHIntra_luma_pred_modes(const CodingUnit& cu) } #endif +#if JVET_L0124_L0208_TRIANGLE +void CABACWriter::triangle_mode( const CodingUnit& cu ) +{ + if( !cu.cs->slice->getSPS()->getSpsNext().getUseTriangle() || !cu.cs->slice->isInterB() || cu.lwidth() * cu.lheight() < TRIANGLE_MIN_SIZE || cu.affine ) + { + return; + } + + unsigned flag_idx = DeriveCtx::CtxTriangleFlag( cu ); + + m_BinEncoder.encodeBin( cu.triangle, Ctx::TriangleFlag(flag_idx) ); + + DTRACE( g_trace_ctx, D_SYNTAX, "triangle_mode() triangle_mode=%d pos=(%d,%d) size: %dx%d\n", cu.triangle, cu.Y().x, cu.Y().y, cu.lumaSize().width, cu.lumaSize().height ); +} +#endif + //================================================================================ // clause 7.3.8.7 //-------------------------------------------------------------------------------- diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 646550b8d..faacf9b6f 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -125,6 +125,9 @@ public: void MHIntra_flag ( const PredictionUnit& pu ); void MHIntra_luma_pred_modes ( const CodingUnit& cu ); #endif +#if JVET_L0124_L0208_TRIANGLE + void triangle_mode ( const CodingUnit& cu ); +#endif // pcm samples (clause 7.3.8.7) void pcm_samples ( const TransformUnit& tu ); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index bd8301680..1c9744660 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -223,6 +223,9 @@ protected: #if JVET_L0100_MULTI_HYPOTHESIS_INTRA bool m_MHIntra; +#endif +#if JVET_L0124_L0208_TRIANGLE + bool m_Triangle; #endif // ADD_NEW_TOOL : (encoder lib) add tool enabling flags and associated parameters here @@ -695,6 +698,10 @@ public: void setUseMHIntra ( bool b ) { m_MHIntra = b; } bool getUseMHIntra () const { return m_MHIntra; } #endif +#if JVET_L0124_L0208_TRIANGLE + void setUseTriangle ( bool b ) { m_Triangle = b; } + bool getUseTriangle () const { return m_Triangle; } +#endif // ADD_NEW_TOOL : (encoder lib) add access functions here diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 1ae622840..2572d4cc6 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -197,6 +197,12 @@ void EncCu::create( EncCfg* encCfg ) m_acRealMergeBuffer[ui].create(chromaFormat, Area(0, 0, uiMaxWidth, uiMaxHeight)); } #endif +#if JVET_L0124_L0208_TRIANGLE + for( unsigned ui = 0; ui < TRIANGLE_MAX_NUM_CANDS; ui++ ) + { + m_acTriangleWeightBuffer[ui].create( chromaFormat, Area( 0, 0, uiMaxWidth, uiMaxHeight ) ); + } +#endif m_CtxBuffer.resize( maxDepth ); m_CurrCtx = 0; @@ -301,6 +307,12 @@ void EncCu::destroy() m_acRealMergeBuffer[ui].destroy(); } #endif +#if JVET_L0124_L0208_TRIANGLE + for( unsigned ui = 0; ui < TRIANGLE_MAX_NUM_CANDS; ui++ ) + { + m_acTriangleWeightBuffer[ui].destroy(); + } +#endif } @@ -739,6 +751,12 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par cu->mmvdSkip = cu->skip == false ? false : cu->mmvdSkip; #endif } +#if JVET_L0124_L0208_TRIANGLE + else if( currTestMode.type == ETM_MERGE_TRIANGLE ) + { + xCheckRDCostMergeTriangle2Nx2N( tempCS, bestCS, partitioner, currTestMode ); + } +#endif else if( currTestMode.type == ETM_INTRA ) { xCheckRDCostIntra( tempCS, bestCS, partitioner, currTestMode ); @@ -1609,6 +1627,10 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& mergeCtx.subPuMvpMiBuf = MotionBuf( m_SubPuMiBuf, bufSize ); } +#if JVET_L0124_L0208_TRIANGLE + setMergeBestSATDCost( MAX_DOUBLE ); +#endif + { // first get merge candidates CodingUnit cu( tempCS->area ); @@ -1779,6 +1801,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& cu.skip = false; #if JVET_L0054_MMVD cu.mmvdSkip = false; +#endif +#if JVET_L0124_L0208_TRIANGLE + cu.triangle = false; #endif cu.partSize = SIZE_2Nx2N; //cu.affine @@ -2073,6 +2098,10 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& } } +#if JVET_L0124_L0208_TRIANGLE + setMergeBestSATDCost( candCostList[0] ); +#endif + #if JVET_L0100_MULTI_HYPOTHESIS_INTRA if (isIntrainterEnabled) { @@ -2170,6 +2199,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& cu.skip = false; #if JVET_L0054_MMVD cu.mmvdSkip = false; +#endif +#if JVET_L0124_L0208_TRIANGLE + cu.triangle = false; #endif cu.partSize = SIZE_2Nx2N; //cu.affine @@ -2336,6 +2368,234 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& } } +#if JVET_L0124_L0208_TRIANGLE +void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) +{ + const Slice &slice = *tempCS->slice; + const SPS &sps = *tempCS->sps; + + CHECK( slice.getSliceType() != B_SLICE, "Triangle mode is only applied to B-slices" ); + + tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); + + bool TrianglecandHasNoResidual[TRIANGLE_MAX_NUM_CANDS]; + for( int MergeCand = 0; MergeCand < TRIANGLE_MAX_NUM_CANDS; MergeCand++ ) + { + TrianglecandHasNoResidual[MergeCand] = false; + } + + bool bestIsSkip = m_pcEncCfg->getUseFastDecisionForMerge() ? bestCS->getCU( partitioner.chType )->rootCbf == 0 : false; + uint8_t NumTriangleCandidate = TRIANGLE_MAX_NUM_CANDS; + uint8_t TriangleNumMrgSATDCand = TRIANGLE_MAX_NUM_SATD_CANDS; + PelUnitBuf acTriangleBuffer[TRIANGLE_MAX_NUM_UNI_CANDS]; + PelUnitBuf acTriangleWeightBuffer[TRIANGLE_MAX_NUM_CANDS]; + static_vector<uint8_t, TRIANGLE_MAX_NUM_CANDS> TriangleRdModeList; + static_vector<double, TRIANGLE_MAX_NUM_CANDS> TrianglecandCostList; + + if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) ) + { + bestIsSkip |= blkCache->isSkip( tempCS->area ); + } + + DistParam distParam; + const bool UseHadamard = !encTestMode.lossless; + m_pcRdCost->setDistParam( distParam, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth( CHANNEL_TYPE_LUMA ), COMPONENT_Y, UseHadamard ); + + const UnitArea localUnitArea( tempCS->area.chromaFormat, Area( 0, 0, tempCS->area.Y().width, tempCS->area.Y().height) ); + + const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda(encTestMode.lossless); + + MergeCtx TriangleMrgCtx; + { + CodingUnit cu( tempCS->area ); + cu.cs = tempCS; + cu.partSize = SIZE_2Nx2N; + cu.predMode = MODE_INTER; + cu.slice = tempCS->slice; + cu.triangle = true; +#if JVET_L0054_MMVD + cu.mmvdSkip = false; +#endif +#if JVET_L0646_GBI + cu.GBiIdx = GBI_DEFAULT; +#endif + + PredictionUnit pu( tempCS->area ); + pu.cu = &cu; + pu.cs = tempCS; + + + PU::getTriangleMergeCandidates( pu, TriangleMrgCtx ); + for( uint8_t MergeCand = 0; MergeCand < TRIANGLE_MAX_NUM_UNI_CANDS; MergeCand++ ) + { + acTriangleBuffer[MergeCand] = m_acMergeBuffer[MergeCand].getBuf(localUnitArea); + TriangleMrgCtx.setMergeInfo( pu, MergeCand ); + PU::spanMotionInfo( pu, TriangleMrgCtx ); + + m_pcInterSearch->motionCompensation( pu, acTriangleBuffer[MergeCand] ); + } + } + + bool TempBufSet = bestIsSkip ? false : true; + TriangleNumMrgSATDCand = bestIsSkip ? TRIANGLE_MAX_NUM_CANDS : TRIANGLE_MAX_NUM_SATD_CANDS; + if( bestIsSkip ) + { + for( uint8_t i = 0; i < TRIANGLE_MAX_NUM_CANDS; i++ ) + { + TriangleRdModeList.push_back(i); + } + } + else + { + CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType ); + + partitioner.setCUData( cu ); + cu.slice = tempCS->slice; + cu.skip = false; + cu.partSize = SIZE_2Nx2N; + cu.predMode = MODE_INTER; + cu.transQuantBypass = encTestMode.lossless; + cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1; + cu.qp = encTestMode.qp; + cu.triangle = true; +#if JVET_L0054_MMVD + cu.mmvdSkip = false; +#endif +#if JVET_L0646_GBI + cu.GBiIdx = GBI_DEFAULT; +#endif + + PredictionUnit &pu = tempCS->addPU( cu, partitioner.chType ); + + int32_t Ratio = abs(g_aucLog2[cu.lwidth()] - g_aucLog2[cu.lheight()]); + if( Ratio >= 2 ) + { + NumTriangleCandidate = 30; + } + else + { + NumTriangleCandidate = TRIANGLE_MAX_NUM_CANDS; + } + + for( uint8_t MergeCand = 0; MergeCand < NumTriangleCandidate; MergeCand++ ) + { + bool SplitDir = g_TriangleCombination[MergeCand][0]; + uint8_t CandIdx0 = g_TriangleCombination[MergeCand][1]; + uint8_t CandIdx1 = g_TriangleCombination[MergeCand][2]; + + pu.mergeIdx = MergeCand; + pu.mergeFlag = true; + acTriangleWeightBuffer[MergeCand] = m_acTriangleWeightBuffer[MergeCand].getBuf( localUnitArea ); + acTriangleBuffer[CandIdx0] = m_acMergeBuffer[CandIdx0].getBuf( localUnitArea ); + acTriangleBuffer[CandIdx1] = m_acMergeBuffer[CandIdx1].getBuf( localUnitArea ); + + m_pcInterSearch->TriangleWeighting( pu, PU::isTriangleEhancedWeight(pu, TriangleMrgCtx, CandIdx0, CandIdx1), SplitDir, CHANNEL_TYPE_LUMA, acTriangleWeightBuffer[MergeCand], acTriangleBuffer[CandIdx0], acTriangleBuffer[CandIdx1] ); + + distParam.cur = acTriangleWeightBuffer[MergeCand].Y(); + + Distortion uiSad = distParam.distFunc( distParam ); + + uint32_t uiBitsCand = g_TriangleIdxBins[MergeCand]; + + double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass; + + updateCandList( MergeCand, cost, TriangleRdModeList, TrianglecandCostList, TriangleNumMrgSATDCand ); + } + + // limit number of candidates using SATD-costs + for( uint8_t i = 0; i < TriangleNumMrgSATDCand; i++ ) + { + if( TrianglecandCostList[i] > MRG_FAST_RATIO * TrianglecandCostList[0] || TrianglecandCostList[i] > getMergeBestSATDCost() ) + { + TriangleNumMrgSATDCand = i; + break; + } + } + + // perform chroma weighting process + for( uint8_t i = 0; i < TriangleNumMrgSATDCand; i++ ) + { + uint8_t MergeCand = TriangleRdModeList[i]; + bool SplitDir = g_TriangleCombination[MergeCand][0]; + uint8_t CandIdx0 = g_TriangleCombination[MergeCand][1]; + uint8_t CandIdx1 = g_TriangleCombination[MergeCand][2]; + + pu.mergeIdx = MergeCand; + pu.mergeFlag = true; + + m_pcInterSearch->TriangleWeighting( pu, PU::isTriangleEhancedWeight(pu, TriangleMrgCtx, CandIdx0, CandIdx1), SplitDir, CHANNEL_TYPE_CHROMA, acTriangleWeightBuffer[MergeCand], acTriangleBuffer[CandIdx0], acTriangleBuffer[CandIdx1] ); + } + + tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); + } + + { + const uint8_t iteration = encTestMode.lossless ? 1 : 2; + for( uint8_t NoResidualPass = 0; NoResidualPass < iteration; NoResidualPass++ ) + { + for( uint8_t MrgHADIdx = 0; MrgHADIdx < TriangleNumMrgSATDCand; MrgHADIdx++ ) + { + uint8_t MergeCand = TriangleRdModeList[MrgHADIdx]; + + if ( ( (NoResidualPass != 0) && TrianglecandHasNoResidual[MergeCand] ) + || ( (NoResidualPass == 0) && bestIsSkip ) ) + { + continue; + } + + bool SplitDir = g_TriangleCombination[MergeCand][0]; + uint8_t CandIdx0 = g_TriangleCombination[MergeCand][1]; + uint8_t CandIdx1 = g_TriangleCombination[MergeCand][2]; + + CodingUnit &cu = tempCS->addCU(tempCS->area, partitioner.chType); + + partitioner.setCUData(cu); + cu.slice = tempCS->slice; + cu.skip = false; + cu.partSize = SIZE_2Nx2N; + cu.predMode = MODE_INTER; + cu.transQuantBypass = encTestMode.lossless; + cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1; + cu.qp = encTestMode.qp; + cu.triangle = true; +#if JVET_L0054_MMVD + cu.mmvdSkip = false; +#endif +#if JVET_L0646_GBI + cu.GBiIdx = GBI_DEFAULT; +#endif + PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType); + + pu.mergeIdx = MergeCand; + pu.mergeFlag = true; + + PU::spanTriangleMotionInfo(pu, TriangleMrgCtx, MergeCand, SplitDir, CandIdx0, CandIdx1 ); + + if( TempBufSet ) + { + tempCS->getPredBuf().copyFrom( acTriangleWeightBuffer[MergeCand] ); + } + else + { + acTriangleBuffer[CandIdx0] = m_acMergeBuffer[CandIdx0].getBuf( localUnitArea ); + acTriangleBuffer[CandIdx1] = m_acMergeBuffer[CandIdx1].getBuf( localUnitArea ); + PelUnitBuf predBuf = tempCS->getPredBuf(); + m_pcInterSearch->TriangleWeighting( pu, PU::isTriangleEhancedWeight(pu, TriangleMrgCtx, CandIdx0, CandIdx1), SplitDir, MAX_NUM_CHANNEL_TYPE, predBuf, acTriangleBuffer[CandIdx0], acTriangleBuffer[CandIdx1] ); + } + + xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, NoResidualPass, NULL, true, ( (NoResidualPass == 0 ) ? &TrianglecandHasNoResidual[MergeCand] : NULL ) ); + + if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip) + { + bestIsSkip = bestCS->getCU(partitioner.chType)->rootCbf == 0; + } + tempCS->initStructData(encTestMode.qp, encTestMode.lossless); + }// end loop MrgHADIdx + } + } +} +#endif + void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) { if( m_modeCtrl->getFastDeltaQp() ) diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index 3607a2f23..60e254f22 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -119,6 +119,10 @@ private: #endif #else PelStorage m_acMergeBuffer[MRG_MAX_NUM_CANDS]; +#endif +#if JVET_L0124_L0208_TRIANGLE + PelStorage m_acTriangleWeightBuffer[TRIANGLE_MAX_NUM_CANDS]; // to store weighted prediction pixles + double m_mergeBestSATDCost; #endif MotionInfo m_SubPuMiBuf [( MAX_CU_SIZE * MAX_CU_SIZE ) >> ( MIN_CU_LOG2 << 1 )]; unsigned int m_subMergeBlkSize[10]; @@ -173,6 +177,11 @@ public: void setClearSubMergeStatic(bool b) { m_clearSubMergeStatic = b; } bool getClearSubMergeStatic() { return m_clearSubMergeStatic; } +#if JVET_L0124_L0208_TRIANGLE + void setMergeBestSATDCost(double cost) { m_mergeBestSATDCost = cost; } + double getMergeBestSATDCost() { return m_mergeBestSATDCost; } +#endif + ~EncCu(); protected: @@ -217,6 +226,10 @@ protected: void xCheckRDCostMerge2Nx2N ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode ); +#if JVET_L0124_L0208_TRIANGLE + void xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode ); +#endif + void xEncodeInterResidual ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode, int residualPass = 0 , CodingStructure* imvCS = NULL , int emtMode = 1 diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index c3c395ad5..55ad6f0e4 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -878,6 +878,9 @@ void EncLib::xInitSPS(SPS &sps) #if JVET_L0100_MULTI_HYPOTHESIS_INTRA sps.getSpsNext().setUseMHIntra ( m_MHIntra ); #endif +#if JVET_L0124_L0208_TRIANGLE + sps.getSpsNext().setUseTriangle ( m_Triangle ); +#endif // ADD_NEW_TOOL : (encoder lib) set tool enabling flags and associated parameters here diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index 0aba5bc5b..c4e07119a 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -1077,6 +1077,12 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru // add inter modes if( m_pcEncCfg->getUseEarlySkipDetection() ) { +#if JVET_L0124_L0208_TRIANGLE + if( cs.sps->getSpsNext().getUseTriangle() && cs.slice->isInterB() ) + { + m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_TRIANGLE, SIZE_2Nx2N, ETO_STANDARD, qp, lossless } ); + } +#endif m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_SKIP, SIZE_2Nx2N, ETO_STANDARD, qp, lossless } ); #if JVET_L0369_SUBBLOCK_MERGE if ( cs.sps->getSpsNext().getUseAffine() || cs.sps->getSpsNext().getUseSubPuMvp() ) @@ -1091,7 +1097,12 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru else { m_ComprCUCtxList.back().testModes.push_back( { ETM_INTER_ME, SIZE_2Nx2N, ETO_STANDARD, qp, lossless } ); - +#if JVET_L0124_L0208_TRIANGLE + if( cs.sps->getSpsNext().getUseTriangle() && cs.slice->isInterB() ) + { + m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_TRIANGLE, SIZE_2Nx2N, ETO_STANDARD, qp, lossless } ); + } +#endif m_ComprCUCtxList.back().testModes.push_back( { ETM_MERGE_SKIP, SIZE_2Nx2N, ETO_STANDARD, qp, lossless } ); #if JVET_L0369_SUBBLOCK_MERGE if ( cs.sps->getSpsNext().getUseAffine() || cs.sps->getSpsNext().getUseSubPuMvp() ) @@ -1313,6 +1324,12 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt { return false; } +#if JVET_L0124_L0208_TRIANGLE + if( encTestmode.type == ETM_MERGE_TRIANGLE && ( partitioner.currArea().lumaSize().area() < TRIANGLE_MIN_SIZE || relatedCU.isIntra ) ) + { + return false; + } +#endif return true; } else if( isModeSplit( encTestmode ) ) diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h index f56fceb06..988ba51c4 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.h +++ b/source/Lib/EncoderLib/EncModeCtrl.h @@ -57,6 +57,9 @@ enum EncTestModeType ETM_MERGE_SKIP, ETM_INTER_ME, ETM_AFFINE, +#if JVET_L0124_L0208_TRIANGLE + ETM_MERGE_TRIANGLE, +#endif ETM_INTRA, ETM_IPCM, ETM_SPLIT_QT, @@ -134,6 +137,9 @@ inline bool isModeInter( const EncTestMode& encTestmode ) // perhaps remove return ( encTestmode.type == ETM_INTER_ME || encTestmode.type == ETM_MERGE_SKIP || encTestmode.type == ETM_AFFINE +#if JVET_L0124_L0208_TRIANGLE + || encTestmode.type == ETM_MERGE_TRIANGLE +#endif ); } diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 8d6f8cb24..5258a13df 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -4860,6 +4860,9 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa #else m_CABACEstimator->affine_flag( cu ); #endif +#if JVET_L0124_L0208_TRIANGLE + m_CABACEstimator->triangle_mode ( cu ); +#endif #if JVET_L0054_MMVD if (cu.mmvdSkip) { @@ -4995,6 +4998,9 @@ uint64_t InterSearch::xGetSymbolFracBitsInter(CodingStructure &cs, Partitioner & #else m_CABACEstimator->affine_flag ( cu ); #endif +#if JVET_L0124_L0208_TRIANGLE + m_CABACEstimator->triangle_mode ( cu ); +#endif #if JVET_L0054_MMVD if (cu.mmvdSkip) { diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index c8a270f6a..34d447271 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -559,6 +559,9 @@ void HLSWriter::codeSPSNext( const SPSNext& spsNext, const bool usePCM ) #if JVET_L0100_MULTI_HYPOTHESIS_INTRA WRITE_FLAG( spsNext.getUseMHIntra() ? 1 : 0, "mhintra_flag" ); #endif +#if JVET_L0124_L0208_TRIANGLE + WRITE_FLAG( spsNext.getUseTriangle() ? 1: 0, "triangle_flag" ); +#endif #if ENABLE_WPP_PARALLELISM WRITE_FLAG( spsNext.getUseNextDQP(), "next_dqp_enabled_flag" ); #else -- GitLab