diff --git a/doc/software-manual.tex b/doc/software-manual.tex index a5dccae4edb0081da0c52e406471b66e09c4c63f..d5bd680429ca895c158468476c415e047a3cfc29 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -2022,6 +2022,12 @@ Enables optimization of non-linear filters for ALF on Chroma channels. Enables or disables symmetric MVD mode. \\ +\Option{RDPCM} & +%\ShortOption{\None} & +\Default{false} & +Enables or disables RDPCM coding mode. +\\ + \end{OptionTableNoShorthand} %% diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 79bac614584a9ae96bd6c0adb8efdefe2d020c73..c8c4e7ac9603e8e8b403b1c3d2f8492e5af8ca86 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -291,6 +291,9 @@ void EncApp::xInitLibCfg() #endif #if JVET_N0449_MMVD_SIMP m_cEncLib.setMmvdDisNum (m_MmvdDisNum); +#endif +#if JVET_N0413_RDPCM + m_cEncLib.setRDPCM ( m_RdpcmMode ); #endif m_cEncLib.setIBCMode ( m_IBCMode ); m_cEncLib.setIBCLocalSearchRangeX ( m_IBCLocalSearchRangeX ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index e9709a4001bf714b927f17bc54336f407771b41e..e7266122e672a7203b1b897d209c4bf98967ca19 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -885,6 +885,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("DMVR", m_DMVR, false, "Decoder-side Motion Vector Refinement") #if JVET_N0449_MMVD_SIMP ("MmvdDisNum", m_MmvdDisNum, 8, "Number of MMVD Distance Entries") +#endif +#if JVET_N0413_RDPCM + ( "RDPCM", m_RdpcmMode, false, "RDPCM") #endif ( "IBC", m_IBCMode, 0u, "IBCMode (0x1:enabled, 0x0:disabled) [default: disabled]") ( "IBCLocalSearchRangeX", m_IBCLocalSearchRangeX, 128u, "Search range of IBC local search in x direction") @@ -1983,6 +1986,9 @@ bool EncAppCfg::xCheckParameter() xConfirmPara(m_DMVR, "DMVR only allowed with NEXT profile"); #if JVET_N0449_MMVD_SIMP xConfirmPara(m_MmvdDisNum, "Number of distance MMVD entry setting only allowed with NEXT profile"); +#endif +#if JVET_N0413_RDPCM + xConfirmPara(m_RdpcmMode, "RDPCM only allowed with NEXT profile"); #endif // ADD_NEW_TOOL : (parameter check) add a check for next tools here } @@ -3183,6 +3189,9 @@ void EncAppCfg::xPrintParameter() msg(VERBOSE, "DMVR:%d ", m_DMVR); #if JVET_N0449_MMVD_SIMP msg(VERBOSE, "MmvdDisNum:%d ", m_MmvdDisNum); +#endif +#if JVET_N0413_RDPCM + msg(VERBOSE, "RDPCM:%d ", m_RdpcmMode ); #endif } msg(VERBOSE, "IBC:%d ", m_IBCMode); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 70ee66a5c29656e445bab876fd236e6beab84dc6..2663a5d6b1852f5f0bc2ccb9d768a717c69f12b7 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -275,6 +275,9 @@ protected: #endif #if JVET_N0449_MMVD_SIMP int m_MmvdDisNum; +#endif +#if JVET_N0413_RDPCM + bool m_RdpcmMode; #endif unsigned m_IBCMode; unsigned m_IBCLocalSearchRangeX; diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index dc1127c6346b9527414ec74dfe5227c91d27e13e..12f6bf8610a732e1687793f107be9a5372f98423 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -219,6 +219,9 @@ static const int HOR_IDX = (1 * (NUM_DIR - 1) + 2); ///< inde static const int DIA_IDX = (2 * (NUM_DIR - 1) + 2); ///< index for intra DIAGONAL mode static const int VER_IDX = (3 * (NUM_DIR - 1) + 2); ///< index for intra VERTICAL mode static const int VDIA_IDX = (4 * (NUM_DIR - 1) + 2); ///< index for intra VDIAGONAL mode +#if JVET_N0413_RDPCM +static const int BDPCM_IDX = (5 * (NUM_DIR - 1) + 2); ///< index for intra VDIAGONAL mode +#endif static const int NOMODE_IDX = MAX_UCHAR; ///< indicating uninitialized elements static const int NUM_CHROMA_MODE = (5 + NUM_LMC_MODE); ///< total number of chroma modes @@ -346,6 +349,9 @@ static const int DMVR_SUBCU_WIDTH_LOG2 = 4; static const int DMVR_SUBCU_HEIGHT_LOG2 = 4; static const int MAX_NUM_SUBCU_DMVR = ((MAX_CU_SIZE * MAX_CU_SIZE) >> (DMVR_SUBCU_WIDTH_LOG2 + DMVR_SUBCU_HEIGHT_LOG2)); static const int DMVR_NUM_ITERATION = 2; +#if JVET_N0413_RDPCM +static const int BDPCM_MAX_CU_SIZE = 32; ///< maximum CU size for RDPCM mode +#endif //QTBT high level parameters //for I slice luma CTB configuration para. diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index bc2f329ab97a10bbe91584ad33e3b147ed4d333d..26351a6d912d6856ee9cb9ddd8273307064f3774 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -42,7 +42,11 @@ #if HEVC_USE_SIGN_HIDING +#if JVET_N0413_RDPCM +CoeffCodingContext::CoeffCodingContext( const TransformUnit& tu, ComponentID component, bool signHide, bool bdpcm ) +#else CoeffCodingContext::CoeffCodingContext(const TransformUnit& tu, ComponentID component, bool signHide) +#endif #else CoeffCodingContext::CoeffCodingContext(const TransformUnit& tu, ComponentID component ) #endif @@ -109,6 +113,9 @@ CoeffCodingContext::CoeffCodingContext(const TransformUnit& tu, ComponentID comp , m_tsGtxFlagCtxSet ( Ctx::TsGtxFlag ) #endif , m_sigCoeffGroupFlag () +#if JVET_N0413_RDPCM + , m_bdpcm (bdpcm) +#endif { // LOGTODO unsigned log2sizeX = m_log2BlockWidth; diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index f6e4946bfce367a302e5d74c943536d64e1f4079..61b33662de966c3bc89113ba10fbfe277056dd4b 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -52,7 +52,11 @@ struct CoeffCodingContext { public: #if HEVC_USE_SIGN_HIDING +#if JVET_N0413_RDPCM + CoeffCodingContext( const TransformUnit& tu, ComponentID component, bool signHide, bool bdpcm = false ); +#else CoeffCodingContext( const TransformUnit& tu, ComponentID component, bool signHide); +#endif #else CoeffCodingContext( const TransformUnit& tu, ComponentID component ); #endif @@ -110,7 +114,9 @@ public: #else unsigned sigGroupCtxId () const { return m_sigGroupCtxId; } #endif - +#if JVET_N0413_RDPCM + bool bdpcm () const { return m_bdpcm; } +#endif unsigned sigCtxIdAbs( int scanPos, const TCoeff* coeff, const int state ) { const uint32_t posY = m_scan[scanPos].y; @@ -306,6 +312,9 @@ private: int m_remainingContextBins; #endif std::bitset<MLS_GRP_NUM> m_sigCoeffGroupFlag; +#if JVET_N0413_RDPCM + const bool m_bdpcm; +#endif }; diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index d922e529968d5c0b6aa9ed802f06b8d59f15eefa..4d4ae4d26b80dbbf88643b7a4dab2b187d4adb96 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -409,6 +409,16 @@ const CtxSet ContextSetCfg::Mvd = ContextSetCfg::addCtxSet { 9, 5, }, }); +#if JVET_N0413_RDPCM +const CtxSet ContextSetCfg::BDPCMMode = ContextSetCfg::addCtxSet +({ + { CNU, CNU, }, + { CNU, CNU, }, + { CNU, CNU, }, + { DWS, DWS, }, +}); +#endif + const CtxSet ContextSetCfg::QtRootCbf = ContextSetCfg::addCtxSet ({ { 109, }, @@ -419,6 +429,15 @@ const CtxSet ContextSetCfg::QtRootCbf = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::QtCbf[] = { +#if JVET_N0413_RDPCM + ContextSetCfg::addCtxSet + ({ + { 141, 127, 139, 140, CNU }, + { 142, 127, 139, 140, CNU }, + { CNU, 111, 124, 111, CNU }, + { 1, 5, 9, 8, DWS }, + }), +#else ContextSetCfg::addCtxSet ({ { 141, 127, 139, 140, }, @@ -426,6 +445,7 @@ const CtxSet ContextSetCfg::QtCbf[] = { CNU, 111, 124, 111, }, { 1, 5, 9, 8, }, }), +#endif ContextSetCfg::addCtxSet ({ { 163, 154, CNU, CNU, CNU, }, @@ -870,10 +890,17 @@ const CtxSet ContextSetCfg::TsResidualSign = { ContextSetCfg::addCtxSet ({ +#if JVET_N0413_RDPCM + { CNU, CNU, }, + { CNU, CNU, }, + { CNU, CNU, }, + { DWS, DWS, }, +#else { CNU, }, { CNU, }, { CNU, }, { DWS, }, +#endif }), }; #endif diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 4cffdab370988809799ef7756ea193cfb201ee8c..d910606f635ea77f47119b08d0ddb82e21006dfd 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -223,6 +223,9 @@ public: static const CtxSet AffineType; static const CtxSet AffMergeIdx; static const CtxSet Mvd; +#if JVET_N0413_RDPCM + static const CtxSet BDPCMMode; +#endif static const CtxSet QtRootCbf; static const CtxSet QtCbf [3]; // [ channel ] static const CtxSet SigCoeffGroup [4]; // [ ChannelType ] diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index 7030269b755452f4d17ca7e1f1316648e09b1192..2d9d7613b1b713e751265a27333704f571a0204b 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -294,9 +294,11 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co const ChannelType channelType = toChannelType( compID ); const int iWidth = piPred.width; const int iHeight = piPred.height; - +#if JVET_N0413_RDPCM + const uint32_t uiDirMode = isLuma( compId ) && pu.cu->bdpcmMode ? BDPCM_IDX : PU::getFinalIntraMode( pu, channelType ); +#else const uint32_t uiDirMode = PU::getFinalIntraMode( pu, channelType ); - +#endif CHECK( g_aucLog2[iWidth] < 2 && pu.cs->pcv->noChroma2x2, "Size not allowed" ); CHECK( g_aucLog2[iWidth] > 7, "Size not allowed" ); @@ -315,6 +317,9 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co { case(PLANAR_IDX): xPredIntraPlanar(srcBuf, piPred); break; case(DC_IDX): xPredIntraDc(srcBuf, piPred, channelType, false); break; +#if JVET_N0413_RDPCM + case(BDPCM_IDX): xPredIntraBDPCM(srcBuf, piPred, pu.cu->bdpcmMode, clpRng); break; +#endif default: xPredIntraAng(srcBuf, piPred, channelType, clpRng); break; } @@ -853,6 +858,44 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch } } +#if JVET_N0413_RDPCM +void IntraPrediction::xPredIntraBDPCM(const CPelBuf &pSrc, PelBuf &pDst, const uint32_t dirMode, const ClpRng& clpRng ) +{ + const int wdt = pDst.width; + const int hgt = pDst.height; + + const int strideP = pDst.stride; + const int strideS = pSrc.stride; + + CHECK( !( dirMode == 1 || dirMode == 2 ), "Incorrect BDPCM mode parameter." ); + + Pel* pred = &pDst.buf[0]; + if( dirMode == 1 ) + { + Pel val; + for( int y = 0; y < hgt; y++ ) + { + val = pSrc.buf[(y + 1) * strideS]; + for( int x = 0; x < wdt; x++ ) + { + pred[x] = val; + } + pred += strideP; + } + } + else + { + for( int y = 0; y < hgt; y++ ) + { + for( int x = 0; x < wdt; x++ ) + { + pred[x] = pSrc.buf[x + 1]; + } + pred += strideP; + } + } +} +#endif bool IntraPrediction::useDPCMForFirstPassIntraEstimation(const PredictionUnit &pu, const uint32_t &uiDirMode) { @@ -1349,6 +1392,9 @@ bool IntraPrediction::useFilteredIntraRefSamples( const ComponentID &compID, con #else if( !isLuma( chType ) && pu.chromaFormat != CHROMA_444 ) { return false; } #endif +#if JVET_N0413_RDPCM + if( isLuma( chType ) && pu.cu->bdpcmMode ) { return false; } +#endif if( pu.cu->ispMode && isLuma(compID) ) { return false; } diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index a2889e3b0978d2aa7aa9fa94c4bb5407f463dd7c..db1a452ad8c8c4f968e8b09645f0a71c7716de8a 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -121,6 +121,9 @@ protected: static bool isIntegerSlope ( const int absAng ) { return (0 == (absAng & 0x1F)) && absAng <=32; } // integer-slope modes 2, DIA_IDX and VDIA_IDX. "absAng <=32" restricts wide-angle integer modes #endif +#if JVET_N0413_RDPCM + void xPredIntraBDPCM ( const CPelBuf &pSrc, PelBuf &pDst, const uint32_t dirMode, const ClpRng& clpRng ); +#endif Pel xGetPredValDc ( const CPelBuf &pSrc, const Size &dstSize ); void xFillReferenceSamples ( const CPelBuf &recoBuf, Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu ); diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index cd0bae703b9f9784254507203dc5154e2c22743f..6941b72138ebed6435b2283f48a6761a4112dc3b 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -749,6 +749,13 @@ unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const De const CodingUnit& cuQ = cu; const CodingUnit& cuP = *cu.cs->getCU( posP, cu.chType ); +#if JVET_N0413_RDPCM + if( ( MODE_INTRA == cuP.predMode && cuP.bdpcmMode ) && ( MODE_INTRA == cuQ.predMode && cuQ.bdpcmMode ) ) + { + return 0; + } +#endif + //-- Set BS for Intra MB : BS = 4 or 3 if( ( MODE_INTRA == cuP.predMode ) || ( MODE_INTRA == cuQ.predMode ) ) { diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp index 1b61df49ee3759f6e99437de4596bcd693aaa4a9..907ee11b36e81e2e117540f9445edac50a4ae5f2 100644 --- a/source/Lib/CommonLib/Quant.cpp +++ b/source/Lib/CommonLib/Quant.cpp @@ -141,6 +141,82 @@ Quant::~Quant() #endif } +#if JVET_N0413_RDPCM +void invResDPCM( const TransformUnit &tu, const ComponentID &compID, CoeffBuf &dstBuf ) +{ + const CompArea &rect = tu.blocks[compID]; + const int wdt = rect.width; + const int hgt = rect.height; + const CCoeffBuf coeffs = tu.getCoeffs(compID); + + const TCoeff* coef = &coeffs.buf[0]; + TCoeff* dst = &dstBuf.buf[0]; + + if( tu.cu->bdpcmMode == 1 ) + { + for( int y = 0; y < hgt; y++ ) + { + dst[0] = coef[0]; + for( int x = 1; x < wdt; x++ ) + { + dst[x] = dst[x - 1] + coef[x]; + } + coef += coeffs.stride; + dst += dstBuf.stride; + } + } + else + { + for( int x = 0; x < wdt; x++ ) + { + dst[x] = coef[x]; + } + for( int y = 0; y < hgt - 1; y++ ) + { + for( int x = 0; x < wdt; x++ ) + { + dst[dstBuf.stride + x] = dst[x] + coef[coeffs.stride + x]; + } + coef += coeffs.stride; + dst += dstBuf.stride; + } + } +} + +void fwdResDPCM( TransformUnit &tu, const ComponentID &compID ) +{ + const CompArea &rect = tu.blocks[compID]; + const int wdt = rect.width; + const int hgt = rect.height; + CoeffBuf coeffs = tu.getCoeffs(compID); + + TCoeff* coef = &coeffs.buf[0]; + + if( tu.cu->bdpcmMode == 1 ) + { + for( int y = 0; y < hgt; y++ ) + { + for( int x = wdt - 1; x > 0; x-- ) + { + coef[x] -= coef[x - 1]; + } + coef += coeffs.stride; + } + } + else + { + coef += coeffs.stride * (hgt - 1); + for( int y = 0; y < hgt - 1; y++ ) + { + for ( int x = 0; x < wdt; x++ ) + { + coef[x] -= coef[x - coeffs.stride]; + } + coef -= coeffs.stride; + } + } +} +#endif #if HEVC_USE_SIGN_HIDING // To minimize the distortion only. No rate is considered. @@ -288,7 +364,9 @@ void Quant::dequant(const TransformUnit &tu, const CompArea &area = tu.blocks[compID]; const uint32_t uiWidth = area.width; const uint32_t uiHeight = area.height; +#if !JVET_N0413_RDPCM const TCoeff *const piQCoef = tu.getCoeffs(compID).buf; +#endif TCoeff *const piCoef = dstCoeff.buf; const uint32_t numSamplesInBlock = uiWidth * uiHeight; const int maxLog2TrDynamicRange = sps->getMaxLog2TrDynamicRange(toChannelType(compID)); @@ -301,6 +379,19 @@ void Quant::dequant(const TransformUnit &tu, #endif const int channelBitDepth = sps->getBitDepth(toChannelType(compID)); +#if JVET_N0413_RDPCM + const TCoeff *coef; + if( tu.cu->bdpcmMode && isLuma(compID) ) + { + invResDPCM( tu, compID, dstCoeff ); + coef = piCoef; + } + else + { + coef = tu.getCoeffs(compID).buf; + } + const TCoeff *const piQCoef = coef; +#endif #if HEVC_USE_SCALING_LISTS CHECK(scalingListType >= SCALING_LIST_NUM, "Invalid scaling list"); #endif @@ -853,6 +944,12 @@ void Quant::quant(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf piQCoef.buf[uiBlockPos] = Clip3<TCoeff>( entropyCodingMinimum, entropyCodingMaximum, quantisedCoefficient ); } // for n +#if JVET_N0413_RDPCM + if( tu.cu->bdpcmMode && isLuma(compID) ) + { + fwdResDPCM( tu, compID ); + } +#endif #if HEVC_USE_SIGN_HIDING if( cctx.signHiding() && uiWidth>=4 && uiHeight>=4 ) { diff --git a/source/Lib/CommonLib/Quant.h b/source/Lib/CommonLib/Quant.h index 3844bad1aeed32c5d06f5707e88f680bb5cda872..5745269c32d45b7f37cdb1ff2a1379756fd5430d 100644 --- a/source/Lib/CommonLib/Quant.h +++ b/source/Lib/CommonLib/Quant.h @@ -58,6 +58,13 @@ // ==================================================================================================================== // Class definition // ==================================================================================================================== +#if JVET_N0413_RDPCM +struct TrQuantParams +{ + int rightShift; + int qScale; +}; +#endif /// QP struct struct QpParam diff --git a/source/Lib/CommonLib/QuantRDOQ.cpp b/source/Lib/CommonLib/QuantRDOQ.cpp index 286e285b249e5fe5bf16a47f36d993376b77e155..86fb173e60d5ad329dfe7cc1d3a7561d6af4fd63 100644 --- a/source/Lib/CommonLib/QuantRDOQ.cpp +++ b/source/Lib/CommonLib/QuantRDOQ.cpp @@ -579,7 +579,18 @@ void QuantRDOQ::quant(TransformUnit &tu, const ComponentID &compID, const CCoeff #if JVET_N0280_RESIDUAL_CODING_TS if( isLuma( compID ) && useTransformSkip ) { +#if JVET_N0413_RDPCM + if( tu.cu->bdpcmMode && isLuma(compID) ) + { + forwardRDPCM( tu, compID, pSrc, uiAbsSum, cQP, ctx ); + } + else + { + xRateDistOptQuantTS( tu, compID, pSrc, uiAbsSum, cQP, ctx ); + } +#else xRateDistOptQuantTS( tu, compID, pSrc, uiAbsSum, cQP, ctx ); +#endif } else { @@ -1487,6 +1498,247 @@ void QuantRDOQ::xRateDistOptQuantTS( TransformUnit &tu, const ComponentID &compI } } +#if JVET_N0413_RDPCM +void QuantRDOQ::forwardRDPCM( TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &coeffs, TCoeff &absSum, const QpParam &qp, const Ctx &ctx ) +{ + const FracBitsAccess& fracBits = ctx.getFracBitsAcess(); + + const SPS &sps = *tu.cs->sps; + const CompArea &rect = tu.blocks[compID]; + const uint32_t width = rect.width; + const uint32_t height = rect.height; + const ChannelType chType = toChannelType(compID); + const int channelBitDepth = sps.getBitDepth(chType); + + const bool extendedPrecision = sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag(); + const int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange(chType); + const int dirMode = tu.cu->bdpcmMode; + + int transformShift = getTransformShift(channelBitDepth, rect.size(), maxLog2TrDynamicRange); + + if (extendedPrecision) + { + transformShift = std::max<int>(0, transformShift); + } + + double blockUncodedCost = 0; +#if HEVC_USE_SCALING_LISTS + const uint32_t log2BlockHeight = g_aucLog2[height]; +#endif + const uint32_t maxNumCoeff = rect.area(); + + CHECK(compID >= MAX_NUM_TBLOCKS, "Invalid component ID"); + +#if HEVC_USE_SCALING_LISTS + int scalingListType = getScalingListType(tu.cu->predMode, compID); + CHECK(scalingListType >= SCALING_LIST_NUM, "Invalid scaling list"); +#endif + + const TCoeff *srcCoeff = coeffs.buf; + TCoeff *dstCoeff = tu.getCoeffs(compID).buf; + + double *costCoeff = m_pdCostCoeff; + double *costSig = m_pdCostSig; + double *costCoeff0 = m_pdCostCoeff0; + + memset(m_pdCostCoeff, 0, sizeof(double) * maxNumCoeff); + memset(m_pdCostSig, 0, sizeof(double) * maxNumCoeff); + memset(m_fullCoeff, 0, sizeof(TCoeff) * maxNumCoeff); + +#if JVET_N0246_MODIFIED_QUANTSCALES + const bool needsSqrt2Scale = TU::needsSqrt2Scale(tu, compID); // should always be false - transform-skipped blocks don't require sqrt(2) compensation. + const int qBits = QUANT_SHIFT + qp.per + transformShift + (needsSqrt2Scale ? -1 : 0); // Right shift of non-RDOQ quantizer; level = (coeff*uiQ + offset)>>q_bits + const int quantisationCoefficient = g_quantScales[needsSqrt2Scale ? 1 : 0][qp.rem]; + const double errorScale = xGetErrScaleCoeff(TU::needsSqrt2Scale(tu, compID), width, height, qp.rem, maxLog2TrDynamicRange, channelBitDepth); + + TrQuantParams trQuantParams; + trQuantParams.rightShift = (IQUANT_SHIFT - (transformShift + qp.per)); + trQuantParams.qScale = g_invQuantScales[needsSqrt2Scale ? 1 : 0][qp.rem]; +#else + + const int qBits = QUANT_SHIFT + qp.per + transformShift; // Right shift of non-RDOQ quantizer; level = (coeff*uiQ + offset)>>q_bits + +#if HM_QTBT_AS_IN_JEM_QUANT + const int quantisationCoefficient = (TU::needsSqrt2Scale(tu, compID) ? (g_quantScales[qp.rem] * 181) >> 7 : g_quantScales[qp.rem]); + const double errorScale = xGetErrScaleCoeff(TU::needsSqrt2Scale(tu, compID), width, height, qp.rem, maxLog2TrDynamicRange, channelBitDepth); +#else + const double blkErrScale = (TU::needsQP3Offset(tu, compID) ? 2.0 : 1.0); + const int quantisationCoefficient = g_quantScales[qp.rem]; + const double errorScale = blkErrScale * xGetErrScaleCoeff(width, height, qp.rem, maxLog2TrDynamicRange, channelBitDepth); +#endif +#endif + + const TCoeff entropyCodingMaximum = (1 << maxLog2TrDynamicRange) - 1; + +#if HEVC_USE_SIGN_HIDING + CoeffCodingContext cctx(tu, compID, tu.cs->slice->getSignDataHidingEnabledFlag()); +#else + CoeffCodingContext cctx(tu, compID); +#endif + const int sbSizeM1 = (1 << cctx.log2CGSize()) - 1; + double baseCost = 0; + uint32_t goRiceParam = 0; + + double *costSigSubBlock = m_pdCostCoeffGroupSig; + memset(costSigSubBlock, 0, (maxNumCoeff >> cctx.log2CGSize()) * sizeof(double)); + + const int sbNum = width * height >> cctx.log2CGSize(); + int scanPos; + coeffGroupRDStats rdStats; + + bool anySigCG = false; + + for (int sbId = 0; sbId < sbNum; sbId++) + { + cctx.initSubblock(sbId); + + memset(&rdStats, 0, sizeof(coeffGroupRDStats)); + + for (int scanPosInSB = 0; scanPosInSB <= sbSizeM1; scanPosInSB++) + { + scanPos = cctx.minSubPos() + scanPosInSB; + //===== quantization ===== + uint32_t blkPos = cctx.blockPos(scanPos); + + const int posX = cctx.posX(scanPos); + const int posY = cctx.posY(scanPos); + const int posS = (1 == dirMode) ? posX : posY; + const int posNb = (1 == dirMode) ? (posX - 1) + posY * coeffs.stride : posX + (posY - 1) * coeffs.stride; + TCoeff predCoeff = (0 != posS) ? m_fullCoeff[posNb] : 0; + + // set coeff + const int64_t tmpLevel = int64_t(abs(srcCoeff[blkPos] - predCoeff)) * quantisationCoefficient; + const Intermediate_Int levelDouble = (Intermediate_Int)std::min<int64_t>(tmpLevel, std::numeric_limits<Intermediate_Int>::max() - (Intermediate_Int(1) << (qBits - 1))); + uint32_t maxAbsLevel = std::min<uint32_t>(uint32_t(entropyCodingMaximum), uint32_t((levelDouble + (Intermediate_Int(1) << (qBits - 1))) >> qBits)); + + const double err = double(levelDouble); + costCoeff0[scanPos] = err * err * errorScale; + blockUncodedCost += costCoeff0[scanPos]; + dstCoeff[blkPos] = maxAbsLevel; + + //===== coefficient level estimation ===== + unsigned ctxIdSig = cctx.sigCtxIdAbsTS(scanPos, dstCoeff); + uint32_t cLevel; + const BinFracBits fracBitsPar = fracBits.getFracBitsArray(cctx.parityCtxIdAbsTS()); + + goRiceParam = cctx.templateAbsSumTS(scanPos, dstCoeff); + const BinFracBits fracBitsSign = fracBits.getFracBitsArray(Ctx::TsResidualSign(toChannelType(compID))); + const uint8_t sign = srcCoeff[blkPos] - predCoeff < 0 ? 1 : 0; + + DTRACE_COND((maxAbsLevel != 0), g_trace_ctx, D_RDOQ_MORE, " uiCtxSig=%d", ctxIdSig); + + const BinFracBits fracBitsSig = fracBits.getFracBitsArray(ctxIdSig); + cLevel = xGetCodedLevelTS(costCoeff[scanPos], costCoeff0[scanPos], costSig[scanPos], + levelDouble, maxAbsLevel, &fracBitsSig, fracBitsPar, cctx, fracBits, fracBitsSign, sign, goRiceParam, qBits, errorScale, 0, extendedPrecision, maxLog2TrDynamicRange); + dstCoeff[blkPos] = cLevel; + + if (sign) + { + dstCoeff[blkPos] = -dstCoeff[blkPos]; + } + xDequantSample( m_fullCoeff[blkPos], dstCoeff[blkPos], trQuantParams ); + m_fullCoeff[blkPos] += predCoeff; + + baseCost += costCoeff[scanPos]; + rdStats.d64SigCost += costSig[scanPos]; + + if (scanPosInSB == 0) + { + rdStats.d64SigCost_0 = costSig[scanPos]; + } + if (dstCoeff[blkPos]) + { + cctx.setSigGroup(); + rdStats.d64CodedLevelandDist += costCoeff[scanPos] - costSig[scanPos]; + rdStats.d64UncodedDist += costCoeff0[scanPos]; + if (scanPosInSB != 0) + { + rdStats.iNNZbeforePos0++; + } + } + } //end for (iScanPosinCG) + + if (!cctx.isSigGroup()) + { + const BinFracBits fracBitsSigGroup = fracBits.getFracBitsArray(cctx.sigGroupCtxId(true)); + baseCost += xGetRateSigCoeffGroup(fracBitsSigGroup, 0) - rdStats.d64SigCost; + costSigSubBlock[cctx.subSetId()] = xGetRateSigCoeffGroup(fracBitsSigGroup, 0); + } + else if (sbId != sbSizeM1 || anySigCG) + { + if (rdStats.iNNZbeforePos0 == 0) + { + baseCost -= rdStats.d64SigCost_0; + rdStats.d64SigCost -= rdStats.d64SigCost_0; + } + // rd-cost if SigCoeffGroupFlag = 0, initialization + double costZeroSB = baseCost; + + const BinFracBits fracBitsSigGroup = fracBits.getFracBitsArray(cctx.sigGroupCtxId(true)); + + baseCost += xGetRateSigCoeffGroup(fracBitsSigGroup, 1); + costZeroSB += xGetRateSigCoeffGroup(fracBitsSigGroup, 0); + costSigSubBlock[cctx.subSetId()] = xGetRateSigCoeffGroup(fracBitsSigGroup, 1); + + costZeroSB += rdStats.d64UncodedDist; // distortion for resetting non-zero levels to zero levels + costZeroSB -= rdStats.d64CodedLevelandDist; // distortion and level cost for keeping all non-zero levels + costZeroSB -= rdStats.d64SigCost; // sig cost for all coeffs, including zero levels and non-zerl levels + + if (costZeroSB < baseCost) + { + cctx.resetSigGroup(); + baseCost = costZeroSB; + costSigSubBlock[cctx.subSetId()] = xGetRateSigCoeffGroup(fracBitsSigGroup, 0); + + for (int scanPosInSB = 0; scanPosInSB < sbSizeM1; scanPosInSB++) + { + scanPos = cctx.minSubPos() + scanPosInSB; + uint32_t blkPos = cctx.blockPos(scanPos); + + const int posX = cctx.posX(scanPos); + const int posY = cctx.posY(scanPos); + const int posS = (1 == dirMode) ? posX : posY; + const int posNb = (1 == dirMode) ? (posX - 1) + posY * coeffs.stride : posX + (posY - 1) * coeffs.stride; + m_fullCoeff[scanPos] = (0 != posS) ? m_fullCoeff[posNb] : 0; + + if (dstCoeff[blkPos]) + { + dstCoeff[blkPos] = 0; + costCoeff[scanPos] = costCoeff0[scanPos]; + costSig[scanPos] = 0; + } + } + } + else + { + anySigCG = true; + } + } + } + + //===== estimate last position ===== + for (int scanPos = 0; scanPos < maxNumCoeff; scanPos++) + { + int blkPos = cctx.blockPos(scanPos); + TCoeff level = dstCoeff[blkPos]; + absSum += level; + } +} + +void QuantRDOQ::xDequantSample(TCoeff& pRes, TCoeff& coeff, const TrQuantParams& trQuantParams) +{ + // xDequant + if (trQuantParams.rightShift > 0) + { + const Intermediate_Int qAdd = Intermediate_Int(1) << (trQuantParams.rightShift - 1); + pRes = TCoeff((Intermediate_Int(coeff) * trQuantParams.qScale + qAdd) >> trQuantParams.rightShift); + } + else + { + pRes = TCoeff((Intermediate_Int(coeff) * trQuantParams.qScale) << -trQuantParams.rightShift); + } +} +#endif inline uint32_t QuantRDOQ::xGetCodedLevelTS( double& codedCost, double& codedCost0, double& codedCostSig, diff --git a/source/Lib/CommonLib/QuantRDOQ.h b/source/Lib/CommonLib/QuantRDOQ.h index 7077e6ef426a37f3001aad689e4a2ca1fa615105..128f47aa306ed603393c7eba1d5e79500fa766b3 100644 --- a/source/Lib/CommonLib/QuantRDOQ.h +++ b/source/Lib/CommonLib/QuantRDOQ.h @@ -67,6 +67,9 @@ public: #endif // quantization void quant ( TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pSrc, TCoeff &uiAbsSum, const QpParam &cQP, const Ctx& ctx ); +#if JVET_N0413_RDPCM + void forwardRDPCM ( TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pSrc, TCoeff &uiAbsSum, const QpParam &cQP, const Ctx &ctx ); +#endif private: #if HEVC_USE_SCALING_LISTS @@ -78,7 +81,9 @@ private: #else double xGetErrScaleCoeff ( const bool needsSqrt2, SizeType width, SizeType height, int qp, const int maxLog2TrDynamicRange, const int channelBitDepth); #endif - +#if JVET_N0413_RDPCM + void xDequantSample ( TCoeff& pRes, TCoeff& coeff, const TrQuantParams& trQuantParams ); +#endif // RDOQ functions void xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pSrc, TCoeff &uiAbsSum, const QpParam &cQP, const Ctx &ctx); @@ -168,6 +173,9 @@ private: int m_rateIncDown [MAX_TB_SIZEY * MAX_TB_SIZEY]; int m_sigRateDelta [MAX_TB_SIZEY * MAX_TB_SIZEY]; TCoeff m_deltaU [MAX_TB_SIZEY * MAX_TB_SIZEY]; +#if JVET_N0413_RDPCM + TCoeff m_fullCoeff [MAX_TB_SIZEY * MAX_TB_SIZEY]; +#endif #endif };// END CLASS DEFINITION QuantRDOQ diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp index e84d183b5fbb3b98a3445416219da4607173ac90..6f6a684818e3786383e5cb25346595252196313f 100644 --- a/source/Lib/CommonLib/TrQuant.cpp +++ b/source/Lib/CommonLib/TrQuant.cpp @@ -678,6 +678,13 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const RDPCMMode rdpcmMode = RDPCM_OFF; rdpcmNxN(tu, compID, cQP, uiAbsSum, rdpcmMode); +#if JVET_N0413_RDPCM + if( tu.cu->bdpcmMode && isLuma(compID) ) + { + tu.mtsIdx = 1; + } +#endif + if (rdpcmMode == RDPCM_OFF) { uiAbsSum = 0; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index acd80e6141f3d32df6cabfc77540bf368ca2715b..99157289830a335c0d5b9b6ab9fe5152f08c0522 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,8 @@ #include <assert.h> #include <cassert> +#define JVET_N0413_RDPCM 1 // Residual DPCM JVET-N0413/N0214 + #define JVET_N0866_UNIF_TRFM_SEL_IMPL_MTS_ISP 1 // JVET-N0866: unified transform derivation for ISP and implicit MTS (combining JVET-N0172, JVET-N0375, JVET-N0419 and JVET-N0420) #define JVET_N0340_TRI_MERGE_CAND 1 diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 739c4518d62332f0d16ba5f07a14ee0b6b1f636d..7a1745d5a12f73d92eedb7606eab598bc73686e8 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -267,6 +267,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other ) affineType = other.affineType; triangle = other.triangle; transQuantBypass = other.transQuantBypass; +#if JVET_N0413_RDPCM + bdpcmMode = other.bdpcmMode; +#endif ipcm = other.ipcm; qp = other.qp; chromaQpAdj = other.chromaQpAdj; @@ -300,6 +303,9 @@ void CodingUnit::initData() affineType = 0; triangle = false; transQuantBypass = false; +#if JVET_N0413_RDPCM + bdpcmMode = 0; +#endif ipcm = false; qp = 0; chromaQpAdj = 0; diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 571354693291ee7dbf6c7f214c473b6c0b0c224f..d11399eb9eca2e6b923cfca15012d2c4afe8af1e 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -305,6 +305,9 @@ struct CodingUnit : public UnitArea int affineType; bool triangle; bool transQuantBypass; +#if JVET_N0413_RDPCM + int bdpcmMode; +#endif bool ipcm; uint8_t imv; bool rootCbf; diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 321523089cb56ea7c0f392f0872df4bdb3965204..32718df43e39ce6198f39f6147c021394d6a4ad0 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -5462,6 +5462,16 @@ uint8_t CU::deriveGbiIdx( uint8_t gbiLO, uint8_t gbiL1 ) } } +#if JVET_N0413_RDPCM +bool CU::bdpcmAllowed( const CodingUnit& cu, const ComponentID compID ) +{ + bool bdpcmAllowed = compID == COMPONENT_Y; + bdpcmAllowed &= CU::isIntra( cu ); + bdpcmAllowed &= ( cu.lwidth() <= 32 && cu.lheight() <= 32 ); + + return bdpcmAllowed; +} +#endif // TU tools bool TU::isNonTransformedResidualRotated(const TransformUnit &tu, const ComponentID &compID) @@ -5495,7 +5505,9 @@ bool TU::isTSAllowed(const TransformUnit &tu, const ComponentID compID) tsAllowed &= tu.cs->pps->getUseTransformSkip(); tsAllowed &= !tu.cu->transQuantBypass; tsAllowed &= ( !tu.cu->ispMode || !isLuma(compID) ); - +#if JVET_N0413_RDPCM + tsAllowed &= !( tu.cu->bdpcmMode && tu.lwidth() <= BDPCM_MAX_CU_SIZE && tu.lheight() <= BDPCM_MAX_CU_SIZE ); +#endif SizeType transformSkipMaxSize = 1 << maxSize; tsAllowed &= tu.lwidth() <= transformSkipMaxSize && tu.lheight() <= transformSkipMaxSize; tsAllowed &= !tu.cu->sbtInfo; @@ -5512,6 +5524,9 @@ bool TU::isMTSAllowed(const TransformUnit &tu, const ComponentID compID) mtsAllowed &= ( tu.lwidth() <= maxSize && tu.lheight() <= maxSize ); mtsAllowed &= !tu.cu->ispMode; mtsAllowed &= !tu.cu->sbtInfo; +#if JVET_N0413_RDPCM + mtsAllowed &= !( tu.cu->bdpcmMode && tu.lwidth() <= BDPCM_MAX_CU_SIZE && tu.lheight() <= BDPCM_MAX_CU_SIZE ); +#endif return mtsAllowed; } diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 89815e85b31aa4f45619e336477942f3f29efdf3..902f8bbbc3ca474b182ef85c52bb0de4d412ccab 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -84,6 +84,10 @@ namespace CU uint8_t getValidGbiIdx (const CodingUnit& cu); void setGbiIdx (CodingUnit& cu, uint8_t uh); uint8_t deriveGbiIdx (uint8_t gbiLO, uint8_t gbiL1); +#if JVET_N0413_RDPCM + bool bdpcmAllowed (const CodingUnit& cu, const ComponentID compID); +#endif + bool divideTuInRows ( const CodingUnit &cu ); bool firstTestISPHorSplit ( const int width, const int height, const ComponentID compID, const CodingUnit *cuLeft = nullptr, const CodingUnit *cuAbove = nullptr ); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 535decc8ea6bca74899a495ba63c548d4d508c0f..37dd601d70d5631abd012012c12bf87fdd18fed9 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -681,6 +681,9 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& // prediction mode and partitioning data pred_mode ( cu ); +#if JVET_N0413_RDPCM + bdpcm_mode( cu, ComponentID( partitioner.chType ) ); +#endif // --> create PUs #if !JVET_N0324_REGULAR_MRG_FLAG @@ -1031,7 +1034,23 @@ void CABACReader::pred_mode( CodingUnit& cu ) } } } +#if JVET_N0413_RDPCM +void CABACReader::bdpcm_mode( CodingUnit& cu, const ComponentID compID ) +{ + cu.bdpcmMode = 0; + + if( !CU::bdpcmAllowed( cu, compID ) ) return; + cu.bdpcmMode = m_BinDecoder.decodeBin( Ctx::BDPCMMode( 0 ) ); + + if( cu.bdpcmMode ) + { + cu.bdpcmMode += m_BinDecoder.decodeBin( Ctx::BDPCMMode( 1 ) ); + } + + DTRACE( g_trace_ctx, D_SYNTAX, "bdpcm_mode() x=%d, y=%d, w=%d, h=%d, bdpcm=%d\n", cu.lumaPos().x, cu.lumaPos().y, cu.lwidth(), cu.lheight(), cu.bdpcmMode ); +} +#endif void CABACReader::pcm_flag( CodingUnit& cu, Partitioner &partitioner ) { const SPS& sps = *cu.cs->sps; @@ -1162,8 +1181,11 @@ void CABACReader::extend_ref_line(CodingUnit& cu) #if !ENABLE_JVET_L0283_MRL return; #endif - +#if JVET_N0413_RDPCM + if ( !cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType) || cu.ipcm || cu.bdpcmMode ) +#else if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType) || cu.ipcm) +#endif { cu.firstPU->multiRefIdx = 0; return; @@ -1208,6 +1230,16 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) return; } +#if JVET_N0413_RDPCM + if( cu.bdpcmMode ) + { + PredictionUnit *pu = cu.firstPU; + unsigned mpm_pred[NUM_MOST_PROBABLE_MODES]; + PU::getIntraMPMs(*pu, mpm_pred); + cu.firstPU->intraDir[0] = mpm_pred[0]; + return; + } +#endif RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__INTRA_DIR_ANG, cu.lumaSize(), CHANNEL_TYPE_LUMA ); // prev_intra_luma_pred_flag @@ -2411,7 +2443,19 @@ bool CABACReader::cbf_comp( CodingStructure& cs, const CompArea& area, unsigned RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2(STATS__CABAC_BITS__QT_CBF, area.size(), area.compID); +#if JVET_N0413_RDPCM + unsigned cbf = 0; + if( area.compID == COMPONENT_Y && cs.getCU( area.pos(), ChannelType( area.compID ) )->bdpcmMode ) + { + cbf = m_BinDecoder.decodeBin( ctxSet( 4 ) ); + } + else + { + cbf = m_BinDecoder.decodeBin( ctxSet( ctxId ) ); + } +#else const unsigned cbf = m_BinDecoder.decodeBin( ctxSet( ctxId ) ); +#endif DTRACE( g_trace_ctx, D_SYNTAX, "cbf_comp() etype=%d pos=(%d,%d) ctx=%d cbf=%d\n", area.compID, area.x, area.y, ctxId, cbf ); return cbf; @@ -2611,7 +2655,11 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) explicit_rdpcm_mode( tu, compID ); #if JVET_N0280_RESIDUAL_CODING_TS +#if JVET_N0413_RDPCM + if( isLuma( compID ) && ( tu.mtsIdx == 1 || tu.cu->bdpcmMode ) ) +#else if( isLuma( compID ) && tu.mtsIdx == 1 ) +#endif { residual_codingTS( tu, compID ); return; @@ -2669,6 +2717,9 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) const bool tsAllowed = TU::isTSAllowed ( tu, compID ); const bool mtsAllowed = TU::isMTSAllowed( tu, compID ); +#if JVET_N0413_RDPCM + if( tu.cu->bdpcmMode ) tu.mtsIdx = 1; +#endif if( !mtsAllowed && !tsAllowed ) return; RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__MTS_FLAGS, tu.blocks[compID], compID ); @@ -2713,9 +2764,17 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) void CABACReader::isp_mode( CodingUnit& cu ) { #if INCLUDE_ISP_CFG_FLAG +#if JVET_N0413_RDPCM + if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm || !cu.cs->sps->getUseISP() || cu.bdpcmMode ) +#else if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm || !cu.cs->sps->getUseISP() ) +#endif +#else +#if JVET_N0413_RDPCM + if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm || cu.bdpcmMode ) #else if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm ) +#endif #endif { cu.ispMode = NOT_INTRA_SUBPARTITIONS; @@ -3038,7 +3097,11 @@ void CABACReader::residual_codingTS( TransformUnit& tu, ComponentID compID ) DTRACE( g_trace_ctx, D_SYNTAX, "residual_codingTS() etype=%d pos=(%d,%d) size=%dx%d\n", tu.blocks[compID].compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.blocks[compID].width, tu.blocks[compID].height ); // init coeff coding context +#if JVET_N0413_RDPCM + CoeffCodingContext cctx ( tu, compID, false, tu.cu->bdpcmMode ); +#else CoeffCodingContext cctx ( tu, compID, false ); +#endif TCoeff* coeff = tu.getCoeffs( compID ).buf; cctx.setNumCtxBins( 2 * tu.lwidth()*tu.lheight() ); @@ -3125,7 +3188,11 @@ void CABACReader::residual_coding_subblockTS( CoeffCodingContext& cctx, TCoeff* int sign; if( cctx.isContextCoded() ) { +#if JVET_N0413_RDPCM + sign = m_BinDecoder.decodeBin( Ctx::TsResidualSign( cctx.bdpcm() ? 1 : 0 ) ); +#else sign = m_BinDecoder.decodeBin( Ctx::TsResidualSign( toChannelType( cctx.compID() ) ) ); +#endif } else { diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index c8dd4878140edec5ea0e524119281a6cbf20d44b..4e651c8eaabe1e7942318d389f21b8bfd665bf84 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -77,6 +77,9 @@ public: void cu_transquant_bypass_flag ( CodingUnit& cu ); void cu_skip_flag ( CodingUnit& cu ); void pred_mode ( CodingUnit& cu ); +#if JVET_N0413_RDPCM + void bdpcm_mode ( CodingUnit& cu, const ComponentID compID ); +#endif void pcm_flag ( CodingUnit& cu, Partitioner& pm ); void cu_pred_data ( CodingUnit& cu ); void cu_gbi_flag ( CodingUnit& cu ); diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 34171b4bd0a872bf95660850781a2f193c13e662..82416b3603648dba4a95f550804adbc18533a8ff 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -595,6 +595,9 @@ void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, C // prediction mode and partitioning data pred_mode ( cu ); +#if JVET_N0413_RDPCM + bdpcm_mode( cu, ComponentID( partitioner.chType ) ); +#endif #if FIX_PCM // pcm samples @@ -807,7 +810,20 @@ void CABACWriter::pred_mode( const CodingUnit& cu ) m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu))); } } +#if JVET_N0413_RDPCM +void CABACWriter::bdpcm_mode( const CodingUnit& cu, const ComponentID compID ) +{ + if( !CU::bdpcmAllowed( cu, compID ) ) return; + + m_BinEncoder.encodeBin( cu.bdpcmMode > 0 ? 1 : 0, Ctx::BDPCMMode( 0 ) ); + if( cu.bdpcmMode ) + { + m_BinEncoder.encodeBin( cu.bdpcmMode > 1 ? 1 : 0, Ctx::BDPCMMode( 1 ) ); + } + DTRACE( g_trace_ctx, D_SYNTAX, "bdpcm_mode() x=%d, y=%d, w=%d, h=%d, bdpcm=%d\n", cu.lumaPos().x, cu.lumaPos().y, cu.lwidth(), cu.lheight(), cu.bdpcmMode ); +} +#endif void CABACWriter::pcm_data( const CodingUnit& cu, Partitioner& partitioner ) { pcm_flag( cu, partitioner ); @@ -949,7 +965,11 @@ void CABACWriter::extend_ref_line(const PredictionUnit& pu) #endif const CodingUnit& cu = *pu.cu; +#if JVET_N0413_RDPCM + if( !cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma( cu.chType ) || cu.bdpcmMode ) +#else if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType)) +#endif { return; } @@ -979,7 +999,11 @@ void CABACWriter::extend_ref_line(const CodingUnit& cu) return; #endif +#if JVET_N0413_RDPCM + if ( !cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType) || cu.ipcm || cu.bdpcmMode ) +#else if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType) || cu.ipcm) +#endif { return; } @@ -1019,6 +1043,17 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu ) return; } +#if JVET_N0413_RDPCM + if( cu.bdpcmMode ) + { + PredictionUnit *pu = cu.firstPU; + unsigned mpm_pred[NUM_MOST_PROBABLE_MODES]; + PU::getIntraMPMs( *pu, mpm_pred ); + cu.firstPU->intraDir[0] = mpm_pred[0]; + return; + } +#endif + const int numMPMs = NUM_MOST_PROBABLE_MODES; const int numBlocks = CU::getNumPUs( cu ); unsigned mpm_preds [4][numMPMs]; @@ -1122,6 +1157,9 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu ) void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu ) { +#if JVET_N0413_RDPCM + if( pu.cu->bdpcmMode ) return; +#endif // prev_intra_luma_pred_flag const int numMPMs = NUM_MOST_PROBABLE_MODES; unsigned mpm_pred[numMPMs]; @@ -2270,8 +2308,18 @@ void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& { const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf, useISP && isLuma(area.compID) ); const CtxSet& ctxSet = Ctx::QtCbf[ area.compID ]; - +#if JVET_N0413_RDPCM + if( area.compID == COMPONENT_Y && cs.getCU( area.pos(), ChannelType( area.compID ) )->bdpcmMode ) + { + m_BinEncoder.encodeBin( cbf, ctxSet( 4 ) ); + } + else + { m_BinEncoder.encodeBin( cbf, ctxSet( ctxId ) ); + } +#else + m_BinEncoder.encodeBin( cbf, ctxSet( ctxId ) ); +#endif DTRACE( g_trace_ctx, D_SYNTAX, "cbf_comp() etype=%d pos=(%d,%d) ctx=%d cbf=%d\n", area.compID, area.x, area.y, ctxId, cbf ); } @@ -2487,7 +2535,11 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID ) explicit_rdpcm_mode( tu, compID ); #if JVET_N0280_RESIDUAL_CODING_TS +#if JVET_N0413_RDPCM + if( isLuma( compID ) && ( tu.mtsIdx == 1 || tu.cu->bdpcmMode ) ) +#else if( isLuma( compID ) && tu.mtsIdx==1 ) +#endif { residual_codingTS( tu, compID ); return; @@ -2605,9 +2657,17 @@ void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID ) void CABACWriter::isp_mode( const CodingUnit& cu ) { #if INCLUDE_ISP_CFG_FLAG +#if JVET_N0413_RDPCM + if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm || !cu.cs->sps->getUseISP() || cu.bdpcmMode ) +#else if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm || !cu.cs->sps->getUseISP() ) +#endif +#else +#if JVET_N0413_RDPCM + if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm || cu.bdpcmMode ) #else if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx || cu.ipcm ) +#endif #endif { CHECK( cu.ispMode != NOT_INTRA_SUBPARTITIONS, "error: cu.intraSubPartitions != 0" ); @@ -2880,7 +2940,11 @@ void CABACWriter::residual_codingTS( const TransformUnit& tu, ComponentID compID DTRACE( g_trace_ctx, D_SYNTAX, "residual_codingTS() etype=%d pos=(%d,%d) size=%dx%d\n", tu.blocks[compID].compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.blocks[compID].width, tu.blocks[compID].height ); // init coeff coding context +#if JVET_N0413_RDPCM + CoeffCodingContext cctx ( tu, compID, false, tu.cu->bdpcmMode ); +#else CoeffCodingContext cctx ( tu, compID, false ); +#endif const TCoeff* coeff = tu.getCoeffs( compID ).buf; cctx.setNumCtxBins( 2 * tu.lwidth()*tu.lheight() ); @@ -2973,7 +3037,11 @@ void CABACWriter::residual_coding_subblockTS( CoeffCodingContext& cctx, const TC int sign = Coeff < 0; if( cctx.isContextCoded() ) { +#if JVET_N0413_RDPCM + m_BinEncoder.encodeBin( sign, Ctx::TsResidualSign( cctx.bdpcm() ? 1 : 0 ) ); +#else m_BinEncoder.encodeBin( sign, Ctx::TsResidualSign( toChannelType( cctx.compID() ) ) ); +#endif } else { diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 59b513a48cfb17113a4a36396419fbf8c26f7731..4d511750a90af4ec76418a4d6f8db8293444b332 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -89,6 +89,9 @@ public: void cu_transquant_bypass_flag ( const CodingUnit& cu ); void cu_skip_flag ( const CodingUnit& cu ); void pred_mode ( const CodingUnit& cu ); +#if JVET_N0413_RDPCM + void bdpcm_mode ( const CodingUnit& cu, const ComponentID compID ); +#endif void pcm_data ( const CodingUnit& cu, Partitioner& pm ); void pcm_flag ( const CodingUnit& cu, Partitioner& pm ); void cu_pred_data ( const CodingUnit& cu ); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 1ddd60bfe7618552f3dd537049463976ce05ac6a..23edf138e4b67d2c230b71af464e7eaa276fffc1 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -248,6 +248,9 @@ protected: #endif #if JVET_N0449_MMVD_SIMP int m_MmvdDisNum; +#endif +#if JVET_N0413_RDPCM + bool m_RdpcmMode; #endif unsigned m_IBCMode; unsigned m_IBCLocalSearchRangeX; @@ -787,6 +790,10 @@ public: #if JVET_N0449_MMVD_SIMP void setMmvdDisNum ( int b ) { m_MmvdDisNum = b; } int getMmvdDisNum () const { return m_MmvdDisNum; } +#endif +#if JVET_N0413_RDPCM + void setRDPCM ( bool b ) { m_RdpcmMode = b; } + bool getRDPCM () const { return m_RdpcmMode; } #endif void setIBCMode (unsigned n) { m_IBCMode = n; } unsigned getIBCMode () const { return m_IBCMode; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 0b79eb2f13eb9ca0dee013ac2155c38196d00a11..05619647a1d5bb4a25560d4e94434c9ec2b44842 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1426,7 +1426,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC m_CABACEstimator->extend_ref_line( cu ); m_CABACEstimator->isp_mode ( cu ); m_CABACEstimator->cu_pred_data ( cu ); - +#if JVET_N0413_RDPCM + m_CABACEstimator->bdpcm_mode ( cu, ComponentID(partitioner.chType) ); +#endif // Encode Coefficients CUCtx cuCtx; cuCtx.isDQPCoded = true; @@ -1476,6 +1478,9 @@ void EncCu::xCheckIntraPCM(CodingStructure *&tempCS, CodingStructure *&bestCS, P cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1; cu.qp = encTestMode.qp; cu.ipcm = true; +#if JVET_N0413_RDPCM + cu.bdpcmMode = 0; +#endif tempCS->addPU( CS::getArea( *tempCS, tempCS->area, partitioner.chType ), partitioner.chType ); diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index c0a24e92f00d296ac0bf0dce796972f6be21c40a..f2bb6340a03bfe15a5c00efb95f855e2e316ad18 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -350,6 +350,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, m_intraModeTestedNormalIntra.clear(); } +#if JVET_N0413_RDPCM + const bool testBDPCM = m_pcEncCfg->getRDPCM() && CU::bdpcmAllowed(cu, ComponentID(partitioner.chType)); +#endif static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> uiHadModeList; static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandCostList; static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandHadList; @@ -836,6 +839,10 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, //===== check modes (using r-d costs) ===== uint32_t uiBestPUMode = 0; int bestExtendRef = 0; +#if JVET_N0413_RDPCM + int bestBDPCMMode = 0; + double bestCostNonBDPCM = MAX_DOUBLE; +#endif CodingStructure *csTemp = m_pTempCS[gp_sizeIdxInfo->idxFrom( cu.lwidth() )][gp_sizeIdxInfo->idxFrom( cu.lheight() )]; CodingStructure *csBest = m_pBestCS[gp_sizeIdxInfo->idxFrom( cu.lwidth() )][gp_sizeIdxInfo->idxFrom( cu.lheight() )]; @@ -852,16 +859,39 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, uint8_t bestIspOption = NOT_INTRA_SUBPARTITIONS; TUIntraSubPartitioner subTuPartitioner( partitioner ); bool ispHorAllZeroCbfs = false, ispVerAllZeroCbfs = false; - +#if JVET_N0413_RDPCM + for( int uiMode = -2 * testBDPCM; uiMode < numModesForFullRD; uiMode++ ) +#else for (uint32_t uiMode = 0; uiMode < numModesForFullRD; uiMode++) +#endif + { +#if JVET_N0413_RDPCM + int multiRefIdx = 0; + uint32_t uiOrgMode; + + if (testBDPCM && uiMode < 0) { + cu.bdpcmMode = -uiMode; + unsigned mpm_pred[NUM_MOST_PROBABLE_MODES]; + PU::getIntraMPMs(pu, mpm_pred); + pu.intraDir[0] = mpm_pred[0]; + uiOrgMode = mpm_pred[0]; + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + } + else + { + cu.bdpcmMode = 0; + uiOrgMode = uiRdModeList[uiMode]; +#else // set luma prediction mode uint32_t uiOrgMode = uiRdModeList[uiMode]; - +#endif cu.ispMode = extendRefList[uiMode] > MRL_NUM_REF_LINES ? extendRefList[uiMode] - MRL_NUM_REF_LINES : NOT_INTRA_SUBPARTITIONS; pu.intraDir[0] = uiOrgMode; +#if !JVET_N0413_RDPCM int multiRefIdx = 0; +#endif pu.multiRefIdx = multiRefIdx; if( cu.ispMode ) { @@ -890,7 +920,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, CHECK( pu.multiRefIdx && (pu.intraDir[0] == PLANAR_IDX), "ERL" ); #endif } - +#if JVET_N0413_RDPCM + } +#endif // set context models m_CABACEstimator->getCtx() = ctxStart; @@ -933,16 +965,27 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, uiBestPUMode = uiOrgMode; bestExtendRef = multiRefIdx; bestIspOption = cu.ispMode; +#if JVET_N0413_RDPCM + bestBDPCMMode = cu.bdpcmMode; +#endif if( csBest->cost < bestCurrentCost ) { bestCurrentCost = csBest->cost; } +#if !JVET_N0413_RDPCM if( !cu.ispMode ) { bestNormalIntraModeIndex = uiMode; } +#endif } - +#if JVET_N0413_RDPCM + if( !cu.ispMode && !cu.bdpcmMode && csBest->cost < bestCostNonBDPCM ) + { + bestCostNonBDPCM = csBest->cost; + bestNormalIntraModeIndex = uiMode; + } +#endif csTemp->releaseIntermediateData(); } // Mode loop cu.ispMode = bestIspOption; @@ -952,6 +995,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, //=== update PU data ==== pu.intraDir[0] = uiBestPUMode; pu.multiRefIdx = bestExtendRef; +#if JVET_N0413_RDPCM + cu.bdpcmMode = bestBDPCMMode; +#endif } //===== reset context models ===== @@ -1334,6 +1380,9 @@ void IntraSearch::xEncIntraHeader( CodingStructure &cs, Partitioner &partitioner m_CABACEstimator->cu_skip_flag( cu ); m_CABACEstimator->pred_mode ( cu ); } +#if JVET_N0413_RDPCM + m_CABACEstimator->bdpcm_mode ( cu, ComponentID(partitioner.chType) ); +#endif if( CU::isIntra(cu) ) { m_CABACEstimator->pcm_data( cu, partitioner );