From f50464582693df4c085c573ad17f1f275939b544 Mon Sep 17 00:00:00 2001
From: Alican Nalci <analci@qti.qualcomm.com>
Date: Thu, 30 Jan 2020 21:05:56 +0100
Subject: [PATCH] Enables chroma BDPCM for 4:2:0 as in JVET-Q0785 Sets CTC
 screen content config to use chroma BDPCM as in JVET-Q0785 Aligns Intra
 Prediction mode with BDPCM mode for chroma as in JVET-Q0110 Adds separate
 chroma contexts for BDPCM as in JVET-Q0110 Aligns signaling order for chroma
 BDPCM to match with Spec as in JVET-Q0351 and JVET-Q0785

---
 cfg/per-class/classF.cfg              |  2 +-
 source/Lib/CommonLib/Contexts.cpp     |  7 ++++++
 source/Lib/CommonLib/TypeDef.h        |  2 ++
 source/Lib/DecoderLib/CABACReader.cpp | 33 ++++++++++++++++++++++++++-
 source/Lib/DecoderLib/VLCReader.cpp   |  4 ++++
 source/Lib/EncoderLib/CABACWriter.cpp | 33 +++++++++++++++++++++++++++
 source/Lib/EncoderLib/EncCu.cpp       |  2 ++
 source/Lib/EncoderLib/IntraSearch.cpp | 12 ++++++++++
 source/Lib/EncoderLib/VLCWriter.cpp   |  6 +++++
 9 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/cfg/per-class/classF.cfg b/cfg/per-class/classF.cfg
index 0edc6f8c1..7646377dc 100644
--- a/cfg/per-class/classF.cfg
+++ b/cfg/per-class/classF.cfg
@@ -1,3 +1,3 @@
 IBC : 1
 HashME : 1
-BDPCM: 1
+BDPCM: 2
diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp
index 840e71802..139c24d1a 100644
--- a/source/Lib/CommonLib/Contexts.cpp
+++ b/source/Lib/CommonLib/Contexts.cpp
@@ -419,10 +419,17 @@ const CtxSet ContextSetCfg::Mvd = ContextSetCfg::addCtxSet
 
 const CtxSet ContextSetCfg::BDPCMMode = ContextSetCfg::addCtxSet
 ({
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+  {  19,  28,  25,  51, },
+  {  40,  36,  17,  28, },
+  {  19,  35,   9,  44, },
+  {   4,   4,   1,   1, },
+#else
   {  19,  28, },
   {  40,  36, },
   {  19,  35, },
   {   4,   4, },
+#endif
 });
 
 const CtxSet ContextSetCfg::QtRootCbf = ContextSetCfg::addCtxSet
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index a68b90ae0..756850b86 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,8 @@
 #include <assert.h>
 #include <cassert>
 
+#define JVET_Q0110_Q0785_CHROMA_BDPCM_420                 1 // JVET-Q0110/Q0785: Enable chroma BDPCM for 420, separate contexts for chroma BDPCM and bug-fixes.
+
 #define JVET_Q0512_ENC_CHROMA_TS_ACT                      1 // JVET-Q0512: encoder-side improvement on enabling chroma transform-skip for ACT
 #define JVET_Q0446_MIP_CONST_SHIFT_OFFSET                 1 // JVET-Q0446: MIP with constant shift and offset
 
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 08e21e183..5f9043eab 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -859,9 +859,11 @@ void CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx&
     end_of_ctu(cu, cuCtx);
     return;
   }
+#if !JVET_Q0110_Q0785_CHROMA_BDPCM_420
   bdpcm_mode( cu, ComponentID( partitioner.chType ) );
   if (!CS::isDualITree(*cu.cs) && isLuma(partitioner.chType))
       bdpcm_mode(cu, ComponentID(CHANNEL_TYPE_CHROMA));
+#endif
 
   // --> create PUs
 
@@ -1145,10 +1147,19 @@ void CABACReader::bdpcm_mode( CodingUnit& cu, const ComponentID compID )
   RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__BDPCM_MODE, cu.block(compID).lumaSize(), compID );
 
   int bdpcmMode;
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+  unsigned ctxId = isLuma( compID ) ? 0 : 2;
+  bdpcmMode = m_BinDecoder.decodeBin( Ctx::BDPCMMode(ctxId) );
+#else
   bdpcmMode = m_BinDecoder.decodeBin(Ctx::BDPCMMode(0));
