diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 599c43e08e50bfd25e08e2d16192a26939b26365..ab22f12e29a6ea1870bb89851025095380eb075e 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -246,6 +246,18 @@ void EncApp::xInitLibCfg() m_cEncLib.setUseGBi ( m_GBi ); m_cEncLib.setUseGBiFast ( m_GBiFast ); #endif +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + m_cEncLib.setUseLadf ( m_LadfEnabed ); + if ( m_LadfEnabed ) + { + m_cEncLib.setLadfNumIntervals ( m_LadfNumIntervals); + for ( int k = 0; k < m_LadfNumIntervals; k++ ) + { + m_cEncLib.setLadfQpOffset( m_LadfQpOffset[k], k ); + m_cEncLib.setLadfIntervalLowerBound(m_LadfIntervalLowerBound[k], k); + } + } +#endif // ADD_NEW_TOOL : (encoder app) add setting of tool enabling flags and associated parameters here m_cEncLib.setMaxCUWidth ( m_QTBT ? m_uiCTUSize : m_uiMaxCUWidth ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index f893b6432374bf077f9aa2d9b113ff6e7bace537..e6723233eeb7f91df4cf1170470b85452e25187e 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -699,6 +699,12 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) SMultiValueInput<bool> cfg_timeCodeSeiHoursFlag (0, 1, 0, MAX_TIMECODE_SEI_SETS); SMultiValueInput<int> cfg_timeCodeSeiTimeOffsetLength (0, 31, 0, MAX_TIMECODE_SEI_SETS); SMultiValueInput<int> cfg_timeCodeSeiTimeOffsetValue (std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), 0, MAX_TIMECODE_SEI_SETS); +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + const int defaultLadfQpOffset[3] = { 1, 0, 1 }; + const int defaultLadfIntervalLowerBound[2] = { 350, 833 }; + SMultiValueInput<int> cfg_LadfQpOffset ( -MAX_QP, MAX_QP, 2, MAX_LADF_INTERVALS, defaultLadfQpOffset, 3 ); + SMultiValueInput<int> cfg_LadfIntervalLowerBound ( 0, std::numeric_limits<int>::max(), 1, MAX_LADF_INTERVALS - 1, defaultLadfIntervalLowerBound, 2 ); +#endif int warnUnknowParameter = 0; #if ENABLE_TRACING @@ -850,6 +856,12 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #if JVET_L0646_GBI ("GBi", m_GBi, false, "Enable Generalized Bi-prediction(GBi)") ("GBiFast", m_GBiFast, false, "Fast methods for Generalized Bi-prediction(GBi)\n") +#endif +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + ("LADF", m_LadfEnabed, false, "Luma adaptive deblocking filter QP Offset(L0414)") + ("LadfNumIntervals", m_LadfNumIntervals, 3, "LADF number of intervals (2-5, inclusive)") + ("LadfQpOffset", cfg_LadfQpOffset, cfg_LadfQpOffset, "LADF QP offset") + ("LadfIntervalLowerBound", cfg_LadfIntervalLowerBound, cfg_LadfIntervalLowerBound, "LADF lower bound for 2nd lowest interval") #endif // ADD_NEW_TOOL : (encoder app) add parsing parameters here @@ -1686,6 +1698,19 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } #endif +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + if ( m_LadfEnabed ) + { + CHECK( m_LadfNumIntervals != cfg_LadfQpOffset.values.size(), "size of LadfQpOffset must be equal to LadfNumIntervals"); + CHECK( m_LadfNumIntervals - 1 != cfg_LadfIntervalLowerBound.values.size(), "size of LadfIntervalLowerBound must be equal to LadfNumIntervals - 1"); + m_LadfQpOffset = cfg_LadfQpOffset.values; + for (int k = 1; k < m_LadfNumIntervals; k++) + { + m_LadfIntervalLowerBound[k] = cfg_LadfIntervalLowerBound.values[k - 1]; + } + } +#endif + // reading external dQP description from file if ( !m_dQPFileName.empty() ) { @@ -3130,6 +3155,9 @@ void EncAppCfg::xPrintParameter() #if JVET_L0646_GBI msg( VERBOSE, "GBi:%d ", m_GBi ); msg( VERBOSE, "GBiFast:%d ", m_GBiFast ); +#endif +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + msg( VERBOSE, "LADF:%d ", m_LadfEnabed ); #endif } // ADD_NEW_TOOL (add some output indicating the usage of tools) diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 1245c737a65ca9e1d2bc4de4d7b7ba24a651d68f..cf5095f67d48a66364d4b438d0a1447d78fca63d 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -227,6 +227,12 @@ protected: #if JVET_L0646_GBI bool m_GBi; bool m_GBiFast; +#endif +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + bool m_LadfEnabed; + int m_LadfNumIntervals; + std::vector<int> m_LadfQpOffset; + int m_LadfIntervalLowerBound[MAX_LADF_INTERVALS]; #endif // ADD_NEW_TOOL : (encoder app) add tool enabling flags and associated parameters here diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 6e853ecfc327faea9aaa70b5afd30c217019b08e..c007a9bba2caa9f1a93991f3cb72e1cd5ff8e573 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -364,6 +364,10 @@ static const unsigned C806_ALF_TEMPPRED_NUM = 6; static const int NTAPS_LUMA = 8; ///< Number of taps for luma static const int NTAPS_CHROMA = 4; ///< Number of taps for chroma +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET +static const int MAX_LADF_INTERVALS = 5; /// max number of luma adaptive deblocking filter qp offset intervals +#endif + // ==================================================================================================================== // Macro functions // ==================================================================================================================== diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index f4b7522fcca5fa803b7c52569a6fd313297f1966..ceec19637f408d69f6a8b0b5cb1551760e6dac11 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -560,6 +560,36 @@ unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const De return ( ( abs( mvQ0.getHor() - mvP0.getHor() ) >= nThreshold ) || ( abs( mvQ0.getVer() - mvP0.getVer() ) >= nThreshold ) ) ? 1 : 0; } +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET +void LoopFilter::deriveLADFShift( const Pel* piSrc, const int iStride, int& iShift, const DeblockEdgeDir edgeDir, const SPS sps ) +{ + uint32_t uiLevel = 0; + iShift = sps.getSpsNext().getLadfQpOffset(0); + + if (edgeDir == EDGE_VER) + { + uiLevel = (piSrc[0] + piSrc[3*iStride] + piSrc[-1] + piSrc[3*iStride - 1]) >> 2; + } + else // (edgeDir == EDGE_HOR) + { + uiLevel = (piSrc[0] + piSrc[3] + piSrc[-iStride] + piSrc[-iStride + 3]) >> 2; + } + + for ( int k = 1; k < sps.getSpsNext().getLadfNumIntervals(); k++ ) + { + const int th = sps.getSpsNext().getLadfIntervalLowerBound( k ); + if ( uiLevel > th ) + { + iShift = sps.getSpsNext().getLadfQpOffset( k ); + } + else + { + break; + } + } +} +#endif + void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge) { const CompArea& lumaArea = cu.block(COMPONENT_Y); @@ -645,6 +675,14 @@ void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edge iQP = (cuP.qp + cuQ.qp + 1) >> 1; +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + if ( sps.getSpsNext().getLadfEnabled() ) + { + int iShift = 0; + deriveLADFShift( piTmpSrc + iSrcStep * (iIdx*pelsInPart), iStride, iShift, edgeDir, sps ); + iQP += iShift; + } +#endif 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)); diff --git a/source/Lib/CommonLib/LoopFilter.h b/source/Lib/CommonLib/LoopFilter.h index efe3a2c154163cfaf08c1d0e72fc8320ea61b24f..2b74f476f92e86527e5f1c9a067c21691fd272f3 100644 --- a/source/Lib/CommonLib/LoopFilter.h +++ b/source/Lib/CommonLib/LoopFilter.h @@ -62,7 +62,7 @@ private: private: /// CU-level deblocking function void xDeblockCU ( CodingUnit& cu, const DeblockEdgeDir edgeDir ); - + // set / get functions void xSetLoopfilterParam ( const CodingUnit& cu ); @@ -79,6 +79,9 @@ private: void xEdgeFilterLuma ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge ); void xEdgeFilterChroma ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge ); +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + void deriveLADFShift( const Pel* piSrc, const int iStride, int& iShift, const DeblockEdgeDir edgeDir, const SPS sps ); +#endif inline void xPelFilterLuma ( Pel* piSrc, const int iOffset, const int tc, const bool sw, const bool bPartPNoFilter, const bool bPartQNoFilter, const int iThrCut, const bool bFilterSecondP, const bool bFilterSecondQ, const ClpRng& clpRng ) const; inline void xPelFilterChroma ( Pel* piSrc, const int iOffset, const int tc, const bool bPartPNoFilter, const bool bPartQNoFilter, const ClpRng& clpRng ) const; diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index a11b0c1b5f0d28a03be401d9f12a87980c1fd241..3200b16cd2abecc90eae4da446e0de92d316240d 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1663,6 +1663,12 @@ SPSNext::SPSNext( SPS& sps ) #if ENABLE_WPP_PARALLELISM , m_NextDQP ( false ) #endif +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + , m_LadfEnabled ( false ) + , m_LadfNumIntervals ( 0 ) + , m_LadfQpOffset { 0 } + , m_LadfIntervalLowerBound { 0 } +#endif // default values for additional parameters , m_CTUSize ( 0 ) diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index f42961dc0bbcc8a9775c09143ea4a5d77d3540d0..33709b63a31cbd0feed2f8e5acf75b74115cb74f 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -817,6 +817,12 @@ private: #if ENABLE_WPP_PARALLELISM bool m_NextDQP; #endif +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + bool m_LadfEnabled; + int m_LadfNumIntervals; + int m_LadfQpOffset[MAX_LADF_INTERVALS]; + int m_LadfIntervalLowerBound[MAX_LADF_INTERVALS]; +#endif public: const static int NumReservedFlags = 32 - 27; /* current number of tool enabling flags */ @@ -888,6 +894,16 @@ public: #if JVET_L0646_GBI void setUseGBi ( bool b ) { m_GBi = b; } bool getUseGBi () const { return m_GBi; } +#endif +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + void setLadfEnabled ( bool b ) { m_LadfEnabled = b; } + bool getLadfEnabled () const { return m_LadfEnabled; } + void setLadfNumIntervals ( int i ) { m_LadfNumIntervals = i; } + int getLadfNumIntervals () const { return m_LadfNumIntervals; } + void setLadfQpOffset ( int value, int idx ) { m_LadfQpOffset[ idx ] = value; } + int getLadfQpOffset ( int idx ) const { return m_LadfQpOffset[ idx ]; } + void setLadfIntervalLowerBound( int value, int idx ) { m_LadfIntervalLowerBound[ idx ] = value; } + int getLadfIntervalLowerBound( int idx ) const { return m_LadfIntervalLowerBound[ idx ]; } #endif //===== additional parameters ===== // qtbt diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 0a2889bb2fb743b1aeb152ae1887d2bf3e815161..b99b27384f6ac4be4cd990d96ff750824fe201a1 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -285,6 +285,7 @@ #define QP_SWITCHING_FOR_PARALLEL 1 ///< Replace floating point QP with a source-file frame number. After switching POC, increase base QP instead of frame level QP. +#define LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET 1 /// JVET-L0414 (CE11.2.2) with explicit signalling of num interval, threshold and qpOffset // ==================================================================================================================== // Derived macros // ==================================================================================================================== diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 33ee5dd2b2e30fe6013792ec7140a81bb0658448..5afb188dc802e0b87573f4b2d8c3f13c421b1b89 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -910,6 +910,21 @@ void HLSyntaxReader::parseSPSNext( SPSNext& spsNext, const bool usePCM ) } +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + READ_FLAG( symbol, "sps_ladf_enabled_flag" ); spsNext.setLadfEnabled( symbol != 0 ); + if ( spsNext.getLadfEnabled() ) + { + int signedSymbol = 0; + READ_CODE( 2, symbol, "sps_num_ladf_intervals_minus2"); spsNext.setLadfNumIntervals( symbol + 2 ); + READ_SVLC(signedSymbol, "sps_ladf_lowest_interval_qp_offset" ); spsNext.setLadfQpOffset( signedSymbol, 0 ); + for ( int k = 1; k < spsNext.getLadfNumIntervals(); k++ ) + { + READ_SVLC(signedSymbol, "sps_ladf_qp_offset" ); spsNext.setLadfQpOffset( signedSymbol, k ); + READ_UVLC( symbol, "sps_ladf_delta_threshold_minus1"); + spsNext.setLadfIntervalLowerBound(symbol + spsNext.getLadfIntervalLowerBound(k - 1) + 1, k); + } + } +#endif // ADD_NEW_TOOL : (sps extension parser) read tool enabling flags and associated parameters here } diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 9be410e7eed79a790804b43952021f1716958298..6ccf7acdff8a3f0792770fd94edd9196d187a1ad 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -210,6 +210,12 @@ protected: #if JVET_L0646_GBI bool m_GBi; bool m_GBiFast; +#endif +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + bool m_LadfEnabled; + int m_LadfNumIntervals; + int m_LadfQpOffset[MAX_LADF_INTERVALS]; + int m_LadfIntervalLowerBound[MAX_LADF_INTERVALS]; #endif // ADD_NEW_TOOL : (encoder lib) add tool enabling flags and associated parameters here @@ -657,6 +663,18 @@ public: bool getUseGBi () const { return m_GBi; } void setUseGBiFast ( uint32_t b ) { m_GBiFast = b; } bool getUseGBiFast () const { return m_GBiFast; } +#endif + +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + void setUseLadf ( bool b ) { m_LadfEnabled = b; } + bool getUseLadf () const { return m_LadfEnabled; } + void setLadfNumIntervals ( int i ) { m_LadfNumIntervals = i; } + int getLadfNumIntervals () const { return m_LadfNumIntervals; } + void setLadfQpOffset ( int value, int idx ){ m_LadfQpOffset[ idx ] = value; } + int getLadfQpOffset ( int idx ) const { return m_LadfQpOffset[ idx ]; } + void setLadfIntervalLowerBound ( int value, int idx ){ m_LadfIntervalLowerBound[ idx ] = value; } + int getLadfIntervalLowerBound ( int idx ) const { return m_LadfIntervalLowerBound[ idx ]; } + #endif // ADD_NEW_TOOL : (encoder lib) add access functions here diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 4b81b3c8495c195b0dd0342204dc67441512234c..3e4b088bdf4739f18998a6aede40021e8839bddb 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -858,6 +858,20 @@ void EncLib::xInitSPS(SPS &sps) #if JVET_L0646_GBI sps.getSpsNext().setUseGBi ( m_GBi ); #endif +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + sps.getSpsNext().setLadfEnabled ( m_LadfEnabled ); + if ( m_LadfEnabled ) + { + sps.getSpsNext().setLadfNumIntervals ( m_LadfNumIntervals ); + for ( int k = 0; k < m_LadfNumIntervals; k++ ) + { + sps.getSpsNext().setLadfQpOffset( m_LadfQpOffset[k], k ); + sps.getSpsNext().setLadfIntervalLowerBound( m_LadfIntervalLowerBound[k], k ); + } + CHECK( m_LadfIntervalLowerBound[0] != 0, "abnormal value set to LadfIntervalLowerBound[0]" ); + } +#endif + // ADD_NEW_TOOL : (encoder lib) set tool enabling flags and associated parameters here int minCUSize = ( /*sps.getSpsNext().getUseQTBT() ? 1 << MIN_CU_LOG2 :*/ sps.getMaxCUWidth() >> sps.getLog2DiffMaxMinCodingBlockSize() ); diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index e53e6f2f40f8b6d67197230abd9f92d291f641e6..ef3b0613175878822ff66b6cd0975177703dd661 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -619,6 +619,19 @@ void HLSWriter::codeSPSNext( const SPSNext& spsNext, const bool usePCM ) { WRITE_UVLC( spsNext.getMTTMode() - 1, "mtt_mode_minus1" ); } +#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET + WRITE_FLAG( spsNext.getLadfEnabled() ? 1 : 0, "sps_ladf_enabled_flag" ); + if ( spsNext.getLadfEnabled() ) + { + WRITE_CODE( spsNext.getLadfNumIntervals() - 2, 2, "sps_num_ladf_intervals_minus2" ); + WRITE_SVLC( spsNext.getLadfQpOffset( 0 ), "sps_ladf_lowest_interval_qp_offset"); + for ( int k = 1; k< spsNext.getLadfNumIntervals(); k++ ) + { + WRITE_SVLC( spsNext.getLadfQpOffset( k ), "sps_ladf_qp_offset" ); + WRITE_UVLC( spsNext.getLadfIntervalLowerBound( k ) - spsNext.getLadfIntervalLowerBound( k - 1 ) - 1, "sps_ladf_delta_threshold_minus1" ); + } + } +#endif // ADD_NEW_TOOL : (sps extension writer) write tool enabling flags and associated parameters here }