From fb9d75f55dc54fc66cf922bc589b604dfcb024d6 Mon Sep 17 00:00:00 2001
From: Philipp Merkle <philipp.merkle@hhi.fraunhofer.de>
Date: Wed, 29 Apr 2020 16:39:36 +0200
Subject: [PATCH 1/2] JVET-R0350: MIP for chroma in case of 4:4:4 format and
 single tree

---
 source/Lib/CommonLib/IntraPrediction.cpp      | 41 +++++++++++++++++
 .../Lib/CommonLib/MatrixIntraPrediction.cpp   | 18 ++++++++
 source/Lib/CommonLib/MatrixIntraPrediction.h  | 10 +++++
 source/Lib/CommonLib/TypeDef.h                |  2 +
 source/Lib/CommonLib/UnitTools.cpp            | 44 +++++++++++++++++++
 source/Lib/CommonLib/UnitTools.h              |  6 +++
 source/Lib/EncoderLib/IntraSearch.cpp         | 10 +++++
 7 files changed, 131 insertions(+)

diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp
index 1c042ca699..61ce6ae0e5 100644
--- a/source/Lib/CommonLib/IntraPrediction.cpp
+++ b/source/Lib/CommonLib/IntraPrediction.cpp
@@ -217,6 +217,9 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
   const int            iWidth       = piPred.width;
   const int            iHeight      = piPred.height;
   CHECK(iWidth == 2, "Width of 2 is not supported");
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+  CHECK(PU::isMIP(pu, toChannelType(compId)), "We should not get here for MIP.");
+#endif
   const uint32_t       uiDirMode    = isLuma( compId ) && pu.cu->bdpcmMode ? BDPCM_IDX : !isLuma(compId) && pu.cu->bdpcmModeChroma ? BDPCM_IDX : PU::getFinalIntraMode(pu, channelType);
 
   CHECK( floorLog2(iWidth) < 2 && pu.cs->pcv->noChroma2x2, "Size not allowed" );
