From a7725e565721d1c82d65d21775808c3cc544e96c Mon Sep 17 00:00:00 2001
From: Hongtao Wang <hongtaow@qti.qualcomm.com>
Date: Wed, 24 Jul 2019 16:09:08 -0700
Subject: [PATCH] JVET-O0122 CE7-3.10: Sign context, level mapping of TS
 residual coding

---
 source/Lib/CommonLib/ContextModelling.cpp |   4 +
 source/Lib/CommonLib/ContextModelling.h   | 135 +++++++++++++++
 source/Lib/CommonLib/Contexts.cpp         |  25 +++
 source/Lib/CommonLib/Contexts.h           |   3 +
 source/Lib/CommonLib/QuantRDOQ.cpp        | 190 ++++++++++++++++++++++
 source/Lib/CommonLib/QuantRDOQ.h          |  32 ++++
 source/Lib/CommonLib/TypeDef.h            |   2 +
 source/Lib/DecoderLib/CABACReader.cpp     |  40 +++++
 source/Lib/EncoderLib/CABACWriter.cpp     |  41 +++++
 9 files changed, 472 insertions(+)

diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp
index 4ef4a5522c..df2dd730a7 100644
--- a/source/Lib/CommonLib/ContextModelling.cpp
+++ b/source/Lib/CommonLib/ContextModelling.cpp
@@ -86,6 +86,10 @@ CoeffCodingContext::CoeffCodingContext( const TransformUnit& tu, ComponentID com
   , m_tsSigFlagCtxSet           ( Ctx::TsSigFlag )
   , m_tsParFlagCtxSet           ( Ctx::TsParFlag )
   , m_tsGtxFlagCtxSet           ( Ctx::TsGtxFlag )
+#if JVET_O0122_TS_SIGN_LEVEL
+  , m_tsLrg1FlagCtxSet          (Ctx::TsLrg1Flag)
+  , m_tsSignFlagCtxSet          (Ctx::TsResidualSign)
+#endif
   , m_sigCoeffGroupFlag         ()
   , m_bdpcm                     (bdpcm)
 {
diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h
index 926efcd3b0..d361b0e379 100644
--- a/source/Lib/CommonLib/ContextModelling.h
+++ b/source/Lib/CommonLib/ContextModelling.h
@@ -205,6 +205,137 @@ public:
   unsigned parityCtxIdAbsTS   ()                  const { return m_tsParFlagCtxSet(      0 ); }
   unsigned greaterXCtxIdAbsTS ( uint8_t offset )  const { return m_tsGtxFlagCtxSet( offset ); }
 
+#if JVET_O0122_TS_SIGN_LEVEL
+  unsigned lrg1CtxIdAbsTS(int scanPos, const TCoeff* coeff, int bdpcm)
+  {
+    const uint32_t  posY = m_scan[scanPos].y;
+    const uint32_t  posX = m_scan[scanPos].x;
+    const TCoeff*   posC = coeff + posX + posY * m_width;
+
+    int             numPos = 0;
+#define UPDATE(x) {int a=abs(x);numPos+=!!a;}
+
+    if (bdpcm)
+    {
+      numPos = 3;
+    }
+    else
+    {
+      if (posX > 0)
+      {
+        UPDATE(posC[-1]);
+      }
+      if (posY > 0)
+      {
+        UPDATE(posC[-(int)m_width]);
+      }
+    }
+
+#undef UPDATE
+    return m_tsLrg1FlagCtxSet(numPos);
+  }
+#endif
+
+#if JVET_O0122_TS_SIGN_LEVEL
+  unsigned signCtxIdAbsTS(int scanPos, const TCoeff* coeff, int bdpcm)
+  {
+    const uint32_t  posY = m_scan[scanPos].y;
+    const uint32_t  posX = m_scan[scanPos].x;
+    const TCoeff*   pData = coeff + posX + posY * m_width;
+
+    int rightSign = 0, belowSign = 0;
+    unsigned signCtx = 0;
+
+    if (posX > 0)
+    {
+      rightSign = pData[-1];
+    }
+    if (posY > 0)
+    {
+      belowSign = pData[-(int)m_width];
+    }
+
+    if ((rightSign == 0 && belowSign == 0) || ((rightSign*belowSign) < 0))
+    {
+      signCtx = 0;
+    }
+    else if (rightSign >= 0 && belowSign >= 0)
+    {
+      signCtx = 1;
+    }
+    else
+    {
+      signCtx = 2;
+    }
+    if (bdpcm)
+    {
+      signCtx += 3;
+    }
+    return m_tsSignFlagCtxSet(signCtx);
+  }
+#endif
+
+#if JVET_O0122_TS_SIGN_LEVEL
+  void neighTS(int &rightPixel, int &belowPixel, int scanPos, const TCoeff* coeff)
+  {
+    const uint32_t  posY = m_scan[scanPos].y;
+    const uint32_t  posX = m_scan[scanPos].x;
+    const TCoeff*   data = coeff + posX + posY * m_width;
+
+    rightPixel = belowPixel = 0;
+
+    if (posX > 0)
+    {
+      rightPixel = data[-1];
+    }
+    if (posY > 0)
+    {
+      belowPixel = data[-(int)m_width];
+    }
+  }
+
+  int deriveModCoeff(int rightPixel, int belowPixel, int absCoeff, int bdpcm = 0)
+  {
+    int pred1, absBelow = abs(belowPixel), absRight = abs(rightPixel);
+
+    int absCoeffMod = absCoeff;
+
+    if (bdpcm == 0)
+    {
+      pred1 = std::max(absBelow, absRight);
+
+      if (absCoeff == pred1)
+      {
+        absCoeffMod = 1;
+      }
+      else
+      {
+        absCoeffMod = absCoeff < pred1 ? absCoeff + 1 : absCoeff;
+      }
+    }
+
+    return(absCoeffMod);
+  }
+
+  int decDeriveModCoeff(int rightPixel, int belowPixel, int absCoeff)
+  {
+    int pred1, absBelow = abs(belowPixel), absRight = abs(rightPixel);
+    pred1 = std::max(absBelow, absRight);
+
+    int absCoeffMod;
+
+    if (absCoeff == 1 && pred1 > 0)
+    {
+      absCoeffMod = pred1;
+    }
+    else
+    {
+      absCoeffMod = absCoeff - (absCoeff <= pred1);
+    }
+    return(absCoeffMod);
+  }
+#endif
+
   unsigned templateAbsSumTS( int scanPos, const TCoeff* coeff )
   {
     const uint32_t  posY  = m_scan[scanPos].y;
@@ -282,6 +413,10 @@ private:
   CtxSet                    m_tsSigFlagCtxSet;
   CtxSet                    m_tsParFlagCtxSet;
   CtxSet                    m_tsGtxFlagCtxSet;
+#if JVET_O0122_TS_SIGN_LEVEL
+  CtxSet                    m_tsLrg1FlagCtxSet;
+  CtxSet                    m_tsSignFlagCtxSet;
+#endif
   int                       m_remainingContextBins;
   std::bitset<MLS_GRP_NUM>  m_sigCoeffGroupFlag;
   const bool                m_bdpcm;
diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp
index 7fd97af5e4..f8576396a0 100644
--- a/source/Lib/CommonLib/Contexts.cpp
+++ b/source/Lib/CommonLib/Contexts.cpp
@@ -840,6 +840,30 @@ const CtxSet ContextSetCfg::TsGtxFlag = ContextSetCfg::addCtxSet
   {   4,   1,   1,   1,   1, },
 });
 
+#if JVET_O0122_TS_SIGN_LEVEL
+const CtxSet ContextSetCfg::TsLrg1Flag = ContextSetCfg::addCtxSet
+({
+  { 139, 108, 124, 111 },
+  { 122, 138, 139, 110 },
+  { 123, 139, 110, 125 },
+  {   4,   2,   1,   5 }
+  });
+#endif
+
+#if JVET_O0122_TS_SIGN_LEVEL
+
+const CtxSet ContextSetCfg::TsResidualSign =
+{
+  ContextSetCfg::addCtxSet
+  ({
+  { 139,  92, 201, 139, 122, 171 },
+  { 124,  77, 171, 169, 121, 187 },
+  { 124,  61, 187, 154, 121, 187 },
+  {   1,   4,   1,   5,   5,   5 }
+    }),
+};
+
+#else
 const CtxSet ContextSetCfg::TsResidualSign =
 {
   ContextSetCfg::addCtxSet
@@ -850,6 +874,7 @@ const CtxSet ContextSetCfg::TsResidualSign =
     {   1,   2, },
    }),
 };
