diff --git a/doc/software-manual.tex b/doc/software-manual.tex index 2603c64e40b6b6166fe5be9a9a137057ece49c82..a2aeb0b0287e680f9c1ae3b0243f420e709c9b20 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -2047,6 +2047,14 @@ Enables optimization of non-linear filters for ALF on Luma channel. Enables optimization of non-linear filters for ALF on Chroma channels. \\ +\Option{MaxNumAlfAlternativesChroma} & +%\ShortOption{\None} & +\Default{8} & +Specified the maximum number of alternative chroma filters that can be +switched at CTB level. Set to 1 to disable alternative chroma filters. +Value shall be in the range 1..8. +\\ + \Option{SMVD} & %\ShortOption{\None} & \Default{false} & diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 573358b74760a58601c227ed83c4ed3645831125..1899e02191fa13a3343b0bb3d26dd4a33dc130c4 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -336,6 +336,9 @@ void EncApp::xInitLibCfg() m_cEncLib.setUseContentBasedFastQtbt ( m_contentBasedFastQtbt ); m_cEncLib.setUseNonLinearAlfLuma ( m_useNonLinearAlfLuma ); m_cEncLib.setUseNonLinearAlfChroma ( m_useNonLinearAlfChroma ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_cEncLib.setMaxNumAlfAlternativesChroma ( m_maxNumAlfAlternativesChroma ); +#endif m_cEncLib.setUseMIP ( m_MIP ); m_cEncLib.setUseFastMIP ( m_useFastMIP ); m_cEncLib.setCrossComponentPredictionEnabledFlag ( m_crossComponentPredictionEnabledFlag ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index ef215530217ef29335e185a47f542afef723e0ae..fdce40a52b0f364cce33db557f1fbc6f4b288d85 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -940,6 +940,10 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("ContentBasedFastQtbt", m_contentBasedFastQtbt, false, "Signal based QTBT speed-up") ("UseNonLinearAlfLuma", m_useNonLinearAlfLuma, true, "Non-linear adaptive loop filters for Luma Channel") ("UseNonLinearAlfChroma", m_useNonLinearAlfChroma, true, "Non-linear adaptive loop filters for Chroma Channels") +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + ("MaxNumAlfAlternativesChroma", m_maxNumAlfAlternativesChroma, + (unsigned)MAX_NUM_ALF_ALTERNATIVES_CHROMA, std::string("Maximum number of alternative Chroma filters (1-") + std::to_string(MAX_NUM_ALF_ALTERNATIVES_CHROMA) + std::string (", inclusive)") ) +#endif ("MIP", m_MIP, true, "Enable MIP (matrix-based intra prediction)") ("FastMIP", m_useFastMIP, false, "Fast encoder search for MIP (matrix-based intra prediction)") // Unit definition parameters @@ -1951,6 +1955,13 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if ( m_alf ) + { + CHECK( m_maxNumAlfAlternativesChroma < 1 || m_maxNumAlfAlternativesChroma > MAX_NUM_ALF_ALTERNATIVES_CHROMA, std::string("The maximum number of ALF Chroma filter alternatives must be in the range (1-") + std::to_string(MAX_NUM_ALF_ALTERNATIVES_CHROMA) + std::string (", inclusive)") ); + } + +#endif // reading external dQP description from file if ( !m_dQPFileName.empty() ) { @@ -3415,8 +3426,11 @@ void EncAppCfg::xPrintParameter() msg( VERBOSE, "AMaxBT:%d ", m_useAMaxBT ); msg( VERBOSE, "E0023FastEnc:%d ", m_e0023FastEnc ); msg( VERBOSE, "ContentBasedFastQtbt:%d ", m_contentBasedFastQtbt ); - msg( VERBOSE, "UseNonLinearALFLuma:%d ", m_useNonLinearAlfLuma ); - msg( VERBOSE, "UseNonLinearALFChroma:%d ", m_useNonLinearAlfChroma ); + msg( VERBOSE, "UseNonLinearAlfLuma:%d ", m_useNonLinearAlfLuma ); + msg( VERBOSE, "UseNonLinearAlfChroma:%d ", m_useNonLinearAlfChroma ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + msg( VERBOSE, "MaxNumAlfAlternativesChroma:%d ", m_maxNumAlfAlternativesChroma ); +#endif if( m_MIP ) msg(VERBOSE, "FastMIP:%d ", m_useFastMIP); msg( VERBOSE, "NumSplitThreads:%d ", m_numSplitThreads ); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index d8bf7be18f069c1f38b5b122e87ccfea3145b6ec..87b431e03fadc863d7bf805e2b00bf82fdc9fe14 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -324,6 +324,9 @@ protected: bool m_contentBasedFastQtbt; bool m_useNonLinearAlfLuma; bool m_useNonLinearAlfChroma; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + unsigned m_maxNumAlfAlternativesChroma; +#endif bool m_MIP; bool m_useFastMIP; diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp index 95004da3fa7aefed20d4016c0442a62ddd894eba..f99bf8b3bb483d47c8944aa84e57c7de2817c707 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp @@ -55,6 +55,9 @@ AdaptiveLoopFilter::AdaptiveLoopFilter() for( int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++ ) { m_ctuEnableFlag[compIdx] = nullptr; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_ctuAlternative[compIdx] = nullptr; +#endif } m_deriveClassificationBlk = deriveClassificationBlk; @@ -210,6 +213,9 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) for( int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++ ) { m_ctuEnableFlag[compIdx] = cs.picture->getAlfCtuEnableFlag( compIdx ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_ctuAlternative[compIdx] = cs.picture->getAlfCtuAlternativeData( compIdx ); +#endif } reconstructCoeffAPSs(cs, true, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) || cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr), false); short* alfCtuFilterIndex = cs.slice->getPic()->getAlfCtbFilterIndex(); @@ -298,7 +304,12 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) { const Area blkSrc( 0, 0, w >> chromaScaleX, h >> chromaScaleY ); const Area blkDst( xStart >> chromaScaleX, yStart >> chromaScaleY, w >> chromaScaleX, h >> chromaScaleY ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx]; + m_filter5x5Blk(m_classifier, recYuv, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs +#else m_filter5x5Blk(m_classifier, recYuv, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal, m_chromaClippFinal, m_clpRngs.comp[compIdx], cs +#endif , m_alfVBChmaCTUHeight , ((yPos + pcv.maxCUHeight >= pcv.lumaHeight) ? pcv.lumaHeight : m_alfVBChmaPos)); } @@ -347,7 +358,12 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) if( m_ctuEnableFlag[compIdx][ctuIdx] ) { Area blk( xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx]; + m_filter5x5Blk(m_classifier, recYuv, tmpYuv, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs +#else m_filter5x5Blk(m_classifier, recYuv, tmpYuv, blk, blk, compID, m_chromaCoeffFinal, m_chromaClippFinal, m_clpRngs.comp[compIdx], cs +#endif , m_alfVBChmaCTUHeight , ((yPos + pcv.maxCUHeight >= pcv.lumaHeight) ? pcv.lumaHeight : m_alfVBChmaPos)); } @@ -362,7 +378,7 @@ void AdaptiveLoopFilter::reconstructCoeffAPSs(CodingStructure& cs, bool luma, bo { //luma APS** aps = cs.slice->getAlfAPSs(); - AlfSliceParam alfSliceParamTmp; + AlfParam alfParamTmp; APS* curAPS; if (luma) { @@ -371,8 +387,8 @@ void AdaptiveLoopFilter::reconstructCoeffAPSs(CodingStructure& cs, bool luma, bo int apsIdx = cs.slice->getTileGroupApsIdLuma()[i]; curAPS = aps[apsIdx]; CHECK(curAPS == NULL, "invalid APS"); - alfSliceParamTmp = curAPS->getAlfAPSParam(); - reconstructCoeff(alfSliceParamTmp, CHANNEL_TYPE_LUMA, isRdo, true); + alfParamTmp = curAPS->getAlfAPSParam(); + reconstructCoeff(alfParamTmp, CHANNEL_TYPE_LUMA, isRdo, true); memcpy(m_coeffApsLuma[i], m_coeffFinal, sizeof(m_coeffFinal)); memcpy(m_clippApsLuma[i], m_clippFinal, sizeof(m_clippFinal)); } @@ -383,24 +399,127 @@ void AdaptiveLoopFilter::reconstructCoeffAPSs(CodingStructure& cs, bool luma, bo { int apsIdxChroma = cs.slice->getTileGroupApsIdChroma(); curAPS = aps[apsIdxChroma]; - alfSliceParamTmp = curAPS->getAlfAPSParam(); - reconstructCoeff(alfSliceParamTmp, CHANNEL_TYPE_CHROMA, isRdo, true); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_alfParamChroma = &curAPS->getAlfAPSParam(); + alfParamTmp = *m_alfParamChroma; +#else + alfParamTmp = curAPS->getAlfAPSParam(); +#endif + reconstructCoeff(alfParamTmp, CHANNEL_TYPE_CHROMA, isRdo, true); } } -void AdaptiveLoopFilter::reconstructCoeff( AlfSliceParam& alfSliceParam, ChannelType channel, const bool isRdo, const bool isRedo ) +void AdaptiveLoopFilter::reconstructCoeff( AlfParam& alfParam, ChannelType channel, const bool isRdo, const bool isRedo ) { int factor = isRdo ? 0 : (1 << (m_NUM_BITS - 1)); AlfFilterType filterType = isLuma( channel ) ? ALF_FILTER_7 : ALF_FILTER_5; int numClasses = isLuma( channel ) ? MAX_NUM_ALF_CLASSES : 1; int numCoeff = filterType == ALF_FILTER_5 ? 7 : 13; int numCoeffMinus1 = numCoeff - 1; - int numFilters = isLuma( channel ) ? alfSliceParam.numLumaFilters : 1; - short* coeff = isLuma( channel ) ? alfSliceParam.lumaCoeff : alfSliceParam.chromaCoeff; - short* clipp = isLuma( channel ) ? alfSliceParam.lumaClipp : alfSliceParam.chromaClipp; +#if !JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + int numFilters = isLuma( channel ) ? alfParam.numLumaFilters : 1; + short* coeff = isLuma( channel ) ? alfParam.lumaCoeff : alfParam.chromaCoeff; + short* clipp = isLuma( channel ) ? alfParam.lumaClipp : alfParam.chromaClipp; +#endif +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const int numAlts = isLuma( channel ) ? 1 : alfParam.numAlternativesChroma; + + for( int altIdx = 0; altIdx < numAlts; ++ altIdx ) + { + int numFilters = isLuma( channel ) ? alfParam.numLumaFilters : 1; + short* coeff = isLuma( channel ) ? alfParam.lumaCoeff : alfParam.chromaCoeff[altIdx]; + short* clipp = isLuma( channel ) ? alfParam.lumaClipp : alfParam.chromaClipp[altIdx]; #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - if( alfSliceParam.alfLumaCoeffDeltaPredictionFlag && isLuma( channel ) ) + if( alfParam.alfLumaCoeffDeltaPredictionFlag && isLuma( channel ) ) + { + for( int i = 1; i < numFilters; i++ ) + { + for( int j = 0; j < numCoeffMinus1; j++ ) + { + coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] += coeff[( i - 1 ) * MAX_NUM_ALF_LUMA_COEFF + j]; + } + } + } + +#endif + for( int filterIdx = 0; filterIdx < numFilters; filterIdx++ ) + { + coeff[filterIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = factor; + } + + if( isChroma( channel ) ) + { + for( int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx ) + { + m_chromaCoeffFinal[altIdx][coeffIdx] = coeff[coeffIdx]; + int clipIdx = alfParam.nonLinearFlag[channel][altIdx] ? clipp[coeffIdx] : 0; + m_chromaClippFinal[altIdx][coeffIdx] = isRdo ? clipIdx : m_alfClippingValues[channel][clipIdx]; + } + m_chromaCoeffFinal[altIdx][numCoeffMinus1] = factor; + m_chromaClippFinal[altIdx][numCoeffMinus1] = isRdo ? 0 : m_alfClippingValues[channel][0]; + continue; + } + for( int classIdx = 0; classIdx < numClasses; classIdx++ ) + { + int filterIdx = alfParam.filterCoeffDeltaIdx[classIdx]; +#if !JVET_O0669_REMOVE_ALF_COEFF_PRED + int fixedFilterIdx = alfParam.fixedFilterSetIndex; + if (fixedFilterIdx > 0 && alfParam.fixedFilterIdx[classIdx] > 0) + { + fixedFilterIdx = m_classToFilterMapping[fixedFilterIdx - 1][classIdx]; + } + else + { + fixedFilterIdx = -1; + } +#endif + for (int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx) + { + m_coeffFinal[classIdx * MAX_NUM_ALF_LUMA_COEFF + coeffIdx] = coeff[filterIdx * MAX_NUM_ALF_LUMA_COEFF + coeffIdx]; +#if !JVET_O0669_REMOVE_ALF_COEFF_PRED + //fixed filter + if (fixedFilterIdx >= 0) + { + m_coeffFinal[classIdx * MAX_NUM_ALF_LUMA_COEFF + coeffIdx] += m_fixedFilterSetCoeff[fixedFilterIdx][coeffIdx]; + } +#endif + } + m_coeffFinal[classIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = factor; + m_clippFinal[classIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = isRdo ? 0 : m_alfClippingValues[channel][0]; + for( int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx ) + { + int clipIdx = alfParam.nonLinearFlag[channel][altIdx] ? (clipp + filterIdx * MAX_NUM_ALF_LUMA_COEFF)[coeffIdx] : 0; + (m_clippFinal + classIdx * MAX_NUM_ALF_LUMA_COEFF)[coeffIdx] = isRdo ? clipIdx : m_alfClippingValues[channel][clipIdx]; + } + m_clippFinal[classIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = + isRdo ? 0 : + m_alfClippingValues[channel][0]; + } + } +#if !JVET_O0669_REMOVE_ALF_COEFF_PRED + + if( isChroma( channel ) ) + return; + + if( isRedo && alfParam.alfLumaCoeffDeltaPredictionFlag ) + { + int numFilters = alfParam.numLumaFilters; + short* coeff = alfParam.lumaCoeff; + + for( int i = numFilters - 1; i > 0; i-- ) + { + for( int j = 0; j < numCoeffMinus1; j++ ) + { + coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] = coeff[i * MAX_NUM_ALF_LUMA_COEFF + j] - coeff[( i - 1 ) * MAX_NUM_ALF_LUMA_COEFF + j]; + } + } + } +#endif +#else + +#if !JVET_O0669_REMOVE_ALF_COEFF_PRED + if( alfParam.alfLumaCoeffDeltaPredictionFlag && isLuma( channel ) ) { for( int i = 1; i < numFilters; i++ ) { @@ -421,8 +540,8 @@ void AdaptiveLoopFilter::reconstructCoeff( AlfSliceParam& alfSliceParam, Channel { for( int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx ) { - m_chromaCoeffFinal[coeffIdx] = alfSliceParam.chromaCoeff[coeffIdx]; - int clipIdx = alfSliceParam.nonLinearFlag[channel] ? clipp[coeffIdx] : 0; + m_chromaCoeffFinal[coeffIdx] = alfParam.chromaCoeff[coeffIdx]; + int clipIdx = alfParam.nonLinearFlag[channel] ? clipp[coeffIdx] : 0; m_chromaClippFinal[coeffIdx] = isRdo ? clipIdx : m_alfClippingValues[channel][clipIdx]; } m_chromaCoeffFinal[numCoeffMinus1] = factor; @@ -433,10 +552,10 @@ void AdaptiveLoopFilter::reconstructCoeff( AlfSliceParam& alfSliceParam, Channel for( int classIdx = 0; classIdx < numClasses; classIdx++ ) { - int filterIdx = alfSliceParam.filterCoeffDeltaIdx[classIdx]; + int filterIdx = alfParam.filterCoeffDeltaIdx[classIdx]; #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - int fixedFilterIdx = alfSliceParam.fixedFilterSetIndex; - if (fixedFilterIdx > 0 && alfSliceParam.fixedFilterIdx[classIdx] > 0) + int fixedFilterIdx = alfParam.fixedFilterSetIndex; + if (fixedFilterIdx > 0 && alfParam.fixedFilterIdx[classIdx] > 0) { fixedFilterIdx = m_classToFilterMapping[fixedFilterIdx - 1][classIdx]; } @@ -460,13 +579,13 @@ void AdaptiveLoopFilter::reconstructCoeff( AlfSliceParam& alfSliceParam, Channel m_clippFinal[classIdx* MAX_NUM_ALF_LUMA_COEFF + numCoeffMinus1] = isRdo ? 0 : m_alfClippingValues[channel][0]; for( int coeffIdx = 0; coeffIdx < numCoeffMinus1; ++coeffIdx ) { - int clipIdx = alfSliceParam.nonLinearFlag[channel] ? (clipp + filterIdx * MAX_NUM_ALF_LUMA_COEFF)[coeffIdx] : 0; + int clipIdx = alfParam.nonLinearFlag[channel] ? (clipp + filterIdx * MAX_NUM_ALF_LUMA_COEFF)[coeffIdx] : 0; (m_clippFinal + classIdx * MAX_NUM_ALF_LUMA_COEFF)[coeffIdx] = isRdo ? clipIdx : m_alfClippingValues[channel][clipIdx]; } } #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - if(isRedo && alfSliceParam.alfLumaCoeffDeltaPredictionFlag ) + if(isRedo && alfParam.alfLumaCoeffDeltaPredictionFlag ) { for( int i = numFilters - 1; i > 0; i-- ) { @@ -477,6 +596,7 @@ void AdaptiveLoopFilter::reconstructCoeff( AlfSliceParam& alfSliceParam, Channel } } #endif +#endif } void AdaptiveLoopFilter::create( const int picWidth, const int picHeight, const ChromaFormat format, const int maxCUWidth, const int maxCUHeight, const int maxCUDepth, const int inputBitDepth[MAX_NUM_CHANNEL_TYPE] ) @@ -889,7 +1009,7 @@ void AdaptiveLoopFilter::deriveClassificationBlk(AlfClassifier** classifier, int } template<AlfFilterType filtType> -void AdaptiveLoopFilter::filterBlk(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, short* filterSet, short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos) +void AdaptiveLoopFilter::filterBlk(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, const short* filterSet, const short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos) { const bool bChroma = isChroma( compId ); if( bChroma ) @@ -918,8 +1038,8 @@ void AdaptiveLoopFilter::filterBlk(AlfClassifier** classifier, const PelUnitBuf const Pel *pImgYPad0, *pImgYPad1, *pImgYPad2, *pImgYPad3, *pImgYPad4, *pImgYPad5, *pImgYPad6; const Pel *pImg0, *pImg1, *pImg2, *pImg3, *pImg4, *pImg5, *pImg6; - short *coef = filterSet; - short *clip = fClipSet; + const short *coef = filterSet; + const short *clip = fClipSet; const int shift = m_NUM_BITS - 1; @@ -987,7 +1107,11 @@ void AdaptiveLoopFilter::filterBlk(AlfClassifier** classifier, const PelUnitBuf for( blkX=0; blkX<4; blkX+=2 ) { Position pos(j + blkDst.x + blkX, i + blkDst.y + blkY); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); +#else CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); +#endif *flags++ = cu->ipcm ? 1 : 0; } } diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.h b/source/Lib/CommonLib/AdaptiveLoopFilter.h index 16c0a9e0bcb7c9fc65005e79d430c60d2c335dc3..42be89b58354401bf9e554e2edc844d0e997d5b8 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.h +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.h @@ -83,7 +83,7 @@ public: AdaptiveLoopFilter(); virtual ~AdaptiveLoopFilter() {} void reconstructCoeffAPSs(CodingStructure& cs, bool luma, bool chroma, bool isRdo); - void reconstructCoeff(AlfSliceParam& alfSliceParam, ChannelType channel, const bool isRdo, const bool isRedo = false); + void reconstructCoeff(AlfParam& alfParam, ChannelType channel, const bool isRdo, const bool isRedo = false); void ALFProcess(CodingStructure& cs); void create( const int picWidth, const int picHeight, const ChromaFormat format, const int maxCUWidth, const int maxCUHeight, const int maxCUDepth, const int inputBitDepth[MAX_NUM_CHANNEL_TYPE] ); void destroy(); @@ -91,7 +91,7 @@ public: void deriveClassification( AlfClassifier** classifier, const CPelBuf& srcLuma, const Area& blkDst, const Area& blk ); void resetPCMBlkClassInfo(CodingStructure & cs, AlfClassifier** classifier, const CPelBuf& srcLuma, const Area& blk); template<AlfFilterType filtType> - static void filterBlk(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, short* filterSet, short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos); + static void filterBlk(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, const short* filterSet, const short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos); #if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING inline static int getMaxGolombIdx( AlfFilterType filterType ) { @@ -101,8 +101,8 @@ public: void(*m_deriveClassificationBlk)(AlfClassifier** classifier, int** laplacian[NUM_DIRECTIONS], const CPelBuf& srcLuma, const Area& blkDst, const Area& blk, const int shift, int vbCTUHeight, int vbPos); - void(*m_filter5x5Blk)(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, short* filterSet, short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos); - void(*m_filter7x7Blk)(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, short* filterSet, short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos); + void(*m_filter5x5Blk)(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, const short* filterSet, const short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos); + void(*m_filter7x7Blk)(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, const short* filterSet, const short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos); #ifdef TARGET_SIMD_X86 void initAdaptiveLoopFilterX86(); @@ -115,19 +115,36 @@ protected: static const int m_classToFilterMapping[NUM_FIXED_FILTER_SETS][MAX_NUM_ALF_CLASSES]; static const int m_fixedFilterSetCoeff[ALF_FIXED_FILTER_NUM][MAX_NUM_ALF_LUMA_COEFF]; short m_fixedFilterSetCoeffDec[NUM_FIXED_FILTER_SETS][MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + short m_coeffApsLuma[ALF_CTB_MAX_NUM_APS][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES]; + short m_clippApsLuma[ALF_CTB_MAX_NUM_APS][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES]; +#else short m_coeffApsLuma[6][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES]; short m_clippApsLuma[6][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES]; +#endif short m_clipDefault[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; bool m_created = false; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + short m_chromaCoeffFinal[MAX_NUM_ALF_ALTERNATIVES_CHROMA][MAX_NUM_ALF_CHROMA_COEFF]; + AlfParam* m_alfParamChroma; +#else short m_chromaCoeffFinal[MAX_NUM_ALF_LUMA_COEFF]; +#endif Pel m_alfClippingValues[MAX_NUM_CHANNEL_TYPE][MaxAlfNumClippingValues]; std::vector<AlfFilterShape> m_filterShapes[MAX_NUM_CHANNEL_TYPE]; AlfClassifier** m_classifier; short m_coeffFinal[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; short m_clippFinal[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + short m_chromaClippFinal[MAX_NUM_ALF_ALTERNATIVES_CHROMA][MAX_NUM_ALF_CHROMA_COEFF]; +#else short m_chromaClippFinal[MAX_NUM_ALF_LUMA_COEFF]; +#endif int** m_laplacian[NUM_DIRECTIONS]; uint8_t* m_ctuEnableFlag[MAX_NUM_COMPONENT]; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + uint8_t* m_ctuAlternative[MAX_NUM_COMPONENT]; +#endif PelStorage m_tempBuf; PelStorage m_tempBuf2; int m_inputBitDepth[MAX_NUM_CHANNEL_TYPE]; diff --git a/source/Lib/CommonLib/AlfParameters.h b/source/Lib/CommonLib/AlfParameters.h new file mode 100644 index 0000000000000000000000000000000000000000..5976a2b91891d741a9bf25864c94d4b6cbc889ec --- /dev/null +++ b/source/Lib/CommonLib/AlfParameters.h @@ -0,0 +1,231 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2019, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file AlfParameters.h + \brief Define types for storing ALF parameters +*/ + +#ifndef __ALFPARAMETERS__ +#define __ALFPARAMETERS__ + +#include <vector> +#include "CommonDef.h" + +//! \ingroup AlfParameters +//! \{ + +enum AlfFilterType +{ + ALF_FILTER_5, + ALF_FILTER_7, + ALF_NUM_OF_FILTER_TYPES +}; + +struct AlfFilterShape +{ + AlfFilterShape( int size ) + : filterLength( size ), + numCoeff( size * size / 4 + 1 ), + filterSize( size * size / 2 + 1 ) + { + if( size == 5 ) + { + pattern = { + 0, + 1, 2, 3, + 4, 5, 6, 5, 4, + 3, 2, 1, + 0 + }; + + weights = { + 2, + 2, 2, 2, + 2, 2, 1, 1 + }; +#if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING + golombIdx = { + 0, + 0, 1, 0, + 0, 1, 2, 2 + }; +#endif + + filterType = ALF_FILTER_5; + } + else if( size == 7 ) + { + pattern = { + 0, + 1, 2, 3, + 4, 5, 6, 7, 8, + 9, 10, 11, 12, 11, 10, 9, + 8, 7, 6, 5, 4, + 3, 2, 1, + 0 + }; + + weights = { + 2, + 2, 2, 2, + 2, 2, 2, 2, 2, + 2, 2, 2, 1, 1 + }; +#if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING + golombIdx = { + 0, + 0, 1, 0, + 0, 1, 2, 1, 0, + 0, 1, 2, 3, 3 + }; +#endif + + filterType = ALF_FILTER_7; + } + else + { + filterType = ALF_NUM_OF_FILTER_TYPES; + CHECK( 0, "Wrong ALF filter shape" ); + } + } + + AlfFilterType filterType; + int filterLength; + int numCoeff; //TO DO: check whether we need both numCoeff and filterSize + int filterSize; + std::vector<int> pattern; + std::vector<int> weights; +#if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING + std::vector<int> golombIdx; +#endif +}; + +struct AlfParam +{ + bool enabledFlag[MAX_NUM_COMPONENT]; // alf_slice_enable_flag, alf_chroma_idc +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + bool nonLinearFlag[MAX_NUM_CHANNEL_TYPE][MAX_NUM_ALF_ALTERNATIVES_CHROMA]; // alf_[luma/chroma]_clip_flag +#else + bool nonLinearFlag[MAX_NUM_CHANNEL_TYPE]; // alf_nonlinear_enable_flag[Luma/Chroma] +#endif + short lumaCoeff[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; // alf_coeff_luma_delta[i][j] + short lumaClipp[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; // alf_clipp_luma_[i][j] +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + int numAlternativesChroma; // alf_chroma_num_alts_minus_one + 1 + short chromaCoeff[MAX_NUM_ALF_ALTERNATIVES_CHROMA][MAX_NUM_ALF_CHROMA_COEFF]; // alf_coeff_chroma[i] + short chromaClipp[MAX_NUM_ALF_ALTERNATIVES_CHROMA][MAX_NUM_ALF_CHROMA_COEFF]; // alf_clipp_chroma[i] +#else + short chromaCoeff[MAX_NUM_ALF_CHROMA_COEFF]; // alf_coeff_chroma[i] + short chromaClipp[MAX_NUM_ALF_CHROMA_COEFF]; // alf_clipp_chroma[i] +#endif + short filterCoeffDeltaIdx[MAX_NUM_ALF_CLASSES]; // filter_coeff_delta[i] + bool alfLumaCoeffFlag[MAX_NUM_ALF_CLASSES]; // alf_luma_coeff_flag[i] + int numLumaFilters; // number_of_filters_minus1 + 1 + bool alfLumaCoeffDeltaFlag; // alf_luma_coeff_delta_flag +#if !JVET_O0669_REMOVE_ALF_COEFF_PRED + bool alfLumaCoeffDeltaPredictionFlag; // alf_luma_coeff_delta_prediction_flag +#endif + std::vector<AlfFilterShape>* filterShapes; + int tLayer; + bool newFilterFlag[MAX_NUM_CHANNEL_TYPE]; +#if !JVET_O0669_REMOVE_ALF_COEFF_PRED + int fixedFilterPattern; + int fixedFilterIdx[MAX_NUM_ALF_CLASSES]; + int fixedFilterSetIndex; +#endif + + AlfParam() + { + reset(); + } + + void reset() + { + std::memset( enabledFlag, false, sizeof( enabledFlag ) ); + std::memset( nonLinearFlag, false, sizeof( nonLinearFlag ) ); + std::memset( lumaCoeff, 0, sizeof( lumaCoeff ) ); + std::memset( lumaClipp, 0, sizeof( lumaClipp ) ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + numAlternativesChroma = 1; +#endif + std::memset( chromaCoeff, 0, sizeof( chromaCoeff ) ); + std::memset( chromaClipp, 0, sizeof( chromaClipp ) ); + std::memset( filterCoeffDeltaIdx, 0, sizeof( filterCoeffDeltaIdx ) ); + std::memset( alfLumaCoeffFlag, true, sizeof( alfLumaCoeffFlag ) ); + numLumaFilters = 1; + alfLumaCoeffDeltaFlag = false; +#if !JVET_O0669_REMOVE_ALF_COEFF_PRED + alfLumaCoeffDeltaPredictionFlag = false; +#endif + tLayer = 0; + memset(newFilterFlag, 0, sizeof(newFilterFlag)); +#if !JVET_O0669_REMOVE_ALF_COEFF_PRED + fixedFilterPattern = 0; + std::memset(fixedFilterIdx, 0, sizeof(fixedFilterIdx)); + fixedFilterSetIndex = 0; +#endif + } + + const AlfParam& operator = ( const AlfParam& src ) + { + std::memcpy( enabledFlag, src.enabledFlag, sizeof( enabledFlag ) ); + std::memcpy( nonLinearFlag, src.nonLinearFlag, sizeof( nonLinearFlag ) ); + std::memcpy( lumaCoeff, src.lumaCoeff, sizeof( lumaCoeff ) ); + std::memcpy( lumaClipp, src.lumaClipp, sizeof( lumaClipp ) ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + numAlternativesChroma = src.numAlternativesChroma; +#endif + std::memcpy( chromaCoeff, src.chromaCoeff, sizeof( chromaCoeff ) ); + std::memcpy( chromaClipp, src.chromaClipp, sizeof( chromaClipp ) ); + std::memcpy( filterCoeffDeltaIdx, src.filterCoeffDeltaIdx, sizeof( filterCoeffDeltaIdx ) ); + std::memcpy( alfLumaCoeffFlag, src.alfLumaCoeffFlag, sizeof( alfLumaCoeffFlag ) ); + numLumaFilters = src.numLumaFilters; + alfLumaCoeffDeltaFlag = src.alfLumaCoeffDeltaFlag; +#if !JVET_O0669_REMOVE_ALF_COEFF_PRED + alfLumaCoeffDeltaPredictionFlag = src.alfLumaCoeffDeltaPredictionFlag; +#endif + filterShapes = src.filterShapes; + tLayer = src.tLayer; + std::memcpy(newFilterFlag, src.newFilterFlag, sizeof(newFilterFlag)); +#if !JVET_O0669_REMOVE_ALF_COEFF_PRED + fixedFilterPattern = src.fixedFilterPattern; + std::memcpy(fixedFilterIdx, src.fixedFilterIdx, sizeof(fixedFilterIdx)); + fixedFilterSetIndex = src.fixedFilterSetIndex; +#endif + return *this; + } +}; + +//! \} + +#endif // end of #ifndef __ALFPARAMETERS__ \ No newline at end of file diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index 84ffabcac71ccc790cabb5ff1ee995b20724ffe9..36d3109af203229fbbe75f7a39754ad409055632 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -327,7 +327,7 @@ const TransformUnit * CodingStructure::getTU( const Position &pos, const Channel } else { - while( pos != tus[idx - 1 + extraIdx]->blocks[effChType].pos() ) + while ( !tus[idx - 1 + extraIdx]->blocks[getFirstComponentOfChannel( effChType )].contains(pos) ) { extraIdx++; } diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index cc2258ac1985888d3af916c9b51064e324fd8be4..b56ee0e5c1b6261b9589e27e34e0c7eec282fa3b 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -176,6 +176,16 @@ static const int MAXIMUM_INTRA_FILTERED_HEIGHT = 16; static const int MIP_MAX_WIDTH = 64; static const int MIP_MAX_HEIGHT = 64; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +static const int MAX_NUM_ALF_ALTERNATIVES_CHROMA = 8; +#endif +static const int MAX_NUM_ALF_CLASSES = 25; +static const int MAX_NUM_ALF_LUMA_COEFF = 13; +static const int MAX_NUM_ALF_CHROMA_COEFF = 7; +static const int MAX_ALF_FILTER_LENGTH = 7; +static const int MAX_NUM_ALF_COEFF = MAX_ALF_FILTER_LENGTH * MAX_ALF_FILTER_LENGTH / 2 + 1; +static const int MAX_ALF_PADDING_SIZE = 4; + static const int ALF_FIXED_FILTER_NUM = 64; static const int ALF_CTB_MAX_NUM_APS = 6; static const int NUM_FIXED_FILTER_SETS = 16; @@ -253,8 +263,13 @@ static const int FAST_UDI_MAX_RDMODE_NUM = (NUM_LUMA_MODE + MAX_NUM_MIP_MODE); / static const int MAX_LFNST_COEF_NUM = 16; +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS +static const int LFNST_LAST_SIG_LUMA = 1; +static const int LFNST_LAST_SIG_CHROMA = 1; +#else static const int LFNST_SIG_NZ_LUMA = 1; static const int LFNST_SIG_NZ_CHROMA = 1; +#endif static const int NUM_LFNST_NUM_PER_SET = 3; @@ -326,7 +341,6 @@ static const int MAX_GR_ORDER_RESIDUAL = 10; static const int AFFINE_MIN_BLOCK_SIZE = 4; ///< Minimum affine MC block size - static const int MMVD_REFINE_STEP = 8; ///< max number of distance step static const int MMVD_MAX_REFINE_NUM = (MMVD_REFINE_STEP * 4); ///< max number of candidate from a base candidate static const int MMVD_BASE_MV_NUM = 2; ///< max number of base candidate @@ -454,6 +468,11 @@ static constexpr int MV_BITS = 18; static constexpr int MV_MAX = (1 << (MV_BITS - 1)) - 1; static constexpr int MV_MIN = -(1 << (MV_BITS - 1)); +#if JVET_O0567_MVDRange_Constraint +static const int MVD_MAX = (1 << 17) - 1; +static const int MVD_MIN = -(1 << 17); +#endif + static const int PIC_ANALYZE_CW_BINS = 32; static const int PIC_CODE_CW_BINS = 16; #if JVET_O0272_LMCS_SIMP_INVERSE_MAPPING diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index 47521d337c841bca5d6328989a9a32e064efa9d7..5db6cf3680a895a12156aeb718f46dee273f4b82 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -236,18 +236,18 @@ void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, u } #if JVET_O0193_REMOVE_TR_DEPTH_IN_CBF_CTX -unsigned DeriveCtx::CtxQtCbf( const ComponentID compID, const bool prevCbCbf, const int ispIdx ) +unsigned DeriveCtx::CtxQtCbf( const ComponentID compID, const bool prevCbf, const int ispIdx ) #else -unsigned DeriveCtx::CtxQtCbf( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf, const int ispIdx ) +unsigned DeriveCtx::CtxQtCbf( const ComponentID compID, const unsigned trDepth, const bool prevCbf, const int ispIdx ) #endif { if( ispIdx && isLuma( compID ) ) { - return 2 + (int)prevCbCbf; + return 2 + (int)prevCbf; } if( compID == COMPONENT_Cr ) { - return ( prevCbCbf ? 1 : 0 ); + return ( prevCbf ? 1 : 0 ); } #if JVET_O0193_REMOVE_TR_DEPTH_IN_CBF_CTX return 0; diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index 1b8df872643e0fa9e8df5c90298d4e59d5f82df8..c9773cc5fdaba7e21f061eb84bdcb47db4497836 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -427,6 +427,18 @@ class CUCtx { public: CUCtx() : isDQPCoded(false), isChromaQpAdjCoded(false), +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + qgStart(false) + { +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS + violatesLfnstConstrained[CHANNEL_TYPE_LUMA ] = false; + violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false; +#endif + lastScanPos[COMPONENT_Y ] = -1; + lastScanPos[COMPONENT_Cb] = -1; + lastScanPos[COMPONENT_Cr] = -1; + } +#else qgStart(false), #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS numNonZeroCoeffNonTs(0) @@ -436,9 +448,22 @@ public: } #else numNonZeroCoeffNonTs(0) {} +#endif #endif CUCtx(int _qp) : isDQPCoded(false), isChromaQpAdjCoded(false), qgStart(false), +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + qp(_qp) + { +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS + violatesLfnstConstrained[CHANNEL_TYPE_LUMA ] = false; + violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false; +#endif + lastScanPos[COMPONENT_Y ] = -1; + lastScanPos[COMPONENT_Cb] = -1; + lastScanPos[COMPONENT_Cr] = -1; + } +#else #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS numNonZeroCoeffNonTs(0), qp(_qp) { @@ -447,13 +472,18 @@ public: } #else numNonZeroCoeffNonTs(0), qp(_qp) {} +#endif #endif ~CUCtx() {} public: bool isDQPCoded; bool isChromaQpAdjCoded; bool qgStart; +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + int lastScanPos[MAX_NUM_COMPONENT]; +#else uint32_t numNonZeroCoeffNonTs; +#endif int8_t qp; // used as a previous(last) QP and for QP prediction #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS bool violatesLfnstConstrained[MAX_NUM_CHANNEL_TYPE]; @@ -502,9 +532,9 @@ namespace DeriveCtx { void CtxSplit ( const CodingStructure& cs, Partitioner& partitioner, unsigned& ctxSpl, unsigned& ctxQt, unsigned& ctxHv, unsigned& ctxHorBt, unsigned& ctxVerBt, bool* canSplit = nullptr ); #if JVET_O0193_REMOVE_TR_DEPTH_IN_CBF_CTX -unsigned CtxQtCbf ( const ComponentID compID, const bool prevCbCbf = false, const int ispIdx = 0 ); +unsigned CtxQtCbf ( const ComponentID compID, const bool prevCbf = false, const int ispIdx = 0 ); #else -unsigned CtxQtCbf ( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf = false, const int ispIdx = 0 ); +unsigned CtxQtCbf ( const ComponentID compID, const unsigned trDepth, const bool prevCbf = false, const int ispIdx = 0 ); #endif unsigned CtxInterDir ( const PredictionUnit& pu ); unsigned CtxSkipFlag ( const CodingUnit& cu ); diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 0241a7569425fba2a5ad31e4e079f70533d15a08..45325644e93214be5bd670ae683d84a56acec741 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -783,6 +783,16 @@ const CtxSet ContextSetCfg::ctbAlfFlag = ContextSetCfg::addCtxSet { 0, 0, 0, 0, 0, 0, 0, 0, 0, }, }); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +const CtxSet ContextSetCfg::ctbAlfAlternative = ContextSetCfg::addCtxSet +({ // Cb, Cr + { 100, 100, }, // B / P (cabac_init_flag) + { 153, 153, }, // P / B (cabac_init_flag) + { 200, 200, }, // I + { 0, 0, }, // shiftIdx +}); + +#endif const CtxSet ContextSetCfg::AlfUseLatestFilt = ContextSetCfg::addCtxSet ({ { 169, }, @@ -907,7 +917,11 @@ const unsigned ContextSetCfg::NumberOfContexts = (unsigned)ContextSetCfg::sm_Ini // combined sets const CtxSet ContextSetCfg::Sao = { ContextSetCfg::SaoMergeFlag, ContextSetCfg::SaoTypeIdx }; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +const CtxSet ContextSetCfg::Alf = { ContextSetCfg::ctbAlfFlag, ContextSetCfg::ctbAlfAlternative, ContextSetCfg::AlfUseLatestFilt, ContextSetCfg::AlfUseTemporalFilt }; +#else const CtxSet ContextSetCfg::Alf = { ContextSetCfg::ctbAlfFlag, ContextSetCfg::AlfUseLatestFilt, ContextSetCfg::AlfUseTemporalFilt }; +#endif template <class BinProbModel> CtxStore<BinProbModel>::CtxStore() diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 10654ba93fbe654ae28846e2601f516b8e7a15db..db203e80230c15f928dc8b84521f126937bcf776 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -260,9 +260,14 @@ public: static const CtxSet ImvFlag; static const CtxSet GBiIdx; static const CtxSet ctbAlfFlag; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + static const CtxSet ctbAlfAlternative; +#endif static const CtxSet AlfUseLatestFilt; static const CtxSet AlfUseTemporalFilt; +#if !JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB static const CtxSet Alf; +#endif static const CtxSet MHIntraFlag; static const CtxSet SmvdFlag; static const CtxSet IBCFlag; @@ -274,6 +279,9 @@ public: // NOTE: The contained CtxSet's should directly follow each other in the initalization list; // otherwise, you will copy more elements than you want !!! static const CtxSet Sao; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + static const CtxSet Alf; +#endif public: static const std::vector<uint8_t>& getInitTable( unsigned initId ); diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index e63eab3936eb31bffd0d610777f59f260350d768..ca75f5db4a375107719f85c29c5502a62c16d6f7 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -194,7 +194,11 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth if (m_piYuvExt[COMPONENT_Y][PRED_BUF_UNFILTERED] == nullptr) // check if first is null (in which case, nothing initialised yet) { +#if JVET_O0364_PADDING + m_iYuvExtSize = (MAX_CU_SIZE * 2 + 1 + MAX_REF_LINE_IDX) * (MAX_CU_SIZE * 2 + 1 + MAX_REF_LINE_IDX); +#else m_iYuvExtSize = (MAX_CU_SIZE * 2 + 1 + MAX_REF_LINE_IDX * 33) * (MAX_CU_SIZE * 2 + 1 + MAX_REF_LINE_IDX * 33); +#endif for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++) { @@ -314,11 +318,16 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co CHECK( g_aucLog2[iWidth] > 7, "Size not allowed" ); const int multiRefIdx = m_ipaParam.multiRefIndex; +#if JVET_O0364_PADDING + const int srcStride = m_topRefLength + 1 + multiRefIdx; + const int srcHStride = m_leftRefLength + 1 + multiRefIdx; +#else const int whRatio = m_ipaParam.whRatio; const int hwRatio = m_ipaParam.hwRatio; const int srcStride = m_topRefLength + 1 + (whRatio + 1) * multiRefIdx; const int srcHStride = m_leftRefLength + 1 + (hwRatio + 1) * multiRefIdx; +#endif const CPelBuf & srcBuf = CPelBuf(getPredictorPtr(compID), srcStride, srcHStride); const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compID)); @@ -519,7 +528,14 @@ void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompA if (dirMode > DC_IDX && dirMode < NUM_LUMA_MODE) // intraPredAngle for directional modes { static const int angTable[32] = { 0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 23, 26, 29, 32, 35, 39, 45, 51, 57, 64, 73, 86, 102, 128, 171, 256, 341, 512, 1024 }; +#if JVET_O0364_PADDING + static const int invAngTable[32] = { + 0, 16384, 8192, 5461, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 712, 630, 565, + 512, 468, 420, 364, 321, 287, 256, 224, 191, 161, 128, 96, 64, 48, 32, 16 + }; // (512 * 32) / Angle +#else static const int invAngTable[32] = { 0, 8192, 4096, 2731, 2048, 1365, 1024, 819, 683, 585, 512, 455, 410, 356, 315, 282, 256, 234, 210, 182, 161, 144, 128, 112, 95, 80, 64, 48, 32, 24, 16, 8 }; // (256 * 32) / Angle +#endif const int absAngMode = abs(intraPredAngleMode); const int signAng = intraPredAngleMode < 0 ? -1 : 1; @@ -537,7 +553,11 @@ void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompA const int sideSize = m_ipaParam.isModeVer ? puSize.height : puSize.width; const int maxScale = 2; +#if JVET_O0364_PADDING + m_ipaParam.angularScale = std::min(maxScale, g_aucLog2[sideSize] - (floorLog2(3 * m_ipaParam.invAngle - 2) - 8)); +#else m_ipaParam.angularScale = std::min(maxScale, g_aucLog2[sideSize] - (floorLog2(3 * m_ipaParam.invAngle - 2) - 7)); +#endif m_ipaParam.applyPDPC &= m_ipaParam.angularScale >= 0; } #else @@ -636,6 +656,25 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch // Initialize the Main and Left reference array. if (intraPredAngle < 0) { +#if JVET_O0364_PADDING + for (int x = 0; x <= width + 1 + multiRefIdx; x++) + { + refAbove[x + height] = pSrc.at(x, 0); + } + for (int y = 0; y <= height + 1 + multiRefIdx; y++) + { + refLeft[y + width] = pSrc.at(0, y); + } + refMain = bIsModeVer ? refAbove + height : refLeft + width; + refSide = bIsModeVer ? refLeft + width : refAbove + height; + + // Extend the Main reference to the left. + int sizeSide = bIsModeVer ? height : width; + for (int k = -sizeSide; k <= -1; k++) + { + refMain[k] = refSide[std::min((-k * invAngle + 256) >> 9, sizeSide)]; + } +#else const int width = pDst.width + 1; const int height = pDst.height + 1; const int lastIdx = (bIsModeVer ? width : height) + multiRefIdx; @@ -661,9 +700,31 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch } refMain[lastIdx] = refMain[lastIdx-1]; refMain[firstIdx] = refMain[firstIdx+1]; +#endif } else { +#if JVET_O0364_PADDING + for (int x = 0; x <= m_topRefLength + multiRefIdx; x++) + { + refAbove[x] = pSrc.at(x, 0); + } + for (int y = 0; y <= m_leftRefLength + multiRefIdx; y++) + { + refLeft[y] = pSrc.at(0, y); + } + + refMain = bIsModeVer ? refAbove : refLeft; + refSide = bIsModeVer ? refLeft : refAbove; + + // Extend main reference to right using replication + int maxIndex = multiRefIdx * (bIsModeVer ? whRatio : hwRatio) + 2; + Pel val = bIsModeVer ? pSrc.at(m_topRefLength + multiRefIdx, 0) : pSrc.at(0, m_leftRefLength + multiRefIdx); + for (int z = 1; z <= maxIndex; z++) + { + refMain[(bIsModeVer ? m_topRefLength : m_leftRefLength) + multiRefIdx + z] = val; + } +#else for (int x = 0; x < m_topRefLength + 1 + (whRatio + 1) * multiRefIdx; x++) { refAbove[x+1] = pSrc.at(x, 0); @@ -680,6 +741,7 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch refMain[-1] = refMain[0]; auto lastIdx = 1 + ((bIsModeVer) ? m_topRefLength + (whRatio + 1) * multiRefIdx : m_leftRefLength + (hwRatio + 1) * multiRefIdx); refMain[lastIdx] = refMain[lastIdx-1]; +#endif } // swap width/height if we are doing a horizontal mode: @@ -763,14 +825,22 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch if (m_ipaParam.applyPDPC) { const int scale = m_ipaParam.angularScale; +#if JVET_O0364_PADDING + int invAngleSum = 256; +#else int invAngleSum = 128; +#endif for (int x = 0; x < std::min(3 << scale, width); x++) { invAngleSum += invAngle; int wL = 32 >> (2 * x >> scale); +#if JVET_O0364_PADDING + Pel left = refSide[y + (invAngleSum >> 9) + 1]; +#else Pel left = refSide[y + (invAngleSum >> 8) + 1]; +#endif pDsty[x] = pDsty[x] + ((wL * (left - pDsty[x]) + 32) >> 6); } } @@ -799,11 +869,19 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch } else { +#if JVET_O0364_PADDING + int invAngleSum0 = 4; +#else int invAngleSum0 = 2; +#endif for (int x = 0; x < width; x++) { invAngleSum0 += invAngle; +#if JVET_O0364_PADDING + int deltaPos0 = invAngleSum0 >> 3; +#else int deltaPos0 = invAngleSum0 >> 2; +#endif int deltaFrac0 = deltaPos0 & 63; int deltaInt0 = deltaPos0 >> 6; @@ -1000,11 +1078,15 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf const int tuHeight = area.height; const int predSize = m_topRefLength; const int predHSize = m_leftRefLength; +#if JVET_O0364_PADDING + const int predStride = predSize + 1 + multiRefIdx; +#else const int cuWidth = cu.blocks[area.compID].width; const int cuHeight = cu.blocks[area.compID].height; const int whRatio = cu.ispMode && isLuma(area.compID) ? std::max(1, cuWidth / cuHeight) : std::max(1, tuWidth / tuHeight); const int hwRatio = cu.ispMode && isLuma(area.compID) ? std::max(1, cuHeight / cuWidth) : std::max(1, tuHeight / tuWidth); const int predStride = predSize + 1 + (whRatio + 1) * multiRefIdx; +#endif const bool noShift = pcv.noChroma2x2 && area.width == 4; // don't shift on the lowest level (chroma not-split) const int unitWidth = tuWidth <= 2 && cu.ispMode && isLuma(area.compID) ? tuWidth : pcv.minCUWidth >> (noShift ? 0 : getComponentScaleX(area.compID, sps.getChromaFormatIdc())); @@ -1228,12 +1310,14 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf currUnit++; } } +#if !JVET_O0364_PADDING // padding of extended samples above right with the last sample int lastSample = multiRefIdx + predSize; for (int j = 1; j <= whRatio * multiRefIdx; j++) { ptrDst[lastSample + j] = ptrDst[lastSample]; } // padding of extended samples below left with the last sample lastSample = multiRefIdx + predHSize; for (int i = 1; i <= hwRatio * multiRefIdx; i++) { ptrDst[(lastSample + i)*predStride] = ptrDst[lastSample*predStride]; } +#endif } void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps @@ -1244,10 +1328,15 @@ void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* { multiRefIdx = 0; } +#if JVET_O0364_PADDING + const int predSize = m_topRefLength + multiRefIdx; + const int predHSize = m_leftRefLength + multiRefIdx; +#else int whRatio = std::max(1, int(area.width / area.height)); int hwRatio = std::max(1, int(area.height / area.width)); const int predSize = m_topRefLength + (whRatio + 1) * multiRefIdx; const int predHSize = m_leftRefLength + (hwRatio + 1) * multiRefIdx; +#endif const int predStride = predSize + 1; diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index e0e76f57c977f463054b9be4c9efd407cf5ee075..bfa59145aa5f56dc8e4418170485737b6412cab1 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -63,12 +63,18 @@ // Tables // ==================================================================================================================== +#if JVET_O0159_10BITTCTABLE_DEBLOCKING +const uint16_t LoopFilter::sm_tcTable[MAX_QP + 1 + DEFAULT_INTRA_TC_OFFSET] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,5,5,5,5,7,7,8,9,10,10,11,13,14,15,17,19,21,24,25,29,33,36,41,45,51,57,64,71,80,89,100,112,125,141,157,177,198,222,250,280,314,352,395 +}; +#else const uint8_t LoopFilter::sm_tcTable[MAX_QP + 1 + DEFAULT_INTRA_TC_OFFSET] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,5,5,6,6,7,8,9,10,11,13,14,16,18,20,22,25 , 28, 31, 35, 39, 44, 50, 56, 63, 70, 79, 88, 99 }; - +#endif const uint8_t LoopFilter::sm_betaTable[MAX_QP + 1] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64 @@ -722,7 +728,11 @@ unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const De if( 0 <= miQ.refIdx[0] ) { mvQ0 = miQ.mv[0]; } if( 0 <= miQ.refIdx[1] ) { mvQ1 = miQ.mv[1]; } +#if JVET_O0061_MV_THR_DEBLOCKING + int nThreshold = (1 << MV_FRACTIONAL_BITS_INTERNAL) >> 1; +#else int nThreshold = 1 << MV_FRACTIONAL_BITS_INTERNAL; +#endif unsigned uiBs = 0; //th can be optimized @@ -774,7 +784,11 @@ unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const De Mv mvP0 = miP.mv[0]; Mv mvQ0 = miQ.mv[0]; +#if JVET_O0061_MV_THR_DEBLOCKING + int nThreshold = (1 << MV_FRACTIONAL_BITS_INTERNAL) >> 1; +#else int nThreshold = 1 << MV_FRACTIONAL_BITS_INTERNAL; +#endif return ( ( abs( mvQ0.getHor() - mvP0.getHor() ) >= nThreshold ) || ( abs( mvQ0.getVer() - mvP0.getVer() ) >= nThreshold ) ) ? (tmpBs + 1) : tmpBs; } @@ -932,7 +946,11 @@ void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edg const int iIndexTC = Clip3(0, MAX_QP + DEFAULT_INTRA_TC_OFFSET, int(iQP + DEFAULT_INTRA_TC_OFFSET*(uiBs - 1) + (tcOffsetDiv2 << 1))); const int iIndexB = Clip3(0, MAX_QP, iQP + (betaOffsetDiv2 << 1)); +#if JVET_O0159_10BITTCTABLE_DEBLOCKING + const int iTc = bitDepthLuma < 10 ? ((sm_tcTable[iIndexTC] + 2) >> (10 - bitDepthLuma)) : ((sm_tcTable[iIndexTC]) << (bitDepthLuma - 10)); +#else const int iTc = sm_tcTable [iIndexTC] * iBitdepthScale; +#endif const int iBeta = sm_betaTable[iIndexB ] * iBitdepthScale; const int iSideThreshold = ( iBeta + ( iBeta >> 1 ) ) >> 3; const int iThrCut = iTc * 10; @@ -1209,8 +1227,11 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed } const int iIndexTC = Clip3<int>(0, MAX_QP + DEFAULT_INTRA_TC_OFFSET, iQP + DEFAULT_INTRA_TC_OFFSET * (bS[chromaIdx] - 1) + (tcOffsetDiv2 << 1)); +#if JVET_O0159_10BITTCTABLE_DEBLOCKING + const int iTc = sps.getBitDepth(CHANNEL_TYPE_CHROMA) < 10 ? ((sm_tcTable[iIndexTC] + 2) >> (10 - sps.getBitDepth(CHANNEL_TYPE_CHROMA))) : ((sm_tcTable[iIndexTC]) << (sps.getBitDepth(CHANNEL_TYPE_CHROMA) - 10)); +#else const int iTc = sm_tcTable[iIndexTC] * iBitdepthScale; - +#endif bool useLongFilter = false; if (largeBoundary) { diff --git a/source/Lib/CommonLib/LoopFilter.h b/source/Lib/CommonLib/LoopFilter.h index 3495d709ca16d8c7aedc388444eec6da2b89fd21..7d1fe7f80d45c908731896696c3d1236a889b79e 100644 --- a/source/Lib/CommonLib/LoopFilter.h +++ b/source/Lib/CommonLib/LoopFilter.h @@ -101,7 +101,11 @@ private: inline int xCalcDP ( Pel* piSrc, const int iOffset ) const; inline int xCalcDQ ( Pel* piSrc, const int iOffset ) const; +#if JVET_O0159_10BITTCTABLE_DEBLOCKING + static const uint16_t sm_tcTable[MAX_QP + 3]; +#else static const uint8_t sm_tcTable[MAX_QP + 3]; +#endif static const uint8_t sm_betaTable[MAX_QP + 1]; public: diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 4ccb3ee858d9db4bc723d886513df93cdd9fe37b..39d803d68424707c4e56d8e28b71697d70c3f585 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -343,6 +343,19 @@ public: m_alfCtbFilterIndex[i] = 0; } } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + std::vector<uint8_t> m_alfCtuAlternative[MAX_NUM_COMPONENT]; + std::vector<uint8_t>& getAlfCtuAlternative( int compIdx ) { return m_alfCtuAlternative[compIdx]; } + uint8_t* getAlfCtuAlternativeData( int compIdx ) { return m_alfCtuAlternative[compIdx].data(); } + void resizeAlfCtuAlternative( int numEntries ) + { + for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ ) + { + m_alfCtuAlternative[compIdx].resize( numEntries ); + std::fill( m_alfCtuAlternative[compIdx].begin(), m_alfCtuAlternative[compIdx].end(), 0 ); + } + } +#endif }; int calcAndPrintHashStatus(const CPelUnitBuf& pic, const class SEIDecodedPictureHash* pictureHashSEI, const BitDepths &bitDepths, const MsgLevel msgl); diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index f5001fbc74512227e1bfe5590dbea59f7011a629..220649a3448f216020fb59ab2689bb1cc1ca338e 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -205,6 +205,9 @@ void Slice::initSlice() m_jointCbCrSignFlag = false; #endif m_enableTMVPFlag = true; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + resetTileGroupAlfEnabledFlag(); +#endif } void Slice::setDefaultClpRng( const SPS& sps ) diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 19d77128a931869d30df3c57696e21ac7a0f6d3d..a4f18555dbd1ee3941c359f800dac838e474f48f 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -47,6 +47,7 @@ #include "ChromaFormat.h" #include "Common.h" #include "HRD.h" +#include "AlfParameters.h" //! \ingroup CommonLib //! \{ @@ -1379,7 +1380,7 @@ class APS private: int m_APSId; // adaptation_parameter_set_id int m_APSType; // aps_params_type - AlfSliceParam m_alfAPSParam; + AlfParam m_alfAPSParam; SliceReshapeInfo m_reshapeAPSInfo; public: @@ -1392,10 +1393,10 @@ public: int getAPSType() const { return m_APSType; } void setAPSType(int type) { m_APSType = type; } - void setAlfAPSParam(AlfSliceParam& alfAPSParam) { m_alfAPSParam = alfAPSParam; } + void setAlfAPSParam(AlfParam& alfAPSParam) { m_alfAPSParam = alfAPSParam; } void setTemporalId(int i) { m_alfAPSParam.tLayer = i; } int getTemporalId() { return m_alfAPSParam.tLayer; } - AlfSliceParam& getAlfAPSParam() { return m_alfAPSParam; } + AlfParam& getAlfAPSParam() { return m_alfAPSParam; } void setReshaperAPSInfo(SliceReshapeInfo& reshapeAPSInfo) { m_reshapeAPSInfo = reshapeAPSInfo; } SliceReshapeInfo& getReshaperAPSInfo() { return m_reshapeAPSInfo; } diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp index d38003361c4a2c4f3c5ac125a9fd54c6f586b952..ab45af5ed2e5cae336fec0a6d378c24c5bfd5bc4 100644 --- a/source/Lib/CommonLib/TrQuant.cpp +++ b/source/Lib/CommonLib/TrQuant.cpp @@ -1231,7 +1231,7 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const void TrQuant::xGetCoeffEnergy( TransformUnit &tu, const ComponentID &compID, const CoeffBuf& coeffs, double* diagRatio, double* horVerRatio ) { if( nullptr == diagRatio || nullptr == horVerRatio ) return; - if( tu.cu->predMode == MODE_INTRA && !tu.cu->ispMode && isLuma( compID ) && tu.cs->sps->getUseISP() && CU::canUseISPSplit( *tu.cu, compID ) != NOT_INTRA_SUBPARTITIONS ) + if( tu.cu->predMode == MODE_INTRA && !tu.cu->ispMode && isLuma( compID ) && tu.cs->sps->getUseISP() && CU::canUseISP( *tu.cu, compID ) ) { const int width = tu.cu->blocks[compID].width; const int height = tu.cu->blocks[compID].height; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 00ad5a574b1749232981ab62ce3f30ec687e37e1..9dc529bf5cbdc3a09a88a64f36ee10e36d74a898 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,16 @@ #include <assert.h> #include <cassert> +#define JVET_O0159_10BITTCTABLE_DEBLOCKING 1 // tc table for 10-bit video + +#define JVET_O0061_MV_THR_DEBLOCKING 1 // a deblocking mv threshold of half pel + +#define JVET_O0046_DQ_SIGNALLING 1 // JVET-O0046: Move delta-QP earlier for 64x64 VPDU processing, applied to CUs >64x64 only + +#define JVET_O0616_400_CHROMA_SUPPORT 1 // JVET-O0616: Various chroma format support in VVC + +#define JVET_O0265_TPM_SIMPLIFICATION 1 // JVET-O0265/JVET-O0629/JVET-O0418/JVET-O0329/JVET-O0378/JVET-O0411/JVET-O0279:Simplified motion field storage for TPM + #define JVET_O0409_EXCLUDE_CODED_SUB_BLK_FLAG_FROM_COUNT 1 // JVET-O0409: exclude coded_subblock_flag from counting context-coded bins in transform skip #define JVET_O1136_TS_BDPCM_SIGNALLING 1 // JVET-O1136: Unified syntax for JVET-O0165/O0200/O0783 on TS and BDPCM signalling @@ -90,6 +100,8 @@ #define JVET_O0543_ICT_ICU_ONLY 1 // JVET-O0543: ICT only in Intra CUs (was Intra slices, modified during adoption) #define JVET_N0288_PROPOSAL1 1 // JVET-N0288 Proposal 1 +#define JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB 1 // JVET-O0090 test 2: CTB selection of ALF alternative chroma filters + #define JVET_O0216_ALF_COEFF_EG3 1 // JVET-O0216/O0302/O0648: using EG3 for ALF coefficients coding #define JVET_O0256_ADJUST_THD_DEPQUANT 1 // JVET-O0256: Fast encoder with adjusted threshold in dependent quantization @@ -138,6 +150,9 @@ #define JVET_O0280_SIMD_TRIANGLE_WEIGHTING 1 // JVET-O0280: SIMD implementation for weighted sample prediction process of triangle prediction mode +#define JVET_O0379_SPEEDUP_TPM_ENCODER 1 // JVET_O0379: Speedup mode decision process for triangle prediction mode + +#define JVET_O0364_PADDING 1 // JVET-O0364 Part 2: clean up padding process in intra prediction #define JVET_O0364_PDPC_DC 1 // JVET-O0364 Part 4: align PDPC process for DC with the one for Planar #define JVET_O0364_PDPC_ANGULAR 1 // JVET-O0364 Part 5: simplify PDPC process for angular modes @@ -157,12 +172,15 @@ #define JVET_O1140_SLICE_DISABLE_BDOF_DMVR_FLAG 1 // JVET-O1140 slice level disable flag for BDOF and DMVR +#define JVET_O0567_MVDRange_Constraint 1 // JVET-O0567: constrain the signalled MVD value to the range of [-2^17, 2^17-1] #define JVET_O0596_CBF_SIG_ALIGN_TO_SPEC 1 // JVET-O0596 align cbf signaling with specification #define JVET_O0193_REMOVE_TR_DEPTH_IN_CBF_CTX 1 // JVET-O0193/JVET-O0375: remove transform depth in cbf context modeling #define JVET_O0594_BDOF_REF_SAMPLE_PADDING 1 // JVET-O0594/O0252/O0506/O0615/O0624: BDOF reference sample padding using the nearest integer sample position +#define JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS 1 // JVET-O0472: LFNST index signalling depends on the position of last significant coefficient + #define FIX_DB_MAX_TRANSFORM_SIZE 1 #define MRG_SHARELIST_SHARSIZE 32 @@ -425,8 +443,7 @@ enum ISPType NOT_INTRA_SUBPARTITIONS = 0, HOR_INTRA_SUBPARTITIONS = 1, VER_INTRA_SUBPARTITIONS = 2, - NUM_INTRA_SUBPARTITIONS_MODES = 3, - CAN_USE_VER_AND_HORL_SPLITS = 4 + NUM_INTRA_SUBPARTITIONS_MODES = 3 }; enum SbtIdx @@ -1414,179 +1431,6 @@ struct XUCache #define SIGN(x) ( (x) >= 0 ? 1 : -1 ) -#define MAX_NUM_ALF_CLASSES 25 -#define MAX_NUM_ALF_LUMA_COEFF 13 -#define MAX_NUM_ALF_CHROMA_COEFF 7 -#define MAX_ALF_FILTER_LENGTH 7 -#define MAX_NUM_ALF_COEFF (MAX_ALF_FILTER_LENGTH * MAX_ALF_FILTER_LENGTH / 2 + 1) -#define MAX_ALF_PADDING_SIZE 4 - -enum AlfFilterType -{ - ALF_FILTER_5, - ALF_FILTER_7, - ALF_NUM_OF_FILTER_TYPES -}; - -struct AlfFilterShape -{ - AlfFilterShape( int size ) - : filterLength( size ), - numCoeff( size * size / 4 + 1 ), - filterSize( size * size / 2 + 1 ) - { - if( size == 5 ) - { - pattern = { - 0, - 1, 2, 3, - 4, 5, 6, 5, 4, - 3, 2, 1, - 0 - }; - - weights = { - 2, - 2, 2, 2, - 2, 2, 1, 1 - }; -#if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING - golombIdx = { - 0, - 0, 1, 0, - 0, 1, 2, 2 - }; -#endif - - filterType = ALF_FILTER_5; - } - else if( size == 7 ) - { - pattern = { - 0, - 1, 2, 3, - 4, 5, 6, 7, 8, - 9, 10, 11, 12, 11, 10, 9, - 8, 7, 6, 5, 4, - 3, 2, 1, - 0 - }; - - weights = { - 2, - 2, 2, 2, - 2, 2, 2, 2, 2, - 2, 2, 2, 1, 1 - }; -#if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING - golombIdx = { - 0, - 0, 1, 0, - 0, 1, 2, 1, 0, - 0, 1, 2, 3, 3 - }; -#endif - - filterType = ALF_FILTER_7; - } - else - { - filterType = ALF_NUM_OF_FILTER_TYPES; - CHECK( 0, "Wrong ALF filter shape" ); - } - } - - AlfFilterType filterType; - int filterLength; - int numCoeff; //TO DO: check whether we need both numCoeff and filterSize - int filterSize; - std::vector<int> pattern; - std::vector<int> weights; -#if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING - std::vector<int> golombIdx; -#endif -}; - -struct AlfSliceParam -{ - bool enabledFlag[MAX_NUM_COMPONENT]; // alf_slice_enable_flag, alf_chroma_idc - bool nonLinearFlag[MAX_NUM_CHANNEL_TYPE]; // alf_nonlinear_enable_flag[Luma/Chroma] - short lumaCoeff[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; // alf_coeff_luma_delta[i][j] - short lumaClipp[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; // alf_clipp_luma_[i][j] - short chromaCoeff[MAX_NUM_ALF_CHROMA_COEFF]; // alf_coeff_chroma[i] - short chromaClipp[MAX_NUM_ALF_CHROMA_COEFF]; // alf_clipp_chroma[i] - short filterCoeffDeltaIdx[MAX_NUM_ALF_CLASSES]; // filter_coeff_delta[i] - bool alfLumaCoeffFlag[MAX_NUM_ALF_CLASSES]; // alf_luma_coeff_flag[i] - int numLumaFilters; // number_of_filters_minus1 + 1 - bool alfLumaCoeffDeltaFlag; // alf_luma_coeff_delta_flag -#if !JVET_O0669_REMOVE_ALF_COEFF_PRED - bool alfLumaCoeffDeltaPredictionFlag; // alf_luma_coeff_delta_prediction_flag -#endif - std::vector<AlfFilterShape>* filterShapes; - int tLayer; - bool newFilterFlag[MAX_NUM_CHANNEL_TYPE]; -#if !JVET_O0669_REMOVE_ALF_COEFF_PRED - int fixedFilterPattern; - int fixedFilterIdx[MAX_NUM_ALF_CLASSES]; - int fixedFilterSetIndex; -#endif - - AlfSliceParam() - { - reset(); - } - - void reset() - { - std::memset( enabledFlag, false, sizeof( enabledFlag ) ); - std::memset( nonLinearFlag, false, sizeof( nonLinearFlag ) ); - std::memset( lumaCoeff, 0, sizeof( lumaCoeff ) ); - std::memset( lumaClipp, 0, sizeof( lumaClipp ) ); - std::memset( chromaCoeff, 0, sizeof( chromaCoeff ) ); - std::memset( chromaClipp, 0, sizeof( chromaClipp ) ); - std::memset( filterCoeffDeltaIdx, 0, sizeof( filterCoeffDeltaIdx ) ); - std::memset( alfLumaCoeffFlag, true, sizeof( alfLumaCoeffFlag ) ); - numLumaFilters = 1; - alfLumaCoeffDeltaFlag = false; -#if !JVET_O0669_REMOVE_ALF_COEFF_PRED - alfLumaCoeffDeltaPredictionFlag = false; -#endif - tLayer = 0; - memset(newFilterFlag, 0, sizeof(newFilterFlag)); -#if !JVET_O0669_REMOVE_ALF_COEFF_PRED - fixedFilterPattern = 0; - std::memset(fixedFilterIdx, 0, sizeof(fixedFilterIdx)); - fixedFilterSetIndex = 0; -#endif - } - - const AlfSliceParam& operator = ( const AlfSliceParam& src ) - { - std::memcpy( enabledFlag, src.enabledFlag, sizeof( enabledFlag ) ); - std::memcpy( nonLinearFlag, src.nonLinearFlag, sizeof( nonLinearFlag ) ); - std::memcpy( lumaCoeff, src.lumaCoeff, sizeof( lumaCoeff ) ); - std::memcpy( lumaClipp, src.lumaClipp, sizeof( lumaClipp ) ); - std::memcpy( chromaCoeff, src.chromaCoeff, sizeof( chromaCoeff ) ); - std::memcpy( chromaClipp, src.chromaClipp, sizeof( chromaClipp ) ); - std::memcpy( filterCoeffDeltaIdx, src.filterCoeffDeltaIdx, sizeof( filterCoeffDeltaIdx ) ); - std::memcpy( alfLumaCoeffFlag, src.alfLumaCoeffFlag, sizeof( alfLumaCoeffFlag ) ); - numLumaFilters = src.numLumaFilters; - alfLumaCoeffDeltaFlag = src.alfLumaCoeffDeltaFlag; -#if !JVET_O0669_REMOVE_ALF_COEFF_PRED - alfLumaCoeffDeltaPredictionFlag = src.alfLumaCoeffDeltaPredictionFlag; -#endif - filterShapes = src.filterShapes; - tLayer = src.tLayer; - std::memcpy(newFilterFlag, src.newFilterFlag, sizeof(newFilterFlag)); -#if !JVET_O0669_REMOVE_ALF_COEFF_PRED - fixedFilterPattern = src.fixedFilterPattern; - std::memcpy(fixedFilterIdx, src.fixedFilterIdx, sizeof(fixedFilterIdx)); - fixedFilterSetIndex = src.fixedFilterSetIndex; -#endif - return *this; - } -}; - //! \} #endif diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 3aec86d1c7ecd686ae3016706a192622e5ba08ab..8ec126e19eb745de437a395df7e7dfb28eed3b8e 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -250,6 +250,7 @@ bool CU::hasNonTsCodedBlock( const CodingUnit& cu ) return hasAnyNonTSCoded; } +#if !JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS uint32_t CU::getNumNonZeroCoeffNonTs( const CodingUnit& cu, const bool lumaFlag, const bool chromaFlag ) { uint32_t count = 0; @@ -260,6 +261,7 @@ uint32_t CU::getNumNonZeroCoeffNonTs( const CodingUnit& cu, const bool lumaFlag, return count; } +#endif #if !JVET_O0094_LFNST_ZERO_PRIM_COEFFS uint32_t CU::getNumNonZeroCoeffNonTsCorner8x8( const CodingUnit& cu, const bool lumaFlag, const bool chromaFlag ) @@ -383,7 +385,7 @@ bool CU::isISPFirst( const CodingUnit &cu, const CompArea &tuArea, const Compone return tuArea == cu.firstTU->blocks[compID]; } -ISPType CU::canUseISPSplit( const CodingUnit &cu, const ComponentID compID ) +bool CU::canUseISP( const CodingUnit &cu, const ComponentID compID ) { const int width = cu.blocks[compID].width; const int height = cu.blocks[compID].height; @@ -392,35 +394,18 @@ ISPType CU::canUseISPSplit( const CodingUnit &cu, const ComponentID compID ) #else const int maxTrSize = MAX_TB_SIZEY; #endif - return CU::canUseISPSplit( width, height, maxTrSize ); + return CU::canUseISP( width, height, maxTrSize ); } -ISPType CU::canUseISPSplit( const int width, const int height, const int maxTrSize ) +bool CU::canUseISP( const int width, const int height, const int maxTrSize ) { - bool widthCannotBeUsed = false, heightCannotBeUsed = false; - - const uint32_t minTuSizeForISP = MIN_TB_SIZEY; - bool notEnoughSamplesToSplit = ( g_aucLog2[width] + g_aucLog2[height] <= ( g_aucLog2[minTuSizeForISP] << 1 ) ); - bool cuSizeLargerThanMaxTrSize = width > maxTrSize || height > maxTrSize; - widthCannotBeUsed = cuSizeLargerThanMaxTrSize || notEnoughSamplesToSplit; - heightCannotBeUsed = cuSizeLargerThanMaxTrSize || notEnoughSamplesToSplit; - - if( !widthCannotBeUsed && !heightCannotBeUsed ) - { - return CAN_USE_VER_AND_HORL_SPLITS; //both splits can be used - } - else if( widthCannotBeUsed && !heightCannotBeUsed ) - { - return VER_INTRA_SUBPARTITIONS; //only the vertical split can be performed - } - else if( !widthCannotBeUsed && heightCannotBeUsed ) - { - return HOR_INTRA_SUBPARTITIONS; //only the horizontal split can be performed - } - else + bool notEnoughSamplesToSplit = ( g_aucLog2[width] + g_aucLog2[height] <= ( g_aucLog2[MIN_TB_SIZEY] << 1 ) ); + bool cuSizeLargerThanMaxTrSize = width > maxTrSize || height > maxTrSize; + if ( notEnoughSamplesToSplit || cuSizeLargerThanMaxTrSize ) { - return NOT_INTRA_SUBPARTITIONS; //neither of the splits can be used + return false; } + return true; } uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit ispType ) @@ -4025,6 +4010,13 @@ void PU::spanTriangleMotionInfo( PredictionUnit &pu, MergeCtx &triangleMrgCtx, c } else if( triangleMrgCtx.interDirNeighbours[candIdx0] == 1 && triangleMrgCtx.interDirNeighbours[candIdx1] == 1 ) { +#if JVET_O0265_TPM_SIMPLIFICATION + biMv.interDir = 1; + biMv.mv[0] = triangleMrgCtx.mvFieldNeighbours[candIdx1 << 1].mv; + biMv.mv[1] = Mv(0, 0); + biMv.refIdx[0] = triangleMrgCtx.mvFieldNeighbours[candIdx1 << 1].refIdx; + biMv.refIdx[1] = -1; +#else 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 ) { @@ -4043,9 +4035,17 @@ void PU::spanTriangleMotionInfo( PredictionUnit &pu, MergeCtx &triangleMrgCtx, c biMv.refIdx[0] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[candIdx1 << 1].refIdx : triangleMrgCtx.mvFieldNeighbours[candIdx0 << 1].refIdx; biMv.refIdx[1] = ( refIdx != -1 ) ? refIdx : -1; } +#endif } else if( triangleMrgCtx.interDirNeighbours[candIdx0] == 2 && triangleMrgCtx.interDirNeighbours[candIdx1] == 2 ) { +#if JVET_O0265_TPM_SIMPLIFICATION + biMv.interDir = 2; + biMv.mv[0] = Mv(0, 0); + biMv.mv[1] = triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].mv; + biMv.refIdx[0] = -1; + biMv.refIdx[1] = triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].refIdx; +#else 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 ) { @@ -4064,6 +4064,7 @@ void PU::spanTriangleMotionInfo( PredictionUnit &pu, MergeCtx &triangleMrgCtx, c biMv.refIdx[0] = ( refIdx != -1 ) ? refIdx : -1; biMv.refIdx[1] = ( refIdx != -1 ) ? triangleMrgCtx.mvFieldNeighbours[(candIdx1 << 1) + 1].refIdx : triangleMrgCtx.mvFieldNeighbours[(candIdx0 << 1) + 1].refIdx; } +#endif } int32_t idxW = (int32_t)(g_aucLog2[pu.lwidth() ] - MIN_CU_LOG2); @@ -4641,6 +4642,7 @@ bool TU::hasCrossCompPredInfo( const TransformUnit &tu, const ComponentID &compI (!CU::isIntra(*tu.cu) || PU::isChromaIntraModeCrossCheckMode(*tu.cs->getPU(tu.blocks[compID].pos(), toChannelType(compID))))); } +#if !JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS uint32_t TU::getNumNonZeroCoeffsNonTS( const TransformUnit& tu, const bool bLuma, const bool bChroma ) { uint32_t count = 0; @@ -4661,6 +4663,7 @@ uint32_t TU::getNumNonZeroCoeffsNonTS( const TransformUnit& tu, const bool bLuma } return count; } +#endif #if !JVET_O0094_LFNST_ZERO_PRIM_COEFFS uint32_t TU::getNumNonZeroCoeffsNonTSCorner8x8( const TransformUnit& tu, const bool lumaFlag, const bool chromaFlag ) { diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 4423e858dd4b5a70a93fc0c4473909a679954872..063a53054fbcde9ea07be75fdab94fc02da21e93 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -78,7 +78,9 @@ namespace CU PartSplit getSplitAtDepth (const CodingUnit& cu, const unsigned depth); bool hasNonTsCodedBlock (const CodingUnit& cu); +#if !JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS uint32_t getNumNonZeroCoeffNonTs ( const CodingUnit& cu, const bool lumaFlag = true, const bool chromaFlag = true ); +#endif uint32_t getNumNonZeroCoeffNonTsCorner8x8( const CodingUnit& cu, const bool lumaFlag = true, const bool chromaFlag = true ); #if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN bool isPredRegDiffFromTB(const CodingUnit& cu, const ComponentID compID); @@ -98,8 +100,8 @@ namespace CU PartSplit getISPType ( const CodingUnit &cu, const ComponentID compID ); bool isISPLast ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ); bool isISPFirst ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ); - ISPType canUseISPSplit ( const CodingUnit &cu, const ComponentID compID ); - ISPType canUseISPSplit ( const int width, const int height, const int maxTrSize = MAX_TB_SIZEY ); + bool canUseISP ( const CodingUnit &cu, const ComponentID compID ); + bool canUseISP ( const int width, const int height, const int maxTrSize = MAX_TB_SIZEY ); uint32_t getISPSplitDim ( const int width, const int height, const PartSplit ispType ); PUTraverser traversePUs ( CodingUnit& cu); @@ -209,7 +211,9 @@ namespace PU // TU tools namespace TU { +#if !JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS uint32_t getNumNonZeroCoeffsNonTS (const TransformUnit &tu, const bool bLuma = true, const bool bChroma = true); +#endif uint32_t getNumNonZeroCoeffsNonTSCorner8x8( const TransformUnit &tu, const bool bLuma = true, const bool bChroma = true ); bool isNonTransformedResidualRotated(const TransformUnit &tu, const ComponentID &compID); bool getCbf (const TransformUnit &tu, const ComponentID &compID); diff --git a/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h b/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h index 618378c692c27e5f8d810fc6ce03f0df920961a6..609a37c8f24e55ab627fb6a17a5564df88a39327 100644 --- a/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h +++ b/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h @@ -353,7 +353,7 @@ static void simdDeriveClassificationBlk(AlfClassifier** classifier, int** laplac } template<X86_VEXT vext> -static void simdFilter5x5Blk(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, short* filterSet, short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos) +static void simdFilter5x5Blk(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, const short* filterSet, const short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos) { const bool bChroma = isChroma( compId ); @@ -382,8 +382,8 @@ static void simdFilter5x5Blk(AlfClassifier** classifier, const PelUnitBuf &recDs const Pel *pImgYPad0, *pImgYPad1, *pImgYPad2, *pImgYPad3, *pImgYPad4; const Pel *pImg0, *pImg1, *pImg2, *pImg3, *pImg4; - short *coef[2] = { filterSet, filterSet }; - short *clip[2] = { fClipSet, fClipSet }; + const short *coef[2] = { filterSet, filterSet }; + const short *clip[2] = { fClipSet, fClipSet }; int transposeIdx[2] = {0, 0}; const int clsSizeY = 4; @@ -496,7 +496,11 @@ static void simdFilter5x5Blk(AlfClassifier** classifier, const PelUnitBuf &recDs for( blkX=0; blkX<8; blkX+=2 ) { Position pos(j + blkDst.x + blkX, i + blkDst.y + blkY); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); +#else CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); +#endif if(cu != NULL) { *flags++ = cu->ipcm ? 1 : 0; @@ -752,7 +756,7 @@ static void simdFilter5x5Blk(AlfClassifier** classifier, const PelUnitBuf &recDs } template<X86_VEXT vext> -static void simdFilter7x7Blk(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, short* filterSet, short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos) +static void simdFilter7x7Blk(AlfClassifier** classifier, const PelUnitBuf &recDst, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blk, const ComponentID compId, const short* filterSet, const short* fClipSet, const ClpRng& clpRng, CodingStructure& cs, int vbCTUHeight, int vbPos) { const bool bChroma = isChroma( compId ); @@ -780,8 +784,8 @@ static void simdFilter7x7Blk(AlfClassifier** classifier, const PelUnitBuf &recDs const Pel *pImgYPad0, *pImgYPad1, *pImgYPad2, *pImgYPad3, *pImgYPad4, *pImgYPad5, *pImgYPad6; const Pel *pImg0, *pImg1, *pImg2, *pImg3, *pImg4, *pImg5, *pImg6; - short *coef[2] = { filterSet, filterSet }; - short *clip[2] = { fClipSet, fClipSet }; + const short *coef[2] = { filterSet, filterSet }; + const short *clip[2] = { fClipSet, fClipSet }; int transposeIdx[2] = {0, 0}; const int clsSizeY = 4; @@ -895,7 +899,11 @@ static void simdFilter7x7Blk(AlfClassifier** classifier, const PelUnitBuf &recDs for( blkX=0; blkX<8; blkX+=2 ) { Position pos(j + blkDst.x + blkX, i + blkDst.y + blkY); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); +#else CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); +#endif if( cu != NULL) { *flags++ = cu->ipcm ? 1 : 0; diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 8da36f60531138377c956b7f52bf46075d10f179..9aaedbdf3ac373ceafd629b095656120b60c0037 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -173,6 +173,24 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i { readAlfCtuFilterIndex(cs, ctuRsAddr); } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( isChroma( (ComponentID)compIdx ) ) + { + int apsIdx = cs.slice->getTileGroupApsIdChroma(); + CHECK(cs.slice->getAlfAPSs()[apsIdx] == nullptr, "APS not initialized"); + const AlfParam& alfParam = cs.slice->getAlfAPSs()[apsIdx]->getAlfAPSParam(); + const int numAlts = alfParam.numAlternativesChroma; + uint8_t* ctbAlfAlternative = cs.slice->getPic()->getAlfCtuAlternativeData( compIdx ); + ctbAlfAlternative[ctuRsAddr] = 0; + if( ctbAlfFlag[ctuRsAddr] ) + { + uint8_t decoded = 0; + while( decoded < numAlts-1 && m_BinDecoder.decodeBin( Ctx::ctbAlfAlternative( compIdx-1 ) ) ) + ++ decoded; + ctbAlfAlternative[ctuRsAddr] = decoded; + } + } +#endif } } } @@ -1395,6 +1413,11 @@ void CABACReader::cu_residual( CodingUnit& cu, Partitioner &partitioner, CUCtx& cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] = false; cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false; #endif +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + cuCtx.lastScanPos[COMPONENT_Y ] = -1; + cuCtx.lastScanPos[COMPONENT_Cb] = -1; + cuCtx.lastScanPos[COMPONENT_Cr] = -1; +#endif ChromaCbfs chromaCbfs; if( cu.ispMode && isLuma( partitioner.chType ) ) @@ -1414,7 +1437,7 @@ void CABACReader::cu_residual( CodingUnit& cu, Partitioner &partitioner, CUCtx& transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs ); #endif } -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS residual_lfnst_mode( cu, cuCtx ); #else residual_lfnst_mode( cu ); @@ -1642,6 +1665,9 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx ) { RefPicList eCurRefList = (RefPicList)(pu.cu->smvdMode - 1); pu.mvd[1 - eCurRefList].set( -pu.mvd[eCurRefList].hor, -pu.mvd[eCurRefList].ver ); +#if JVET_O0567_MVDRange_Constraint + CHECK(!((pu.mvd[1 - eCurRefList].getHor() >= MVD_MIN) && (pu.mvd[1 - eCurRefList].getHor() <= MVD_MAX)) || !((pu.mvd[1 - eCurRefList].getVer() >= MVD_MIN) && (pu.mvd[1 - eCurRefList].getVer() <= MVD_MAX)), "Illegal MVD value"); +#endif pu.refIdx[1 - eCurRefList] = pu.cs->slice->getSymRefIdx( 1 - eCurRefList ); } @@ -2390,6 +2416,9 @@ void CABACReader::mvd_coding( Mv &rMvd ) } } rMvd = Mv(horAbs, verAbs); +#if JVET_O0567_MVDRange_Constraint + CHECK(!((horAbs >= MVD_MIN) && (horAbs <= MVD_MAX)) || !((verAbs >= MVD_MIN) && (verAbs <= MVD_MAX)), "Illegal MVD value"); +#endif } @@ -2498,7 +2527,11 @@ void CABACReader::transform_unit( TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& c } #endif +#if JVET_O0046_DQ_SIGNALLING + if( cu.lwidth() > 64 || cu.lheight() > 64 || cbfLuma || cbfChroma ) +#else if( cbfLuma || cbfChroma ) +#endif { if( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded ) { @@ -2520,7 +2553,7 @@ void CABACReader::transform_unit( TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& c } if( cbfLuma ) { -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS residual_coding( tu, COMPONENT_Y, cuCtx ); #else residual_coding( tu, COMPONENT_Y ); @@ -2536,7 +2569,7 @@ void CABACReader::transform_unit( TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& c } if( tu.cbf[ compID ] ) { -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS residual_coding( tu, compID, cuCtx ); #else residual_coding( tu, compID ); @@ -2622,7 +2655,7 @@ void CABACReader::joint_cb_cr( TransformUnit& tu ) } #endif -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID, CUCtx& cuCtx ) #else void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) @@ -2680,6 +2713,12 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) const int maxLfnstPos = ((tu.blocks[compID].height == 4 && tu.blocks[compID].width == 4) || (tu.blocks[compID].height == 8 && tu.blocks[compID].width == 8)) ? 7 : 15; cuCtx.violatesLfnstConstrained[ toChannelType(compID) ] |= cctx.scanPosLast() > maxLfnstPos; } +#endif +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + if( tu.mtsIdx != MTS_SKIP && tu.blocks[ compID ].height >= 4 && tu.blocks[ compID ].width >= 4 ) + { + cuCtx.lastScanPos[compID] = cctx.scanPosLast(); + } #endif // parse subblocks const int stateTransTab = ( tu.cs->slice->getDepQuantEnabledFlag() ? 32040 : 0 ); @@ -2769,38 +2808,20 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) void CABACReader::isp_mode( CodingUnit& cu ) { - if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm || !cu.cs->sps->getUseISP() || cu.bdpcmMode ) + if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm || !cu.cs->sps->getUseISP() || cu.bdpcmMode || !CU::canUseISP( cu, getFirstComponentOfChannel( cu.chType ) ) ) { cu.ispMode = NOT_INTRA_SUBPARTITIONS; return; } - const ISPType allowedSplits = CU::canUseISPSplit( cu, getFirstComponentOfChannel( cu.chType ) ); - if( allowedSplits == NOT_INTRA_SUBPARTITIONS ) - { - cu.ispMode = NOT_INTRA_SUBPARTITIONS; - return; - } + int symbol = m_BinDecoder.decodeBin(Ctx::ISPMode(0)); RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__ISP_MODE_FLAG ); - cu.ispMode = NOT_INTRA_SUBPARTITIONS; - int symbol = m_BinDecoder.decodeBin( Ctx::ISPMode( 0 ) ); if( symbol ) { - if( allowedSplits == HOR_INTRA_SUBPARTITIONS ) - { - cu.ispMode = HOR_INTRA_SUBPARTITIONS; - } - else if( allowedSplits == VER_INTRA_SUBPARTITIONS ) - { - cu.ispMode = VER_INTRA_SUBPARTITIONS; - } - else - { - RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__ISP_SPLIT_FLAG ); - cu.ispMode = 1 + m_BinDecoder.decodeBin( Ctx::ISPMode( 1 ) ); - } + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__ISP_SPLIT_FLAG ); + cu.ispMode = 1 + m_BinDecoder.decodeBin( Ctx::ISPMode( 1 ) ); } DTRACE( g_trace_ctx, D_SYNTAX, "intra_subPartitions() etype=%d pos=(%d,%d) ispIdx=%d\n", cu.chType, cu.blocks[cu.chType].x, cu.blocks[cu.chType].y, (int)cu.ispMode ); } @@ -2830,7 +2851,7 @@ void CABACReader::explicit_rdpcm_mode( TransformUnit& tu, ComponentID compID ) } } -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS void CABACReader::residual_lfnst_mode( CodingUnit& cu, CUCtx& cuCtx ) #else void CABACReader::residual_lfnst_mode( CodingUnit& cu ) @@ -2848,19 +2869,35 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu ) { const bool lumaFlag = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? true : false ) : true; const bool chromaFlag = CS::isDualITree( *cu.cs ) ? ( isChroma( cu.chType ) ? true : false ) : true; +#if !JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS bool nonZeroCoeffNonTs; +#endif #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS bool nonZeroCoeffNonTsCorner8x8 = ( lumaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] ) || (chromaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] ); #else bool nonZeroCoeffNonTsCorner8x8 = CU::getNumNonZeroCoeffNonTsCorner8x8( cu, lumaFlag, chromaFlag ) > 0; #endif +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + const bool skipLfnst = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA ) : + ( cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA ) ) : + ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA && cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA ); +#else const int nonZeroCoeffThr = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA; nonZeroCoeffNonTs = CU::getNumNonZeroCoeffNonTs( cu, lumaFlag, chromaFlag ) > nonZeroCoeffThr; +#endif #if JVET_O0368_LFNST_WITH_DCT2_ONLY const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2); +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + if( skipLfnst || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 ) +#else if (!nonZeroCoeffNonTs || nonZeroCoeffNonTsCorner8x8 || isNonDCT2) +#endif +#else +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + if( skipLfnst || nonZeroCoeffNonTsCorner8x8 ) #else if( !nonZeroCoeffNonTs || nonZeroCoeffNonTsCorner8x8 ) +#endif #endif { cu.lfnstIdx = 0; @@ -3308,6 +3345,12 @@ void CABACReader::residual_coding_subblockTS( CoeffCodingContext& cctx, TCoeff* cutoffVal = 2; for (int i = 0; i < numGtBins; i++) { +#if JVET_O0122_TS_SIGN_LEVEL + if( tcoeff < 0) + { + tcoeff = -tcoeff; + } +#endif if (tcoeff >= cutoffVal) { RExt__DECODER_DEBUG_BIT_STATISTICS_SET(ctype_gt2); diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 2f86875b4176884a1f3dde68729c7a229309e310..c6e2afa9040b42f2e0081123e512cdfa708cdf53 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -122,7 +122,7 @@ public: #else void transform_tree ( CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType = TU_NO_ISP, const int subTuIdx = -1 ); #endif - bool cbf_comp ( CodingStructure& cs, const CompArea& area, unsigned depth, const bool prevCbCbf = false, const bool useISP = false ); + bool cbf_comp ( CodingStructure& cs, const CompArea& area, unsigned depth, const bool prevCbf = false, const bool useISP = false ); // mvd coding (clause 7.3.8.9) void mvd_coding ( Mv &rMvd ); @@ -137,13 +137,13 @@ public: void cu_chroma_qp_offset ( CodingUnit& cu ); // residual coding (clause 7.3.8.11) -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS void residual_coding ( TransformUnit& tu, ComponentID compID, CUCtx& cuCtx ); #else void residual_coding ( TransformUnit& tu, ComponentID compID ); #endif void mts_coding ( TransformUnit& tu, ComponentID compID ); -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS void residual_lfnst_mode ( CodingUnit& cu, CUCtx& cuCtx ); #else void residual_lfnst_mode ( CodingUnit& cu ); diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 64e053eeb8e13faf42ccc42fa5824ac8d1c3d291..e78d641bfddd226e6893c1543794737f54d3d284 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -206,7 +206,16 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri { std::copy( pic->getAlfCtuEnableFlag()[compIdx].begin(), pic->getAlfCtuEnableFlag()[compIdx].end(), pcEncPic->getAlfCtuEnableFlag()[compIdx].begin() ); } +#if JVET_N0415_CTB_ALF + pcEncPic->resizeAlfCtbFilterIndex(pic->cs->pcv->sizeInCtus); + memcpy( pcEncPic->getAlfCtbFilterIndex(), pic->getAlfCtbFilterIndex(), sizeof(short)*pic->cs->pcv->sizeInCtus ); +#endif + +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + std::copy( pic->getAlfCtuAlternative(COMPONENT_Cb).begin(), pic->getAlfCtuAlternative(COMPONENT_Cb).end(), pcEncPic->getAlfCtuAlternative(COMPONENT_Cb).begin() ); + std::copy( pic->getAlfCtuAlternative(COMPONENT_Cr).begin(), pic->getAlfCtuAlternative(COMPONENT_Cr).end(), pcEncPic->getAlfCtuAlternative(COMPONENT_Cr).begin() ); +#endif for( int i = 0; i < pic->slices.size(); i++ ) { pcEncPic->slices[i]->setTileGroupNumAps(pic->slices[i]->getTileGroupNumAps()); diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp index 1da86e80022a9934be94379e57652b229858578d..5def5c887f3b9bb4677059532d536c172354b91a 100644 --- a/source/Lib/DecoderLib/DecSlice.cpp +++ b/source/Lib/DecoderLib/DecSlice.cpp @@ -98,6 +98,9 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb { cs.picture->resizeAlfCtuEnableFlag( cs.pcv->sizeInCtus ); cs.picture->resizeAlfCtbFilterIndex(cs.pcv->sizeInCtus); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + cs.picture->resizeAlfCtuAlternative( cs.pcv->sizeInCtus ); +#endif } const unsigned numSubstreams = slice->getNumberOfSubstreamSizes() + 1; diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 1a8ecc240ce99ccff93803610af269b32335afc3..4916dc593e19f94f2546d8a72dae77dfe4ea3200 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -798,7 +798,10 @@ void HLSyntaxReader::parseAlfAps( APS* aps ) { uint32_t code; - AlfSliceParam param = aps->getAlfAPSParam(); + AlfParam param = aps->getAlfAPSParam(); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + param.reset(); +#endif param.enabledFlag[COMPONENT_Y] = param.enabledFlag[COMPONENT_Cb] = param.enabledFlag[COMPONENT_Cr] = true; READ_FLAG(code, "alf_luma_new_filter"); param.newFilterFlag[CHANNEL_TYPE_LUMA] = code; @@ -809,7 +812,11 @@ void HLSyntaxReader::parseAlfAps( APS* aps ) if (param.newFilterFlag[CHANNEL_TYPE_LUMA]) { READ_FLAG(code, "alf_luma_clip"); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + param.nonLinearFlag[CHANNEL_TYPE_LUMA][0] = code ? true : false; +#else param.nonLinearFlag[CHANNEL_TYPE_LUMA] = code ? true : false; +#endif xReadTruncBinCode(code, MAX_NUM_ALF_CLASSES); //number_of_filters_minus1 param.numLumaFilters = code + 1; if (param.numLumaFilters > 1) @@ -844,13 +851,33 @@ void HLSyntaxReader::parseAlfAps( APS* aps ) } } #endif +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + alfFilter( param, false, 0 ); +#else alfFilter(param, false); +#endif } if (param.newFilterFlag[CHANNEL_TYPE_CHROMA]) { +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( MAX_NUM_ALF_ALTERNATIVES_CHROMA > 1 ) + READ_UVLC( code, "alf_chroma_num_alts_minus1" ); + else + code = 0; + + param.numAlternativesChroma = code + 1; + + for( int altIdx=0; altIdx < param.numAlternativesChroma; ++altIdx ) + { + READ_FLAG( code, "alf_nonlinear_enable_flag_chroma" ); + param.nonLinearFlag[CHANNEL_TYPE_CHROMA][altIdx] = code ? true : false; + alfFilter( param, true, altIdx ); + } +#else READ_FLAG(code, "alf_luma_clip"); param.nonLinearFlag[CHANNEL_TYPE_CHROMA] = code ? true : false; - alfFilter(param, true); + alfFilter(param, true); +#endif } aps->setAlfAPSParam(param); } @@ -1781,7 +1808,18 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para pcSlice->setAlfAPSs(apsId); - alfChromaIdc = truncatedUnaryEqProb(3); //alf_chroma_idc +#if JVET_O0616_400_CHROMA_SUPPORT + if (bChroma) + { +#endif + alfChromaIdc = truncatedUnaryEqProb(3); //alf_chroma_idc +#if JVET_O0616_400_CHROMA_SUPPORT + } + else + { + alfChromaIdc = 0; + } +#endif if (alfChromaIdc) { #if JVET_O0288_UNIFY_ALF_SLICE_TYPE_REMOVAL @@ -2147,16 +2185,24 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para if (pcSlice->getLmcsEnabledFlag()) { +#if JVET_O0428_LMCS_CLEANUP + READ_CODE(2, uiCode, "slice_lmcs_aps_id"); +#else READ_CODE(5, uiCode, "slice_lmcs_aps_id"); +#endif pcSlice->setLmcsAPSId(uiCode); #if !JVET_O1109_UNFIY_CRS if (!(sps->getUseDualITree() && pcSlice->isIntra())) { +#endif +#if JVET_O0616_400_CHROMA_SUPPORT + if (bChroma) + { #endif READ_FLAG(uiCode, "slice_chroma_residual_scale_flag"); pcSlice->setLmcsChromaResidualScaleFlag(uiCode == 1); -#if !JVET_O1109_UNFIY_CRS +#if !JVET_O1109_UNFIY_CRS || JVET_O0616_400_CHROMA_SUPPORT } else { @@ -2634,33 +2680,37 @@ int HLSyntaxReader::alfGolombDecode( const int k, const bool signed_val ) return nr; } -void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChroma ) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +void HLSyntaxReader::alfFilter( AlfParam& alfParam, const bool isChroma, const int altIdx ) +#else +void HLSyntaxReader::alfFilter( AlfParam& alfParam, const bool isChroma ) +#endif { uint32_t code; if( !isChroma ) { READ_FLAG( code, "alf_luma_coeff_delta_flag" ); - alfSliceParam.alfLumaCoeffDeltaFlag = code; + alfParam.alfLumaCoeffDeltaFlag = code; - if( !alfSliceParam.alfLumaCoeffDeltaFlag ) + if( !alfParam.alfLumaCoeffDeltaFlag ) { - std::memset( alfSliceParam.alfLumaCoeffFlag, true, sizeof( alfSliceParam.alfLumaCoeffFlag ) ); + std::memset( alfParam.alfLumaCoeffFlag, true, sizeof( alfParam.alfLumaCoeffFlag ) ); #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - if( alfSliceParam.numLumaFilters > 1 ) + if( alfParam.numLumaFilters > 1 ) { READ_FLAG( code, "alf_luma_coeff_delta_prediction_flag" ); - alfSliceParam.alfLumaCoeffDeltaPredictionFlag = code; + alfParam.alfLumaCoeffDeltaPredictionFlag = code; } else { - alfSliceParam.alfLumaCoeffDeltaPredictionFlag = 0; + alfParam.alfLumaCoeffDeltaPredictionFlag = 0; } #endif } #if !JVET_O0669_REMOVE_ALF_COEFF_PRED else { - alfSliceParam.alfLumaCoeffDeltaPredictionFlag = 0; + alfParam.alfLumaCoeffDeltaPredictionFlag = 0; } #endif } @@ -2677,9 +2727,15 @@ void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChrom int kMin = code + 1; static int kMinTab[MAX_NUM_ALF_COEFF]; #endif - const int numFilters = isChroma ? 1 : alfSliceParam.numLumaFilters; - short* coeff = isChroma ? alfSliceParam.chromaCoeff : alfSliceParam.lumaCoeff; - short* clipp = isChroma ? alfSliceParam.chromaClipp : alfSliceParam.lumaClipp; + const int numFilters = isChroma ? 1 : alfParam.numLumaFilters; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + short* coeff = isChroma ? alfParam.chromaCoeff[altIdx] : alfParam.lumaCoeff; + short* clipp = isChroma ? alfParam.chromaClipp[altIdx] : alfParam.lumaClipp; +#else + short* coeff = isChroma ? alfParam.chromaCoeff : alfParam.lumaCoeff; + short* clipp = isChroma ? alfParam.chromaClipp : alfParam.lumaClipp; +#endif + #if !JVET_O0216_ALF_COEFF_EG3 for( int idx = 0; idx < maxGolombIdx; idx++ ) { @@ -2691,12 +2747,12 @@ void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChrom #endif if( !isChroma ) { - if( alfSliceParam.alfLumaCoeffDeltaFlag ) + if( alfParam.alfLumaCoeffDeltaFlag ) { - for( int ind = 0; ind < alfSliceParam.numLumaFilters; ++ind ) + for( int ind = 0; ind < alfParam.numLumaFilters; ++ind ) { READ_FLAG( code, "alf_luma_coeff_flag[i]" ); - alfSliceParam.alfLumaCoeffFlag[ind] = code; + alfParam.alfLumaCoeffFlag[ind] = code; } } } @@ -2704,7 +2760,7 @@ void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChrom // Filter coefficients for( int ind = 0; ind < numFilters; ++ind ) { - if( !isChroma && !alfSliceParam.alfLumaCoeffFlag[ind] && alfSliceParam.alfLumaCoeffDeltaFlag ) + if( !isChroma && !alfParam.alfLumaCoeffFlag[ind] && alfParam.alfLumaCoeffDeltaFlag ) { memset( coeff + ind * MAX_NUM_ALF_LUMA_COEFF, 0, sizeof( *coeff ) * alfShape.numCoeff ); continue; @@ -2721,7 +2777,11 @@ void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChrom } // Clipping values coding - if ( alfSliceParam.nonLinearFlag[isChroma] ) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if ( alfParam.nonLinearFlag[isChroma][altIdx] ) +#else + if ( alfParam.nonLinearFlag[isChroma] ) +#endif { #if !JVET_O0064_SIMP_ALF_CLIP_CODING READ_UVLC( code, "clip_min_golomb_order" ); @@ -2745,7 +2805,7 @@ void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChrom { memcpy( recCoeff, coeff, sizeof(short) * numFilters * MAX_NUM_ALF_LUMA_COEFF ); #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - if( alfSliceParam.alfLumaCoeffDeltaPredictionFlag ) + if( alfParam.alfLumaCoeffDeltaPredictionFlag ) { for( int i = 1; i < numFilters; i++ ) { @@ -2763,7 +2823,7 @@ void HLSyntaxReader::alfFilter( AlfSliceParam& alfSliceParam, const bool isChrom for( int ind = 0; ind < numFilters; ++ind ) { #if !JVET_O0064_SIMP_ALF_CLIP_CODING - if( !isChroma && !alfSliceParam.alfLumaCoeffFlag[ind] && alfSliceParam.alfLumaCoeffDeltaFlag ) + if( !isChroma && !alfParam.alfLumaCoeffFlag[ind] && alfParam.alfLumaCoeffDeltaFlag ) { std::fill_n( clipp + ind * MAX_NUM_ALF_LUMA_COEFF, alfShape.numCoeff, 0 ); continue; diff --git a/source/Lib/DecoderLib/VLCReader.h b/source/Lib/DecoderLib/VLCReader.h index 1ff98fa3b148294e999b6f2df491ef2328b8828e..9f50ab02772a4f908e718ec2211851f42fbc0dbf 100644 --- a/source/Lib/DecoderLib/VLCReader.h +++ b/source/Lib/DecoderLib/VLCReader.h @@ -165,7 +165,11 @@ public: void parseScalingList ( ScalingList* scalingList ); void decodeScalingList ( ScalingList *scalingList, uint32_t sizeId, uint32_t listId); void parseReshaper ( SliceReshapeInfo& sliceReshaperInfo, const SPS* pcSPS, const bool isIntra ); - void alfFilter( AlfSliceParam& alfSliceParam, const bool isChroma ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + void alfFilter( AlfParam& alfParam, const bool isChroma, const int altIdx ); +#else + void alfFilter( AlfParam& alfParam, const bool isChroma ); +#endif private: int truncatedUnaryEqProb( const int maxSymbol ); diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 6797116d34f1949ebf50b83aaab2042babae7e1a..e1c54cfe2e21c48899a7a2fd560e93db8d84518a 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -176,6 +176,16 @@ void CABACWriter::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i { codeAlfCtuFilterIndex(cs, ctuRsAddr, cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y)); } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if (isChroma(ComponentID(compIdx))) + { + uint8_t* ctbAlfFlag = cs.slice->getTileGroupAlfEnabledFlag((ComponentID)compIdx) ? cs.slice->getPic()->getAlfCtuEnableFlag( compIdx ) : nullptr; + if( ctbAlfFlag && ctbAlfFlag[ctuRsAddr] ) + { + codeAlfCtuAlternative( cs, ctuRsAddr, compIdx ); + } + } +#endif } } @@ -1294,6 +1304,11 @@ void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, C cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] = false; cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false; #endif +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + cuCtx.lastScanPos[COMPONENT_Y ] = -1; + cuCtx.lastScanPos[COMPONENT_Cb] = -1; + cuCtx.lastScanPos[COMPONENT_Cr] = -1; +#endif #if !JVET_O0596_CBF_SIG_ALIGN_TO_SPEC ChromaCbfs chromaCbfs; @@ -2176,12 +2191,12 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit } } -void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf, const bool useISP ) +void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbf, const bool useISP ) { #if JVET_O0193_REMOVE_TR_DEPTH_IN_CBF_CTX - const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, prevCbCbf, useISP && isLuma(area.compID) ); + const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, prevCbf, useISP && isLuma(area.compID) ); #else - const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf, useISP && isLuma(area.compID) ); + const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbf, useISP && isLuma(area.compID) ); #endif const CtxSet& ctxSet = Ctx::QtCbf[ area.compID ]; if( area.compID == COMPONENT_Y && cs.getCU( area.pos(), ChannelType( area.compID ) )->bdpcmMode ) @@ -2383,7 +2398,11 @@ void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaC } #endif +#if JVET_O0046_DQ_SIGNALLING + if( cu.lwidth() > 64 || cu.lheight() > 64 || cbfLuma || cbfChroma ) +#else if( cbfLuma || cbfChroma ) +#endif { if( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded ) { @@ -2405,7 +2424,7 @@ void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaC } if( cbfLuma ) { -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS residual_coding( tu, COMPONENT_Y, &cuCtx ); #else residual_coding( tu, COMPONENT_Y ); @@ -2421,7 +2440,7 @@ void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaC } if( cbf[ compID ] ) { -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS residual_coding( tu, compID, &cuCtx ); #else residual_coding( tu, compID ); @@ -2508,7 +2527,7 @@ void CABACWriter::joint_cb_cr( const TransformUnit& tu ) } #endif -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID, CUCtx* cuCtx ) #else void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID) @@ -2579,6 +2598,12 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID) const int maxLfnstPos = ((tu.blocks[compID].height == 4 && tu.blocks[compID].width == 4) || (tu.blocks[compID].height == 8 && tu.blocks[compID].width == 8)) ? 7 : 15; cuCtx->violatesLfnstConstrained[ toChannelType(compID) ] |= cctx.scanPosLast() > maxLfnstPos; } +#endif +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + if( cuCtx && tu.mtsIdx != MTS_SKIP && tu.blocks[ compID ].height >= 4 && tu.blocks[ compID ].width >= 4 ) + { + cuCtx->lastScanPos[compID] = cctx.scanPosLast(); + } #endif // code last coeff position last_sig_coeff( cctx, tu, compID ); @@ -2671,26 +2696,19 @@ void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID ) void CABACWriter::isp_mode( const CodingUnit& cu ) { - if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm || !cu.cs->sps->getUseISP() || cu.bdpcmMode ) + if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm || !cu.cs->sps->getUseISP() || cu.bdpcmMode || !CU::canUseISP( cu, getFirstComponentOfChannel( cu.chType ) ) ) { - CHECK( cu.ispMode != NOT_INTRA_SUBPARTITIONS, "error: cu.intraSubPartitions != 0" ); + CHECK( cu.ispMode != NOT_INTRA_SUBPARTITIONS, "cu.ispMode != 0" ); return; } - const ISPType allowedSplits = CU::canUseISPSplit( cu, getFirstComponentOfChannel( cu.chType ) ); - if( allowedSplits == NOT_INTRA_SUBPARTITIONS ) return; - - if( cu.ispMode == NOT_INTRA_SUBPARTITIONS ) + if ( cu.ispMode == NOT_INTRA_SUBPARTITIONS ) { m_BinEncoder.encodeBin( 0, Ctx::ISPMode( 0 ) ); } else { m_BinEncoder.encodeBin( 1, Ctx::ISPMode( 0 ) ); - - if( allowedSplits == CAN_USE_VER_AND_HORL_SPLITS ) - { - m_BinEncoder.encodeBin( cu.ispMode - 1, Ctx::ISPMode( 1 ) ); - } + m_BinEncoder.encodeBin( cu.ispMode - 1, Ctx::ISPMode( 1 ) ); } DTRACE( g_trace_ctx, D_SYNTAX, "intra_subPartitions() etype=%d pos=(%d,%d) ispIdx=%d\n", cu.chType, cu.blocks[cu.chType].x, cu.blocks[cu.chType].y, (int)cu.ispMode ); } @@ -2729,20 +2747,36 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx ) { const bool lumaFlag = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? true : false ) : true; const bool chromaFlag = CS::isDualITree( *cu.cs ) ? ( isChroma( cu.chType ) ? true : false ) : true; +#if !JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS bool nonZeroCoeffNonTs; +#endif #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS bool nonZeroCoeffNonTsCorner8x8 = ( lumaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] ) || (chromaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] ); #else bool nonZeroCoeffNonTsCorner8x8 = CU::getNumNonZeroCoeffNonTsCorner8x8( cu, lumaFlag, chromaFlag ) > 0; #endif +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + const bool skipLfnst = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA ) : + ( cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA ) ) : + ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA && cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA ); +#else const int nonZeroCoeffThr = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA; cuCtx.numNonZeroCoeffNonTs = CU::getNumNonZeroCoeffNonTs( cu, lumaFlag, chromaFlag ); nonZeroCoeffNonTs = cuCtx.numNonZeroCoeffNonTs > nonZeroCoeffThr; +#endif #if JVET_O0368_LFNST_WITH_DCT2_ONLY const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2); +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + if( skipLfnst || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 ) +#else if (!nonZeroCoeffNonTs || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 ) +#endif +#else +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + if( skipLfnst || nonZeroCoeffNonTsCorner8x8 ) #else if( !nonZeroCoeffNonTs || nonZeroCoeffNonTsCorner8x8 ) +#endif #endif { return; @@ -3151,7 +3185,13 @@ void CABACWriter::residual_coding_subblockTS( CoeffCodingContext& cctx, const TC #if JVET_O0619_GTX_SINGLE_PASS_TS_RESIDUAL_CODING for (int scanPos = firstSigPos; scanPos <= minSubPos; scanPos++) { +#if JVET_O0122_TS_SIGN_LEVEL + unsigned absLevel; + cctx.neighTS(rightPixel, belowPixel, scanPos, coeff); + absLevel = cctx.deriveModCoeff(rightPixel, belowPixel, abs(coeff[cctx.blockPos(scanPos)]), cctx.bdpcm()); +#else unsigned absLevel = abs(coeff[cctx.blockPos(scanPos)]); +#endif cutoffVal = 2; for (int i = 0; i < numGtBins; i++) { @@ -3336,7 +3376,7 @@ void CABACWriter::exp_golomb_eqprob( unsigned symbol, unsigned count ) m_BinEncoder.encodeBinsEP( bins, numBins ); } -void CABACWriter::codeAlfCtuEnableFlags( CodingStructure& cs, ChannelType channel, AlfSliceParam* alfParam) +void CABACWriter::codeAlfCtuEnableFlags( CodingStructure& cs, ChannelType channel, AlfParam* alfParam) { if( isLuma( channel ) ) { @@ -3351,7 +3391,7 @@ void CABACWriter::codeAlfCtuEnableFlags( CodingStructure& cs, ChannelType channe codeAlfCtuEnableFlags( cs, COMPONENT_Cr, alfParam ); } } -void CABACWriter::codeAlfCtuEnableFlags( CodingStructure& cs, ComponentID compID, AlfSliceParam* alfParam) +void CABACWriter::codeAlfCtuEnableFlags( CodingStructure& cs, ComponentID compID, AlfParam* alfParam) { uint32_t numCTUs = cs.pcv->sizeInCtus; @@ -3361,7 +3401,7 @@ void CABACWriter::codeAlfCtuEnableFlags( CodingStructure& cs, ComponentID compID } } -void CABACWriter::codeAlfCtuEnableFlag( CodingStructure& cs, uint32_t ctuRsAddr, const int compIdx, AlfSliceParam* alfParam) +void CABACWriter::codeAlfCtuEnableFlag( CodingStructure& cs, uint32_t ctuRsAddr, const int compIdx, AlfParam* alfParam) { const bool alfComponentEnabled = (alfParam != NULL) ? alfParam->enabledFlag[compIdx] : cs.slice->getTileGroupAlfEnabledFlag((ComponentID)compIdx); @@ -3546,5 +3586,58 @@ void CABACWriter::codeAlfCtuFilterIndex(CodingStructure& cs, uint32_t ctuRsAddr, xWriteTruncBinCode(filterSetIdx, NUM_FIXED_FILTER_SETS); } } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +void CABACWriter::codeAlfCtuAlternatives( CodingStructure& cs, ChannelType channel, AlfParam* alfParam) +{ + if( isChroma( channel ) ) + { + if (alfParam->enabledFlag[COMPONENT_Cb]) + codeAlfCtuAlternatives( cs, COMPONENT_Cb, alfParam ); + if (alfParam->enabledFlag[COMPONENT_Cr]) + codeAlfCtuAlternatives( cs, COMPONENT_Cr, alfParam ); + } +} +void CABACWriter::codeAlfCtuAlternatives( CodingStructure& cs, ComponentID compID, AlfParam* alfParam) +{ + if( compID == COMPONENT_Y ) + return; + uint32_t numCTUs = cs.pcv->sizeInCtus; + uint8_t* ctbAlfFlag = cs.slice->getPic()->getAlfCtuEnableFlag( compID ); + + for( int ctuIdx = 0; ctuIdx < numCTUs; ctuIdx++ ) + { + if( ctbAlfFlag[ctuIdx] ) + { + codeAlfCtuAlternative( cs, ctuIdx, compID, alfParam ); + } + } +} + +void CABACWriter::codeAlfCtuAlternative( CodingStructure& cs, uint32_t ctuRsAddr, const int compIdx, const AlfParam* alfParam) +{ + if( compIdx == COMPONENT_Y ) + return; + int apsIdx = alfParam ? 0 : cs.slice->getTileGroupApsIdChroma(); + const AlfParam& alfParamRef = alfParam ? (*alfParam) : cs.slice->getAlfAPSs()[apsIdx]->getAlfAPSParam(); + + if( alfParam || (cs.sps->getALFEnabledFlag() && cs.slice->getTileGroupAlfEnabledFlag( (ComponentID)compIdx )) ) + { + uint8_t* ctbAlfFlag = cs.slice->getPic()->getAlfCtuEnableFlag( compIdx ); + + if( ctbAlfFlag[ctuRsAddr] ) + { + const int numAlts = alfParamRef.numAlternativesChroma; + uint8_t* ctbAlfAlternative = cs.slice->getPic()->getAlfCtuAlternativeData( compIdx ); + unsigned numOnes = ctbAlfAlternative[ctuRsAddr]; + assert( ctbAlfAlternative[ctuRsAddr] < numAlts ); + for( int i = 0; i < numOnes; ++i ) + m_BinEncoder.encodeBin( 1, Ctx::ctbAlfAlternative( compIdx-1 ) ); + if( numOnes < numAlts-1 ) + m_BinEncoder.encodeBin( 0, Ctx::ctbAlfAlternative( compIdx-1 ) ); + } + } +} + +#endif //! \} diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 46cc2b033c282c4af99f658ba6e1e8da72709bb5..2840e7b1b3ae12aaf2349a7ff69aa2d13b7b6a35 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -135,7 +135,7 @@ public: #else void transform_tree ( const CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType = TU_NO_ISP, const int subTuIdx = -1 ); #endif - void cbf_comp ( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf = false, const bool useISP = false ); + void cbf_comp ( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbf = false, const bool useISP = false ); // mvd coding (clause 7.3.8.9) void mvd_coding ( const Mv &rMvd, int8_t imv ); @@ -149,7 +149,7 @@ public: void cu_chroma_qp_offset ( const CodingUnit& cu ); // residual coding (clause 7.3.8.11) -#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS +#if JVET_O0094_LFNST_ZERO_PRIM_COEFFS || JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS void residual_coding ( const TransformUnit& tu, ComponentID compID, CUCtx* cuCtx = nullptr ); #else void residual_coding ( const TransformUnit& tu, ComponentID compID ); @@ -171,10 +171,16 @@ public: // cross component prediction (clause 7.3.8.12) void cross_comp_pred ( const TransformUnit& tu, ComponentID compID ); - void codeAlfCtuEnableFlags ( CodingStructure& cs, ChannelType channel, AlfSliceParam* alfParam); - void codeAlfCtuEnableFlags ( CodingStructure& cs, ComponentID compID, AlfSliceParam* alfParam); - void codeAlfCtuEnableFlag ( CodingStructure& cs, uint32_t ctuRsAddr, const int compIdx, AlfSliceParam* alfParam ); + void codeAlfCtuEnableFlags ( CodingStructure& cs, ChannelType channel, AlfParam* alfParam); + void codeAlfCtuEnableFlags ( CodingStructure& cs, ComponentID compID, AlfParam* alfParam); + void codeAlfCtuEnableFlag ( CodingStructure& cs, uint32_t ctuRsAddr, const int compIdx, AlfParam* alfParam ); void codeAlfCtuFilterIndex(CodingStructure& cs, uint32_t ctuRsAddr, bool alfEnableLuma); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + + void codeAlfCtuAlternatives ( CodingStructure& cs, ChannelType channel, AlfParam* alfParam); + void codeAlfCtuAlternatives ( CodingStructure& cs, ComponentID compID, AlfParam* alfParam); + void codeAlfCtuAlternative ( CodingStructure& cs, uint32_t ctuRsAddr, const int compIdx, const AlfParam* alfParam = NULL ); +#endif private: void unary_max_symbol ( unsigned symbol, unsigned ctxId0, unsigned ctxIdN, unsigned maxSymbol ); diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp index 893b55eab536c7f9dd646af49792981089859904..06341c3b6e3a8f6deb1e59e97e06f7a81293e5d5 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp @@ -427,7 +427,11 @@ void EncAdaptiveLoopFilter::create( const EncCfg* encCfg, const int picWidth, co for( int channelIdx = 0; channelIdx < MAX_NUM_CHANNEL_TYPE; channelIdx++ ) { ChannelType chType = (ChannelType)channelIdx; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + int numClasses = channelIdx ? MAX_NUM_ALF_ALTERNATIVES_CHROMA : MAX_NUM_ALF_CLASSES; +#else int numClasses = channelIdx ? 1 : MAX_NUM_ALF_CLASSES; +#endif m_alfCovarianceFrame[chType] = new AlfCovariance*[m_filterShapes[chType].size()]; for( int i = 0; i != m_filterShapes[chType].size(); i++ ) { @@ -442,6 +446,18 @@ void EncAdaptiveLoopFilter::create( const EncCfg* encCfg, const int picWidth, co for( int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++ ) { m_ctuEnableFlagTmp[compIdx] = new uint8_t[m_numCTUsInPic]; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_ctuEnableFlagTmp2[compIdx] = new uint8_t[m_numCTUsInPic]; + if( isLuma( ComponentID(compIdx) ) ) + { + m_ctuAlternativeTmp[compIdx] = nullptr; + } + else + { + m_ctuAlternativeTmp[compIdx] = new uint8_t[m_numCTUsInPic]; + std::fill_n( m_ctuAlternativeTmp[compIdx], m_numCTUsInPic, 0 ); + } +#endif ChannelType chType = toChannelType( ComponentID( compIdx ) ); int numClasses = compIdx ? 1 : MAX_NUM_ALF_CLASSES; @@ -469,8 +485,13 @@ void EncAdaptiveLoopFilter::create( const EncCfg* encCfg, const int picWidth, co } } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_filterCoeffSet = new int*[std::max(MAX_NUM_ALF_CLASSES, MAX_NUM_ALF_ALTERNATIVES_CHROMA)]; + m_filterClippSet = new int*[std::max(MAX_NUM_ALF_CLASSES, MAX_NUM_ALF_ALTERNATIVES_CHROMA)]; +#else m_filterCoeffSet = new int*[MAX_NUM_ALF_CLASSES]; m_filterClippSet = new int*[MAX_NUM_ALF_CLASSES]; +#endif m_diffFilterCoeff = new int*[MAX_NUM_ALF_CLASSES]; for( int i = 0; i < MAX_NUM_ALF_CLASSES; i++ ) @@ -524,6 +545,20 @@ void EncAdaptiveLoopFilter::destroy() m_ctuEnableFlagTmp[compIdx] = nullptr; } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( m_ctuEnableFlagTmp2[compIdx] ) + { + delete[] m_ctuEnableFlagTmp2[compIdx]; + m_ctuEnableFlagTmp2[compIdx] = nullptr; + } + + if( m_ctuAlternativeTmp[compIdx] ) + { + delete[] m_ctuAlternativeTmp[compIdx]; + m_ctuAlternativeTmp[compIdx] = nullptr; + } + +#endif if( m_alfCovariance[compIdx] ) { ChannelType chType = toChannelType( ComponentID( compIdx ) ); @@ -630,11 +665,11 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda alfAPS = nullptr; } } - AlfSliceParam alfSliceParam; - alfSliceParam.reset(); + AlfParam alfParam; + alfParam.reset(); const TempCtx ctxStart(m_CtxCache, AlfCtx(m_CABACEstimator->getCtx())); // set available filter shapes - alfSliceParam.filterShapes = m_filterShapes; + alfParam.filterShapes = m_filterShapes; // set clipping range m_clpRngs = cs.slice->getClpRngs(); @@ -643,10 +678,13 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda for( int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++ ) { m_ctuEnableFlag[compIdx] = cs.picture->getAlfCtuEnableFlag( compIdx ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_ctuAlternative[compIdx] = cs.picture->getAlfCtuAlternativeData( compIdx ); +#endif } // reset ALF parameters - alfSliceParam.reset(); + alfParam.reset(); int shiftLuma = 2 * DISTORTION_PRECISION_ADJUSTMENT(m_inputBitDepth[CHANNEL_TYPE_LUMA]); int shiftChroma = 2 * DISTORTION_PRECISION_ADJUSTMENT(m_inputBitDepth[CHANNEL_TYPE_CHROMA]); m_lambda[COMPONENT_Y] = lambdas[COMPONENT_Y] * double(1 << shiftLuma); @@ -723,8 +761,18 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda // get CTB stats for filtering deriveStatsForFiltering( orgYuv, recYuv, cs ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + for (int ctbIdx = 0; ctbIdx < m_numCTUsInPic; ctbIdx++) + { + cs.slice->getPic()->getAlfCtbFilterIndex()[ctbIdx] = NUM_FIXED_FILTER_SETS; + } + // consider using new filter (only) + alfParam.newFilterFlag[CHANNEL_TYPE_LUMA] = true; + alfParam.newFilterFlag[CHANNEL_TYPE_CHROMA] = true; + cs.slice->setTileGroupNumAps(1); // Only new filter for RD cost optimization +#endif // derive filter (luma) - alfEncoder( cs, alfSliceParam, orgYuv, recYuv, cs.getRecoBuf(), CHANNEL_TYPE_LUMA + alfEncoder( cs, alfParam, orgYuv, recYuv, cs.getRecoBuf(), CHANNEL_TYPE_LUMA #if ENABLE_QPA , lambdaChromaWeight #endif @@ -732,15 +780,21 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda // derive filter (chroma) { - alfEncoder( cs, alfSliceParam, orgYuv, recYuv, cs.getRecoBuf(), CHANNEL_TYPE_CHROMA + alfEncoder( cs, alfParam, orgYuv, recYuv, cs.getRecoBuf(), CHANNEL_TYPE_CHROMA #if ENABLE_QPA , lambdaChromaWeight #endif ); } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + // let alfEncoderCtb decide now + alfParam.newFilterFlag[CHANNEL_TYPE_LUMA] = false; + alfParam.newFilterFlag[CHANNEL_TYPE_CHROMA] = false; + cs.slice->setTileGroupNumAps(0); +#endif m_CABACEstimator->getCtx() = AlfCtx(ctxStart); - alfEncoderCtb(cs, alfSliceParam + alfEncoderCtb(cs, alfParam #if ENABLE_QPA , lambdaChromaWeight #endif @@ -757,18 +811,38 @@ double EncAdaptiveLoopFilter::deriveCtbAlfEnableFlags( CodingStructure& cs, cons { TempCtx ctxTempStart( m_CtxCache ); TempCtx ctxTempBest( m_CtxCache ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + TempCtx ctxTempAltStart( m_CtxCache ); + TempCtx ctxTempAltBest( m_CtxCache ); +#endif const ComponentID compIDFirst = isLuma( channel ) ? COMPONENT_Y : COMPONENT_Cb; const ComponentID compIDLast = isLuma( channel ) ? COMPONENT_Y : COMPONENT_Cr; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const int numAlts = isLuma( channel ) ? 1 : m_alfParamTemp.numAlternativesChroma; +#endif double cost = 0; distUnfilter = 0; - setEnableFlag(m_alfSliceParamTemp, channel, true); + setEnableFlag(m_alfParamTemp, channel, true); #if ENABLE_QPA CHECK ((chromaWeight > 0.0) && (cs.slice->getSliceCurStartCtuTsAddr() != 0), "incompatible start CTU address, must be 0"); #endif - reconstructCoeff(m_alfSliceParamTemp, channel, true, isLuma(channel)); + reconstructCoeff(m_alfParamTemp, channel, true, isLuma(channel)); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + for( int altIdx = 0; altIdx < (isLuma(channel) ? 1 : MAX_NUM_ALF_ALTERNATIVES_CHROMA); altIdx++) + { + for (int classIdx = 0; classIdx < (isLuma(channel) ? MAX_NUM_ALF_CLASSES : 1); classIdx++) + { + for (int i = 0; i < (isLuma(channel) ? MAX_NUM_ALF_LUMA_COEFF : MAX_NUM_ALF_CHROMA_COEFF); i++) + { + m_filterCoeffSet[isLuma(channel) ? classIdx : altIdx][i] = isLuma(channel) ? m_coeffFinal[classIdx * MAX_NUM_ALF_LUMA_COEFF + i] : m_chromaCoeffFinal[altIdx][i]; + m_filterClippSet[isLuma(channel) ? classIdx : altIdx][i] = isLuma(channel) ? m_clippFinal[classIdx * MAX_NUM_ALF_LUMA_COEFF + i] : m_chromaClippFinal[altIdx][i]; + } + } + } +#else for (int classIdx = 0; classIdx < (isLuma(channel) ? MAX_NUM_ALF_CLASSES : 1); classIdx++) { for (int i = 0; i < (isLuma(channel) ? MAX_NUM_ALF_LUMA_COEFF : MAX_NUM_ALF_CHROMA_COEFF); i++) @@ -777,30 +851,85 @@ double EncAdaptiveLoopFilter::deriveCtbAlfEnableFlags( CodingStructure& cs, cons m_filterClippSet[classIdx][i] = isLuma(channel) ? m_clippFinal[classIdx* MAX_NUM_ALF_LUMA_COEFF + i] : m_chromaClippFinal[i]; } } +#endif for( int ctuIdx = 0; ctuIdx < m_numCTUsInPic; ctuIdx++ ) { for( int compID = compIDFirst; compID <= compIDLast; compID++ ) { +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +#if ENABLE_QPA + const double ctuLambda = chromaWeight > 0.0 ? (isLuma (channel) ? cs.picture->m_uEnerHpCtu[ctuIdx] : cs.picture->m_uEnerHpCtu[ctuIdx] / chromaWeight) : m_lambda[compID]; +#else + const double ctuLambda = m_lambda[compID]; +#endif +#endif + double distUnfilterCtu = getUnfilteredDistortion( m_alfCovariance[compID][iShapeIdx][ctuIdx], numClasses ); ctxTempStart = AlfCtx( m_CABACEstimator->getCtx() ); m_CABACEstimator->resetBits(); m_ctuEnableFlag[compID][ctuIdx] = 1; - m_CABACEstimator->codeAlfCtuEnableFlag( cs, ctuIdx, compID, &m_alfSliceParamTemp ); - double costOn = distUnfilterCtu + getFilteredDistortion( m_alfCovariance[compID][iShapeIdx][ctuIdx], numClasses, m_alfSliceParamTemp.numLumaFilters - 1, numCoeff ); + m_CABACEstimator->codeAlfCtuEnableFlag( cs, ctuIdx, compID, &m_alfParamTemp ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( isLuma( channel ) ) + { + // Evaluate cost of signaling filter set index for convergence of filters enabled flag / filter derivation + assert( cs.slice->getPic()->getAlfCtbFilterIndex()[ctuIdx] == NUM_FIXED_FILTER_SETS ); + assert( cs.slice->getTileGroupNumAps() == 1 ); + m_CABACEstimator->codeAlfCtuFilterIndex(cs, ctuIdx, &m_alfParamTemp.enabledFlag[COMPONENT_Y]); + } + double costOn = distUnfilterCtu + ctuLambda * FracBitsScale*(double)m_CABACEstimator->getEstFracBits(); + +#else + double costOn = distUnfilterCtu + getFilteredDistortion( m_alfCovariance[compID][iShapeIdx][ctuIdx], numClasses, m_alfParamTemp.numLumaFilters - 1, numCoeff ); #if ENABLE_QPA const double ctuLambda = chromaWeight > 0.0 ? (isLuma (channel) ? cs.picture->m_uEnerHpCtu[ctuIdx] : cs.picture->m_uEnerHpCtu[ctuIdx] / chromaWeight) : m_lambda[compID]; #else const double ctuLambda = m_lambda[compID]; #endif costOn += ctuLambda * FracBitsScale*(double)m_CABACEstimator->getEstFracBits(); +#endif ctxTempBest = AlfCtx( m_CABACEstimator->getCtx() ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( isLuma( channel ) ) + { + costOn += getFilteredDistortion( m_alfCovariance[compID][iShapeIdx][ctuIdx], numClasses, m_alfParamTemp.numLumaFilters - 1, numCoeff ); + } + else + { + double bestAltCost = MAX_DOUBLE; + int bestAltIdx = -1; + ctxTempAltStart = AlfCtx( ctxTempBest ); + for( int altIdx = 0; altIdx < numAlts; ++altIdx ) + { + if( altIdx ) + m_CABACEstimator->getCtx() = AlfCtx( ctxTempAltStart ); + m_CABACEstimator->resetBits(); + m_ctuAlternative[compID][ctuIdx] = altIdx; + m_CABACEstimator->codeAlfCtuAlternative( cs, ctuIdx, compID, &m_alfParamTemp ); + double r_altCost = ctuLambda * FracBitsScale*(double)m_CABACEstimator->getEstFracBits(); + + double altDist = 0.; + altDist += m_alfCovariance[compID][iShapeIdx][ctuIdx][0].calcErrorForCoeffs( m_filterClippSet[altIdx], m_filterCoeffSet[altIdx], numCoeff, m_NUM_BITS ); + + double altCost = altDist + r_altCost; + if( altCost < bestAltCost ) + { + bestAltCost = altCost; + bestAltIdx = altIdx; + ctxTempBest = AlfCtx( m_CABACEstimator->getCtx() ); + } + } + m_ctuAlternative[compID][ctuIdx] = bestAltIdx; + costOn += bestAltCost; + } +#endif m_CABACEstimator->getCtx() = AlfCtx( ctxTempStart ); m_CABACEstimator->resetBits(); m_ctuEnableFlag[compID][ctuIdx] = 0; - m_CABACEstimator->codeAlfCtuEnableFlag( cs, ctuIdx, compID, &m_alfSliceParamTemp); + m_CABACEstimator->codeAlfCtuEnableFlag( cs, ctuIdx, compID, &m_alfParamTemp); double costOff = distUnfilterCtu + ctuLambda * FracBitsScale*(double)m_CABACEstimator->getEstFracBits(); if( costOn < costOff ) @@ -820,15 +949,15 @@ double EncAdaptiveLoopFilter::deriveCtbAlfEnableFlags( CodingStructure& cs, cons if( isChroma( channel ) ) { - setEnableFlag(m_alfSliceParamTemp, channel, m_ctuEnableFlag); - const int alfChromaIdc = m_alfSliceParamTemp.enabledFlag[COMPONENT_Cb] * 2 + m_alfSliceParamTemp.enabledFlag[COMPONENT_Cr]; + setEnableFlag(m_alfParamTemp, channel, m_ctuEnableFlag); + const int alfChromaIdc = m_alfParamTemp.enabledFlag[COMPONENT_Cb] * 2 + m_alfParamTemp.enabledFlag[COMPONENT_Cr]; cost += lengthTruncatedUnary(alfChromaIdc, 3) * m_lambda[channel]; } return cost; } -void EncAdaptiveLoopFilter::alfEncoder( CodingStructure& cs, AlfSliceParam& alfSliceParam, const PelUnitBuf& orgUnitBuf, const PelUnitBuf& recExtBuf, const PelUnitBuf& recBuf, const ChannelType channel +void EncAdaptiveLoopFilter::alfEncoder( CodingStructure& cs, AlfParam& alfParam, const PelUnitBuf& orgUnitBuf, const PelUnitBuf& recExtBuf, const PelUnitBuf& recBuf, const ChannelType channel #if ENABLE_QPA , const double lambdaChromaWeight // = 0.0 #endif @@ -839,99 +968,173 @@ void EncAdaptiveLoopFilter::alfEncoder( CodingStructure& cs, AlfSliceParam& alfS double costMin = MAX_DOUBLE; - std::vector<AlfFilterShape>& alfFilterShape = alfSliceParam.filterShapes[channel]; + std::vector<AlfFilterShape>& alfFilterShape = alfParam.filterShapes[channel]; m_bitsNewFilter[channel] = 0; const int numClasses = isLuma( channel ) ? MAX_NUM_ALF_CLASSES : 1; int uiCoeffBits = 0; for( int iShapeIdx = 0; iShapeIdx < alfFilterShape.size(); iShapeIdx++ ) { - m_alfSliceParamTemp = alfSliceParam; + m_alfParamTemp = alfParam; //1. get unfiltered distortion +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( isChroma(channel) ) + m_alfParamTemp.numAlternativesChroma = 1; +#endif double cost = getUnfilteredDistortion( m_alfCovarianceFrame[channel][iShapeIdx], channel ); cost /= 1.001; // slight preference for unfiltered choice if( cost < costMin ) { costMin = cost; - setEnableFlag( alfSliceParam, channel, false ); + setEnableFlag( alfParam, channel, false ); // no CABAC signalling ctxBest = AlfCtx( ctxStart ); setCtuEnableFlag( m_ctuEnableFlagTmp, channel, 0 ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( isChroma(channel) ) + setCtuAlternativeChroma( m_ctuAlternativeTmp, 0 ); +#endif } const int nonLinearFlagMax = +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + ( isLuma( channel ) ? m_encCfg->getUseNonLinearAlfLuma() : 0 ) // For Chroma non linear flag is check for each alternative filter +#else ( isLuma( channel ) ? m_encCfg->getUseNonLinearAlfLuma() : m_encCfg->getUseNonLinearAlfChroma() ) +#endif ? 2 : 1; for( int nonLinearFlag = 0; nonLinearFlag < nonLinearFlagMax; nonLinearFlag++ ) { - //2. all CTUs are on - setEnableFlag( m_alfSliceParamTemp, channel, true ); - m_alfSliceParamTemp.nonLinearFlag[channel] = nonLinearFlag; - m_CABACEstimator->getCtx() = AlfCtx( ctxStart ); - setCtuEnableFlag( m_ctuEnableFlag, channel, 1 ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + for( int numAlternatives = isLuma( channel ) ? 1 : getMaxNumAlternativesChroma(); numAlternatives > 0; numAlternatives-- ) + { + if( isChroma( channel ) ) + m_alfParamTemp.numAlternativesChroma = numAlternatives; +#endif + //2. all CTUs are on + setEnableFlag( m_alfParamTemp, channel, true ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( isLuma( channel ) ) + m_alfParamTemp.nonLinearFlag[channel][0] = nonLinearFlag; +#else + m_alfParamTemp.nonLinearFlag[channel] = nonLinearFlag; +#endif + m_CABACEstimator->getCtx() = AlfCtx( ctxStart ); + setCtuEnableFlag( m_ctuEnableFlag, channel, 1 ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + // all alternatives are on + if( isChroma( channel ) ) + initCtuAlternativeChroma( m_ctuAlternative ); + cost = getFilterCoeffAndCost( cs, 0, channel, true, iShapeIdx, uiCoeffBits ); +#else cost = getFilterCoeffAndCost( cs, 0, channel, nonLinearFlag != 0, iShapeIdx, uiCoeffBits ); +#endif - if( cost < costMin ) - { - m_bitsNewFilter[channel] = uiCoeffBits; - costMin = cost; - copyAlfSliceParam( alfSliceParam, m_alfSliceParamTemp, channel ); - ctxBest = AlfCtx( m_CABACEstimator->getCtx() ); - setCtuEnableFlag( m_ctuEnableFlagTmp, channel, 1 ); - } + if( cost < costMin ) + { + m_bitsNewFilter[channel] = uiCoeffBits; + costMin = cost; + copyAlfParam( alfParam, m_alfParamTemp, channel ); + ctxBest = AlfCtx( m_CABACEstimator->getCtx() ); + setCtuEnableFlag( m_ctuEnableFlagTmp, channel, 1 ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( isChroma(channel) ) + copyCtuAlternativeChroma( m_ctuAlternativeTmp, m_ctuAlternative ); +#endif + } - //3. CTU decision - double distUnfilter = 0; + //3. CTU decision + double distUnfilter = 0; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + double prevItCost = MAX_DOUBLE; +#endif +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const int iterNum = isLuma(channel) ? (2 * 4 + 1) : (2 * (2 + m_alfParamTemp.numAlternativesChroma - 1) + 1); +#else const int iterNum = isLuma(channel) ? (2 * 4 + 1) : (2 * 2 + 1); +#endif - for( int iter = 0; iter < iterNum; iter++ ) - { - if ((iter & 0x01) == 0) + for( int iter = 0; iter < iterNum; iter++ ) { - m_CABACEstimator->getCtx() = AlfCtx(ctxStart); - cost = m_lambda[channel] * uiCoeffBits; - cost += deriveCtbAlfEnableFlags(cs, iShapeIdx, channel, + if ((iter & 0x01) == 0) + { + m_CABACEstimator->getCtx() = AlfCtx(ctxStart); + cost = m_lambda[channel] * uiCoeffBits; + cost += deriveCtbAlfEnableFlags(cs, iShapeIdx, channel, #if ENABLE_QPA - lambdaChromaWeight, + lambdaChromaWeight, +#endif + numClasses, alfFilterShape[iShapeIdx].numCoeff, distUnfilter); + if (cost < costMin) + { + m_bitsNewFilter[channel] = uiCoeffBits; + costMin = cost; + ctxBest = AlfCtx(m_CABACEstimator->getCtx()); + copyCtuEnableFlag(m_ctuEnableFlagTmp, m_ctuEnableFlag, channel); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( isChroma(channel) ) + copyCtuAlternativeChroma( m_ctuAlternativeTmp, m_ctuAlternative ); +#endif + copyAlfParam(alfParam, m_alfParamTemp, channel); + } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + else if ( cost >= prevItCost ) + { + // High probability that we have converged or we are diverging + break; + } + prevItCost = cost; #endif - numClasses, alfFilterShape[iShapeIdx].numCoeff, distUnfilter ); - if (cost < costMin) - { - m_bitsNewFilter[channel] = uiCoeffBits; - costMin = cost; - ctxBest = AlfCtx(m_CABACEstimator->getCtx()); - copyCtuEnableFlag(m_ctuEnableFlagTmp, m_ctuEnableFlag, channel); - copyAlfSliceParam(alfSliceParam, m_alfSliceParamTemp, channel); } - } - else - { - // unfiltered distortion is added due to some CTBs may not use filter + else + { + // unfiltered distortion is added due to some CTBs may not use filter +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + // no need to reset CABAC here, since uiCoeffBits is not affected + /*cost = */getFilterCoeffAndCost( cs, distUnfilter, channel, true, iShapeIdx, uiCoeffBits ); +#else cost = getFilterCoeffAndCost(cs, distUnfilter, channel, true, iShapeIdx, uiCoeffBits); - } - }//for iter +#endif + } + }//for iter + // Decrease number of alternatives and reset ctu params and filters +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + } +#endif }// for nonLineaFlag }//for shapeIdx m_CABACEstimator->getCtx() = AlfCtx( ctxBest ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( isChroma(channel) ) + copyCtuAlternativeChroma( m_ctuAlternative, m_ctuAlternativeTmp ); + copyCtuEnableFlag( m_ctuEnableFlag, m_ctuEnableFlagTmp, channel ); +#endif } -void EncAdaptiveLoopFilter::copyAlfSliceParam( AlfSliceParam& alfSliceParamDst, AlfSliceParam& alfSliceParamSrc, ChannelType channel ) +void EncAdaptiveLoopFilter::copyAlfParam( AlfParam& alfParamDst, AlfParam& alfParamSrc, ChannelType channel ) { if( isLuma( channel ) ) { - memcpy( &alfSliceParamDst, &alfSliceParamSrc, sizeof( AlfSliceParam ) ); + memcpy( &alfParamDst, &alfParamSrc, sizeof( AlfParam ) ); } else { - alfSliceParamDst.nonLinearFlag[channel] = alfSliceParamSrc.nonLinearFlag[channel]; - alfSliceParamDst.enabledFlag[COMPONENT_Cb] = alfSliceParamSrc.enabledFlag[COMPONENT_Cb]; - alfSliceParamDst.enabledFlag[COMPONENT_Cr] = alfSliceParamSrc.enabledFlag[COMPONENT_Cr]; - memcpy( alfSliceParamDst.chromaCoeff, alfSliceParamSrc.chromaCoeff, sizeof( alfSliceParamDst.chromaCoeff ) ); - memcpy( alfSliceParamDst.chromaClipp, alfSliceParamSrc.chromaClipp, sizeof( alfSliceParamDst.chromaClipp ) ); +#if !JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + alfParamDst.nonLinearFlag[channel] = alfParamSrc.nonLinearFlag[channel]; +#endif + alfParamDst.enabledFlag[COMPONENT_Cb] = alfParamSrc.enabledFlag[COMPONENT_Cb]; + alfParamDst.enabledFlag[COMPONENT_Cr] = alfParamSrc.enabledFlag[COMPONENT_Cr]; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + alfParamDst.numAlternativesChroma = alfParamSrc.numAlternativesChroma; + memcpy( alfParamDst.nonLinearFlag[CHANNEL_TYPE_CHROMA], alfParamSrc.nonLinearFlag[CHANNEL_TYPE_CHROMA], sizeof( alfParamDst.nonLinearFlag[CHANNEL_TYPE_CHROMA] ) ); +#endif + memcpy( alfParamDst.chromaCoeff, alfParamSrc.chromaCoeff, sizeof( alfParamDst.chromaCoeff ) ); + memcpy( alfParamDst.chromaClipp, alfParamSrc.chromaClipp, sizeof( alfParamDst.chromaClipp ) ); } } + double EncAdaptiveLoopFilter::getFilterCoeffAndCost( CodingStructure& cs, double distUnfilter, ChannelType channel, bool bReCollectStat, int iShapeIdx, int& uiCoeffBits, bool onlyFilterCost ) { //collect stat based on CTU decision @@ -943,32 +1146,79 @@ double EncAdaptiveLoopFilter::getFilterCoeffAndCost( CodingStructure& cs, double double dist = distUnfilter; uiCoeffBits = 0; int uiSliceFlag = 0; - AlfFilterShape& alfFilterShape = m_alfSliceParamTemp.filterShapes[channel][iShapeIdx]; + AlfFilterShape& alfFilterShape = m_alfParamTemp.filterShapes[channel][iShapeIdx]; //get filter coeff if( isLuma( channel ) ) { - std::fill_n(m_alfClipMerged[iShapeIdx][0][0], MAX_NUM_ALF_LUMA_COEFF*MAX_NUM_ALF_CLASSES*MAX_NUM_ALF_CLASSES, m_alfSliceParamTemp.nonLinearFlag[channel] ? AlfNumClippingValues[CHANNEL_TYPE_LUMA] / 2 : 0); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + std::fill_n(m_alfClipMerged[iShapeIdx][0][0], MAX_NUM_ALF_LUMA_COEFF*MAX_NUM_ALF_CLASSES*MAX_NUM_ALF_CLASSES, m_alfParamTemp.nonLinearFlag[channel][0] ? AlfNumClippingValues[CHANNEL_TYPE_LUMA] / 2 : 0); +#else + std::fill_n(m_alfClipMerged[iShapeIdx][0][0], MAX_NUM_ALF_LUMA_COEFF*MAX_NUM_ALF_CLASSES*MAX_NUM_ALF_CLASSES, m_alfParamTemp.nonLinearFlag[channel] ? AlfNumClippingValues[CHANNEL_TYPE_LUMA] / 2 : 0); +#endif // Reset Merge Tmp Cov m_alfCovarianceMerged[iShapeIdx][MAX_NUM_ALF_CLASSES].reset(AlfNumClippingValues[channel]); m_alfCovarianceMerged[iShapeIdx][MAX_NUM_ALF_CLASSES + 1].reset(AlfNumClippingValues[channel]); //distortion - dist += mergeFiltersAndCost( m_alfSliceParamTemp, alfFilterShape, m_alfCovarianceFrame[channel][iShapeIdx], m_alfCovarianceMerged[iShapeIdx], m_alfClipMerged[iShapeIdx], uiCoeffBits ); + dist += mergeFiltersAndCost( m_alfParamTemp, alfFilterShape, m_alfCovarianceFrame[channel][iShapeIdx], m_alfCovarianceMerged[iShapeIdx], m_alfClipMerged[iShapeIdx], uiCoeffBits ); } else { //distortion +#if !JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB assert(alfFilterShape.numCoeff == m_alfCovarianceFrame[channel][iShapeIdx][0].numCoeff); - std::fill_n(m_filterClippSet[0], MAX_NUM_ALF_CHROMA_COEFF, m_alfSliceParamTemp.nonLinearFlag[channel] ? AlfNumClippingValues[CHANNEL_TYPE_CHROMA] / 2 : 0); - dist += m_alfCovarianceFrame[channel][iShapeIdx][0].pixAcc + deriveCoeffQuant( m_filterClippSet[0], m_filterCoeffSet[0], m_alfCovarianceFrame[channel][iShapeIdx][0], alfFilterShape, m_NUM_BITS, m_alfSliceParamTemp.nonLinearFlag[channel] ); - //setEnableFlag( m_alfSliceParamTemp, channel, m_ctuEnableFlag ); - const int alfChromaIdc = m_alfSliceParamTemp.enabledFlag[COMPONENT_Cb] * 2 + m_alfSliceParamTemp.enabledFlag[COMPONENT_Cr]; + std::fill_n(m_filterClippSet[0], MAX_NUM_ALF_CHROMA_COEFF, m_alfParamTemp.nonLinearFlag[channel] ? AlfNumClippingValues[CHANNEL_TYPE_CHROMA] / 2 : 0); + dist += m_alfCovarianceFrame[channel][iShapeIdx][0].pixAcc + deriveCoeffQuant( m_filterClippSet[0], m_filterCoeffSet[0], m_alfCovarianceFrame[channel][iShapeIdx][0], alfFilterShape, m_NUM_BITS, m_alfParamTemp.nonLinearFlag[channel] ); +#endif + //setEnableFlag( m_alfParamTemp, channel, m_ctuEnableFlag ); + const int alfChromaIdc = m_alfParamTemp.enabledFlag[COMPONENT_Cb] * 2 + m_alfParamTemp.enabledFlag[COMPONENT_Cr]; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + for( int altIdx = 0; altIdx < m_alfParamTemp.numAlternativesChroma; ++altIdx ) + { + assert(alfFilterShape.numCoeff == m_alfCovarianceFrame[channel][iShapeIdx][altIdx].numCoeff); + AlfParam bestSliceParam; + double bestCost = MAX_DOUBLE; + double bestDist = MAX_DOUBLE; + int bestCoeffBits = 0; + const int nonLinearFlagMax = m_encCfg->getUseNonLinearAlfChroma() ? 2 : 1; + + for( int nonLinearFlag = 0; nonLinearFlag < nonLinearFlagMax; nonLinearFlag++ ) + { + m_alfParamTemp.nonLinearFlag[channel][altIdx] = nonLinearFlag; + + std::fill_n(m_filterClippSet[altIdx], MAX_NUM_ALF_CHROMA_COEFF, nonLinearFlag ? AlfNumClippingValues[CHANNEL_TYPE_CHROMA] / 2 : 0 ); + double dist = m_alfCovarianceFrame[channel][iShapeIdx][altIdx].pixAcc + deriveCoeffQuant( m_filterClippSet[altIdx], m_filterCoeffSet[altIdx], m_alfCovarianceFrame[channel][iShapeIdx][altIdx], alfFilterShape, m_NUM_BITS, nonLinearFlag ); + for( int i = 0; i < MAX_NUM_ALF_CHROMA_COEFF; i++ ) + { + m_alfParamTemp.chromaCoeff[altIdx][i] = m_filterCoeffSet[altIdx][i]; + m_alfParamTemp.chromaClipp[altIdx][i] = m_filterClippSet[altIdx][i]; + } + int coeffBits = getChromaCoeffRate( m_alfParamTemp, altIdx ); + double cost = dist + m_lambda[channel] * coeffBits; + if( cost < bestCost ) + { + bestCost = cost; + bestDist = dist; + bestCoeffBits = coeffBits; + bestSliceParam = m_alfParamTemp; + } + } + uiCoeffBits += bestCoeffBits; + dist += bestDist; + m_alfParamTemp = bestSliceParam; + } + uiCoeffBits += lengthUvlc( m_alfParamTemp.numAlternativesChroma-1 ); + uiCoeffBits += m_alfParamTemp.numAlternativesChroma; // non-linear flags + uiSliceFlag = lengthTruncatedUnary(alfChromaIdc, 3) + - lengthTruncatedUnary( 0, 3 ); // rate already put on Luma +#else for( int i = 0; i < MAX_NUM_ALF_CHROMA_COEFF; i++ ) { - m_alfSliceParamTemp.chromaCoeff[i] = m_filterCoeffSet[0][i]; - m_alfSliceParamTemp.chromaClipp[i] = m_filterClippSet[0][i]; + m_alfParamTemp.chromaCoeff[i] = m_filterCoeffSet[0][i]; + m_alfParamTemp.chromaClipp[i] = m_filterClippSet[0][i]; } - uiCoeffBits += getCoeffRate( m_alfSliceParamTemp, true ); + uiCoeffBits += getCoeffRate( m_alfParamTemp, true ); uiSliceFlag = lengthTruncatedUnary(alfChromaIdc, 3); +#endif } if (onlyFilterCost) { @@ -976,15 +1226,35 @@ double EncAdaptiveLoopFilter::getFilterCoeffAndCost( CodingStructure& cs, double } double rate = uiCoeffBits + uiSliceFlag; m_CABACEstimator->resetBits(); - m_CABACEstimator->codeAlfCtuEnableFlags( cs, channel, &m_alfSliceParamTemp); + m_CABACEstimator->codeAlfCtuEnableFlags( cs, channel, &m_alfParamTemp); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + for( int ctuIdx = 0; ctuIdx < m_numCTUsInPic; ctuIdx++ ) + { + if( isLuma( channel ) ) + { + // Evaluate cost of signaling filter set index for convergence of filters enabled flag / filter derivation + assert( cs.slice->getPic()->getAlfCtbFilterIndex()[ctuIdx] == NUM_FIXED_FILTER_SETS ); + assert( cs.slice->getTileGroupNumAps() == 1 ); + m_CABACEstimator->codeAlfCtuFilterIndex(cs, ctuIdx, &m_alfParamTemp.enabledFlag[COMPONENT_Y]); + } + } + m_CABACEstimator->codeAlfCtuAlternatives( cs, channel, &m_alfParamTemp ); +#endif rate += FracBitsScale * (double)m_CABACEstimator->getEstFracBits(); return dist + m_lambda[channel] * rate; } -int EncAdaptiveLoopFilter::getCoeffRate( AlfSliceParam& alfSliceParam, bool isChroma ) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +int EncAdaptiveLoopFilter::getChromaCoeffRate( AlfParam& alfParam, int altIdx ) +#else +int EncAdaptiveLoopFilter::getCoeffRate( AlfParam& alfParam, bool isChroma ) +#endif { int iBits = 0; +#if !JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB assert( isChroma ); +#endif + AlfFilterShape alfShape(5); #if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING memset( m_bitsCoeffScan, 0, sizeof( m_bitsCoeffScan ) ); @@ -995,7 +1265,11 @@ int EncAdaptiveLoopFilter::getCoeffRate( AlfSliceParam& alfSliceParam, bool isCh // vlc for all for( int i = 0; i < alfShape.numCoeff - 1; i++ ) { - int coeffVal = abs( alfSliceParam.chromaCoeff[i] ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + int coeffVal = abs( alfParam.chromaCoeff[altIdx][i] ); +#else + int coeffVal = abs( alfParam.chromaCoeff[i] ); +#endif for( int k = 1; k < 15; k++ ) { @@ -1021,20 +1295,40 @@ int EncAdaptiveLoopFilter::getCoeffRate( AlfSliceParam& alfSliceParam, bool isCh for( int i = 0; i < alfShape.numCoeff - 1; i++ ) { #if JVET_O0216_ALF_COEFF_EG3 - iBits += lengthGolomb( alfSliceParam.chromaCoeff[i], 3 ); // alf_coeff_chroma[i], alf_coeff_luma_delta[i][j] +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + iBits += lengthGolomb( alfParam.chromaCoeff[altIdx][i], 3 ); // alf_coeff_chroma[altIdx][i] +#else + iBits += lengthGolomb( alfParam.chromaCoeff[i], 3 ); // alf_coeff_chroma[i], alf_coeff_luma_delta[i][j] +#endif +#else +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + iBits += lengthGolomb( alfParam.chromaCoeff[altIdx][i], m_kMinTab[alfShape.golombIdx[i]] ); // alf_coeff_chroma[altIdx][i] #else - iBits += lengthGolomb( alfSliceParam.chromaCoeff[i], m_kMinTab[alfShape.golombIdx[i]] ); // alf_coeff_chroma[i], alf_coeff_luma_delta[i][j] + iBits += lengthGolomb( alfParam.chromaCoeff[i], m_kMinTab[alfShape.golombIdx[i]] ); // alf_coeff_chroma[i], alf_coeff_luma_delta[i][j] +#endif #endif } - if( m_alfSliceParamTemp.nonLinearFlag[isChroma] ) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_CHROMA][altIdx] ) +#else + if( m_alfParamTemp.nonLinearFlag[isChroma] ) +#endif { #if JVET_O0064_SIMP_ALF_CLIP_CODING for (int i = 0; i < alfShape.numCoeff - 1; i++) { - if (!abs(alfSliceParam.chromaCoeff[i])) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( !abs( alfParam.chromaCoeff[altIdx][i] ) ) +#else + if( !abs( alfParam.chromaCoeff[i] ) ) +#endif { - alfSliceParam.chromaClipp[i] = 0; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + alfParam.chromaClipp[altIdx][i] = 0; +#else + alfParam.chromaClipp[i] = 0; +#endif } } iBits += ((alfShape.numCoeff - 1) << 1); @@ -1043,9 +1337,17 @@ int EncAdaptiveLoopFilter::getCoeffRate( AlfSliceParam& alfSliceParam, bool isCh // vlc for all for( int i = 0; i < alfShape.numCoeff - 1; i++ ) { - if( !abs( alfSliceParam.chromaCoeff[i] ) ) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( !abs( alfParam.chromaCoeff[altIdx][i] ) ) +#else + if( !abs( alfParam.chromaCoeff[i] ) ) +#endif continue; - int coeffVal = abs( alfSliceParam.chromaClipp[i] ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + int coeffVal = abs( alfParam.chromaClipp[altIdx][i] ); +#else + int coeffVal = abs( alfParam.chromaClipp[i] ); +#endif for( int k = 1; k < 15; k++ ) { @@ -1077,9 +1379,17 @@ int EncAdaptiveLoopFilter::getCoeffRate( AlfSliceParam& alfSliceParam, bool isCh // Filter coefficients for( int i = 0; i < alfShape.numCoeff - 1; i++ ) { - if( !abs( alfSliceParam.chromaCoeff[i] ) ) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( !abs( alfParam.chromaCoeff[altIdx][i] ) ) +#else + if( !abs( alfParam.chromaCoeff[i] ) ) +#endif continue; - iBits += lengthGolomb( alfSliceParam.chromaClipp[i], m_kMinTab[alfShape.golombIdx[i]], false ); // alf_coeff_chroma[i], alf_coeff_luma_delta[i][j] +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + iBits += lengthGolomb( alfParam.chromaClipp[altIdx][i], m_kMinTab[alfShape.golombIdx[i]], false ); // alf_coeff_chroma[i], alf_coeff_luma_delta[i][j] +#else + iBits += lengthGolomb( alfParam.chromaClipp[i], m_kMinTab[alfShape.golombIdx[i]], false ); // alf_coeff_chroma[i], alf_coeff_luma_delta[i][j] +#endif } #endif } @@ -1122,7 +1432,7 @@ double EncAdaptiveLoopFilter::getFilteredDistortion( AlfCovariance* cov, const i return dist; } -double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfSliceParam& alfSliceParam, AlfFilterShape& alfShape, AlfCovariance* covFrame, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], int& uiCoeffBits ) +double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfParam& alfParam, AlfFilterShape& alfShape, AlfCovariance* covFrame, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], int& uiCoeffBits ) { int numFiltersBest = 0; int numFilters = MAX_NUM_ALF_CLASSES; @@ -1140,7 +1450,7 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfSliceParam& alfSliceParam, while( numFilters >= 1 ) { - dist = deriveFilterCoeffs(covFrame, covMerged, clipMerged, alfShape, m_filterIndices[numFilters - 1], numFilters, errorForce0CoeffTab, alfSliceParam); + dist = deriveFilterCoeffs(covFrame, covMerged, clipMerged, alfShape, m_filterIndices[numFilters - 1], numFilters, errorForce0CoeffTab, alfParam); // filter coeffs are stored in m_filterCoeffSet distForce0 = getDistForce0( alfShape, numFilters, errorForce0CoeffTab, codedVarBins ); #if JVET_O0669_REMOVE_ALF_COEFF_PRED @@ -1158,12 +1468,12 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfSliceParam& alfSliceParam, cost = cost0; } #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - if (alfSliceParam.fixedFilterSetIndex > 0) + if (alfParam.fixedFilterSetIndex > 0) { int len = 0; - len += getTBlength(alfSliceParam.fixedFilterSetIndex - 1, NUM_FIXED_FILTER_SETS); + len += getTBlength(alfParam.fixedFilterSetIndex - 1, NUM_FIXED_FILTER_SETS); len += 1; //fixed filter flag pattern - if (alfSliceParam.fixedFilterPattern > 0) + if (alfParam.fixedFilterPattern > 0) { len += MAX_NUM_ALF_CLASSES; //"fixed_filter_flag" for each class } @@ -1182,7 +1492,7 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfSliceParam& alfSliceParam, numFilters--; } - dist = deriveFilterCoeffs( covFrame, covMerged, clipMerged, alfShape, m_filterIndices[numFiltersBest - 1], numFiltersBest, errorForce0CoeffTab, alfSliceParam ); + dist = deriveFilterCoeffs( covFrame, covMerged, clipMerged, alfShape, m_filterIndices[numFiltersBest - 1], numFiltersBest, errorForce0CoeffTab, alfParam ); #if JVET_O0669_REMOVE_ALF_COEFF_PRED coeffBits = deriveFilterCoefficientsPredictionMode( alfShape, m_filterCoeffSet, m_diffFilterCoeff, numFiltersBest ); #else @@ -1194,25 +1504,25 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfSliceParam& alfSliceParam, cost = dist + m_lambda[COMPONENT_Y] * coeffBits; cost0 = distForce0 + m_lambda[COMPONENT_Y] * coeffBitsForce0; - alfSliceParam.numLumaFilters = numFiltersBest; + alfParam.numLumaFilters = numFiltersBest; double distReturn; if (cost <= cost0) { distReturn = dist; - alfSliceParam.alfLumaCoeffDeltaFlag = 0; + alfParam.alfLumaCoeffDeltaFlag = 0; uiCoeffBits = coeffBits; #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - alfSliceParam.alfLumaCoeffDeltaPredictionFlag = bestPredMode; + alfParam.alfLumaCoeffDeltaPredictionFlag = bestPredMode; #endif } else { distReturn = distForce0; - alfSliceParam.alfLumaCoeffDeltaFlag = 1; + alfParam.alfLumaCoeffDeltaFlag = 1; uiCoeffBits = coeffBitsForce0; - memcpy( alfSliceParam.alfLumaCoeffFlag, codedVarBins, sizeof( codedVarBins ) ); + memcpy( alfParam.alfLumaCoeffFlag, codedVarBins, sizeof( codedVarBins ) ); #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - alfSliceParam.alfLumaCoeffDeltaPredictionFlag = 0; + alfParam.alfLumaCoeffDeltaPredictionFlag = 0; #endif for( int varInd = 0; varInd < numFiltersBest; varInd++ ) @@ -1225,51 +1535,51 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfSliceParam& alfSliceParam, } } - for( int ind = 0; ind < alfSliceParam.numLumaFilters; ++ind ) + for( int ind = 0; ind < alfParam.numLumaFilters; ++ind ) { for( int i = 0; i < alfShape.numCoeff; i++ ) { #if JVET_O0669_REMOVE_ALF_COEFF_PRED - alfSliceParam.lumaCoeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_filterCoeffSet[ind][i]; + alfParam.lumaCoeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_filterCoeffSet[ind][i]; #else - if( alfSliceParam.alfLumaCoeffDeltaPredictionFlag ) + if( alfParam.alfLumaCoeffDeltaPredictionFlag ) { - alfSliceParam.lumaCoeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_diffFilterCoeff[ind][i]; + alfParam.lumaCoeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_diffFilterCoeff[ind][i]; } else { - alfSliceParam.lumaCoeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_filterCoeffSet[ind][i]; + alfParam.lumaCoeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_filterCoeffSet[ind][i]; } #endif - alfSliceParam.lumaClipp[ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_filterClippSet[ind][i]; + alfParam.lumaClipp[ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_filterClippSet[ind][i]; } } - memcpy( alfSliceParam.filterCoeffDeltaIdx, m_filterIndices[numFiltersBest - 1], sizeof( short ) * MAX_NUM_ALF_CLASSES ); - uiCoeffBits += getNonFilterCoeffRate( alfSliceParam ); + memcpy( alfParam.filterCoeffDeltaIdx, m_filterIndices[numFiltersBest - 1], sizeof( short ) * MAX_NUM_ALF_CLASSES ); + uiCoeffBits += getNonFilterCoeffRate( alfParam ); return distReturn; } -int EncAdaptiveLoopFilter::getNonFilterCoeffRate( AlfSliceParam& alfSliceParam ) +int EncAdaptiveLoopFilter::getNonFilterCoeffRate( AlfParam& alfParam ) { int len = 1 // alf_coefficients_delta_flag + lengthTruncatedUnary( 0, 3 ) // chroma_idc = 0, it is signalled when ALF is enabled for luma - + getTBlength( alfSliceParam.numLumaFilters - 1, MAX_NUM_ALF_CLASSES ); //numLumaFilters + + getTBlength( alfParam.numLumaFilters - 1, MAX_NUM_ALF_CLASSES ); //numLumaFilters - if( alfSliceParam.numLumaFilters > 1 ) + if( alfParam.numLumaFilters > 1 ) { for( int i = 0; i < MAX_NUM_ALF_CLASSES; i++ ) { - len += getTBlength( (int)alfSliceParam.filterCoeffDeltaIdx[i], alfSliceParam.numLumaFilters ); //filter_coeff_delta[i] + len += getTBlength( (int)alfParam.filterCoeffDeltaIdx[i], alfParam.numLumaFilters ); //filter_coeff_delta[i] } } #if !JVET_O0669_REMOVE_ALF_COEFF_PRED len++; //fixed filter set flag - if (alfSliceParam.fixedFilterSetIndex > 0) + if (alfParam.fixedFilterSetIndex > 0) { - len += getTBlength(alfSliceParam.fixedFilterSetIndex - 1, NUM_FIXED_FILTER_SETS); + len += getTBlength(alfParam.fixedFilterSetIndex - 1, NUM_FIXED_FILTER_SETS); len += 1; //fixed filter flag pattern - if (alfSliceParam.fixedFilterPattern > 0) + if (alfParam.fixedFilterPattern > 0) len += MAX_NUM_ALF_CLASSES; //"fixed_filter_flag" for each class } #endif @@ -1380,7 +1690,11 @@ int EncAdaptiveLoopFilter::getCostFilterCoeffForce0( AlfFilterShape& alfShape, i } } - if( m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][0] ) +#else + if( m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ) +#endif { #if JVET_O0064_SIMP_ALF_CLIP_CODING for (int ind = 0; ind < numFilters; ++ind) @@ -1447,7 +1761,7 @@ int EncAdaptiveLoopFilter::getCostFilterCoeffForce0( AlfFilterShape& alfShape, i #if JVET_O0669_REMOVE_ALF_COEFF_PRED int EncAdaptiveLoopFilter::deriveFilterCoefficientsPredictionMode( AlfFilterShape& alfShape, int **filterSet, int** filterCoeffDiff, const int numFilters ) { - return (m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? getCostFilterClipp(alfShape, filterSet, numFilters) : 0) + getCostFilterCoeff(alfShape, filterSet, numFilters); + return (m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? getCostFilterClipp(alfShape, filterSet, numFilters) : 0) + getCostFilterCoeff(alfShape, filterSet, numFilters); #else int EncAdaptiveLoopFilter::deriveFilterCoefficientsPredictionMode( AlfFilterShape& alfShape, int **filterSet, int** filterCoeffDiff, const int numFilters, int& predMode ) { @@ -1472,7 +1786,11 @@ int EncAdaptiveLoopFilter::deriveFilterCoefficientsPredictionMode( AlfFilterShap predMode = ( ratePredMode1 < ratePredMode0 && numFilters > 1 ) ? 1 : 0; - int rateClipp = m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? getCostFilterClipp( alfShape, filterSet, numFilters ) : 0; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + int rateClipp = m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][0] ? getCostFilterClipp( alfShape, filterSet, numFilters ) : 0; +#else + int rateClipp = m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? getCostFilterClipp( alfShape, filterSet, numFilters ) : 0; +#endif return ( numFilters > 1 ? 1 : 0 ) // coeff_delta_pred_mode_flag + rateClipp @@ -1529,6 +1847,7 @@ int EncAdaptiveLoopFilter::getCostFilterClipp( AlfFilterShape& alfShape, int **p return (numFilters * (alfShape.numCoeff - 1)) << 1; #else memset( m_bitsCoeffScan, 0, sizeof( m_bitsCoeffScan ) ); + for( int filterIdx = 0; filterIdx < numFilters; ++filterIdx ) { for( int i = 0; i < alfShape.numCoeff - 1; i++ ) @@ -1542,6 +1861,7 @@ int EncAdaptiveLoopFilter::getCostFilterClipp( AlfFilterShape& alfShape, int **p } } } + int len = getGolombKMin( alfShape, numFilters, m_kMinTab, m_bitsCoeffScan ); return len //min_golomb_order + getMaxGolombIdx( alfShape.filterType ) //golomb_order_increase_flag @@ -1624,8 +1944,12 @@ double EncAdaptiveLoopFilter::getDistForce0( AlfFilterShape& alfShape, const int } } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][0] ) +#else + if( m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ) +#endif #if JVET_O0064_SIMP_ALF_CLIP_CODING - if (m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA]) { for (int ind = 0; ind < numFilters; ++ind) { @@ -1639,7 +1963,6 @@ double EncAdaptiveLoopFilter::getDistForce0( AlfFilterShape& alfShape, const int } } #else - if( m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ) { memset( m_bitsCoeffScan, 0, sizeof( m_bitsCoeffScan ) ); for( int ind = 0; ind < numFilters; ++ind ) @@ -1770,23 +2093,29 @@ int EncAdaptiveLoopFilter::lengthGolomb( int coeffVal, int k, bool signed_coeff } } -double EncAdaptiveLoopFilter::deriveFilterCoeffs( AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], AlfFilterShape& alfShape, short* filterIndices, int numFilters, double errorTabForce0Coeff[MAX_NUM_ALF_CLASSES][2], AlfSliceParam& alfSliceParam ) +double EncAdaptiveLoopFilter::deriveFilterCoeffs( AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], AlfFilterShape& alfShape, short* filterIndices, int numFilters, double errorTabForce0Coeff[MAX_NUM_ALF_CLASSES][2], AlfParam& alfParam ) { double error = 0.0; AlfCovariance& tmpCov = covMerged[MAX_NUM_ALF_CLASSES]; #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - alfSliceParam.fixedFilterSetIndex = 0; + alfParam.fixedFilterSetIndex = 0; AlfCovariance& tmpCovFf = covMerged[MAX_NUM_ALF_CLASSES + 1]; double factor = 1 << (m_NUM_BITS - 1); double errorMin = 0; double errorMinPerClass[MAX_NUM_ALF_CLASSES] = { 0 }; double errorCurSetPerClass[MAX_NUM_ALF_CLASSES] = { 0 }; int fixedFilterFlagPerClass[MAX_NUM_ALF_CLASSES] = { 0 }; - - if (!alfSliceParam.nonLinearFlag[CHANNEL_TYPE_LUMA]) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if (!alfParam.nonLinearFlag[CHANNEL_TYPE_LUMA][0]) +#else + if (!alfParam.nonLinearFlag[CHANNEL_TYPE_LUMA]) +#endif { - alfSliceParam.fixedFilterSetIndex = 0; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +#else + alfParam.fixedFilterSetIndex = 0; +#endif for (int filterSetIdx = 0; filterSetIdx < NUM_FIXED_FILTER_SETS; filterSetIdx++) { double errorCur = 0; @@ -1809,21 +2138,21 @@ double EncAdaptiveLoopFilter::deriveFilterCoeffs( AlfCovariance* cov, AlfCovaria if (errorCur < errorMin) { - memcpy(alfSliceParam.fixedFilterIdx, fixedFilterFlagPerClass, sizeof(fixedFilterFlagPerClass)); - alfSliceParam.fixedFilterSetIndex = filterSetIdx + 1; + memcpy(alfParam.fixedFilterIdx, fixedFilterFlagPerClass, sizeof(fixedFilterFlagPerClass)); + alfParam.fixedFilterSetIndex = filterSetIdx + 1; errorMin = errorCur; std::memcpy(errorMinPerClass, errorCurSetPerClass, sizeof(errorMinPerClass)); } } - alfSliceParam.fixedFilterPattern = 0; - if (alfSliceParam.fixedFilterSetIndex > 0) + alfParam.fixedFilterPattern = 0; + if (alfParam.fixedFilterSetIndex > 0) { for (int classIdx = 0; classIdx < MAX_NUM_ALF_CLASSES; classIdx++) { - if (alfSliceParam.fixedFilterIdx[classIdx] == 0) + if (alfParam.fixedFilterIdx[classIdx] == 0) { - alfSliceParam.fixedFilterPattern = 1; + alfParam.fixedFilterPattern = 1; break; } } @@ -1831,6 +2160,7 @@ double EncAdaptiveLoopFilter::deriveFilterCoeffs( AlfCovariance* cov, AlfCovaria } #endif + for( int filtIdx = 0; filtIdx < numFilters; filtIdx++ ) { tmpCov.reset(); @@ -1844,11 +2174,15 @@ double EncAdaptiveLoopFilter::deriveFilterCoeffs( AlfCovariance* cov, AlfCovaria #else //adjust stat tmpCovFf = cov[classIdx]; - if (alfSliceParam.fixedFilterSetIndex > 0 && alfSliceParam.fixedFilterIdx[classIdx] > 0 - && alfSliceParam.nonLinearFlag[CHANNEL_TYPE_LUMA] == false + if (alfParam.fixedFilterSetIndex > 0 && alfParam.fixedFilterIdx[classIdx] > 0 +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + && alfParam.nonLinearFlag[CHANNEL_TYPE_LUMA][0] == false +#else + && alfParam.nonLinearFlag[CHANNEL_TYPE_LUMA] == false +#endif ) { - int fixedFilterIdx = m_classToFilterMapping[alfSliceParam.fixedFilterSetIndex - 1][classIdx]; + int fixedFilterIdx = m_classToFilterMapping[alfParam.fixedFilterSetIndex - 1][classIdx]; tmpCovFf.pixAcc += errorMinPerClass[classIdx]; for (int i = 0; i < MAX_NUM_ALF_LUMA_COEFF; i++) { @@ -1964,20 +2298,33 @@ void EncAdaptiveLoopFilter::mergeClasses( const AlfFilterShape& alfShape, AlfCov indexList[i] = i; availableClass[i] = true; covMerged[i] = cov[i]; - covMerged[i].numBins = m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? AlfNumClippingValues[COMPONENT_Y] : 1; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + covMerged[i].numBins = m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][0] ? AlfNumClippingValues[COMPONENT_Y] : 1; +#else + covMerged[i].numBins = m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? AlfNumClippingValues[COMPONENT_Y] : 1; +#endif } // Try merging different covariance matrices // temporal AlfCovariance structure is allocated as the last element in covMerged array, the size of covMerged is MAX_NUM_ALF_CLASSES + 1 AlfCovariance& tmpCov = covMerged[MAX_NUM_ALF_CLASSES]; - tmpCov.numBins = m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? AlfNumClippingValues[COMPONENT_Y] : 1; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + tmpCov.numBins = m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][0] ? AlfNumClippingValues[COMPONENT_Y] : 1; +#else + tmpCov.numBins = m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? AlfNumClippingValues[COMPONENT_Y] : 1; +#endif // init Clip for( int i = 0; i < numClasses; i++ ) { - std::fill_n(clipMerged[numRemaining-1][i], MAX_NUM_ALF_LUMA_COEFF, m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? AlfNumClippingValues[CHANNEL_TYPE_LUMA] / 2 : 0); - if ( m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + std::fill_n(clipMerged[numRemaining-1][i], MAX_NUM_ALF_LUMA_COEFF, m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][0] ? AlfNumClippingValues[CHANNEL_TYPE_LUMA] / 2 : 0); + if ( m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][0] ) +#else + std::fill_n(clipMerged[numRemaining-1][i], MAX_NUM_ALF_LUMA_COEFF, m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? AlfNumClippingValues[CHANNEL_TYPE_LUMA] / 2 : 0); + if ( m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ) +#endif { err[i] = covMerged[i].optimizeFilterClip( alfShape, clipMerged[numRemaining-1][i] ); } @@ -2008,7 +2355,11 @@ void EncAdaptiveLoopFilter::mergeClasses( const AlfFilterShape& alfShape, AlfCov { tmpClip[l] = (clipMerged[numRemaining-1][i][l] + clipMerged[numRemaining-1][j][l] + 1 ) >> 1; } - double errorMerged = m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? tmpCov.optimizeFilterClip( alfShape, tmpClip ) : tmpCov.calculateError( tmpClip ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + double errorMerged = m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][0] ? tmpCov.optimizeFilterClip( alfShape, tmpClip ) : tmpCov.calculateError( tmpClip ); +#else + double errorMerged = m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] ? tmpCov.optimizeFilterClip( alfShape, tmpClip ) : tmpCov.calculateError( tmpClip ); +#endif double error = errorMerged - error1 - error2; if( error < errorMin ) @@ -2078,6 +2429,27 @@ void EncAdaptiveLoopFilter::mergeClasses( const AlfFilterShape& alfShape, AlfCov void EncAdaptiveLoopFilter::getFrameStats( ChannelType channel, int iShapeIdx ) { int numClasses = isLuma( channel ) ? MAX_NUM_ALF_CLASSES : 1; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + int numAlternatives = isLuma( channel ) ? 1 : m_alfParamTemp.numAlternativesChroma; + // When calling this function m_ctuEnableFlag shall be set to 0 for CTUs using alternative APS + // Here we compute frame stats for building new alternative filters + for( int altIdx = 0; altIdx < numAlternatives; ++altIdx ) + { + for( int i = 0; i < numClasses; i++ ) + { + m_alfCovarianceFrame[channel][iShapeIdx][isLuma( channel ) ? i : altIdx].reset(AlfNumClippingValues[channel]); + } + if( isLuma( channel ) ) + { + getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_LUMA][iShapeIdx], m_alfCovariance[COMPONENT_Y][iShapeIdx], m_ctuEnableFlag[COMPONENT_Y], nullptr, numClasses, altIdx ); + } + else + { + getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_CHROMA][iShapeIdx], m_alfCovariance[COMPONENT_Cb][iShapeIdx], m_ctuEnableFlag[COMPONENT_Cb], m_ctuAlternative[COMPONENT_Cb], numClasses, altIdx ); + getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_CHROMA][iShapeIdx], m_alfCovariance[COMPONENT_Cr][iShapeIdx], m_ctuEnableFlag[COMPONENT_Cr], m_ctuAlternative[COMPONENT_Cr], numClasses, altIdx ); + } + } +#else for( int i = 0; i < numClasses; i++ ) { m_alfCovarianceFrame[channel][iShapeIdx][i].reset(AlfNumClippingValues[channel]); @@ -2091,10 +2463,31 @@ void EncAdaptiveLoopFilter::getFrameStats( ChannelType channel, int iShapeIdx ) getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_CHROMA][iShapeIdx], m_alfCovariance[COMPONENT_Cb][iShapeIdx], m_ctuEnableFlag[COMPONENT_Cb], numClasses ); getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_CHROMA][iShapeIdx], m_alfCovariance[COMPONENT_Cr][iShapeIdx], m_ctuEnableFlag[COMPONENT_Cr], numClasses ); } +#endif } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +void EncAdaptiveLoopFilter::getFrameStat( AlfCovariance* frameCov, AlfCovariance** ctbCov, uint8_t* ctbEnableFlags, uint8_t* ctbAltIdx, const int numClasses, int altIdx ) +#else void EncAdaptiveLoopFilter::getFrameStat( AlfCovariance* frameCov, AlfCovariance** ctbCov, uint8_t* ctbEnableFlags, const int numClasses ) +#endif { +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const ChannelType channel = (!ctbAltIdx ? CHANNEL_TYPE_LUMA : CHANNEL_TYPE_CHROMA); + for( int ctuIdx = 0; ctuIdx < m_numCTUsInPic; ctuIdx++ ) + { + if( ctbEnableFlags[ctuIdx] ) + { + for( int classIdx = 0; classIdx < numClasses; classIdx++ ) + { + if( isLuma( channel ) || altIdx == ctbAltIdx[ctuIdx] ) + { + frameCov[isLuma( channel ) ? classIdx : altIdx] += ctbCov[ctuIdx][classIdx]; + } + } + } + } +#else for( int i = 0; i < m_numCTUsInPic; i++ ) { if( ctbEnableFlags[i] ) @@ -2105,6 +2498,7 @@ void EncAdaptiveLoopFilter::getFrameStat( AlfCovariance* frameCov, AlfCovariance } } } +#endif } void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnitBuf& recYuv, CodingStructure& cs ) @@ -2135,13 +2529,23 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit for( int channelIdx = 0; channelIdx < numberOfChannels; channelIdx++ ) { const ChannelType channelID = ChannelType( channelIdx ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const int numAlts = channelID == CHANNEL_TYPE_LUMA ? 1 : MAX_NUM_ALF_ALTERNATIVES_CHROMA; +#endif const int numClasses = isLuma( channelID ) ? MAX_NUM_ALF_CLASSES : 1; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + for( int altIdx = 0; altIdx < numAlts; ++altIdx ) +#endif for( int shape = 0; shape != m_filterShapes[channelIdx].size(); shape++ ) { for( int classIdx = 0; classIdx < numClasses; classIdx++ ) { +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_alfCovarianceFrame[channelIdx][shape][isLuma( channelID ) ? classIdx : altIdx].reset(AlfNumClippingValues[channelID]); +#else m_alfCovarianceFrame[channelIdx][shape][classIdx].reset(AlfNumClippingValues[channelID]); +#endif } } } @@ -2225,7 +2629,11 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit for( int classIdx = 0; classIdx < numClasses; classIdx++ ) { +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_alfCovarianceFrame[chType][shape][isLuma( compID ) ? classIdx : 0] += m_alfCovariance[compIdx][shape][ctuRsAddr][classIdx]; +#else m_alfCovarianceFrame[chType][shape][classIdx] += m_alfCovariance[compIdx][shape][ctuRsAddr][classIdx]; +#endif } } } @@ -2259,7 +2667,11 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit for( int classIdx = 0; classIdx < numClasses; classIdx++ ) { +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_alfCovarianceFrame[chType][shape][isLuma( compID ) ? classIdx : 0] += m_alfCovariance[compIdx][shape][ctuRsAddr][classIdx]; +#else m_alfCovarianceFrame[chType][shape][classIdx] += m_alfCovariance[compIdx][shape][ctuRsAddr][classIdx]; +#endif } } } @@ -2492,7 +2904,7 @@ void EncAdaptiveLoopFilter::calcCovariance(int ELocal[MAX_NUM_ALF_LUMA_COEFF][Ma -void EncAdaptiveLoopFilter::setEnableFlag( AlfSliceParam& alfSlicePara, ChannelType channel, bool val ) +void EncAdaptiveLoopFilter::setEnableFlag( AlfParam& alfSlicePara, ChannelType channel, bool val ) { if( channel == CHANNEL_TYPE_LUMA ) { @@ -2504,7 +2916,7 @@ void EncAdaptiveLoopFilter::setEnableFlag( AlfSliceParam& alfSlicePara, ChannelT } } -void EncAdaptiveLoopFilter::setEnableFlag( AlfSliceParam& alfSlicePara, ChannelType channel, uint8_t** ctuFlags ) +void EncAdaptiveLoopFilter::setEnableFlag( AlfParam& alfSlicePara, ChannelType channel, uint8_t** ctuFlags ) { const ComponentID compIDFirst = isLuma( channel ) ? COMPONENT_Y : COMPONENT_Cb; const ComponentID compIDLast = isLuma( channel ) ? COMPONENT_Y : COMPONENT_Cr; @@ -2592,7 +3004,7 @@ void EncAdaptiveLoopFilter::initDistortion() } } } -void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& alfSliceParamNewFilters +void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfParamNewFilters #if ENABLE_QPA , const double lambdaChromaWeight #endif @@ -2602,13 +3014,21 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a TempCtx ctxBest(m_CtxCache); TempCtx ctxTempStart(m_CtxCache); TempCtx ctxTempBest(m_CtxCache); - AlfSliceParam alfSliceParamNewFiltersBest = alfSliceParamNewFilters; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + TempCtx ctxTempFiltBest( m_CtxCache ); + TempCtx ctxTempAltStart( m_CtxCache ); + TempCtx ctxTempAltBest( m_CtxCache ); +#endif + AlfParam alfParamNewFiltersBest = alfParamNewFilters; APS** apss = cs.slice->getAlfAPSs(); short* alfCtbFilterSetIndex = cs.picture->getAlfCtbFilterIndex(); - bool hasNewFilters[2] = { alfSliceParamNewFilters.enabledFlag[COMPONENT_Y] , alfSliceParamNewFilters.enabledFlag[COMPONENT_Cb] || alfSliceParamNewFilters.enabledFlag[COMPONENT_Cr] }; + bool hasNewFilters[2] = { alfParamNewFilters.enabledFlag[COMPONENT_Y] , alfParamNewFilters.enabledFlag[COMPONENT_Cb] || alfParamNewFilters.enabledFlag[COMPONENT_Cr] }; initDistortion(); //luma +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_alfParamTemp = alfParamNewFilters; +#endif setCtuEnableFlag(m_ctuEnableFlag, CHANNEL_TYPE_LUMA, 1); getFrameStats(CHANNEL_TYPE_LUMA, 0); setCtuEnableFlag(m_ctuEnableFlag, CHANNEL_TYPE_LUMA, 0); @@ -2633,7 +3053,7 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a else { bitsNewFilter = m_bitsNewFilter[CHANNEL_TYPE_LUMA]; - reconstructCoeff(alfSliceParamNewFilters, CHANNEL_TYPE_LUMA, true, true); + reconstructCoeff(alfParamNewFilters, CHANNEL_TYPE_LUMA, true, true); } } int numIter = useNewFilter ? 2 : 1; @@ -2647,8 +3067,8 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a } for (int iter = 0; iter < numIter; iter++) { - m_alfSliceParamTemp = alfSliceParamNewFilters; - m_alfSliceParamTemp.enabledFlag[CHANNEL_TYPE_LUMA] = true; + m_alfParamTemp = alfParamNewFilters; + m_alfParamTemp.enabledFlag[CHANNEL_TYPE_LUMA] = true; double curCost = getTBlength(numTemporalAps + useNewFilter, ALF_CTB_MAX_NUM_APS + 1) * m_lambda[CHANNEL_TYPE_LUMA]; if (iter > 0) //re-derive new filter-set { @@ -2681,17 +3101,25 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a { int bitNL[2] = { 0, 0 }; double errNL[2] = { 0.0, 0.0 }; - m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] = 1; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][0] = 1; +#else + m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] = 1; +#endif if (m_encCfg->getUseNonLinearAlfLuma()) { errNL[1] = getFilterCoeffAndCost(cs, 0, CHANNEL_TYPE_LUMA, true, 0, bitNL[1], true); - m_alfSliceParamTempNL = m_alfSliceParamTemp; + m_alfParamTempNL = m_alfParamTemp; } else { errNL[1] = MAX_DOUBLE; } - m_alfSliceParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] = 0; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][0] = 0; +#else + m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA] = 0; +#endif errNL[0] = getFilterCoeffAndCost(cs, 0, CHANNEL_TYPE_LUMA, true, 0, bitNL[0], true); int bitsNewFilterTempLuma = bitNL[0]; @@ -2700,13 +3128,13 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a { err = errNL[1]; bitsNewFilterTempLuma = bitNL[1]; - m_alfSliceParamTemp = m_alfSliceParamTempNL; + m_alfParamTemp = m_alfParamTempNL; } if (dDistOrgNewFilter + m_lambda[CHANNEL_TYPE_LUMA] * m_bitsNewFilter[CHANNEL_TYPE_LUMA] < err) //re-derived filter is not good, skip { continue; } - reconstructCoeff(m_alfSliceParamTemp, CHANNEL_TYPE_LUMA, true, true); + reconstructCoeff(m_alfParamTemp, CHANNEL_TYPE_LUMA, true, true); bitsNewFilter = bitsNewFilterTempLuma; } else //no blocks using new filter, skip @@ -2729,9 +3157,9 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a //rate m_CABACEstimator->getCtx() = AlfCtx(ctxTempStart); m_CABACEstimator->resetBits(); - m_CABACEstimator->codeAlfCtuEnableFlag(cs, ctbIdx, COMPONENT_Y, &m_alfSliceParamTemp); + m_CABACEstimator->codeAlfCtuEnableFlag(cs, ctbIdx, COMPONENT_Y, &m_alfParamTemp); alfCtbFilterSetIndex[ctbIdx] = filterSetIdx; - m_CABACEstimator->codeAlfCtuFilterIndex(cs, ctbIdx, &m_alfSliceParamTemp.enabledFlag[COMPONENT_Y]); + m_CABACEstimator->codeAlfCtuFilterIndex(cs, ctbIdx, &m_alfParamTemp.enabledFlag[COMPONENT_Y]); double rateOn = FracBitsScale *(double)m_CABACEstimator->getEstFracBits(); //distortion double dist = distUnfilterCtb; @@ -2783,7 +3211,7 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a //rate m_CABACEstimator->getCtx() = AlfCtx(ctxTempStart); m_CABACEstimator->resetBits(); - m_CABACEstimator->codeAlfCtuEnableFlag(cs, ctbIdx, COMPONENT_Y, &m_alfSliceParamTemp); + m_CABACEstimator->codeAlfCtuEnableFlag(cs, ctbIdx, COMPONENT_Y, &m_alfParamTemp); //cost double costOff = distUnfilterCtb + m_lambda[COMPONENT_Y] * FracBitsScale*(double)m_CABACEstimator->getEstFracBits(); if (costOn < costOff) @@ -2820,14 +3248,14 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a bestApsIds[i] = apsIds[i - useNewFilter]; } } - alfSliceParamNewFiltersBest = m_alfSliceParamTemp; + alfParamNewFiltersBest = m_alfParamTemp; ctxBest = AlfCtx(m_CABACEstimator->getCtx()); copyCtuEnableFlag(m_ctuEnableFlagTmp, m_ctuEnableFlag, CHANNEL_TYPE_LUMA); for (int ctuIdx = 0; ctuIdx < m_numCTUsInPic; ctuIdx++) { m_alfCtbFilterSetIndexTmp[ctuIdx] = alfCtbFilterSetIndex[ctuIdx]; } - alfSliceParamNewFiltersBest.newFilterFlag[CHANNEL_TYPE_LUMA] = useNewFilter; + alfParamNewFiltersBest.newFilterFlag[CHANNEL_TYPE_LUMA] = useNewFilter; } }//for (int iter = 0; iter < numIter; iter++) }// for (int numTemporalAps = 0; numTemporalAps < apsIds.size(); numTemporalAps++) @@ -2843,7 +3271,7 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a } else { - alfSliceParamNewFiltersBest.tLayer = cs.slice->getTLayer(); + alfParamNewFiltersBest.tLayer = cs.slice->getTLayer(); cs.slice->setTileGroupAlfEnabledFlag(COMPONENT_Y, true); cs.slice->setTileGroupNumAps((int)bestApsIds.size()); cs.slice->setAlfAPSs(bestApsIds); @@ -2852,7 +3280,7 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a { alfCtbFilterSetIndex[ctuIdx] = m_alfCtbFilterSetIndexTmp[ctuIdx]; } - if (alfSliceParamNewFiltersBest.newFilterFlag[CHANNEL_TYPE_LUMA]) + if (alfParamNewFiltersBest.newFilterFlag[CHANNEL_TYPE_LUMA]) { APS* newAPS = m_apsMap->getPS((newApsId << NUM_APS_TYPE_LEN) + ALF_APS); if (newAPS == NULL) @@ -2861,7 +3289,7 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a newAPS->setAPSId(newApsId); newAPS->setAPSType(ALF_APS); } - newAPS->setAlfAPSParam(alfSliceParamNewFiltersBest); + newAPS->setAlfAPSParam(alfParamNewFiltersBest); m_apsMap->setChangedFlag((newApsId << NUM_APS_TYPE_LEN) + ALF_APS); m_apsIdStart = newApsId; } @@ -2874,6 +3302,14 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a } //chroma +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + m_alfParamTemp = alfParamNewFiltersBest; + if( m_alfParamTemp.numAlternativesChroma < 1 ) + { + m_alfParamTemp.numAlternativesChroma = 1; + } + setCtuAlternativeChroma( m_ctuAlternative, 0 ); +#endif setCtuEnableFlag(m_ctuEnableFlag, CHANNEL_TYPE_CHROMA, 1); getFrameStats(CHANNEL_TYPE_CHROMA, 0); costOff = getUnfilteredDistortion(m_alfCovarianceFrame[CHANNEL_TYPE_CHROMA][0], CHANNEL_TYPE_CHROMA) + m_lambda[CHANNEL_TYPE_CHROMA] * 1.0; @@ -2881,11 +3317,11 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a m_CABACEstimator->getCtx() = AlfCtx(ctxBest); ctxStart = AlfCtx(m_CABACEstimator->getCtx()); int newApsIdChroma = -1; - if (alfSliceParamNewFiltersBest.newFilterFlag[CHANNEL_TYPE_LUMA] && (alfSliceParamNewFiltersBest.enabledFlag[COMPONENT_Cb] || alfSliceParamNewFiltersBest.enabledFlag[COMPONENT_Cr])) + if (alfParamNewFiltersBest.newFilterFlag[CHANNEL_TYPE_LUMA] && (alfParamNewFiltersBest.enabledFlag[COMPONENT_Cb] || alfParamNewFiltersBest.enabledFlag[COMPONENT_Cr])) { newApsIdChroma = newApsId; } - else if (alfSliceParamNewFiltersBest.enabledFlag[COMPONENT_Cb] || alfSliceParamNewFiltersBest.enabledFlag[COMPONENT_Cr]) + else if (alfParamNewFiltersBest.enabledFlag[COMPONENT_Cb] || alfParamNewFiltersBest.enabledFlag[COMPONENT_Cr]) { int curId = m_apsIdStart; while (newApsIdChroma < 0) @@ -2915,22 +3351,22 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a #endif if (curApsId == newApsIdChroma) { - m_alfSliceParamTemp = alfSliceParamNewFilters; + m_alfParamTemp = alfParamNewFilters; curCost += m_lambda[CHANNEL_TYPE_CHROMA] * m_bitsNewFilter[CHANNEL_TYPE_CHROMA]; } else if (curAPS && curAPS->getTemporalId() <= cs.slice->getTLayer() && curAPS->getAlfAPSParam().newFilterFlag[CHANNEL_TYPE_CHROMA]) { - m_alfSliceParamTemp = curAPS->getAlfAPSParam(); + m_alfParamTemp = curAPS->getAlfAPSParam(); } else { continue; } - reconstructCoeff(m_alfSliceParamTemp, CHANNEL_TYPE_CHROMA, true, true); + reconstructCoeff(m_alfParamTemp, CHANNEL_TYPE_CHROMA, true, true); m_CABACEstimator->getCtx() = AlfCtx(ctxStart); for (int compId = 1; compId < MAX_NUM_COMPONENT; compId++) { - m_alfSliceParamTemp.enabledFlag[compId] = true; + m_alfParamTemp.enabledFlag[compId] = true; for (int ctbIdx = 0; ctbIdx < m_numCTUsInPic; ctbIdx++) { double distUnfilterCtu = m_ctbDistortionUnfilter[compId][ctbIdx]; @@ -2941,8 +3377,54 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a m_CABACEstimator->getCtx() = AlfCtx(ctxTempStart); m_CABACEstimator->resetBits(); //ctb flag - m_CABACEstimator->codeAlfCtuEnableFlag(cs, ctbIdx, compId, &m_alfSliceParamTemp); + m_CABACEstimator->codeAlfCtuEnableFlag(cs, ctbIdx, compId, &m_alfParamTemp); double rateOn = FracBitsScale*(double)m_CABACEstimator->getEstFracBits(); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +#if ENABLE_QPA + const double ctuLambda = lambdaChromaWeight > 0.0 ? cs.picture->m_uEnerHpCtu[ctbIdx] / lambdaChromaWeight : m_lambda[compId]; +#else + const double ctuLambda = m_lambda[compId]; +#endif + double dist = MAX_DOUBLE; + int numAlts = m_alfParamTemp.numAlternativesChroma; + ctxTempBest = AlfCtx( m_CABACEstimator->getCtx() ); + double bestAltRate = 0; + double bestAltCost = MAX_DOUBLE; + int bestAltIdx = -1; + ctxTempAltStart = AlfCtx( ctxTempBest ); + for( int altIdx = 0; altIdx < numAlts; ++altIdx ) + { + if( altIdx ) + m_CABACEstimator->getCtx() = AlfCtx( ctxTempAltStart ); + m_CABACEstimator->resetBits(); + m_ctuAlternative[compId][ctbIdx] = altIdx; + m_CABACEstimator->codeAlfCtuAlternative( cs, ctbIdx, compId, &m_alfParamTemp ); + double altRate = FracBitsScale *(double)m_CABACEstimator->getEstFracBits(); + double r_altCost = ctuLambda * altRate; + + //distortion + for (int i = 0; i < MAX_NUM_ALF_CHROMA_COEFF; i++) + { + m_filterTmp[i] = m_chromaCoeffFinal[altIdx][i]; + m_clipTmp[i] = m_chromaClippFinal[altIdx][i]; + } + double altDist = m_alfCovariance[compId][0][ctbIdx][0].calcErrorForCoeffs( m_clipTmp, m_filterTmp, MAX_NUM_ALF_CHROMA_COEFF, m_NUM_BITS ); + double altCost = altDist + r_altCost; + if( altCost < bestAltCost ) + { + bestAltCost = altCost; + bestAltIdx = altIdx; + bestAltRate = altRate; + ctxTempBest = AlfCtx( m_CABACEstimator->getCtx() ); + dist = altDist; + } + } + m_ctuAlternative[compId][ctbIdx] = bestAltIdx; + rateOn += bestAltRate; + dist += distUnfilterCtu; + //cost + double costOn = dist + ctuLambda * rateOn; +#else //distortion for (int i = 0; i < MAX_NUM_ALF_CHROMA_COEFF; i++) { @@ -2952,12 +3434,13 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a double dist = distUnfilterCtu + m_alfCovariance[compId][0][ctbIdx][0].calcErrorForCoeffs(m_clipTmp, m_filterTmp, MAX_NUM_ALF_CHROMA_COEFF, m_NUM_BITS); double costOn = dist + m_lambda[compId] * rateOn; ctxTempBest = AlfCtx(m_CABACEstimator->getCtx()); +#endif //cost off m_ctuEnableFlag[compId][ctbIdx] = 0; //rate m_CABACEstimator->getCtx() = AlfCtx(ctxTempStart); m_CABACEstimator->resetBits(); - m_CABACEstimator->codeAlfCtuEnableFlag(cs, ctbIdx, compId, &m_alfSliceParamTemp); + m_CABACEstimator->codeAlfCtuEnableFlag(cs, ctbIdx, compId, &m_alfParamTemp); //cost double costOff = distUnfilterCtu + m_lambda[compId] * FracBitsScale*(double)m_CABACEstimator->getEstFracBits(); if (costOn < costOff) @@ -2974,17 +3457,24 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a } } //chroma idc - setEnableFlag(m_alfSliceParamTemp, CHANNEL_TYPE_CHROMA, m_ctuEnableFlag); - const int alfChromaIdc = m_alfSliceParamTemp.enabledFlag[COMPONENT_Cb] * 2 + m_alfSliceParamTemp.enabledFlag[COMPONENT_Cr]; + setEnableFlag(m_alfParamTemp, CHANNEL_TYPE_CHROMA, m_ctuEnableFlag); + const int alfChromaIdc = m_alfParamTemp.enabledFlag[COMPONENT_Cb] * 2 + m_alfParamTemp.enabledFlag[COMPONENT_Cr]; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + curCost += (lengthTruncatedUnary(alfChromaIdc, 3) - lengthTruncatedUnary(0, 3)) * m_lambda[CHANNEL_TYPE_CHROMA]; +#else curCost += lengthTruncatedUnary(alfChromaIdc, 3) * m_lambda[CHANNEL_TYPE_CHROMA]; +#endif if (curCost < costMin) { costMin = curCost; cs.slice->setTileGroupApsIdChroma(curApsId); - cs.slice->setTileGroupAlfEnabledFlag(COMPONENT_Cb, m_alfSliceParamTemp.enabledFlag[COMPONENT_Cb]); - cs.slice->setTileGroupAlfEnabledFlag(COMPONENT_Cr, m_alfSliceParamTemp.enabledFlag[COMPONENT_Cr]); + cs.slice->setTileGroupAlfEnabledFlag(COMPONENT_Cb, m_alfParamTemp.enabledFlag[COMPONENT_Cb]); + cs.slice->setTileGroupAlfEnabledFlag(COMPONENT_Cr, m_alfParamTemp.enabledFlag[COMPONENT_Cr]); copyCtuEnableFlag(m_ctuEnableFlagTmp, m_ctuEnableFlag, CHANNEL_TYPE_CHROMA); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + copyCtuAlternativeChroma(m_ctuAlternativeTmp, m_ctuAlternative); +#endif } } if (costOff < costMin) @@ -2996,6 +3486,9 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a else { copyCtuEnableFlag(m_ctuEnableFlag, m_ctuEnableFlagTmp, CHANNEL_TYPE_CHROMA); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + copyCtuAlternativeChroma(m_ctuAlternative, m_ctuAlternativeTmp); +#endif if (cs.slice->getTileGroupApsIdChroma() == newApsIdChroma) //new filter { APS* newAPS = m_apsMap->getPS((newApsIdChroma << NUM_APS_TYPE_LEN) + ALF_APS); @@ -3007,13 +3500,28 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfSliceParam& a newAPS->getAlfAPSParam().reset(); } newAPS->getAlfAPSParam().newFilterFlag[CHANNEL_TYPE_CHROMA] = true; - newAPS->getAlfAPSParam().nonLinearFlag[CHANNEL_TYPE_CHROMA] = alfSliceParamNewFilters.nonLinearFlag[CHANNEL_TYPE_CHROMA]; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + newAPS->getAlfAPSParam().numAlternativesChroma = alfParamNewFilters.numAlternativesChroma; + for( int altIdx = 0; altIdx < MAX_NUM_ALF_ALTERNATIVES_CHROMA; ++altIdx ) + newAPS->getAlfAPSParam().nonLinearFlag[CHANNEL_TYPE_CHROMA][altIdx] = alfParamNewFilters.nonLinearFlag[CHANNEL_TYPE_CHROMA][altIdx]; +#else + newAPS->getAlfAPSParam().nonLinearFlag[CHANNEL_TYPE_CHROMA] = alfParamNewFilters.nonLinearFlag[CHANNEL_TYPE_CHROMA]; +#endif newAPS->getAlfAPSParam().tLayer = cs.slice->getTLayer(); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + for (int altIdx = 0; altIdx < MAX_NUM_ALF_ALTERNATIVES_CHROMA; ++altIdx ) for (int i = 0; i < MAX_NUM_ALF_CHROMA_COEFF; i++) { - newAPS->getAlfAPSParam().chromaCoeff[i] = alfSliceParamNewFilters.chromaCoeff[i]; - newAPS->getAlfAPSParam().chromaClipp[i] = alfSliceParamNewFilters.chromaClipp[i]; + newAPS->getAlfAPSParam().chromaCoeff[altIdx][i] = alfParamNewFilters.chromaCoeff[altIdx][i]; + newAPS->getAlfAPSParam().chromaClipp[altIdx][i] = alfParamNewFilters.chromaClipp[altIdx][i]; } +#else + for (int i = 0; i < MAX_NUM_ALF_CHROMA_COEFF; i++) + { + newAPS->getAlfAPSParam().chromaCoeff[i] = alfParamNewFilters.chromaCoeff[i]; + newAPS->getAlfAPSParam().chromaClipp[i] = alfParamNewFilters.chromaClipp[i]; + } +#endif m_apsMap->setChangedFlag((newApsIdChroma << NUM_APS_TYPE_LEN) + ALF_APS); m_apsIdStart = newApsIdChroma; } @@ -3106,9 +3614,16 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB { const Area blkSrc(0, 0, w >> chromaScaleX, h >> chromaScaleY); const Area blkDst(xStart >> chromaScaleX, yStart >> chromaScaleY, w >> chromaScaleX, h >> chromaScaleY); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const int alt_num = m_ctuAlternative[compID][ctuIdx]; + m_filter5x5Blk(m_classifier, recBuf, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs + , m_alfVBChmaCTUHeight + , ((yPos + pcv.maxCUHeight >= pcv.lumaHeight) ? pcv.lumaHeight : m_alfVBChmaPos) +#else m_filter5x5Blk(m_classifier, recBuf, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal, m_chromaClippFinal, m_clpRngs.comp[compIdx], cs , m_alfVBChmaCTUHeight , ((yPos + pcv.maxCUHeight >= pcv.lumaHeight) ? pcv.lumaHeight : m_alfVBChmaPos) +#endif ); } } @@ -3153,9 +3668,16 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB if (m_ctuEnableFlag[compIdx][ctuIdx]) { Area blk(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const int alt_num = m_ctuAlternative[compID][ctuIdx]; + m_filter5x5Blk(m_classifier, recBuf, recExtBuf, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs + , m_alfVBChmaCTUHeight + , ((yPos + pcv.maxCUHeight >= pcv.lumaHeight) ? pcv.lumaHeight : m_alfVBChmaPos) +#else m_filter5x5Blk(m_classifier, recBuf, recExtBuf, blk, blk, compID, m_chromaCoeffFinal, m_chromaClippFinal, m_clpRngs.comp[compIdx], cs , m_alfVBChmaCTUHeight , ((yPos + pcv.maxCUHeight >= pcv.lumaHeight) ? pcv.lumaHeight : m_alfVBChmaPos) +#endif ); } } @@ -3164,3 +3686,40 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB } } } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + +void EncAdaptiveLoopFilter::copyCtuAlternativeChroma( uint8_t* ctuAltsDst[MAX_NUM_COMPONENT], uint8_t* ctuAltsSrc[MAX_NUM_COMPONENT] ) +{ + std::copy_n( ctuAltsSrc[COMPONENT_Cb], m_numCTUsInPic, ctuAltsDst[COMPONENT_Cb] ); + std::copy_n( ctuAltsSrc[COMPONENT_Cr], m_numCTUsInPic, ctuAltsDst[COMPONENT_Cr] ); +} + +void EncAdaptiveLoopFilter::setCtuAlternativeChroma( uint8_t* ctuAlts[MAX_NUM_COMPONENT], uint8_t val ) +{ + std::fill_n( ctuAlts[COMPONENT_Cb], m_numCTUsInPic, val ); + std::fill_n( ctuAlts[COMPONENT_Cr], m_numCTUsInPic, val ); +} + +void EncAdaptiveLoopFilter::initCtuAlternativeChroma( uint8_t* ctuAlts[MAX_NUM_COMPONENT] ) +{ + uint8_t altIdx = 0; + for( int ctuIdx = 0; ctuIdx < m_numCTUsInPic; ++ctuIdx ) + { + ctuAlts[COMPONENT_Cb][ctuIdx] = altIdx; + if( (ctuIdx+1) * m_alfParamTemp.numAlternativesChroma >= (altIdx+1)*m_numCTUsInPic ) + ++altIdx; + } + altIdx = 0; + for( int ctuIdx = 0; ctuIdx < m_numCTUsInPic; ++ctuIdx ) + { + ctuAlts[COMPONENT_Cr][ctuIdx] = altIdx; + if( (ctuIdx+1) * m_alfParamTemp.numAlternativesChroma >= (altIdx+1)*m_numCTUsInPic ) + ++altIdx; + } +} + +int EncAdaptiveLoopFilter::getMaxNumAlternativesChroma( ) +{ + return std::min<int>( m_numCTUsInPic * 2, m_encCfg->getMaxNumAlfAlternativesChroma() ); +} +#endif diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h index 59b1bdb956502419945d75c10b706775e2a8a9f1..42dc89c3fc7c49ea7558f2820301213d65a0b72a 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h @@ -231,11 +231,18 @@ public: private: const EncCfg* m_encCfg; AlfCovariance*** m_alfCovariance[MAX_NUM_COMPONENT]; // [compIdx][shapeIdx][ctbAddr][classIdx] +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + AlfCovariance** m_alfCovarianceFrame[MAX_NUM_CHANNEL_TYPE]; // [CHANNEL][shapeIdx][lumaClassIdx/chromaAltIdx] + uint8_t* m_ctuEnableFlagTmp[MAX_NUM_COMPONENT]; + uint8_t* m_ctuEnableFlagTmp2[MAX_NUM_COMPONENT]; + uint8_t* m_ctuAlternativeTmp[MAX_NUM_COMPONENT]; +#else AlfCovariance** m_alfCovarianceFrame[MAX_NUM_CHANNEL_TYPE]; // [CHANNEL][shapeIdx][classIdx] uint8_t* m_ctuEnableFlagTmp[MAX_NUM_COMPONENT]; +#endif //for RDO - AlfSliceParam m_alfSliceParamTemp; + AlfParam m_alfParamTemp; ParameterSetMap<APS>* m_apsMap; AlfCovariance m_alfCovarianceMerged[ALF_NUM_OF_FILTER_TYPES][MAX_NUM_ALF_CLASSES + 2]; int m_alfClipMerged[ALF_NUM_OF_FILTER_TYPES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF]; @@ -244,8 +251,13 @@ private: double m_lambda[MAX_NUM_COMPONENT]; const double FracBitsScale = 1.0 / double( 1 << SCALE_BITS ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + int** m_filterCoeffSet; // [lumaClassIdx/chromaAltIdx][coeffIdx] + int** m_filterClippSet; // [lumaClassIdx/chromaAltIdx][coeffIdx] +#else int** m_filterCoeffSet; int** m_filterClippSet; +#endif int** m_diffFilterCoeff; #if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING int m_kMinTab[MAX_NUM_ALF_LUMA_COEFF]; @@ -257,7 +269,7 @@ private: double *m_ctbDistortionFixedFilter; double *m_ctbDistortionUnfilter[MAX_NUM_COMPONENT]; std::vector<short> m_alfCtbFilterSetIndexTmp; - AlfSliceParam m_alfSliceParamTempNL; + AlfParam m_alfParamTempNL; int m_clipDefaultEnc[MAX_NUM_ALF_LUMA_COEFF]; int m_filterTmp[MAX_NUM_ALF_LUMA_COEFF]; int m_clipTmp[MAX_NUM_ALF_LUMA_COEFF]; @@ -267,7 +279,7 @@ public: virtual ~EncAdaptiveLoopFilter() {} void initDistortion(); std::vector<int> getAvaiApsIdsLuma(CodingStructure& cs, int &newApsId); - void alfEncoderCtb(CodingStructure& cs, AlfSliceParam& alfSliceParamNewFilters + void alfEncoderCtb(CodingStructure& cs, AlfParam& alfParamNewFilters #if ENABLE_QPA , const double lambdaChromaWeight #endif @@ -285,19 +297,24 @@ public: #if !JVET_O0216_ALF_COEFF_EG3 || !JVET_O0064_SIMP_ALF_CLIP_CODING static int getGolombKMin( AlfFilterShape& alfShape, const int numFilters, int kMinTab[MAX_NUM_ALF_LUMA_COEFF], int bitsCoeffScan[m_MAX_SCAN_VAL][m_MAX_EXP_GOLOMB] ); #endif + void setApsIdStart( int i) { m_apsIdStart = i; } private: - void alfEncoder( CodingStructure& cs, AlfSliceParam& alfSliceParam, const PelUnitBuf& orgUnitBuf, const PelUnitBuf& recExtBuf, const PelUnitBuf& recBuf, const ChannelType channel + void alfEncoder( CodingStructure& cs, AlfParam& alfParam, const PelUnitBuf& orgUnitBuf, const PelUnitBuf& recExtBuf, const PelUnitBuf& recBuf, const ChannelType channel #if ENABLE_QPA , const double lambdaChromaWeight = 0.0 #endif ); - void copyAlfSliceParam( AlfSliceParam& alfSliceParamDst, AlfSliceParam& alfSliceParamSrc, ChannelType channel ); - double mergeFiltersAndCost( AlfSliceParam& alfSliceParam, AlfFilterShape& alfShape, AlfCovariance* covFrame, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], int& uiCoeffBits ); + void copyAlfParam( AlfParam& alfParamDst, AlfParam& alfParamSrc, ChannelType channel ); + double mergeFiltersAndCost( AlfParam& alfParam, AlfFilterShape& alfShape, AlfCovariance* covFrame, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], int& uiCoeffBits ); void getFrameStats( ChannelType channel, int iShapeIdx ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + void getFrameStat( AlfCovariance* frameCov, AlfCovariance** ctbCov, uint8_t* ctbEnableFlags, uint8_t* ctbAltIdx, const int numClasses, int altIdx ); +#else void getFrameStat( AlfCovariance* frameCov, AlfCovariance** ctbCov, uint8_t* ctbEnableFlags, const int numClasses ); +#endif void deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnitBuf& recYuv, CodingStructure& cs ); void getBlkStats(AlfCovariance* alfCovariace, const AlfFilterShape& shape, AlfClassifier** classifier, Pel* org, const int orgStride, Pel* rec, const int recStride, const CompArea& areaDst, const CompArea& area, const ChannelType channel, int vbCTUHeight, int vbPos); void calcCovariance(int ELocal[MAX_NUM_ALF_LUMA_COEFF][MaxAlfNumClippingValues], const Pel *rec, const int stride, const AlfFilterShape& shape, const int transposeIdx, const ChannelType channel, int vbDistance); @@ -305,7 +322,7 @@ private: double getFilterCoeffAndCost( CodingStructure& cs, double distUnfilter, ChannelType channel, bool bReCollectStat, int iShapeIdx, int& uiCoeffBits, bool onlyFilterCost = false ); - double deriveFilterCoeffs(AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], AlfFilterShape& alfShape, short* filterIndices, int numFilters, double errorTabForce0Coeff[MAX_NUM_ALF_CLASSES][2], AlfSliceParam& alfSliceParam); + double deriveFilterCoeffs(AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], AlfFilterShape& alfShape, short* filterIndices, int numFilters, double errorTabForce0Coeff[MAX_NUM_ALF_CLASSES][2], AlfParam& alfParam); #if JVET_O0669_REMOVE_ALF_COEFF_PRED int deriveFilterCoefficientsPredictionMode( AlfFilterShape& alfShape, int **filterSet, int** filterCoeffDiff, const int numFilters ); #else @@ -322,7 +339,7 @@ private: double getDistCoeffForce0( bool* codedVarBins, double errorForce0CoeffTab[MAX_NUM_ALF_CLASSES][2], int* bitsVarBin, const int numFilters ); int lengthTruncatedUnary( int symbol, int maxSymbol ); int lengthUvlc( int uiCode ); - int getNonFilterCoeffRate( AlfSliceParam& alfSliceParam ); + int getNonFilterCoeffRate( AlfParam& alfParam ); int getTBlength( int uiSymbol, const int uiMaxSymbol ); int getCostFilterCoeffForce0( AlfFilterShape& alfShape, int **pDiffQFilterCoeffIntPP, const int numFilters, bool* codedVarBins ); @@ -337,16 +354,26 @@ private: int lengthFilterClipps( AlfFilterShape& alfShape, const int numFilters, int **FilterCoeff, int* kMinTab ); #endif double getDistForce0( AlfFilterShape& alfShape, const int numFilters, double errorTabForce0Coeff[MAX_NUM_ALF_CLASSES][2], bool* codedVarBins ); - int getCoeffRate( AlfSliceParam& alfSliceParam, bool isChroma ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + int getChromaCoeffRate( AlfParam& alfParam, int altIdx ); +#else + int getCoeffRate( AlfParam& alfParam, bool isChroma ); +#endif double getUnfilteredDistortion( AlfCovariance* cov, ChannelType channel ); double getUnfilteredDistortion( AlfCovariance* cov, const int numClasses ); double getFilteredDistortion( AlfCovariance* cov, const int numClasses, const int numFiltersMinus1, const int numCoeff ); - void setEnableFlag( AlfSliceParam& alfSlicePara, ChannelType channel, bool val ); - void setEnableFlag( AlfSliceParam& alfSlicePara, ChannelType channel, uint8_t** ctuFlags ); + void setEnableFlag( AlfParam& alfSlicePara, ChannelType channel, bool val ); + void setEnableFlag( AlfParam& alfSlicePara, ChannelType channel, uint8_t** ctuFlags ); void setCtuEnableFlag( uint8_t** ctuFlags, ChannelType channel, uint8_t val ); void copyCtuEnableFlag( uint8_t** ctuFlagsDst, uint8_t** ctuFlagsSrc, ChannelType channel ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + void initCtuAlternativeChroma( uint8_t* ctuAlts[MAX_NUM_COMPONENT] ); + void setCtuAlternativeChroma( uint8_t* ctuAlts[MAX_NUM_COMPONENT], uint8_t val ); + void copyCtuAlternativeChroma( uint8_t* ctuAltsDst[MAX_NUM_COMPONENT], uint8_t* ctuAltsSrc[MAX_NUM_COMPONENT] ); + int getMaxNumAlternativesChroma( ); +#endif }; diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index df9f1d2a620e05d9e0441bb38a6f449a97760010..1a4af6c703fe9f96b779e00f5e984c930ab6017d 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -329,6 +329,9 @@ protected: bool m_contentBasedFastQtbt; bool m_useNonLinearAlfLuma; bool m_useNonLinearAlfChroma; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + unsigned m_maxNumAlfAlternativesChroma; +#endif bool m_MIP; bool m_useFastMIP; @@ -938,6 +941,10 @@ public: bool getUseNonLinearAlfLuma () const { return m_useNonLinearAlfLuma; } void setUseNonLinearAlfChroma ( bool b ) { m_useNonLinearAlfChroma = b; } bool getUseNonLinearAlfChroma () const { return m_useNonLinearAlfChroma; } +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + void setMaxNumAlfAlternativesChroma ( uint32_t u ) { m_maxNumAlfAlternativesChroma = u; } + uint32_t getMaxNumAlfAlternativesChroma () const { return m_maxNumAlfAlternativesChroma; } +#endif void setUseMIP ( bool b ) { m_MIP = b; } bool getUseMIP () const { return m_MIP; } void setUseFastMIP ( bool b ) { m_useFastMIP = b; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 482d694b75ec11fc62d8a80afaa889ed232917b2..b16f155702f2f65ff5ed3ef95e7e7a877bec2885 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1523,6 +1523,18 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC xCheckDQP( *tempCS, partitioner ); // Check if low frequency non-separable transform (LFNST) is too expensive +#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS + const bool skipLfnst = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA ) : + ( cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA ) ) : + ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA && cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA ); + if( lfnstIdx && skipLfnst ) + { + if( cuCtx.lastScanPos[ COMPONENT_Y ] > -1 || cuCtx.lastScanPos[ COMPONENT_Cb ] > -1 || cuCtx.lastScanPos[ COMPONENT_Cr ] > -1 ) + { + tempCS->cost = MAX_DOUBLE; + } + } +#else const int nonZeroCoeffThr = CS::isDualITree( *tempCS ) ? ( isLuma( partitioner.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA; if( lfnstIdx && cuCtx.numNonZeroCoeffNonTs <= nonZeroCoeffThr ) { @@ -1531,6 +1543,7 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC tempCS->cost = MAX_DOUBLE; } } +#endif if( mtsFlag == 0 && lfnstIdx == 0 ) { @@ -2450,12 +2463,16 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru trianglecandHasNoResidual[mergeCand] = false; } +#if JVET_O0379_SPEEDUP_TPM_ENCODER + bool bestIsSkip = false; +#else bool bestIsSkip; CodingUnit* cuTemp = bestCS->getCU(partitioner.chType); if (cuTemp) bestIsSkip = m_pcEncCfg->getUseFastDecisionForMerge() ? bestCS->getCU(partitioner.chType)->rootCbf == 0 : false; else bestIsSkip = false; +#endif uint8_t numTriangleCandidate = TRIANGLE_MAX_NUM_CANDS; uint8_t triangleNumMrgSATDCand = TRIANGLE_MAX_NUM_SATD_CANDS; PelUnitBuf triangleBuffer[TRIANGLE_MAX_NUM_UNI_CANDS]; @@ -2464,10 +2481,12 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru static_vector<double, TRIANGLE_MAX_NUM_CANDS> tianglecandCostList; uint8_t numTriangleCandComb = slice.getMaxNumTriangleCand() * (slice.getMaxNumTriangleCand() - 1) * 2; +#if !JVET_O0379_SPEEDUP_TPM_ENCODER if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) ) { bestIsSkip |= blkCache->isSkip( tempCS->area ); } +#endif DistParam distParam; const bool useHadamard = !encTestMode.lossless && !tempCS->slice->getDisableSATDForRD(); @@ -2511,6 +2530,9 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru } } +#if JVET_O0379_SPEEDUP_TPM_ENCODER + triangleNumMrgSATDCand = min(triangleNumMrgSATDCand, numTriangleCandComb); +#else bool tempBufSet = bestIsSkip ? false : true; triangleNumMrgSATDCand = bestIsSkip ? TRIANGLE_MAX_NUM_CANDS : TRIANGLE_MAX_NUM_SATD_CANDS; triangleNumMrgSATDCand = min(triangleNumMrgSATDCand, numTriangleCandComb); @@ -2522,6 +2544,7 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru } } else +#endif { CodingUnit &cu = tempCS->addCU( tempCS->area, partitioner.chType ); @@ -2665,6 +2688,9 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru tempCS->initStructData( encTestMode.qp, encTestMode.lossless ); return; } +#if JVET_O0379_SPEEDUP_TPM_ENCODER + tempCS->getPredBuf().copyFrom( triangleWeightedBuffer[mergeCand] ); +#else if( tempBufSet ) { tempCS->getPredBuf().copyFrom( triangleWeightedBuffer[mergeCand] ); @@ -2676,7 +2702,7 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru PelUnitBuf predBuf = tempCS->getPredBuf(); m_pcInterSearch->weightedTriangleBlk( pu, splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, triangleBuffer[candIdx0], triangleBuffer[candIdx1] ); } - +#endif xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, noResidualPass, ( noResidualPass == 0 ? &trianglecandHasNoResidual[mergeCand] : NULL ) ); if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip) @@ -3901,6 +3927,36 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS bool swapped = false; // avoid unwanted data copy bool reloadCU = false; +#if JVET_O0567_MVDRange_Constraint + const PredictionUnit& pu = *cu->firstPU; + const int affineShiftTab[3] = { MV_PRECISION_INTERNAL - MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL - MV_PRECISION_SIXTEENTH, MV_PRECISION_INTERNAL - MV_PRECISION_INT }; + const int normalShiftTab[3] = { MV_PRECISION_INTERNAL - MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL - MV_PRECISION_INT, MV_PRECISION_INTERNAL - MV_PRECISION_4PEL }; + int mvShift; + + for (int refList = 0; refList < NUM_REF_PIC_LIST_01; refList++) + { + if (pu.refIdx[refList] >= 0) + { + if (!cu->affine) + { + mvShift = normalShiftTab[cu->imv]; + Mv signaledmvd(pu.mvd[refList].getHor() >> mvShift, pu.mvd[refList].getVer() >> mvShift); + if (!((signaledmvd.getHor() >= MVD_MIN) && (signaledmvd.getHor() <= MVD_MAX)) || !((signaledmvd.getVer() >= MVD_MIN) && (signaledmvd.getVer() <= MVD_MAX))) + return; + } + else + { + for (int ctrlP = 1 + (cu->affineType == AFFINEMODEL_6PARAM); ctrlP >= 0; ctrlP--) + { + mvShift = affineShiftTab[cu->imv]; + Mv signaledmvd(pu.mvdAffi[refList][ctrlP].getHor() >> mvShift, pu.mvdAffi[refList][ctrlP].getVer() >> mvShift); + if (!((signaledmvd.getHor() >= MVD_MIN) && (signaledmvd.getHor() <= MVD_MAX)) || !((signaledmvd.getVer() >= MVD_MIN) && (signaledmvd.getVer() <= MVD_MAX))) + return; + } + } + } + } +#else // Not allow very big |MVd| to avoid CABAC crash caused by too large MVd. Normally no impact on coding performance. const int maxMvd = 1 << 15; const PredictionUnit& pu = *cu->firstPU; @@ -3928,6 +3984,7 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS } } } +#endif // avoid MV exceeding 18-bit dynamic range const int maxMv = 1 << 17; if (!cu->affine && !pu.mergeFlag) diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 220161396c16e1962e198c3e2a942ed50233e67b..c348ae0e23623207e95894ef085a82df0ac29ec8 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -2071,6 +2071,9 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, if( pcSlice->getSPS()->getALFEnabledFlag() ) { pcPic->resizeAlfCtuEnableFlag( numberOfCtusInFrame ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + pcPic->resizeAlfCtuAlternative( numberOfCtusInFrame ); +#endif pcPic->resizeAlfCtbFilterIndex(numberOfCtusInFrame); } @@ -2494,6 +2497,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, for (int apsId = 0; apsId < MAX_NUM_APS; apsId++) //HD: shouldn't this be looping over slice_alf_aps_id_luma[ i ]? By looping over MAX_NUM_APS, it is possible unused ALF APS is written. Please check! { ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap(); + APS* aps = apsMap->getPS((apsId << NUM_APS_TYPE_LEN) + ALF_APS); bool writeAPS = aps && apsMap->getChangedFlag((apsId << NUM_APS_TYPE_LEN) + ALF_APS); if (!aps && pcSlice->getAlfAPSs() && pcSlice->getAlfAPSs()[apsId]) @@ -2501,7 +2505,8 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, writeAPS = true; aps = pcSlice->getAlfAPSs()[apsId]; // use asp from slice header *apsMap->allocatePS(apsId) = *aps; //allocate and cpy - } + m_pcALF->setApsIdStart( apsId ); + } if (writeAPS ) { diff --git a/source/Lib/EncoderLib/EncReshape.cpp b/source/Lib/EncoderLib/EncReshape.cpp index 0c95c850f2112f7ba1c8f7bd6869024515f454c3..5a4b1bbd4569aa14372c4e603eba22ba314e153e 100644 --- a/source/Lib/EncoderLib/EncReshape.cpp +++ b/source/Lib/EncoderLib/EncReshape.cpp @@ -1858,9 +1858,6 @@ void EncReshape::constructReshaperLMCS() { m_inputPivot[i] = m_initCW * i; } -#if JVET_O0272_LMCS_SIMP_INVERSE_MAPPING - adjustLmcsPivot(); -#endif m_sliceReshapeInfo.reshaperModelMinBinIdx = 0; m_sliceReshapeInfo.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS - 1; @@ -1881,6 +1878,10 @@ void EncReshape::constructReshaperLMCS() } } +#if JVET_O0272_LMCS_SIMP_INVERSE_MAPPING + adjustLmcsPivot(); +#endif + int maxAbsDeltaCW = 0, absDeltaCW = 0, deltaCW = 0; for (int i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++) { @@ -2084,10 +2085,6 @@ void EncReshape::constructReshaperSDR() m_binCW[i] = m_binCW[2 * i] + m_binCW[2 * i + 1]; } -#if JVET_O0272_LMCS_SIMP_INVERSE_MAPPING - adjustLmcsPivot(); -#endif - m_sliceReshapeInfo.reshaperModelMinBinIdx = 0; m_sliceReshapeInfo.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS - 1; for (int i = 0; i < PIC_CODE_CW_BINS; i++) @@ -2107,6 +2104,10 @@ void EncReshape::constructReshaperSDR() } } +#if JVET_O0272_LMCS_SIMP_INVERSE_MAPPING + adjustLmcsPivot(); +#endif + int maxAbsDeltaCW = 0, absDeltaCW = 0, deltaCW = 0; for (int i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++) { @@ -2196,34 +2197,65 @@ void EncReshape::adjustLmcsPivot() int totCW = bdShift != 0 ? (bdShift > 0 ? m_reshapeLUTSize / (1 << bdShift) : m_reshapeLUTSize * (1 << (-bdShift))) : m_reshapeLUTSize; int orgCW = totCW / PIC_CODE_CW_BINS; int log2SegSize = g_aucLog2[LMCS_SEG_SIZE]; + m_reshapePivot[0] = 0; for (int i = 0; i < PIC_CODE_CW_BINS; i++) { - m_reshapePivot[i+1] = m_reshapePivot[i] + m_binCW[i]; + m_reshapePivot[i + 1] = m_reshapePivot[i] + m_binCW[i]; + } + int segIdxMax = (m_reshapePivot[m_sliceReshapeInfo.reshaperModelMaxBinIdx + 1] >> log2SegSize); + for (int i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++) + { + m_reshapePivot[i + 1] = m_reshapePivot[i] + m_binCW[i]; int segIdxCurr = (m_reshapePivot[i] >> log2SegSize); int segIdxNext = (m_reshapePivot[i + 1] >> log2SegSize); - if ((segIdxCurr == segIdxNext) && (m_reshapePivot[i] != m_reshapePivot[i + 1]) && (m_reshapePivot[i] != (segIdxCurr << log2SegSize))) + + if ((segIdxCurr == segIdxNext) && (m_reshapePivot[i] != (segIdxCurr << log2SegSize))) { - int16_t adjustVal = ((segIdxCurr + 1) << log2SegSize) - m_reshapePivot[i + 1]; - m_reshapePivot[i + 1] += adjustVal; - m_binCW[i] += adjustVal; - for (int j = i + 1; j < PIC_CODE_CW_BINS; j++) + if (segIdxCurr == segIdxMax) { - if (m_binCW[j] < (adjustVal + (orgCW >> 3))) + m_reshapePivot[i] = m_reshapePivot[m_sliceReshapeInfo.reshaperModelMaxBinIdx + 1]; + for (int j = i; j <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; j++) { - adjustVal -= (m_binCW[j] - (orgCW >> 3)); - m_binCW[j] = (orgCW >> 3); + m_reshapePivot[j + 1] = m_reshapePivot[i]; + m_binCW[j] = 0; } - else + m_binCW[i - 1] = m_reshapePivot[i] - m_reshapePivot[i - 1]; + break; + } + else + { + int16_t adjustVal = ((segIdxCurr + 1) << log2SegSize) - m_reshapePivot[i + 1]; + m_reshapePivot[i + 1] += adjustVal; + m_binCW[i] += adjustVal; + + for (int j = i + 1; j <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; j++) { - m_binCW[j] -= adjustVal; - adjustVal = 0; + if (m_binCW[j] < (adjustVal + (orgCW >> 3))) + { + adjustVal -= (m_binCW[j] - (orgCW >> 3)); + m_binCW[j] = (orgCW >> 3); + } + else + { + m_binCW[j] -= adjustVal; + adjustVal = 0; + } + if (adjustVal == 0) + break; } - if (adjustVal == 0) - break; } } } + + for (int i = PIC_CODE_CW_BINS - 1; i >= 0; i--) + { + if (m_binCW[i] > 0) + { + m_sliceReshapeInfo.reshaperModelMaxBinIdx = i; + break; + } + } } #endif diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 9f501fe5b2eab56103500b47daf0a6907f0ac431..cc7c2a3bbb86529efdff2d49909b0a4f2070520d 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -317,49 +317,21 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, { mtsUsageFlag = 0; } - int nOptionsForISP = ( sps.getUseISP() && cu.mtsFlag == 0 && cu.lfnstIdx == 0 ) ? NUM_INTRA_SUBPARTITIONS_MODES : 1; - double bestCurrentCost = bestCostSoFar; - int ispOptions[NUM_INTRA_SUBPARTITIONS_MODES] = { 0 }; - if( nOptionsForISP > 1 ) - { + double bestCurrentCost = bestCostSoFar; #if MAX_TB_SIZE_SIGNALLING - auto splitsThatCanBeUsedForISP = CU::canUseISPSplit( width, height, cu.cs->sps->getMaxTbSize() ); + bool testISP = sps.getUseISP() && cu.mtsFlag == 0 && cu.lfnstIdx == 0 && CU::canUseISP( width, height, cu.cs->sps->getMaxTbSize() ); #else - auto splitsThatCanBeUsedForISP = CU::canUseISPSplit( width, height, MAX_TB_SIZEY ); + bool testISP = sps.getUseISP() && cu.mtsFlag == 0 && cu.lfnstIdx == 0 && CU::canUseISP( width, height, MAX_TB_SIZEY ); #endif - if( splitsThatCanBeUsedForISP == CAN_USE_VER_AND_HORL_SPLITS ) - { - const CodingUnit* cuLeft = cu.ispMode != NOT_INTRA_SUBPARTITIONS ? cs.getCU( cs.area.blocks[partitioner.chType].pos().offset( -1, 0 ), partitioner.chType ) : nullptr; - const CodingUnit* cuAbove = cu.ispMode != NOT_INTRA_SUBPARTITIONS ? cs.getCU( cs.area.blocks[partitioner.chType].pos().offset( 0, -1 ), partitioner.chType ) : nullptr; - bool ispHorIsFirstTest = CU::firstTestISPHorSplit( width, height, COMPONENT_Y, cuLeft, cuAbove ); - if( ispHorIsFirstTest ) - { - ispOptions[1] = HOR_INTRA_SUBPARTITIONS; - ispOptions[2] = VER_INTRA_SUBPARTITIONS; - } - else - { - ispOptions[1] = VER_INTRA_SUBPARTITIONS; - ispOptions[2] = HOR_INTRA_SUBPARTITIONS; - } - } - else if( splitsThatCanBeUsedForISP == HOR_INTRA_SUBPARTITIONS ) - { - nOptionsForISP = 2; - ispOptions[1] = HOR_INTRA_SUBPARTITIONS; - } - else if( splitsThatCanBeUsedForISP == VER_INTRA_SUBPARTITIONS ) - { - nOptionsForISP = 2; - ispOptions[1] = VER_INTRA_SUBPARTITIONS; - } - else - { - nOptionsForISP = 1; - } + bool ispHorIsFirstTest = testISP ? CU::firstTestISPHorSplit( width, height, COMPONENT_Y, nullptr, nullptr ) : true; + int ispOptions[] = { NOT_INTRA_SUBPARTITIONS, HOR_INTRA_SUBPARTITIONS, VER_INTRA_SUBPARTITIONS }; + if ( !ispHorIsFirstTest ) + { + ispOptions[1] = VER_INTRA_SUBPARTITIONS; + ispOptions[2] = HOR_INTRA_SUBPARTITIONS; } - if( nOptionsForISP > 1 ) + if( testISP ) { //variables for the full RD list without MRL modes m_rdModeListWithoutMrl .clear(); @@ -580,7 +552,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } } } - if( nOptionsForISP > 1 ) + if ( testISP ) { //we save the list with no mrl modes to keep only the Hadamard selected modes (no mpms) m_rdModeListWithoutMrl = uiRdModeList; @@ -694,7 +666,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, CandCostList.push_back(0); } } - if( nOptionsForISP > 1 ) + if ( testISP ) { //we add the ISP MPMs to the list without mrl modes m_rdModeListWithoutMrlHor = m_rdModeListWithoutMrl; @@ -705,7 +677,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, m_rdModeListWithoutMrlVer[k].ispMod = VER_INTRA_SUBPARTITIONS; } static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM>* listPointer; - for( int k = 1; k < nOptionsForISP; k++ ) + for( int k = 1; k < NUM_INTRA_SUBPARTITIONS_MODES; k++ ) { cu.ispMode = ispOptions[k]; listPointer = &( cu.ispMode == HOR_INTRA_SUBPARTITIONS ? m_rdModeListWithoutMrlHor : m_rdModeListWithoutMrlVer ); @@ -790,14 +762,14 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } } - if( nOptionsForISP > 1 ) // we remove the non-MPMs from the ISP lists + if( testISP ) // we remove the non-MPMs from the ISP lists { static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeListCopyHor = m_rdModeListWithoutMrlHor; m_rdModeListWithoutMrlHor.clear(); static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeListCopyVer = m_rdModeListWithoutMrlVer; m_rdModeListWithoutMrlVer.clear(); static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> *listPointerCopy, *listPointer; - for( int ispOptionIdx = 1; ispOptionIdx < nOptionsForISP; ispOptionIdx++ ) + for( int ispOptionIdx = 1; ispOptionIdx < NUM_INTRA_SUBPARTITIONS_MODES; ispOptionIdx++ ) { cu.ispMode = ispOptions[ispOptionIdx]; //we get the mpm cand list @@ -844,7 +816,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, if (maxSize > 0) { uiRdModeList.resize(std::min<size_t>(uiRdModeList.size(), maxSize)); - if (nOptionsForISP > 1) + if ( testISP ) { m_rdModeListWithoutMrlHor.resize(std::min<size_t>(m_rdModeListWithoutMrlHor.size(), maxSize)); m_rdModeListWithoutMrlVer.resize(std::min<size_t>(m_rdModeListWithoutMrlVer.size(), maxSize)); @@ -867,7 +839,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } } - if ( nOptionsForISP > 1 ) + if ( testISP ) { //we create a single full RD list that includes all intra modes using regular intra, MRL and ISP auto* firstIspList = ispOptions[1] == HOR_INTRA_SUBPARTITIONS ? &m_rdModeListWithoutMrlHor : &m_rdModeListWithoutMrlVer; @@ -1827,7 +1799,7 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp const bool bUseCrossCPrediction = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isChroma( compID ) && PU::isChromaIntraModeCrossCheckMode( pu ) && checkCrossCPrediction; const bool ccUseRecoResi = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate(); - const bool ispSplitIsAllowed = sps.getUseISP() && CU::canUseISPSplit( *tu.cu, compID ); + const bool ispSplitIsAllowed = sps.getUseISP() && CU::canUseISP( *tu.cu, compID ); //===== init availability pattern ===== diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 76fedd8078b7e7967309bbc696dff6e02fd9783d..7eecd893e4479c1f0074d381bec1f4b2d4b7acae 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -486,14 +486,18 @@ void HLSWriter::codeAPS( APS* pcAPS ) void HLSWriter::codeAlfAps( APS* pcAPS ) { - AlfSliceParam param = pcAPS->getAlfAPSParam(); + AlfParam param = pcAPS->getAlfAPSParam(); WRITE_FLAG(param.newFilterFlag[CHANNEL_TYPE_LUMA], "alf_luma_new_filter"); WRITE_FLAG(param.newFilterFlag[CHANNEL_TYPE_CHROMA], "alf_chroma_new_filter"); if (param.newFilterFlag[CHANNEL_TYPE_LUMA]) { - WRITE_FLAG(param.nonLinearFlag[CHANNEL_TYPE_LUMA], "alf_luma_clip"); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + WRITE_FLAG( param.nonLinearFlag[CHANNEL_TYPE_LUMA][0], "alf_luma_clip" ); +#else + WRITE_FLAG( param.nonLinearFlag[CHANNEL_TYPE_LUMA], "alf_luma_clip" ); +#endif xWriteTruncBinCode(param.numLumaFilters - 1, MAX_NUM_ALF_CLASSES); //number_of_filters_minus1 if (param.numLumaFilters > 1) @@ -522,13 +526,27 @@ void HLSWriter::codeAlfAps( APS* pcAPS ) } } #endif +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + alfFilter(param, false, 0); +#else alfFilter(param, false); +#endif } if (param.newFilterFlag[CHANNEL_TYPE_CHROMA]) { +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( MAX_NUM_ALF_ALTERNATIVES_CHROMA > 1 ) + WRITE_UVLC( param.numAlternativesChroma - 1, "alf_chroma_num_alts_minus1" ); + for( int altIdx=0; altIdx < param.numAlternativesChroma; ++altIdx ) + { + WRITE_FLAG( param.nonLinearFlag[CHANNEL_TYPE_CHROMA][altIdx], "alf_nonlinear_enable_flag_chroma" ); + alfFilter(param, true, altIdx); + } +#else WRITE_FLAG(param.nonLinearFlag[CHANNEL_TYPE_CHROMA], "alf_chroma_clip"); alfFilter(param, true); +#endif } } @@ -1231,7 +1249,14 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) } const int alfChromaIdc = pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) + pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cr) * 2 ; - truncatedUnaryEqProb(alfChromaIdc, 3); // alf_chroma_idc +#if JVET_O0616_400_CHROMA_SUPPORT + if (chromaEnabled) + { +#endif + truncatedUnaryEqProb(alfChromaIdc, 3); // alf_chroma_idc +#if JVET_O0616_400_CHROMA_SUPPORT + } +#endif if (alfChromaIdc) { #if JVET_O0288_UNIFY_ALF_SLICE_TYPE_REMOVAL @@ -1469,11 +1494,22 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) WRITE_FLAG( pcSlice->getLmcsEnabledFlag()? 1 : 0, "slice_lmcs_enabled_flag"); if (pcSlice->getLmcsEnabledFlag()) { +#if JVET_O0428_LMCS_CLEANUP + WRITE_CODE(pcSlice->getLmcsAPSId(), 2, "slice_lmcs_aps_id"); +#else WRITE_CODE(pcSlice->getLmcsAPSId(), 5, "slice_lmcs_aps_id"); +#endif #if !JVET_O1109_UNFIY_CRS if (!(pcSlice->getSPS()->getUseDualITree() && pcSlice->isIntra())) #endif - WRITE_FLAG(pcSlice->getLmcsChromaResidualScaleFlag(), "slice_chroma_residual_scale_flag"); +#if JVET_O0616_400_CHROMA_SUPPORT + if (chromaEnabled) + { +#endif + WRITE_FLAG(pcSlice->getLmcsChromaResidualScaleFlag(), "slice_chroma_residual_scale_flag"); +#if JVET_O0616_400_CHROMA_SUPPORT + } +#endif } } @@ -1801,17 +1837,21 @@ void HLSWriter::alfGolombEncode( int coeff, int k, const bool signed_coeff ) } } -void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChroma ) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +void HLSWriter::alfFilter( const AlfParam& alfParam, const bool isChroma, const int altIdx ) +#else +void HLSWriter::alfFilter( const AlfParam& alfParam, const bool isChroma ) +#endif { if( !isChroma ) { - WRITE_FLAG( alfSliceParam.alfLumaCoeffDeltaFlag, "alf_luma_coeff_delta_flag" ); + WRITE_FLAG( alfParam.alfLumaCoeffDeltaFlag, "alf_luma_coeff_delta_flag" ); #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - if( !alfSliceParam.alfLumaCoeffDeltaFlag ) + if( !alfParam.alfLumaCoeffDeltaFlag ) { - if( alfSliceParam.numLumaFilters > 1 ) + if( alfParam.numLumaFilters > 1 ) { - WRITE_FLAG( alfSliceParam.alfLumaCoeffDeltaPredictionFlag, "alf_luma_coeff_delta_prediction_flag" ); + WRITE_FLAG( alfParam.alfLumaCoeffDeltaPredictionFlag, "alf_luma_coeff_delta_prediction_flag" ); } } #endif @@ -1822,15 +1862,20 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro memset( bitsCoeffScan, 0, sizeof( bitsCoeffScan ) ); const int maxGolombIdx = AdaptiveLoopFilter::getMaxGolombIdx( alfShape.filterType ); #endif - const short* coeff = isChroma ? alfSliceParam.chromaCoeff : alfSliceParam.lumaCoeff; - const short* clipp = isChroma ? alfSliceParam.chromaClipp : alfSliceParam.lumaClipp; - const int numFilters = isChroma ? 1 : alfSliceParam.numLumaFilters; +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + const short* coeff = isChroma ? alfParam.chromaCoeff[altIdx] : alfParam.lumaCoeff; + const short* clipp = isChroma ? alfParam.chromaClipp[altIdx] : alfParam.lumaClipp; +#else + const short* coeff = isChroma ? alfParam.chromaCoeff : alfParam.lumaCoeff; + const short* clipp = isChroma ? alfParam.chromaClipp : alfParam.lumaClipp; +#endif + const int numFilters = isChroma ? 1 : alfParam.numLumaFilters; // vlc for all #if !JVET_O0216_ALF_COEFF_EG3 for( int ind = 0; ind < numFilters; ++ind ) { - if( isChroma || !alfSliceParam.alfLumaCoeffDeltaFlag || alfSliceParam.alfLumaCoeffFlag[ind] ) + if( isChroma || !alfParam.alfLumaCoeffDeltaFlag || alfParam.alfLumaCoeffFlag[ind] ) { for( int i = 0; i < alfShape.numCoeff - 1; i++ ) { @@ -1862,11 +1907,11 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro #endif if( !isChroma ) { - if( alfSliceParam.alfLumaCoeffDeltaFlag ) + if( alfParam.alfLumaCoeffDeltaFlag ) { for( int ind = 0; ind < numFilters; ++ind ) { - WRITE_FLAG( alfSliceParam.alfLumaCoeffFlag[ind], "alf_luma_coeff_flag[i]" ); + WRITE_FLAG( alfParam.alfLumaCoeffFlag[ind], "alf_luma_coeff_flag[i]" ); } } } @@ -1874,7 +1919,7 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro // Filter coefficients for( int ind = 0; ind < numFilters; ++ind ) { - if( !isChroma && !alfSliceParam.alfLumaCoeffFlag[ind] && alfSliceParam.alfLumaCoeffDeltaFlag ) + if( !isChroma && !alfParam.alfLumaCoeffFlag[ind] && alfParam.alfLumaCoeffDeltaFlag ) { continue; } @@ -1890,7 +1935,11 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro } // Clipping values coding - if( alfSliceParam.nonLinearFlag[isChroma] ) +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + if( alfParam.nonLinearFlag[isChroma][altIdx] ) +#else + if( alfParam.nonLinearFlag[isChroma] ) +#endif { #if JVET_O0064_SIMP_ALF_CLIP_CODING for (int ind = 0; ind < numFilters; ++ind) @@ -1912,7 +1961,7 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro { memcpy( recCoeff, coeff, sizeof(short) * numFilters * MAX_NUM_ALF_LUMA_COEFF ); #if !JVET_O0669_REMOVE_ALF_COEFF_PRED - if( alfSliceParam.alfLumaCoeffDeltaPredictionFlag ) + if( alfParam.alfLumaCoeffDeltaPredictionFlag ) { for( int i = 1; i < numFilters; i++ ) { @@ -1927,7 +1976,7 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro // vlc for all for( int ind = 0; ind < numFilters; ++ind ) { - if( isChroma || !alfSliceParam.alfLumaCoeffDeltaFlag || alfSliceParam.alfLumaCoeffFlag[ind] ) + if( isChroma || !alfParam.alfLumaCoeffDeltaFlag || alfParam.alfLumaCoeffFlag[ind] ) { for( int i = 0; i < alfShape.numCoeff - 1; i++ ) { @@ -1962,7 +2011,7 @@ void HLSWriter::alfFilter( const AlfSliceParam& alfSliceParam, const bool isChro // Filter coefficients for( int ind = 0; ind < numFilters; ++ind ) { - if( !isChroma && !alfSliceParam.alfLumaCoeffFlag[ind] && alfSliceParam.alfLumaCoeffDeltaFlag ) + if( !isChroma && !alfParam.alfLumaCoeffFlag[ind] && alfParam.alfLumaCoeffDeltaFlag ) { continue; } diff --git a/source/Lib/EncoderLib/VLCWriter.h b/source/Lib/EncoderLib/VLCWriter.h index 2fd162f2391b0412f6077439c2808603d3ed5e63..82758fb33c02f0a0507bc97c227c73b69808cf66 100644 --- a/source/Lib/EncoderLib/VLCWriter.h +++ b/source/Lib/EncoderLib/VLCWriter.h @@ -137,7 +137,11 @@ public: void codeTilesWPPEntryPoint ( Slice* pSlice ); void codeScalingList ( const ScalingList &scalingList ); - void alfFilter( const AlfSliceParam& alfSliceParam, const bool isChroma ); +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB + void alfFilter( const AlfParam& alfParam, const bool isChroma, const int altIdx ); +#else + void alfFilter( const AlfParam& alfParam, const bool isChroma ); +#endif private: void xWriteTruncBinCode( uint32_t uiSymbol, const int uiMaxSymbol );