diff --git a/source/Lib/CommonLib/DepQuant.cpp b/source/Lib/CommonLib/DepQuant.cpp
index 152fe036d39b71d6d30e1c68b7ba0a52d2e9cd90..cf2b3e241b5bd0edc685c6b7617a8b3a0d98a9c1 100644
--- a/source/Lib/CommonLib/DepQuant.cpp
+++ b/source/Lib/CommonLib/DepQuant.cpp
@@ -679,7 +679,11 @@ namespace DQIntern
   {
     CHECKD( lambda <= 0.0, "Lambda must be greater than 0" );
 
+#if JVET_O0919_TS_MIN_QP
+    const int         qpDQ                  = cQP.Qp(tu.mtsIdx==MTS_SKIP && isLuma(compID)) + 1;
+#else
     const int         qpDQ                  = cQP.Qp + 1;
+#endif
     const int         qpPer                 = qpDQ / 6;
     const int         qpRem                 = qpDQ - 6 * qpPer;
     const SPS&        sps                   = *tu.cs->sps;
@@ -748,7 +752,11 @@ namespace DQIntern
     }
 
     //----- set dequant parameters -----
+#if JVET_O0919_TS_MIN_QP
+    const int         qpDQ                  = cQP.Qp(tu.mtsIdx==MTS_SKIP && isLuma(compID)) + 1;
+#else
     const int         qpDQ                  = cQP.Qp + 1;
+#endif
     const int         qpPer                 = qpDQ / 6;
     const int         qpRem                 = qpDQ - 6 * qpPer;
     const SPS&        sps                   = *tu.cs->sps;