+#endif
   if (bdpcmMode)
   {
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+    bdpcmMode += m_BinDecoder.decodeBin( Ctx::BDPCMMode(ctxId+1) );
+#else
     bdpcmMode += m_BinDecoder.decodeBin(Ctx::BDPCMMode(1));
+#endif
   }
   if (isLuma(compID))
   {
@@ -1172,7 +1183,19 @@ void CABACReader::cu_pred_data( CodingUnit &cu )
 {
   if( CU::isIntra( cu ) )
   {
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+    if( cu.Y().valid() )
+	{
+      bdpcm_mode(cu, COMPONENT_Y );
+    }
+#endif
     intra_luma_pred_modes( cu );
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+    if( !cu.Y().valid() || ( !cu.isSepTree() && cu.Y().valid() ) )
+    {
+      bdpcm_mode(cu, ComponentID(CHANNEL_TYPE_CHROMA));
+    } 
+#endif
     intra_chroma_pred_modes( cu );
     return;
   }
@@ -1413,6 +1436,13 @@ void CABACReader::intra_chroma_pred_modes( CodingUnit& cu )
     return;
   }
 
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+  if( cu.bdpcmModeChroma )
+  {
+    cu.firstPU->intraDir[1] = cu.bdpcmModeChroma == 2 ? VER_IDX : HOR_IDX;
+    return;
+  }
+#endif
   PredictionUnit *pu = cu.firstPU;
 
   {
@@ -1450,7 +1480,7 @@ void CABACReader::intra_chroma_pred_mode(PredictionUnit& pu)
   }
 
   // LM chroma mode
-
+#if !JVET_Q0110_Q0785_CHROMA_BDPCM_420
   if (pu.cu->bdpcmModeChroma)
   {
     unsigned chromaCandModes[NUM_CHROMA_MODE];
@@ -1458,6 +1488,7 @@ void CABACReader::intra_chroma_pred_mode(PredictionUnit& pu)
     pu.intraDir[1] = chromaCandModes[0];
     return;
   }
+#endif
 
   if (pu.cs->sps->getUseLMChroma() && pu.cu->checkCCLMAllowed())
   {
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 7d65fe720..48752f8cc 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -1505,7 +1505,11 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   if (pcSPS->getTransformSkipEnabledFlag())
   {
       READ_FLAG(uiCode, "sps_bdpcm_enabled_flag");
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+      if( uiCode )
+#else
       if (uiCode && pcSPS->getChromaFormatIdc() == CHROMA_444 )
+#endif
       {
           READ_FLAG(uiCode, "sps_bdpcm_enabled_chroma_flag");
           uiCode++;
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 441fe0465..5b851d934 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -691,9 +691,11 @@ void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, C
     end_of_ctu(cu, cuCtx);
     return;
   }
+#if !JVET_Q0110_Q0785_CHROMA_BDPCM_420
   bdpcm_mode( cu, ComponentID( partitioner.chType ) );
   if (!CS::isDualITree(cs) && isLuma(partitioner.chType))
       bdpcm_mode(cu, ComponentID(CHANNEL_TYPE_CHROMA));
+#endif
 
   // prediction data ( intra prediction modes / reference indexes + motion vectors )
   cu_pred_data( cu );
@@ -818,11 +820,20 @@ void CABACWriter::bdpcm_mode( const CodingUnit& cu, const ComponentID compID )
 
   int bdpcmMode = isLuma(compID) ? cu.bdpcmMode : cu.bdpcmModeChroma;
 
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+  unsigned ctxId = isLuma(compID) ? 0 : 2; 
+  m_BinEncoder.encodeBin(bdpcmMode > 0 ? 1 : 0, Ctx::BDPCMMode(ctxId));
+#else
   m_BinEncoder.encodeBin(bdpcmMode > 0 ? 1 : 0, Ctx::BDPCMMode(0));
+#endif
 
   if (bdpcmMode)
   {
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+    m_BinEncoder.encodeBin(bdpcmMode > 1 ? 1 : 0, Ctx::BDPCMMode(ctxId+1));
+#else
     m_BinEncoder.encodeBin(bdpcmMode > 1 ? 1 : 0, Ctx::BDPCMMode(1));
+#endif
   }
   if (isLuma(compID))
   {
@@ -839,7 +850,20 @@ void CABACWriter::cu_pred_data( const CodingUnit& cu )
 {
   if( CU::isIntra( cu ) )
   {
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+    if( cu.Y().valid() )
+    {
+      bdpcm_mode( cu, COMPONENT_Y );
+    }
+#endif
+
     intra_luma_pred_modes  ( cu );
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+    if( !cu.Y().valid() || ( !cu.isSepTree() && cu.Y().valid() ) )
+    {
+      bdpcm_mode( cu, ComponentID(CHANNEL_TYPE_CHROMA) );
+    } 
+#endif
     intra_chroma_pred_modes( cu );
     return;
   }
@@ -1204,6 +1228,13 @@ void CABACWriter::intra_chroma_pred_modes( const CodingUnit& cu )
     return;
   }
 
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+  if( cu.bdpcmModeChroma )
+  {
+    cu.firstPU->intraDir[1] = cu.bdpcmModeChroma == 2 ? VER_IDX : HOR_IDX;
+    return;
+  }
+#endif
   const PredictionUnit* pu = cu.firstPU;
 
   intra_chroma_pred_mode( *pu );
@@ -1237,10 +1268,12 @@ void CABACWriter::intra_chroma_lmc_mode(const PredictionUnit& pu)
 
 void CABACWriter::intra_chroma_pred_mode(const PredictionUnit& pu)
 {
+#if !JVET_Q0110_Q0785_CHROMA_BDPCM_420
   if (pu.cu->bdpcmModeChroma)
   {
       return;
   }
+#endif
 
   const unsigned intraDir = pu.intraDir[1];
   if (pu.cu->colorTransform)
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 011ce09d3..452e7cec6 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -1835,9 +1835,11 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS
           m_CABACEstimator->pred_mode      ( cu );
           m_CABACEstimator->adaptive_color_transform(cu);
           m_CABACEstimator->cu_pred_data   ( cu );
+#if !JVET_Q0110_Q0785_CHROMA_BDPCM_420
           m_CABACEstimator->bdpcm_mode     ( cu, ComponentID(partitioner.chType) );
           if (!CS::isDualITree(*cu.cs) && isLuma(partitioner.chType))
               m_CABACEstimator->bdpcm_mode(cu, ComponentID(CHANNEL_TYPE_CHROMA));
+#endif
 
           // Encode Coefficients
           CUCtx cuCtx;
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index 02a43bae9..ecacd5094 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -1426,7 +1426,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
         if (uiMode < 0)
         {
             cu.bdpcmModeChroma = -uiMode;
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420 
+            chromaIntraMode = cu.bdpcmModeChroma == 2 ? chromaCandModes[1] : chromaCandModes[2];
+#else
             chromaIntraMode = chromaCandModes[0];
+#endif
         }
         else
         {
@@ -2590,9 +2594,11 @@ void IntraSearch::xEncIntraHeader( CodingStructure &cs, Partitioner &partitioner
       {
         return;
       }
+#if !JVET_Q0110_Q0785_CHROMA_BDPCM_420
       m_CABACEstimator->bdpcm_mode  ( cu, ComponentID(partitioner.chType) );
       if (!CS::isDualITree(cs) && isLuma(partitioner.chType))
           m_CABACEstimator->bdpcm_mode(cu, ComponentID(CHANNEL_TYPE_CHROMA));
+#endif
     }
 
     PredictionUnit &pu = *cs.getPU(partitioner.currArea().lumaPos(), partitioner.chType);
@@ -2602,6 +2608,9 @@ void IntraSearch::xEncIntraHeader( CodingStructure &cs, Partitioner &partitioner
     {
       if ( !cu.Y().valid())
         m_CABACEstimator->pred_mode( cu );
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+      m_CABACEstimator->bdpcm_mode( cu, COMPONENT_Y );
+#endif
       m_CABACEstimator->intra_luma_pred_mode( pu );
     }
   }
@@ -2614,6 +2623,9 @@ void IntraSearch::xEncIntraHeader( CodingStructure &cs, Partitioner &partitioner
 
     if( isFirst )
     {
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+      m_CABACEstimator->bdpcm_mode( cu, ComponentID(CHANNEL_TYPE_CHROMA) );
+#endif
       m_CABACEstimator->intra_chroma_pred_mode( pu );
     }
   }
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 056819f01..a4e36d773 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -962,14 +962,20 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   if (pcSPS->getTransformSkipEnabledFlag())
   {
       WRITE_FLAG(pcSPS->getBDPCMEnabled() ? 1 : 0, "sps_bdpcm_enabled_flag");
+#if JVET_Q0110_Q0785_CHROMA_BDPCM_420
+      if( pcSPS->getBDPCMEnabled() )
+#else
       if (pcSPS->getBDPCMEnabled() && pcSPS->getChromaFormatIdc() == CHROMA_444)
+#endif
       {
           WRITE_FLAG(pcSPS->getBDPCMEnabled() == BDPCM_LUMACHROMA ? 1 : 0, "sps_bdpcm_enabled_chroma_flag");
       }
+#if !JVET_Q0110_Q0785_CHROMA_BDPCM_420
       else 
       {
         CHECK(pcSPS->getBDPCMEnabled() == BDPCM_LUMACHROMA, "BDPCM for chroma can be used for 444 only.")
       }
+#endif
   }
   else
   {
-- 
GitLab