+#endif
 // clang-format on
 
 const unsigned ContextSetCfg::NumberOfContexts = (unsigned)ContextSetCfg::sm_InitTables[0].size();
diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h
index e68c790960..214ff17b13 100644
--- a/source/Lib/CommonLib/Contexts.h
+++ b/source/Lib/CommonLib/Contexts.h
@@ -235,6 +235,9 @@ public:
   static const CtxSet   TsSigFlag;
   static const CtxSet   TsParFlag;
   static const CtxSet   TsGtxFlag;
+#if JVET_O0122_TS_SIGN_LEVEL
+  static const CtxSet   TsLrg1Flag;
+#endif
   static const CtxSet   TsResidualSign;
   static const CtxSet   MVPIdx;
   static const CtxSet   SaoMergeFlag;
diff --git a/source/Lib/CommonLib/QuantRDOQ.cpp b/source/Lib/CommonLib/QuantRDOQ.cpp
index 79195fe3e8..704d3ba871 100644
--- a/source/Lib/CommonLib/QuantRDOQ.cpp
+++ b/source/Lib/CommonLib/QuantRDOQ.cpp
@@ -1243,6 +1243,10 @@ void QuantRDOQ::xRateDistOptQuantTS( TransformUnit &tu, const ComponentID &compI
   memset( m_pdCostCoeff,  0, sizeof( double ) *  maxNumCoeff );
   memset( m_pdCostSig,    0, sizeof( double ) *  maxNumCoeff );
 
+#if JVET_O0122_TS_SIGN_LEVEL
+  m_bdpcm = 0;
+#endif
+
   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];