@@ -1721,7 +1729,11 @@ void DepQuant::quant( TransformUnit &tu, const ComponentID &compID, const CCoeff
   if( tu.cs->slice->getDepQuantEnabledFlag() && (tu.mtsIdx != MTS_SKIP || !isLuma(compID)) )
   {
     //===== scaling matrix ====
+#if JVET_O0919_TS_MIN_QP
+    const int         qpDQ            = cQP.Qp(tu.mtsIdx==MTS_SKIP && isLuma(compID)) + 1;
+#else
     const int         qpDQ            = cQP.Qp + 1;
+#endif
     const int         qpPer           = qpDQ / 6;
     const int         qpRem           = qpDQ - 6 * qpPer;
     const CompArea    &rect           = tu.blocks[compID];
@@ -1744,7 +1756,11 @@ void DepQuant::dequant( const TransformUnit &tu, CoeffBuf &dstCoeff, const Compo
 {
   if( tu.cs->slice->getDepQuantEnabledFlag() && (tu.mtsIdx != MTS_SKIP || !isLuma(compID)) )
   {
+#if JVET_O0919_TS_MIN_QP
+    const int         qpDQ            = cQP.Qp(tu.mtsIdx==MTS_SKIP && isLuma(compID)) + 1;
+#else
     const int         qpDQ            = cQP.Qp + 1;
+#endif
     const int         qpPer           = qpDQ / 6;
     const int         qpRem           = qpDQ - 6 * qpPer;
     const CompArea    &rect           = tu.blocks[compID];
diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp
index 94ca3df437c07fc540e513e4b95ad6d5e498382d..e597d9da311f7dcb8266bf115f77161828092920 100644
--- a/source/Lib/CommonLib/Quant.cpp
+++ b/source/Lib/CommonLib/Quant.cpp
@@ -65,6 +65,9 @@
 QpParam::QpParam(const int           qpy,
                  const ChannelType   chType,
                  const int           qpBdOffset,
+#if JVET_O0919_TS_MIN_QP
+                 const int           minQpMinus4,
+#endif
                  const int           chromaQPOffset,
                  const ChromaFormat  chFmt,
                  const int           dqp )
@@ -91,9 +94,26 @@ QpParam::QpParam(const int           qpy,
 
   baseQp = Clip3( 0, MAX_QP+qpBdOffset, baseQp + dqp );
 
+#if JVET_O0919_TS_MIN_QP
+  Qps[0] =baseQp;
+  pers[0]=baseQp/6;
+  rems[0]=baseQp%6;
+
+  int baseQpTS = baseQp;
+
+  if( isLuma( chType ) )
+  {
+    baseQpTS = std::max(baseQpTS , 4 + minQpMinus4);
+  }
+
+  Qps[1]  = baseQpTS;
+  pers[1] = baseQpTS / 6;
+  rems[1] = baseQpTS % 6;
+#else
   Qp =baseQp;
   per=baseQp/6;
   rem=baseQp%6;
+#endif
 }
 
 QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int QP /*= -MAX_INT*/)
@@ -126,7 +146,11 @@ QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int
 
   int dqp = 0;
 
+#if JVET_O0919_TS_MIN_QP
+  *this = QpParam(QP <= -MAX_INT ? tu.cu->qp : QP, toChannelType(compID), tu.cs->sps->getQpBDOffset(toChannelType(compID)), tu.cs->sps->getMinQpMinus4(toChannelType(compID)), chromaQpOffset, tu.chromaFormat, dqp);
+#else
   *this = QpParam(QP <= -MAX_INT ? tu.cu->qp : QP, toChannelType(compID), tu.cs->sps->getQpBDOffset(toChannelType(compID)), chromaQpOffset, tu.chromaFormat, dqp);
+#endif
 }
 
 
@@ -397,8 +421,13 @@ void Quant::dequant(const TransformUnit &tu,
   const bool needSqrtAdjustment     = TU::needsBlockSizeTrafoScale( tu, compID );
   const int  iTransformShift        = (bClipTransformShiftTo0 ? std::max<int>(0, originalTransformShift) : originalTransformShift) + (needSqrtAdjustment?-1:0);
 
+#if JVET_O0919_TS_MIN_QP
+  const int QP_per = cQP.per( tu.mtsIdx==MTS_SKIP && isLuma(compID) );
+  const int QP_rem = cQP.rem( tu.mtsIdx==MTS_SKIP && isLuma(compID) );
+#else
   const int QP_per = cQP.per;
   const int QP_rem = cQP.rem;
+#endif
 
   const int  rightShift = (IQUANT_SHIFT - (iTransformShift + QP_per)) + (enableScalingLists ? LOG2_SCALING_LIST_NEUTRAL_VALUE : 0);
 
@@ -943,7 +972,11 @@ void Quant::quant(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf
     CHECK(scalingListType >= SCALING_LIST_NUM, "Invalid scaling list");
     const uint32_t uiLog2TrWidth = g_aucLog2[uiWidth];
     const uint32_t uiLog2TrHeight = g_aucLog2[uiHeight];
+#if JVET_O0919_TS_MIN_QP
+    int *piQuantCoeff = getQuantCoeff(scalingListType, cQP.rem(useTransformSkip), uiLog2TrWidth, uiLog2TrHeight);
+#else
     int *piQuantCoeff = getQuantCoeff(scalingListType, cQP.rem, uiLog2TrWidth, uiLog2TrHeight);
+#endif
 
     const bool enableScalingLists             = getUseScalingList(uiWidth, uiHeight, useTransformSkip);
 
@@ -951,7 +984,11 @@ void Quant::quant(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf
     // compensated by a bit-shift (the quantised result will be sqrt(2) * larger than required).
     // The quantScale table and shift is used to compensate for this.
     const bool needSqrtAdjustment= TU::needsBlockSizeTrafoScale( tu, compID );
+#if JVET_O0919_TS_MIN_QP
+    const int defaultQuantisationCoefficient    = g_quantScales[needSqrtAdjustment?1:0][cQP.rem(useTransformSkip)];
+#else
     const int defaultQuantisationCoefficient    = g_quantScales[needSqrtAdjustment?1:0][cQP.rem];
+#endif
     int iTransformShift = getTransformShift(channelBitDepth, rect.size(), maxLog2TrDynamicRange) + ( needSqrtAdjustment?-1:0);
 
     if (useTransformSkip && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag())
@@ -960,7 +997,11 @@ void Quant::quant(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf
     }
 
 
+#if JVET_O0919_TS_MIN_QP
+    const int iQBits = QUANT_SHIFT + cQP.per(useTransformSkip) + iTransformShift;
+#else
     const int iQBits = QUANT_SHIFT + cQP.per + iTransformShift;
+#endif
     // QBits will be OK for any internal bit depth as the reduction in transform shift is balanced by an increase in Qp_per due to QpBDOffset
 
     const int64_t iAdd = int64_t(tu.cs->slice->isIRAP() ? 171 : 85) << int64_t(iQBits - 9);
@@ -1014,7 +1055,11 @@ bool Quant::xNeedRDOQ(TransformUnit &tu, const ComponentID &compID, const CCoeff
 
   const uint32_t uiLog2TrWidth  = g_aucLog2[uiWidth];
   const uint32_t uiLog2TrHeight = g_aucLog2[uiHeight];
+#if JVET_O0919_TS_MIN_QP
+  int *piQuantCoeff         = getQuantCoeff(scalingListType, cQP.rem(useTransformSkip), uiLog2TrWidth, uiLog2TrHeight);
+#else
   int *piQuantCoeff         = getQuantCoeff(scalingListType, cQP.rem, uiLog2TrWidth, uiLog2TrHeight);
+#endif
 
   const bool enableScalingLists             = getUseScalingList(uiWidth, uiHeight, (useTransformSkip != 0));
 
@@ -1024,7 +1069,11 @@ bool Quant::xNeedRDOQ(TransformUnit &tu, const ComponentID &compID, const CCoeff
     * Then a QP+3 (sqrt(2)) or QP-3 (1/sqrt(2)) method could be used to get the required result
     */
   const bool needSqrtAdjustment= TU::needsBlockSizeTrafoScale( tu, compID );
+#if JVET_O0919_TS_MIN_QP
+  const int defaultQuantisationCoefficient    = g_quantScales[needSqrtAdjustment?1:0][cQP.rem(useTransformSkip)];
+#else
   const int defaultQuantisationCoefficient    = g_quantScales[needSqrtAdjustment?1:0][cQP.rem];
+#endif
   int iTransformShift = getTransformShift(channelBitDepth, rect.size(), maxLog2TrDynamicRange) + (needSqrtAdjustment?-1:0);
 
   if (useTransformSkip && sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag())
@@ -1033,7 +1082,11 @@ bool Quant::xNeedRDOQ(TransformUnit &tu, const ComponentID &compID, const CCoeff
   }
 
 
+#if JVET_O0919_TS_MIN_QP
+  const int iQBits = QUANT_SHIFT + cQP.per(useTransformSkip) + iTransformShift;
+#else
   const int iQBits = QUANT_SHIFT + cQP.per + iTransformShift;
+#endif
   assert(iQBits>=0);
   // QBits will be OK for any internal bit depth as the reduction in transform shift is balanced by an increase in Qp_per due to QpBDOffset
 
@@ -1066,13 +1119,22 @@ void Quant::transformSkipQuantOneSample(TransformUnit &tu, const ComponentID &co
   const int            iTransformShift                = getTransformShift(channelBitDepth, rect.size(), maxLog2TrDynamicRange);
   const int            scalingListType                = getScalingListType(tu.cu->predMode, compID);
   const bool           enableScalingLists             = getUseScalingList(uiWidth, uiHeight, true);
+#if JVET_O0919_TS_MIN_QP
+  const bool useTransformSkip      = tu.mtsIdx == MTS_SKIP && isLuma(compID);
+  const int            defaultQuantisationCoefficient = g_quantScales[0][cQP.rem(useTransformSkip)];
+#else
   const int            defaultQuantisationCoefficient = g_quantScales[0][cQP.rem];
+#endif
 
   CHECK( scalingListType >= SCALING_LIST_NUM, "Invalid scaling list" );
 
   const uint32_t uiLog2TrWidth      = g_aucLog2[uiWidth];
   const uint32_t uiLog2TrHeight     = g_aucLog2[uiHeight];
+#if JVET_O0919_TS_MIN_QP
+  const int *const piQuantCoeff = getQuantCoeff(scalingListType, cQP.rem(useTransformSkip), uiLog2TrWidth, uiLog2TrHeight);
+#else
   const int *const piQuantCoeff = getQuantCoeff(scalingListType, cQP.rem, uiLog2TrWidth, uiLog2TrHeight);
+#endif
 
   /* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be
   * implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the
@@ -1080,7 +1142,11 @@ void Quant::transformSkipQuantOneSample(TransformUnit &tu, const ComponentID &co
   * Then a QP+3 (sqrt(2)) or QP-3 (1/sqrt(2)) method could be used to get the required result
   */
 
+#if JVET_O0919_TS_MIN_QP
+  const int iQBits = QUANT_SHIFT + cQP.per(useTransformSkip) + iTransformShift;
+#else
   const int iQBits = QUANT_SHIFT + cQP.per + iTransformShift;
+#endif
   // QBits will be OK for any internal bit depth as the reduction in transform shift is balanced by an increase in Qp_per due to QpBDOffset
   const int iAdd = int64_t(bUseHalfRoundingPoint ? 256 : (tu.cs->slice->isIRAP() ? 171 : 85)) << int64_t(iQBits - 9);
   TCoeff transformedCoefficient;
@@ -1117,8 +1183,13 @@ void Quant::invTrSkipDeQuantOneSample(TransformUnit &tu, const ComponentID &comp
   const CompArea      &rect                   = tu.blocks[compID];
   const uint32_t           uiWidth                = rect.width;
   const uint32_t           uiHeight               = rect.height;
+#if JVET_O0919_TS_MIN_QP
+  const int            QP_per                 = cQP.per(tu.mtsIdx==MTS_SKIP && isLuma(compID));
+  const int            QP_rem                 = cQP.rem(tu.mtsIdx==MTS_SKIP && isLuma(compID));
+#else
   const int            QP_per                 = cQP.per;
   const int            QP_rem                 = cQP.rem;
+#endif
   const int            maxLog2TrDynamicRange  = sps.getMaxLog2TrDynamicRange(toChannelType(compID));
   const int            channelBitDepth        = sps.getBitDepth(toChannelType(compID));
   const int            iTransformShift        = getTransformShift(channelBitDepth, rect.size(), maxLog2TrDynamicRange);
diff --git a/source/Lib/CommonLib/Quant.h b/source/Lib/CommonLib/Quant.h
index b53de50b4884da9a9f8f4b2c5238beaf5eb56078..5c26400cca277a918f61c24d9d71513f98572215 100644
--- a/source/Lib/CommonLib/Quant.h
+++ b/source/Lib/CommonLib/Quant.h
@@ -67,15 +67,24 @@ struct TrQuantParams
 /// QP struct
 struct QpParam
 {
+#if JVET_O0919_TS_MIN_QP
+  int Qps[2];
+  int pers[2];
+  int rems[2];
+#else
   int Qp;
   int per;
   int rem;
+#endif
 
 private:
 
   QpParam(const int           qpy,
           const ChannelType   chType,
           const int           qpBdOffset,
+#if JVET_O0919_TS_MIN_QP
+          const int           qpBdOffsetInput,
+#endif
           const int           chromaQPOffset,
           const ChromaFormat  chFmt,
           const int           dqp );
@@ -84,6 +93,12 @@ public:
 
   QpParam(const TransformUnit& tu, const ComponentID &compID, const int QP = -MAX_INT);
 
+#if JVET_O0919_TS_MIN_QP
+  int Qp ( const bool ts ) const { return Qps [ts?1:0]; }
+  int per( const bool ts ) const { return pers[ts?1:0]; }
+  int rem( const bool ts ) const { return rems[ts?1:0]; }
+#endif
+
 }; // END STRUCT DEFINITION QpParam
 
 /// transform and quantization class
diff --git a/source/Lib/CommonLib/QuantRDOQ.cpp b/source/Lib/CommonLib/QuantRDOQ.cpp
index 30e3ba2e25340ca6c46e851055c8e5b475cb26b3..d21646a22f860e9c8280efcaeb8b5717402837f3 100644
--- a/source/Lib/CommonLib/QuantRDOQ.cpp
+++ b/source/Lib/CommonLib/QuantRDOQ.cpp
@@ -628,13 +628,28 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID,
 
 
   const bool needSqrtAdjustment= TU::needsBlockSizeTrafoScale( tu, compID );
+#if JVET_O0919_TS_MIN_QP
+  const bool   isTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID);
+  const double *const pdErrScale = xGetErrScaleCoeffSL(scalingListType, uiLog2BlockWidth, uiLog2BlockHeight, cQP.rem(isTransformSkip));
+  const int    *const piQCoef    = getQuantCoeff(scalingListType, cQP.rem(isTransformSkip), uiLog2BlockWidth, uiLog2BlockHeight);
+#else
   const double *const pdErrScale = xGetErrScaleCoeffSL(scalingListType, uiLog2BlockWidth, uiLog2BlockHeight, cQP.rem);
   const int    *const piQCoef    = getQuantCoeff(scalingListType, cQP.rem, uiLog2BlockWidth, uiLog2BlockHeight);
   const bool   isTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID);
+#endif
   const bool   enableScalingLists             = getUseScalingList(uiWidth, uiHeight, isTransformSkip);
+#if JVET_O0919_TS_MIN_QP
+  const int    defaultQuantisationCoefficient = g_quantScales[ needSqrtAdjustment ?1:0][cQP.rem(isTransformSkip)];
+  const double defaultErrorScale              = xGetErrScaleCoeffNoScalingList(scalingListType, (uiLog2BlockWidth-1), (uiLog2BlockHeight-1), cQP.rem(isTransformSkip));
+#else
   const int    defaultQuantisationCoefficient = g_quantScales[ needSqrtAdjustment ?1:0][cQP.rem];
   const double defaultErrorScale              = xGetErrScaleCoeffNoScalingList(scalingListType, (uiLog2BlockWidth-1), (uiLog2BlockHeight-1), cQP.rem);
+#endif
+#if JVET_O0919_TS_MIN_QP
+  const int iQBits = QUANT_SHIFT + cQP.per(isTransformSkip) + iTransformShift + (needSqrtAdjustment?-1:0);                   // Right shift of non-RDOQ quantizer;  level = (coeff*uiQ + offset)>>q_bits
+#else
   const int iQBits = QUANT_SHIFT + cQP.per + iTransformShift + (needSqrtAdjustment?-1:0);                   // Right shift of non-RDOQ quantizer;  level = (coeff*uiQ + offset)>>q_bits
+#endif
 
 
   const TCoeff entropyCodingMinimum = -(1 << maxLog2TrDynamicRange);
@@ -1078,9 +1093,18 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID,
 
   if( cctx.signHiding() && uiAbsSum>=2)
   {
+#if JVET_O0919_TS_MIN_QP
+    const double inverseQuantScale = double(g_invQuantScales[0][cQP.rem(isTransformSkip)]);
+#else
     const double inverseQuantScale = double(g_invQuantScales[0][cQP.rem]);
+#endif
+#if JVET_O0919_TS_MIN_QP
+    int64_t rdFactor = (int64_t)(inverseQuantScale * inverseQuantScale * (1 << (2 * cQP.per(isTransformSkip))) / m_dLambda / 16
+                                  / (1 << (2 * DISTORTION_PRECISION_ADJUSTMENT(channelBitDepth)))
+#else
     int64_t rdFactor = (int64_t)(inverseQuantScale * inverseQuantScale * (1 << (2 * cQP.per)) / m_dLambda / 16
                                / (1 << (2 * DISTORTION_PRECISION_ADJUSTMENT(channelBitDepth)))
+#endif
                              + 0.5);
 
     int lastCG = -1;
@@ -1252,9 +1276,16 @@ void QuantRDOQ::xRateDistOptQuantTS( TransformUnit &tu, const ComponentID &compI
 #endif
 
   const bool   needsSqrt2Scale = TU::needsSqrt2Scale( tu, compID );  // should always be false - transform-skipped blocks don't require sqrt(2) compensation.
+#if JVET_O0919_TS_MIN_QP
+  const bool   isTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID);
+  const int    qBits = QUANT_SHIFT + qp.per(isTransformSkip) + 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(isTransformSkip)];
+  const double errorScale              = xGetErrScaleCoeff( TU::needsSqrt2Scale( tu, compID ), width, height, qp.rem(isTransformSkip), maxLog2TrDynamicRange, channelBitDepth );
+#else
   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 );
+#endif
 
   const TCoeff entropyCodingMaximum = ( 1 << maxLog2TrDynamicRange ) - 1;
 
@@ -1500,13 +1531,25 @@ void QuantRDOQ::forwardRDPCM( TransformUnit &tu, const ComponentID &compID, cons
 #endif
 
   const bool   needsSqrt2Scale = TU::needsSqrt2Scale(tu, compID);  // should always be false - transform-skipped blocks don't require sqrt(2) compensation.
+#if JVET_O0919_TS_MIN_QP
+  const bool   isTransformSkip = tu.mtsIdx==MTS_SKIP && isLuma(compID);
+  const int    qBits = QUANT_SHIFT + qp.per(isTransformSkip) + 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(isTransformSkip)];
+  const double errorScale = xGetErrScaleCoeff(TU::needsSqrt2Scale(tu, compID), width, height, qp.rem(isTransformSkip), maxLog2TrDynamicRange, channelBitDepth);
+#else
   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);
+#endif
 
   TrQuantParams trQuantParams;
+#if JVET_O0919_TS_MIN_QP
+  trQuantParams.rightShift = (IQUANT_SHIFT - (transformShift + qp.per(isTransformSkip)));
+  trQuantParams.qScale = g_invQuantScales[needsSqrt2Scale ? 1 : 0][qp.rem(isTransformSkip)];
+#else
   trQuantParams.rightShift = (IQUANT_SHIFT - (transformShift + qp.per));
   trQuantParams.qScale = g_invQuantScales[needsSqrt2Scale ? 1 : 0][qp.rem];
+#endif
 
   const TCoeff entropyCodingMaximum = (1 << maxLog2TrDynamicRange) - 1;
 
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index a4f18555dbd1ee3941c359f800dac838e474f48f..fbdddaca2b5f7e21935c5c0ce3ee4816add0972b 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -735,6 +735,9 @@ private:
   // Parameter
   BitDepths         m_bitDepths;
   int               m_qpBDOffset[MAX_NUM_CHANNEL_TYPE];
+#if JVET_O0919_TS_MIN_QP
+  int               m_minQpMinus4[MAX_NUM_CHANNEL_TYPE]; //  QP_internal - QP_input;
+#endif
   int               m_pcmBitDepths[MAX_NUM_CHANNEL_TYPE];
   bool              m_bPCMFilterDisableFlag;
 
@@ -929,6 +932,10 @@ public:
   int                     getDifferentialLumaChromaBitDepth() const                                       { return int(m_bitDepths.recon[CHANNEL_TYPE_LUMA]) - int(m_bitDepths.recon[CHANNEL_TYPE_CHROMA]); }
   int                     getQpBDOffset(ChannelType type) const                                           { return m_qpBDOffset[type];                                           }
   void                    setQpBDOffset(ChannelType type, int i)                                          { m_qpBDOffset[type] = i;                                              }
+#if JVET_O0919_TS_MIN_QP
+  int                     getMinQpMinus4(ChannelType type) const                                         { return m_minQpMinus4[type];                                           }
+  void                    setMinQpMinus4(ChannelType type, int i)                                        { m_minQpMinus4[type] = i;                                              }
+#endif
 
   void                    setSAOEnabledFlag(bool bVal)                                                    { m_saoEnabledFlag = bVal;                                                    }
   bool                    getSAOEnabledFlag() const                                                       { return m_saoEnabledFlag;                                                    }
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 950943b0355ecdadb289900397fd4c0a576300a5..a10f888f7e1a9b82bd41d2c5673efb2da59734c9 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -62,6 +62,8 @@
 
 #define JVET_O0366_AFFINE_BCW                             1 // JVET-O0366: Simplifications on BCW index derivation process
 
+#define JVET_O0919_TS_MIN_QP                              1 // JVET-O0919: Minimum QP for Transform Skip Mode
+
 #define JVET_O1168_CU_CHROMA_QP_OFFSET                    1 // JVET-O1168: cu chroma QP offset
 
 #define JVET_O0368_LFNST_WITH_DCT2_ONLY                   1 // JVET-O0368/O0292/O0521/O0466: disable LFNST for non-DCT2 MTS candidates normatively
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index dbfaff778578a45855f7f6aee357da9923c808a9..51003b3cb4edb7829aa3d207820a119bf762f4b5 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -1090,6 +1090,10 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   pcSPS->setBitDepth(CHANNEL_TYPE_LUMA, 8 + uiCode);
 
   pcSPS->setQpBDOffset(CHANNEL_TYPE_LUMA, (int) (6*uiCode) );
+#if JVET_O0919_TS_MIN_QP
+  READ_UVLC(     uiCode, "min_qp_luma_minus4" );
+  pcSPS->setMinQpMinus4(CHANNEL_TYPE_LUMA, uiCode);
+#endif
 
   READ_UVLC( uiCode,    "bit_depth_chroma_minus8" );
   CHECK(uiCode > 8, "Invalid chroma bit depth signalled");
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index ce97ff3119d935a3e1285c6efe55d32a056a4ef0..c905446a5e17daca3dcac32bdb6974d7ed112e55 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -976,6 +976,9 @@ void EncLib::xInitSPS(SPS &sps)
   {
     sps.setBitDepth      (ChannelType(channelType), m_bitDepth[channelType] );
     sps.setQpBDOffset  (ChannelType(channelType), (6 * (m_bitDepth[channelType] - 8)));
+#if JVET_O0919_TS_MIN_QP
+    sps.setMinQpMinus4(ChannelType(channelType), (6 * (m_bitDepth[channelType] - m_inputBitDepth[channelType])));
+#endif
     sps.setPCMBitDepth (ChannelType(channelType), m_PCMBitDepth[channelType]         );
   }
 
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 090b22b84f6a144e8c39f3af8849a93fcb82007c..2239266d1c6f9ca65fe8bcdcbef2e6ed89fd2cb2 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -732,6 +732,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   }
 
   WRITE_UVLC( pcSPS->getBitDepth(CHANNEL_TYPE_LUMA) - 8,                      "bit_depth_luma_minus8" );
+#if JVET_O0919_TS_MIN_QP
+  WRITE_UVLC( pcSPS->getMinQpMinus4(CHANNEL_TYPE_LUMA),                      "min_qp_luma_minus4" );
+#endif
 
   const bool         chromaEnabled         = isChromaEnabled(format);
   WRITE_UVLC( chromaEnabled ? (pcSPS->getBitDepth(CHANNEL_TYPE_CHROMA) - 8):0,  "bit_depth_chroma_minus8" );