@@ -1836,24 +1839,62 @@ void IntraPrediction::initIntraMip( const PredictionUnit &pu, const CompArea &ar
 
   // prepare input (boundary) data for prediction
   CHECK( m_ipaParam.refFilterFlag, "ERROR: unfiltered refs expected for MIP" );
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+  Pel       *ptrSrc     = getPredictorPtr(area.compID);
+  const int  srcStride  = m_refBufferStride[area.compID];
+  const int  srcHStride = 2;
+
+  m_matrixIntraPred.prepareInputForPred(CPelBuf(ptrSrc, srcStride, srcHStride), area,
+                                        pu.cu->slice->getSPS()->getBitDepth(toChannelType(area.compID)), area.compID);
+#else
   Pel *ptrSrc = getPredictorPtr( COMPONENT_Y );
   const int srcStride  = m_refBufferStride[COMPONENT_Y];
   const int srcHStride = 2;
 
   m_matrixIntraPred.prepareInputForPred( CPelBuf( ptrSrc, srcStride, srcHStride ), area, pu.cu->slice->getSPS()->getBitDepth( CHANNEL_TYPE_LUMA ) );
+#endif
 }
 
 void IntraPrediction::predIntraMip( const ComponentID compId, PelBuf &piPred, const PredictionUnit &pu )
 {
+#if !JVET_R0350_MIP_CHROMA_444_SINGLETREE
   CHECK( compId != COMPONENT_Y, "Error: chroma not supported" );
+#endif
   CHECK( piPred.width > MIP_MAX_WIDTH || piPred.height > MIP_MAX_HEIGHT, "Error: block size not supported for MIP" );
   CHECK( piPred.width != (1 << floorLog2(piPred.width)) || piPred.height != (1 << floorLog2(piPred.height)), "Error: expecting blocks of size 2^M x 2^N" );
 
   // generate mode-specific prediction
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+  uint32_t modeIdx       = MAX_NUM_MIP_MODE;
+  bool     transposeFlag = false;
+  if (compId == COMPONENT_Y)
+  {
+    modeIdx       = pu.intraDir[CHANNEL_TYPE_LUMA];
+    transposeFlag = pu.mipTransposedFlag;
+  }
+  else
+  {
+    const PredictionUnit &coLocatedLumaPU = PU::getCoLocatedLumaPU(pu);
+
+    CHECK(pu.intraDir[CHANNEL_TYPE_CHROMA] != DM_CHROMA_IDX, "Error: MIP is only supported for chroma with DM_CHROMA.");
+    CHECK(!coLocatedLumaPU.cu->mipFlag, "Error: Co-located luma CU should use MIP.");
+
+    modeIdx       = coLocatedLumaPU.intraDir[CHANNEL_TYPE_LUMA];
+    transposeFlag = coLocatedLumaPU.mipTransposedFlag;
+  }
+  const int bitDepth = pu.cu->slice->getSPS()->getBitDepth(toChannelType(compId));
+
+  CHECK(modeIdx >= getNumModesMip(piPred), "Error: Invalid mode.");
+#else
   const int bitDepth = pu.cu->slice->getSPS()->getBitDepth( CHANNEL_TYPE_LUMA );
+#endif
 
   static_vector<int, MIP_MAX_WIDTH* MIP_MAX_HEIGHT> predMip( piPred.width * piPred.height );
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+  m_matrixIntraPred.predBlock(predMip.data(), modeIdx, transposeFlag, bitDepth, compId);
+#else
   m_matrixIntraPred.predBlock( predMip.data(), pu.intraDir[CHANNEL_TYPE_LUMA], pu.mipTransposedFlag, bitDepth );
+#endif
 
   for( int y = 0; y < piPred.height; y++ )
   {
diff --git a/source/Lib/CommonLib/MatrixIntraPrediction.cpp b/source/Lib/CommonLib/MatrixIntraPrediction.cpp
index 9ddb6bac7e..cad260400e 100644
--- a/source/Lib/CommonLib/MatrixIntraPrediction.cpp
+++ b/source/Lib/CommonLib/MatrixIntraPrediction.cpp
@@ -43,6 +43,9 @@
 
 
 MatrixIntraPrediction::MatrixIntraPrediction():
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+  m_component(MAX_NUM_COMPONENT),
+#endif
   m_reducedBoundary          (MIP_MAX_INPUT_SIZE),
   m_reducedBoundaryTransposed(MIP_MAX_INPUT_SIZE),
   m_inputOffset      ( 0 ),
@@ -58,9 +61,16 @@ MatrixIntraPrediction::MatrixIntraPrediction():
 {
 }
 
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area &block, const int bitDepth,
+                                                const ComponentID compId)
+{
+  m_component = compId;
 
+#else
 void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area& block, const int bitDepth)
 {
+#endif
   // Step 1: Save block size and calculate dependent values
   initPredBlockParams(block);
 
@@ -114,8 +124,16 @@ void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area&
   }
 }
 
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+void MatrixIntraPrediction::predBlock(int *const result, const int modeIdx, const bool transpose, const int bitDepth,
+                                      const ComponentID compId)
+{
+  CHECK(m_component != compId, "Boundary has not been prepared for this component.");
+
+#else
 void MatrixIntraPrediction::predBlock(int* const result, const int modeIdx, const bool transpose, const int bitDepth)
 {
+#endif
   const bool needUpsampling = ( m_upsmpFactorHor > 1 ) || ( m_upsmpFactorVer > 1 );
 
   const uint8_t* matrix = getMatrixData(modeIdx);
diff --git a/source/Lib/CommonLib/MatrixIntraPrediction.h b/source/Lib/CommonLib/MatrixIntraPrediction.h
index d9b3b377bd..2b69661e3b 100644
--- a/source/Lib/CommonLib/MatrixIntraPrediction.h
+++ b/source/Lib/CommonLib/MatrixIntraPrediction.h
@@ -50,10 +50,20 @@ class MatrixIntraPrediction
 public:
   MatrixIntraPrediction();
 
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+  void prepareInputForPred(const CPelBuf &pSrc, const Area &block, const int bitDepth, const ComponentID compId);
+  void predBlock(int *const result, const int modeIdx, const bool transpose, const int bitDepth,
+                 const ComponentID compId);
+#else
   void prepareInputForPred(const CPelBuf &pSrc, const Area& block, const int bitDepth);
   void predBlock(int* const result, const int modeIdx, const bool transpose, const int bitDepth);
+#endif
 
   private:
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+    ComponentID m_component;
+
+#endif
     static_vector<int, MIP_MAX_INPUT_SIZE> m_reducedBoundary;           // downsampled             boundary of a block
     static_vector<int, MIP_MAX_INPUT_SIZE> m_reducedBoundaryTransposed; // downsampled, transposed boundary of a block
     int                                    m_inputOffset;
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index fd000c8a19..c89950cd2b 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -81,6 +81,8 @@
 #define JVET_R0156_ASPECT3_SPS_CLEANUP                    1 // Condition sps_sublayer_dpb_params_flag on sps_ptl_dpb_hrd_params_present_flag, in addition to sps_max_sublayer_minus1,	JVET-R0156 proposal 3, JVET-R0170, JVET-R0222 proposal 2
 
 
+#define JVET_R0350_MIP_CHROMA_444_SINGLETREE              1 // JVET-R0350: MIP for chroma in case of 4:4:4 format and single tree
+
 //########### place macros to be be kept below this line ###############
 
 #define JVET_R0164_MEAN_SCALED_SATD                       1 // JVET-R0164: Use a mean scaled version of SATD in encoder decisions
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 0c191dc742..114323451f 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -553,9 +553,27 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType
 
 bool PU::isMIP(const PredictionUnit &pu, const ChannelType &chType)
 {
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+  if (chType == CHANNEL_TYPE_LUMA)
+  {
+    // Default case if chType is omitted.
+    return pu.cu->mipFlag;
+  }
+  else
+  {
+    return isDMChromaMIP(pu) && (pu.intraDir[CHANNEL_TYPE_CHROMA] == DM_CHROMA_IDX);
+  }
+#else
   return (chType == CHANNEL_TYPE_LUMA && pu.cu->mipFlag);
+#endif
 }
 
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+bool PU::isDMChromaMIP(const PredictionUnit &pu)
+{
+  return !pu.cu->isSepTree() && (pu.chromaFormat == CHROMA_444) && getCoLocatedLumaPU(pu).cu->mipFlag;
+}
+#endif
 
 uint32_t PU::getIntraDirLuma( const PredictionUnit &pu )
 {
@@ -582,6 +600,14 @@ void PU::getIntraChromaCandModes( const PredictionUnit &pu, unsigned modeList[NU
     modeList[6] = MDLM_T_IDX;
     modeList[7] = DM_CHROMA_IDX;
 
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+    // If Direct Mode is MIP, mode cannot be already in the list.
+    if (isDMChromaMIP(pu))
+    {
+      return;
+    }
+
+#endif
     const uint32_t lumaMode = getCoLocatedIntraLumaMode(pu);
     for( int i = 0; i < 4; i++ )
     {
@@ -638,6 +664,23 @@ uint32_t PU::getFinalIntraMode( const PredictionUnit &pu, const ChannelType &chT
   return uiIntraMode;
 }
 
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+const PredictionUnit &PU::getCoLocatedLumaPU(const PredictionUnit &pu)
+{
+  Position              topLeftPos = pu.blocks[pu.chType].lumaPos();
+  Position              refPos     = topLeftPos.offset(pu.blocks[pu.chType].lumaSize().width  >> 1,
+                                                       pu.blocks[pu.chType].lumaSize().height >> 1);
+  const PredictionUnit &lumaPU     = pu.cu->isSepTree() ? *pu.cs->picture->cs->getPU(refPos, CHANNEL_TYPE_LUMA)
+                                                        : *pu.cs->getPU(topLeftPos, CHANNEL_TYPE_LUMA);
+
+  return lumaPU;
+}
+
+uint32_t PU::getCoLocatedIntraLumaMode(const PredictionUnit &pu)
+{
+  return PU::getIntraDirLuma(PU::getCoLocatedLumaPU(pu));
+}
+#else
 uint32_t PU::getCoLocatedIntraLumaMode( const PredictionUnit &pu )
 {
   Position topLeftPos = pu.blocks[pu.chType].lumaPos();
@@ -646,6 +689,7 @@ uint32_t PU::getCoLocatedIntraLumaMode( const PredictionUnit &pu )
 
   return PU::getIntraDirLuma( lumaPU );
 }
+#endif
 
 int PU::getWideAngIntraMode( const TransformUnit &tu, const uint32_t dirMode, const ComponentID compID )
 {
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index 2df81f6ee6..9f6f0cfcf1 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -129,8 +129,14 @@ namespace PU
   int  getLMSymbolList(const PredictionUnit &pu, int *modeList);
   int  getIntraMPMs(const PredictionUnit &pu, unsigned *mpm, const ChannelType &channelType = CHANNEL_TYPE_LUMA);
   bool          isMIP                 (const PredictionUnit &pu, const ChannelType &chType = CHANNEL_TYPE_LUMA);
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+  bool          isDMChromaMIP         (const PredictionUnit &pu);
+#endif
   uint32_t      getIntraDirLuma       (const PredictionUnit &pu);
   void getIntraChromaCandModes        (const PredictionUnit &pu, unsigned modeList[NUM_CHROMA_MODE]);
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+  const PredictionUnit &getCoLocatedLumaPU(const PredictionUnit &pu);
+#endif
   uint32_t getFinalIntraMode              (const PredictionUnit &pu, const ChannelType &chType);
   uint32_t getCoLocatedIntraLumaMode      (const PredictionUnit &pu);
   int getWideAngIntraMode             ( const TransformUnit &tu, const uint32_t dirMode, const ComponentID compID );
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index d5e4c502e5..b8b2966501 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -4956,6 +4956,16 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio
       predIntraChromaLM( COMPONENT_Cb, piPredCb, pu, cbArea, predMode );
       predIntraChromaLM( COMPONENT_Cr, piPredCr, pu, crArea, predMode );
     }
+#if JVET_R0350_MIP_CHROMA_444_SINGLETREE
+    else if (PU::isMIP(pu, CHANNEL_TYPE_CHROMA))
+    {
+      initIntraMip(pu, cbArea);
+      predIntraMip(COMPONENT_Cb, piPredCb, pu);
+
+      initIntraMip(pu, crArea);
+      predIntraMip(COMPONENT_Cr, piPredCr, pu);
+    }
+#endif
     else
     {
       predIntraAng( COMPONENT_Cb, piPredCb, pu);
-- 
GitLab


From c5bc23ea727280ddfc104f911500ab2ec4cc0ec7 Mon Sep 17 00:00:00 2001
From: Philipp Merkle <philipp.merkle@hhi.fraunhofer.de>
Date: Thu, 30 Apr 2020 07:51:21 +0200
Subject: [PATCH 2/2] updated error message

---
 source/Lib/CommonLib/IntraPrediction.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp
index 61ce6ae0e5..3a24c156f1 100644
--- a/source/Lib/CommonLib/IntraPrediction.cpp
+++ b/source/Lib/CommonLib/IntraPrediction.cpp
@@ -1884,7 +1884,7 @@ void IntraPrediction::predIntraMip( const ComponentID compId, PelBuf &piPred, co
   }
   const int bitDepth = pu.cu->slice->getSPS()->getBitDepth(toChannelType(compId));
 
-  CHECK(modeIdx >= getNumModesMip(piPred), "Error: Invalid mode.");
+  CHECK(modeIdx >= getNumModesMip(piPred), "Error: Wrong MIP mode index");
 #else
   const int bitDepth = pu.cu->slice->getSPS()->getBitDepth( CHANNEL_TYPE_LUMA );
 #endif
-- 
GitLab