@@ -1250,6 +1254,11 @@ void QuantRDOQ::xRateDistOptQuantTS( TransformUnit &tu, const ComponentID &compI
 
   const TCoeff entropyCodingMaximum = ( 1 << maxLog2TrDynamicRange ) - 1;
 
+#if JVET_O0122_TS_SIGN_LEVEL
+  uint32_t coeffLevels[3];
+  double   coeffLevelError[4];
+#endif
+
   CoeffCodingContext cctx( tu, compID, tu.cs->slice->getSignDataHidingEnabledFlag() );
   const int sbSizeM1    = ( 1 << cctx.log2CGSize() ) - 1;
   double    baseCost    = 0;
@@ -1282,12 +1291,42 @@ void QuantRDOQ::xRateDistOptQuantTS( TransformUnit &tu, const ComponentID &compI
       // set coeff
       const int64_t          tmpLevel    = int64_t( abs( srcCoeff[blkPos] ) ) * quantisationCoefficient;
       const Intermediate_Int levelDouble = (Intermediate_Int)std::min<int64_t>( tmpLevel, std::numeric_limits<Intermediate_Int>::max() - ( Intermediate_Int( 1 ) << ( qBits - 1 ) ) );
+
+#if JVET_O0122_TS_SIGN_LEVEL
+      uint32_t roundAbsLevel = std::min<uint32_t>(uint32_t(entropyCodingMaximum), uint32_t((levelDouble + (Intermediate_Int(1) << (qBits - 1))) >> qBits));
+      uint32_t minAbsLevel = (roundAbsLevel > 1 ? roundAbsLevel - 1 : 1);
+
+      uint32_t downAbsLevel = std::min<uint32_t>(uint32_t(entropyCodingMaximum), uint32_t(levelDouble >> qBits));
+      uint32_t upAbsLevel = std::min<uint32_t>(uint32_t(entropyCodingMaximum), downAbsLevel + 1);
+
+      m_testedLevels = 0;
+      coeffLevels[m_testedLevels++] = roundAbsLevel;
+
+      if (minAbsLevel != roundAbsLevel)
+        coeffLevels[m_testedLevels++] = minAbsLevel;
+
+      int rightPixel, belowPixel, predPixel;
+
+      cctx.neighTS(rightPixel, belowPixel, scanPos, dstCoeff);
+      predPixel = cctx.deriveModCoeff(rightPixel, belowPixel, upAbsLevel, 0);
+
+      if (upAbsLevel != roundAbsLevel && upAbsLevel != minAbsLevel && predPixel == 1)
+        coeffLevels[m_testedLevels++] = upAbsLevel;
+
+      double dErr = double(levelDouble);
+      coeffLevelError[0] = dErr * dErr * errorScale;
+
+      costCoeff0[scanPos] = coeffLevelError[0];
+      blockUncodedCost   += costCoeff0[ scanPos ];
+      dstCoeff[blkPos]    = coeffLevels[0];
+#else
             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;
+#endif
 
       //===== coefficient level estimation =====
             unsigned    ctxIdSig = cctx.sigCtxIdAbsTS( scanPos, dstCoeff );
@@ -1295,24 +1334,50 @@ void QuantRDOQ::xRateDistOptQuantTS( TransformUnit &tu, const ComponentID &compI
       const BinFracBits fracBitsPar = fracBits.getFracBitsArray( cctx.parityCtxIdAbsTS() );
 
       goRiceParam = cctx.templateAbsSumTS( scanPos, dstCoeff );
+#if JVET_O0122_TS_SIGN_LEVEL
+      unsigned ctxIdSign = cctx.signCtxIdAbsTS(scanPos, dstCoeff, 0);
+      const BinFracBits fracBitsSign = fracBits.getFracBitsArray(ctxIdSign);
+#else
       const BinFracBits fracBitsSign = fracBits.getFracBitsArray( Ctx::TsResidualSign( toChannelType(compID) ) );
+#endif
       const uint8_t     sign         = srcCoeff[ blkPos ] < 0 ? 1 : 0;
 
+#if JVET_O0122_TS_SIGN_LEVEL
+      DTRACE_COND( ( coeffLevels[0] != 0 ), g_trace_ctx, D_RDOQ_MORE, " uiCtxSig=%d", ctxIdSig );
+#else
       DTRACE_COND( ( maxAbsLevel != 0 ), g_trace_ctx, D_RDOQ_MORE, " uiCtxSig=%d", ctxIdSig );
+#endif
 
+#if JVET_O0122_TS_SIGN_LEVEL
+      unsigned gt1CtxId = cctx.lrg1CtxIdAbsTS(scanPos, dstCoeff, 0);
+      const BinFracBits fracBitsGr1 = fracBits.getFracBitsArray(gt1CtxId);
+
+#endif
       const BinFracBits fracBitsSig = fracBits.getFracBitsArray( ctxIdSig );
       bool lastCoeff = false; //
       if (scanPosInSB == lastPosCoded && noCoeffCoded == 0)
       {
         lastCoeff = true;
       }
+#if JVET_O0122_TS_SIGN_LEVEL
+      cLevel = xGetCodedLevelTSPred( costCoeff[ scanPos ], costCoeff0[ scanPos ], costSig[ scanPos ], levelDouble, qBits, errorScale, coeffLevels, coeffLevelError,
+                                    &fracBitsSig, fracBitsPar, cctx, fracBits, fracBitsSign, fracBitsGr1, sign, rightPixel, belowPixel, goRiceParam, lastCoeff, extendedPrecision, maxLog2TrDynamicRange);
+#else
       cLevel = xGetCodedLevelTS( costCoeff[ scanPos ], costCoeff0[ scanPos ], costSig[ scanPos ],
                                  levelDouble, maxAbsLevel, &fracBitsSig, fracBitsPar, cctx, fracBits, fracBitsSign, sign, goRiceParam, qBits, errorScale, lastCoeff, extendedPrecision, maxLog2TrDynamicRange );
+#endif
+
       if (cLevel > 0)
       {
         noCoeffCoded++;
       }
+
+#if JVET_O0122_TS_SIGN_LEVEL
+      TCoeff level = cLevel;
+      dstCoeff[blkPos] = (level != 0 && srcCoeff[blkPos] < 0) ? -level : level;
+#else
       dstCoeff[ blkPos ]  = cLevel;
+#endif
       baseCost           += costCoeff[ scanPos ];
       rdStats.d64SigCost += costSig[ scanPos ];
 
@@ -1376,8 +1441,12 @@ void QuantRDOQ::xRateDistOptQuantTS( TransformUnit &tu, const ComponentID &compI
   {
     int blkPos = cctx.blockPos( scanPos );
     TCoeff level = dstCoeff[ blkPos ];
+#if !JVET_O0122_TS_SIGN_LEVEL
     absSum += level;
     dstCoeff[ blkPos ] = ( level != 0 && srcCoeff[ blkPos ] < 0 ) ? -level : level;
+#else
+    absSum += abs(level);
+#endif
   }
 }
 
@@ -1422,6 +1491,10 @@ void QuantRDOQ::forwardRDPCM( TransformUnit &tu, const ComponentID &compID, cons
   memset(m_pdCostSig, 0, sizeof(double) *  maxNumCoeff);
   memset(m_fullCoeff, 0, sizeof(TCoeff) * maxNumCoeff);
 
+#if JVET_O0122_TS_SIGN_LEVEL
+  m_bdpcm = dirMode;
+#endif
+
   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];
@@ -1433,6 +1506,11 @@ void QuantRDOQ::forwardRDPCM( TransformUnit &tu, const ComponentID &compID, cons
 
   const TCoeff entropyCodingMaximum = (1 << maxLog2TrDynamicRange) - 1;
 
+#if JVET_O0122_TS_SIGN_LEVEL
+  uint32_t coeffLevels[3];
+  double   coeffLevelError[4];
+#endif
+
   CoeffCodingContext cctx(tu, compID, tu.cs->slice->getSignDataHidingEnabledFlag());
   const int sbSizeM1 = (1 << cctx.log2CGSize()) - 1;
   double    baseCost = 0;
@@ -1471,12 +1549,30 @@ void QuantRDOQ::forwardRDPCM( TransformUnit &tu, const ComponentID &compID, cons
       // 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)));
+#if JVET_O0122_TS_SIGN_LEVEL
+      uint32_t roundAbsLevel = std::min<uint32_t>(uint32_t(entropyCodingMaximum), uint32_t((levelDouble + (Intermediate_Int(1) << (qBits - 1))) >> qBits));
+      uint32_t minAbsLevel = (roundAbsLevel > 1 ? roundAbsLevel - 1 : 1);
+
+      m_testedLevels = 0;
+      coeffLevels[m_testedLevels++] = roundAbsLevel;
+
+      if (minAbsLevel != roundAbsLevel)
+        coeffLevels[m_testedLevels++] = minAbsLevel;
+
+      double dErr = double(levelDouble);
+      coeffLevelError[0]  = dErr * dErr * errorScale;
+
+      costCoeff0[scanPos] = coeffLevelError[0];
+      blockUncodedCost   += costCoeff0[scanPos];
+      dstCoeff[blkPos]    = coeffLevels[0];
+#else
       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;
+#endif
 
       //===== coefficient level estimation =====
       unsigned    ctxIdSig = cctx.sigCtxIdAbsTS(scanPos, dstCoeff);
@@ -1484,10 +1580,23 @@ void QuantRDOQ::forwardRDPCM( TransformUnit &tu, const ComponentID &compID, cons
       const BinFracBits fracBitsPar = fracBits.getFracBitsArray(cctx.parityCtxIdAbsTS());
 
       goRiceParam = cctx.templateAbsSumTS(scanPos, dstCoeff);
+#if JVET_O0122_TS_SIGN_LEVEL
+      unsigned ctxIdSign = cctx.signCtxIdAbsTS(scanPos, dstCoeff, dirMode);
+      const BinFracBits fracBitsSign = fracBits.getFracBitsArray(ctxIdSign);
+#else
       const BinFracBits fracBitsSign = fracBits.getFracBitsArray(Ctx::TsResidualSign(1));
+#endif
       const uint8_t     sign = srcCoeff[blkPos] - predCoeff < 0 ? 1 : 0;
+#if JVET_O0122_TS_SIGN_LEVEL
+      unsigned gt1CtxId = cctx.lrg1CtxIdAbsTS(scanPos, dstCoeff, dirMode);
+      const BinFracBits fracBitsGr1 = fracBits.getFracBitsArray(gt1CtxId);
+#endif
 
+#if JVET_O0122_TS_SIGN_LEVEL
+      DTRACE_COND((dstCoeff[blkPos] != 0), g_trace_ctx, D_RDOQ_MORE, " uiCtxSig=%d", ctxIdSig);
+#else
       DTRACE_COND((maxAbsLevel != 0), g_trace_ctx, D_RDOQ_MORE, " uiCtxSig=%d", ctxIdSig);
+#endif
 
       const BinFracBits fracBitsSig = fracBits.getFracBitsArray(ctxIdSig);
       bool lastCoeff = false; //
@@ -1495,8 +1604,16 @@ void QuantRDOQ::forwardRDPCM( TransformUnit &tu, const ComponentID &compID, cons
       {
         lastCoeff = true;
       }
+#if JVET_O0122_TS_SIGN_LEVEL
+      int rightPixel, belowPixel;
+      cctx.neighTS(rightPixel, belowPixel, scanPos, dstCoeff);
+      cLevel = xGetCodedLevelTSPred(costCoeff[scanPos], costCoeff0[scanPos], costSig[scanPos], levelDouble, qBits, errorScale, coeffLevels, coeffLevelError,
+        &fracBitsSig, fracBitsPar, cctx, fracBits, fracBitsSign, fracBitsGr1, sign, rightPixel, belowPixel, goRiceParam, lastCoeff, extendedPrecision, maxLog2TrDynamicRange);
+#else
       cLevel = xGetCodedLevelTS(costCoeff[scanPos], costCoeff0[scanPos], costSig[scanPos],
         levelDouble, maxAbsLevel, &fracBitsSig, fracBitsPar, cctx, fracBits, fracBitsSign, sign, goRiceParam, qBits, errorScale, lastCoeff, extendedPrecision, maxLog2TrDynamicRange);
+#endif
+
       if (cLevel > 0)
       {
         noCoeffCoded++;
@@ -1596,6 +1713,73 @@ void QuantRDOQ::xDequantSample(TCoeff& pRes, TCoeff& coeff, const TrQuantParams&
     pRes = TCoeff((Intermediate_Int(coeff) * trQuantParams.qScale) << -trQuantParams.rightShift);
   }
 }
+
+#if JVET_O0122_TS_SIGN_LEVEL
+inline uint32_t QuantRDOQ::xGetCodedLevelTSPred(double&            rd64CodedCost,
+  double&            rd64CodedCost0,
+  double&            rd64CodedCostSig,
+  Intermediate_Int    levelDouble,
+  int                 qBits,
+  double              errorScale,
+  uint32_t coeffLevels[],
+  double coeffLevelError[],
+  const BinFracBits* fracBitsSig,
+  const BinFracBits& fracBitsPar,
+  CoeffCodingContext& cctx,
+  const FracBitsAccess& fracBitsAccess,
+  const BinFracBits& fracBitsSign,
+  const BinFracBits& fracBitsGt1,
+  const uint8_t      sign,
+  int                rightPixel,
+  int                belowPixel,
+  uint16_t           ricePar,
+  bool               isLast,
+  bool               useLimitedPrefixLength,
+  const int          maxLog2TrDynamicRange
+) const
+{
+  double currCostSig = 0;
+  uint32_t   bestAbsLevel = 0;
+  if (!isLast && coeffLevels[0] < 3)
+  {
+    rd64CodedCostSig = xGetRateSigCoef(*fracBitsSig, 0);
+    rd64CodedCost = rd64CodedCost0 + rd64CodedCostSig;
+    if (coeffLevels[0] == 0)
+    {
+      return bestAbsLevel;
+    }
+  }
+  else
+  {
+    rd64CodedCost = MAX_DOUBLE;
+  }
+
+  if (!isLast)
+  {
+    currCostSig = xGetRateSigCoef(*fracBitsSig, 1);
+  }
+
+  for (int errorInd = 1; errorInd <= m_testedLevels; errorInd++)
+  {
+    int absLevel = coeffLevels[errorInd - 1];
+    double dErr = 0.0;
+    dErr = double(levelDouble - (Intermediate_Int(absLevel) << qBits));
+    coeffLevelError[errorInd] = dErr * dErr * errorScale;
+    int modAbsLevel = cctx.deriveModCoeff(rightPixel, belowPixel, absLevel, m_bdpcm);
+    double dCurrCost = coeffLevelError[errorInd] + xGetICost(xGetICRateTS(modAbsLevel, fracBitsPar, cctx, fracBitsAccess, fracBitsSign, fracBitsGt1, sign, ricePar, useLimitedPrefixLength, maxLog2TrDynamicRange));
+    dCurrCost += currCostSig;
+
+    if (dCurrCost < rd64CodedCost)
+    {
+      bestAbsLevel = absLevel;
+      rd64CodedCost = dCurrCost;
+      rd64CodedCostSig = currCostSig;
+    }
+  }
+
+  return bestAbsLevel;
+}
+#else
 inline uint32_t QuantRDOQ::xGetCodedLevelTS(       double&             codedCost,
                                                    double&             codedCost0,
                                                    double&             codedCostSig,
@@ -1654,12 +1838,16 @@ inline uint32_t QuantRDOQ::xGetCodedLevelTS(       double&             codedCost
 
   return bestAbsLevel;
 }
+#endif
 
 inline int QuantRDOQ::xGetICRateTS( const uint32_t            absLevel,
                                     const BinFracBits&        fracBitsPar,
                                     const CoeffCodingContext& cctx,
                                     const FracBitsAccess&     fracBitsAccess,
                                     const BinFracBits&        fracBitsSign,
+#if JVET_O0122_TS_SIGN_LEVEL
+                                    const BinFracBits&        fracBitsGt1,
+#endif
                                     const uint8_t             sign,
                                     const uint16_t            ricePar,
                                     const bool                useLimitedPrefixLength,
@@ -1667,8 +1855,10 @@ inline int QuantRDOQ::xGetICRateTS( const uint32_t            absLevel,
 {
   int rate = fracBitsSign.intBits[sign];
 
+#if !JVET_O0122_TS_SIGN_LEVEL
   const uint16_t     ctxGt1      = cctx.greaterXCtxIdAbsTS( 0 );
   const BinFracBits &fracBitsGt1 = fracBitsAccess.getFracBitsArray( ctxGt1 );
+#endif
 
   if( absLevel > 1 )
   {
diff --git a/source/Lib/CommonLib/QuantRDOQ.h b/source/Lib/CommonLib/QuantRDOQ.h
index 1f50f3663e..0010d40c10 100644
--- a/source/Lib/CommonLib/QuantRDOQ.h
+++ b/source/Lib/CommonLib/QuantRDOQ.h
@@ -122,6 +122,30 @@ private:
 
   void xRateDistOptQuantTS( TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &coeffs, TCoeff &absSum, const QpParam &qp, const Ctx &ctx );
 
+#if JVET_O0122_TS_SIGN_LEVEL
+  inline uint32_t xGetCodedLevelTSPred(double&            rd64CodedCost,
+    double&            rd64CodedCost0,
+    double&            rd64CodedCostSig,
+    Intermediate_Int    levelDouble,
+    int                 qBits,
+    double              errorScale,
+    uint32_t coeffLevels[],
+    double coeffLevelError[],
+    const BinFracBits* fracBitsSig,
+    const BinFracBits& fracBitsPar,
+    CoeffCodingContext& cctx,
+    const FracBitsAccess& fracBitsAccess,
+    const BinFracBits& fracBitsSign,
+    const BinFracBits& fracBitsGt1,
+    const uint8_t      sign,
+    int                rightPixel,
+    int                belowPixel,
+    uint16_t           ricePar,
+    bool               isLast,
+    bool               useLimitedPrefixLength,
+    const int          maxLog2TrDynamicRange
+  ) const;
+#else
   inline uint32_t xGetCodedLevelTS(       double&             codedCost,
                                           double&             codedCost0,
                                           double&             codedCostSig,
@@ -139,12 +163,16 @@ private:
                                           bool                isLast,
                                           bool                useLimitedPrefixLength,
                                     const int                 maxLog2TrDynamicRange ) const;
+#endif
 
   inline int xGetICRateTS   ( const uint32_t            absLevel,
                               const BinFracBits&        fracBitsPar,
                               const CoeffCodingContext& cctx,
                               const FracBitsAccess&     fracBitsAccess,
                               const BinFracBits&        fracBitsSign,
+#if JVET_O0122_TS_SIGN_LEVEL
+                              const BinFracBits&        fracBitsGt1,
+#endif
                               const uint8_t             sign,
                               const uint16_t            ricePar,
                               const bool                useLimitedPrefixLength,
@@ -164,6 +192,10 @@ private:
   int    m_sigRateDelta       [MAX_TB_SIZEY * MAX_TB_SIZEY];
   TCoeff m_deltaU             [MAX_TB_SIZEY * MAX_TB_SIZEY];
   TCoeff m_fullCoeff          [MAX_TB_SIZEY * MAX_TB_SIZEY];
+#if JVET_O0122_TS_SIGN_LEVEL
+  int   m_bdpcm;
+  int   m_testedLevels;
+#endif
 };// END CLASS DEFINITION QuantRDOQ
 
 //! \}
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 51316ba78b..8bb29364a3 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -58,6 +58,8 @@
 
 #define JVET_O0284_CONDITION_SMVD_MVDL1ZEROFLAG           1 // JVET-O0284: condition sym_mvd_flag on mvd_l1_zero_flag
 
+#define JVET_O0122_TS_SIGN_LEVEL                          1 // JVET-O0122: Sign context and level mapping of TS residual coding.
+
 #define JVET_O0438_SPS_AFFINE_AMVR_FLAG                   1 // JVET-O0438: affine AMVR control flag conditioned on affine control flag in SPS
 
 #define JVET_O0065_CABAC_INIT                             0 // JVET-O0065: CABAC initialization
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 3f56195fa7..46f1f83e01 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -3204,7 +3204,12 @@ void CABACReader::residual_coding_subblockTS( CoeffCodingContext& cctx, TCoeff*
       int sign;
       if( cctx.isContextCoded() )
       {
+#if JVET_O0122_TS_SIGN_LEVEL
+        const unsigned signCtxId = cctx.signCtxIdAbsTS(nextSigPos, coeff, cctx.bdpcm());
+        sign = m_BinDecoder.decodeBin(signCtxId);
+#else
         sign = m_BinDecoder.decodeBin( Ctx::TsResidualSign(  cctx.bdpcm() ? 1 : 0 ) );
+#endif
       }
       else
       {
@@ -3217,6 +3222,19 @@ void CABACReader::residual_coding_subblockTS( CoeffCodingContext& cctx, TCoeff*
 
       RExt__DECODER_DEBUG_BIT_STATISTICS_SET( ctype_gt1 );
       unsigned gt1Flag;
+#if JVET_O0122_TS_SIGN_LEVEL
+      const unsigned gt1CtxId = cctx.lrg1CtxIdAbsTS(nextSigPos, coeff, cctx.bdpcm());
+      if( cctx.isContextCoded() )
+      {
+        gt1Flag = m_BinDecoder.decodeBin(gt1CtxId);
+        DTRACE( g_trace_ctx, D_SYNTAX_RESI, "ts_gt1_flag() bin=%d ctx=%d\n", gt1Flag, gt1CtxId );
+      }
+      else
+      {
+        gt1Flag = m_BinDecoder.decodeBinEP( );
+        DTRACE( g_trace_ctx, D_SYNTAX_RESI, "ts_gt1_flag() EPbin=%d\n", gt1Flag );
+      }
+#else
       if( cctx.isContextCoded() )
       {
         gt1Flag = m_BinDecoder.decodeBin( cctx.greaterXCtxIdAbsTS(0) );
@@ -3227,6 +3245,7 @@ void CABACReader::residual_coding_subblockTS( CoeffCodingContext& cctx, TCoeff*
         gt1Flag = m_BinDecoder.decodeBinEP( );
         DTRACE( g_trace_ctx, D_SYNTAX_RESI, "ts_gt1_flag() EPbin=%d\n", gt1Flag );
       }
+#endif
 
       unsigned parFlag = 0;
       if( gt1Flag )
@@ -3243,7 +3262,11 @@ void CABACReader::residual_coding_subblockTS( CoeffCodingContext& cctx, TCoeff*
           DTRACE( g_trace_ctx, D_SYNTAX_RESI, "ts_par_flag() EPbin=%d\n", parFlag );
         }
       }
+#if JVET_O0122_TS_SIGN_LEVEL
+      coeff[ blkPos ] = (sign ? -1 : 1 ) * (1 + parFlag + gt1Flag);
+#else
       coeff[ blkPos ] += 1 + parFlag + gt1Flag;
+#endif
     }
   }
 
@@ -3256,6 +3279,12 @@ void CABACReader::residual_coding_subblockTS( CoeffCodingContext& cctx, TCoeff*
     for( int scanPos = firstSigPos; scanPos <= minSubPos; scanPos++ )
     {
       TCoeff& tcoeff = coeff[cctx.blockPos( scanPos )];
+#if JVET_O0122_TS_SIGN_LEVEL
+      if( tcoeff < 0)
+      {
+        tcoeff = -tcoeff;
+      }
+#endif
       if( tcoeff >= cutoffVal )
       {
         RExt__DECODER_DEBUG_BIT_STATISTICS_SET( ctype_gt2 );
@@ -3289,6 +3318,17 @@ void CABACReader::residual_coding_subblockTS( CoeffCodingContext& cctx, TCoeff*
       DTRACE( g_trace_ctx, D_SYNTAX_RESI, "ts_rem_val() bin=%d ctx=%d sp=%d\n", rem, rice, scanPos );
       tcoeff += ( rem << 1 );
     }
+#if JVET_O0122_TS_SIGN_LEVEL
+    if (!cctx.bdpcm())
+    {
+      if (tcoeff > 0)
+      {
+        int rightPixel, belowPixel;
+        cctx.neighTS(rightPixel, belowPixel, scanPos, coeff);
+        tcoeff = cctx.decDeriveModCoeff(rightPixel, belowPixel, tcoeff);
+      }
+    }
+#endif
   }
 
   //===== set final coefficents =====
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 37ae687126..081a36d53b 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -3022,6 +3022,10 @@ void CABACWriter::residual_coding_subblockTS( CoeffCodingContext& cctx, const TC
   int       remAbsLevel   = -1;
   int       numNonZero    =  0;
 
+#if JVET_O0122_TS_SIGN_LEVEL
+  int rightPixel, belowPixel, modAbsCoeff;
+#endif
+
   for( ; nextSigPos <= minSubPos; nextSigPos++ )
   {
     TCoeff    Coeff      = coeff[ cctx.blockPos( nextSigPos ) ];
@@ -3047,16 +3051,40 @@ void CABACWriter::residual_coding_subblockTS( CoeffCodingContext& cctx, const TC
       int sign = Coeff < 0;
       if( cctx.isContextCoded() )
       {
+#if JVET_O0122_TS_SIGN_LEVEL
+        const unsigned signCtxId = cctx.signCtxIdAbsTS(nextSigPos, coeff, cctx.bdpcm());
+        m_BinEncoder.encodeBin(sign, signCtxId);
+#else
         m_BinEncoder.encodeBin( sign, Ctx::TsResidualSign( cctx.bdpcm() ? 1 : 0 ) );
+#endif
       }
       else
       {
         m_BinEncoder.encodeBinEP( sign );
       }
       numNonZero++;
+#if JVET_O0122_TS_SIGN_LEVEL
+      cctx.neighTS(rightPixel, belowPixel, nextSigPos, coeff);
+      modAbsCoeff = cctx.deriveModCoeff(rightPixel, belowPixel, abs(Coeff), cctx.bdpcm());
+      remAbsLevel = modAbsCoeff - 1;
+#else
       remAbsLevel = abs( Coeff ) - 1;
+#endif
 
       unsigned gt1 = !!remAbsLevel;
+#if JVET_O0122_TS_SIGN_LEVEL
+      const unsigned gt1CtxId = cctx.lrg1CtxIdAbsTS(nextSigPos, coeff, cctx.bdpcm());
+      if (cctx.isContextCoded())
+      {
+        m_BinEncoder.encodeBin(gt1, gt1CtxId);
+        DTRACE(g_trace_ctx, D_SYNTAX_RESI, "ts_gt1_flag() bin=%d ctx=%d\n", gt1, gt1CtxId);
+      }
+      else
+      {
+        m_BinEncoder.encodeBinEP(gt1);
+        DTRACE(g_trace_ctx, D_SYNTAX_RESI, "ts_gt1_flag() EPbin=%d\n", gt1);
+      }
+#else
       if( cctx.isContextCoded() )
       {
         m_BinEncoder.encodeBin( gt1, cctx.greaterXCtxIdAbsTS(0) );
@@ -3067,6 +3095,7 @@ void CABACWriter::residual_coding_subblockTS( CoeffCodingContext& cctx, const TC
         m_BinEncoder.encodeBinEP( gt1 );
         DTRACE( g_trace_ctx, D_SYNTAX_RESI, "ts_gt1_flag() EPbin=%d\n", gt1 );
       }
+#endif
 
       if( gt1 )
       {
@@ -3092,7 +3121,13 @@ void CABACWriter::residual_coding_subblockTS( CoeffCodingContext& cctx, const TC
   {
     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
       if( absLevel >= cutoffVal )
       {
         unsigned gt2 = ( absLevel >= ( cutoffVal + 2 ) );
@@ -3114,8 +3149,14 @@ void CABACWriter::residual_coding_subblockTS( CoeffCodingContext& cctx, const TC
   //===== coeff bypass ====
   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
     TCoeff    Coeff     = coeff[ cctx.blockPos( scanPos ) ];
     unsigned  absLevel  = abs( Coeff );
+#endif
     if( absLevel >= cutoffVal )
     {
       int       rice = cctx.templateAbsSumTS( scanPos, coeff );
-- 
GitLab