From e070f6a9a5acd46dc8006bff0930a2e520360701 Mon Sep 17 00:00:00 2001
From: Kiran Misra <misrak@sharplabs.com>
Date: Wed, 17 Apr 2019 04:40:53 +0200
Subject: [PATCH] JVET-N0473, JVET-N0098: Deblocking of ISP/SBT TU boundaries

---
 source/Lib/CommonLib/CodingStructure.cpp |   4 +
 source/Lib/CommonLib/LoopFilter.cpp      | 280 +++++++++++++++++++++++
 source/Lib/CommonLib/LoopFilter.h        |  15 ++
 source/Lib/CommonLib/TypeDef.h           |   1 +
 4 files changed, 300 insertions(+)

diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp
index f6b020abb3..2d69c798af 100644
--- a/source/Lib/CommonLib/CodingStructure.cpp
+++ b/source/Lib/CommonLib/CodingStructure.cpp
@@ -286,7 +286,11 @@ TransformUnit* CodingStructure::getTU( const Position &pos, const ChannelType ef
           }
           else
           {
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+            while( !tus[idx - 1 + extraIdx]->blocks[getFirstComponentOfChannel( effChType )].contains( pos ) )
+#else
             while( pos != tus[idx - 1 + extraIdx]->blocks[getFirstComponentOfChannel( effChType )].pos() )
+#endif
             {
               extraIdx++;
             }
diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp
index acb93d171b..cd0bae703b 100644
--- a/source/Lib/CommonLib/LoopFilter.cpp
+++ b/source/Lib/CommonLib/LoopFilter.cpp
@@ -148,6 +148,10 @@ void LoopFilter::loopFilterPic( CodingStructure& cs
                                 )
 {
   const PreCalcValues& pcv = *cs.pcv;
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+  m_shiftHor = ::getComponentScaleX( COMPONENT_Cb, cs.pcv->chrFormat );
+  m_shiftVer = ::getComponentScaleY( COMPONENT_Cb, cs.pcv->chrFormat );
+#endif
 
   DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "poc", cs.slice->getPOC() ) ) );
 #if ENABLE_TRACING
@@ -168,6 +172,13 @@ void LoopFilter::loopFilterPic( CodingStructure& cs
     {
       memset( m_aapucBS       [EDGE_VER].data(), 0,     m_aapucBS       [EDGE_VER].byte_size() );
       memset( m_aapbEdgeFilter[EDGE_VER].data(), false, m_aapbEdgeFilter[EDGE_VER].byte_size() );
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+      memset( m_maxFilterLengthP, 0, sizeof(m_maxFilterLengthP) );
+      memset( m_maxFilterLengthQ, 0, sizeof(m_maxFilterLengthQ) );
+      memset( m_transformEdge, false, sizeof(m_transformEdge) );
+      m_ctuXLumaSamples = x << pcv.maxCUWidthLog2;
+      m_ctuYLumaSamples = y << pcv.maxCUHeightLog2;
+#endif
 
       const UnitArea ctuArea( pcv.chrFormat, Area( x << pcv.maxCUWidthLog2, y << pcv.maxCUHeightLog2, pcv.maxCUWidth, pcv.maxCUWidth ) );
 
@@ -181,6 +192,11 @@ void LoopFilter::loopFilterPic( CodingStructure& cs
       {
         memset( m_aapucBS       [EDGE_VER].data(), 0,     m_aapucBS       [EDGE_VER].byte_size() );
         memset( m_aapbEdgeFilter[EDGE_VER].data(), false, m_aapbEdgeFilter[EDGE_VER].byte_size() );
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+        memset( m_maxFilterLengthP, 0, sizeof(m_maxFilterLengthP) );
+        memset( m_maxFilterLengthQ, 0, sizeof(m_maxFilterLengthQ) );
+        memset( m_transformEdge, false, sizeof(m_transformEdge) );
+#endif
 
         for( auto &currCU : cs.traverseCUs( CS::getArea( cs, ctuArea, CH_C ), CH_C ) )
         {
@@ -197,6 +213,13 @@ void LoopFilter::loopFilterPic( CodingStructure& cs
     {
       memset( m_aapucBS       [EDGE_HOR].data(), 0,     m_aapucBS       [EDGE_HOR].byte_size() );
       memset( m_aapbEdgeFilter[EDGE_HOR].data(), false, m_aapbEdgeFilter[EDGE_HOR].byte_size() );
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+      memset( m_maxFilterLengthP, 0, sizeof(m_maxFilterLengthP) );
+      memset( m_maxFilterLengthQ, 0, sizeof(m_maxFilterLengthQ) );
+      memset( m_transformEdge, false, sizeof(m_transformEdge) );
+      m_ctuXLumaSamples = x << pcv.maxCUWidthLog2;
+      m_ctuYLumaSamples = y << pcv.maxCUHeightLog2;
+#endif
 
       const UnitArea ctuArea( pcv.chrFormat, Area( x << pcv.maxCUWidthLog2, y << pcv.maxCUHeightLog2, pcv.maxCUWidth, pcv.maxCUWidth ) );
 
@@ -210,6 +233,11 @@ void LoopFilter::loopFilterPic( CodingStructure& cs
       {
         memset( m_aapucBS       [EDGE_HOR].data(), 0,     m_aapucBS       [EDGE_HOR].byte_size() );
         memset( m_aapbEdgeFilter[EDGE_HOR].data(), false, m_aapbEdgeFilter[EDGE_HOR].byte_size() );
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+        memset( m_maxFilterLengthP, 0, sizeof(m_maxFilterLengthP) );
+        memset( m_maxFilterLengthQ, 0, sizeof(m_maxFilterLengthQ) );
+        memset( m_transformEdge, false, sizeof(m_transformEdge) );
+#endif
 
         for( auto &currCU : cs.traverseCUs( CS::getArea( cs, ctuArea, CH_C ), CH_C ) )
         {
@@ -244,10 +272,16 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir )
   const Area area          = cu.Y().valid() ? cu.Y() : Area( recalcPosition( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].pos() ), recalcSize( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].size() ) );
 
   xSetLoopfilterParam( cu );
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+  static_vector<int, 2*MAX_CU_SIZE> edgeIdx;
+  edgeIdx.clear();
+#else
   bool implicitTU = false;
+#endif
   for( auto &currTU : CU::traverseTUs( cu ) )
   {
     const Area& areaTu    = cu.Y().valid() ? currTU.block( COMPONENT_Y ) : area;
+#if !JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
     const bool xOff = currTU.blocks[cu.chType].x != cu.blocks[cu.chType].x;
     const bool yOff = currTU.blocks[cu.chType].y != cu.blocks[cu.chType].y;
     if ((yOff != 0) && (edgeDir == EDGE_HOR))
@@ -258,8 +292,13 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir )
     {
       implicitTU = true;
     }
+#endif
     xSetEdgefilterMultiple( cu, EDGE_VER, areaTu, m_stLFCUParam.internalEdge );
     xSetEdgefilterMultiple( cu, EDGE_HOR, areaTu, m_stLFCUParam.internalEdge );
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+    xSetMaxFilterLengthPQFromTransformSizes( edgeDir, cu, currTU );
+    edgeIdx.push_back( ( edgeDir == EDGE_HOR ) ? ( currTU.blocks[cu.chType].y - cu.blocks[cu.chType].y ) / 4 : ( currTU.blocks[cu.chType].x - cu.blocks[cu.chType].x ) / 4 );
+#endif
   }
 
   bool mvSubBlocks = false;
@@ -272,6 +311,9 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir )
 
     xSetEdgefilterMultiple( cu, EDGE_VER, areaPu, (xOff ? m_stLFCUParam.internalEdge : m_stLFCUParam.leftEdge), xOff );
     xSetEdgefilterMultiple( cu, EDGE_HOR, areaPu, (yOff ? m_stLFCUParam.internalEdge : m_stLFCUParam.topEdge),  yOff );
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+    edgeIdx.push_back( ( edgeDir == EDGE_HOR ) ? ( currPU.blocks[cu.chType].y - cu.blocks[cu.chType].y ) / 4 : ( currPU.blocks[cu.chType].x - cu.blocks[cu.chType].x ) / 4 );
+#endif
 
     if ((currPU.mergeFlag && (currPU.mergeType == MRG_TYPE_SUBPU_ATMVP)) || cu.affine)
     {
@@ -282,6 +324,9 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir )
         {
           const Area mvBlockH(cu.Y().x, cu.Y().y + off, cu.Y().width, pcv.minCUHeight);
           xSetEdgefilterMultiple(cu, EDGE_HOR, mvBlockH, m_stLFCUParam.internalEdge, 1);
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+          edgeIdx.push_back( ( currPU.blocks[cu.chType].y + off - cu.blocks[cu.chType].y ) / 4 );
+#endif
         }
       }
       else
@@ -290,13 +335,23 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir )
         {
           const Area mvBlockV(cu.Y().x + off, cu.Y().y, pcv.minCUWidth, cu.Y().height);
           xSetEdgefilterMultiple(cu, EDGE_VER, mvBlockV, m_stLFCUParam.internalEdge, 1);
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+          edgeIdx.push_back( ( currPU.blocks[cu.chType].x + off - cu.blocks[cu.chType].x ) / 4 );
+#endif
         }
       }
     }
+
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+    xSetMaxFilterLengthPQForCodingSubBlocks( edgeDir, cu, currPU, mvSubBlocks, subBlockSize, areaPu );
+#endif
   }
   if (cu.firstPU->mhIntraFlag)
   {
     const uint32_t dirMode = PU::getFinalIntraMode(*(cu.firstPU), cu.chType);
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+    edgeIdx.push_back( 0 );
+#endif
     if (edgeDir == EDGE_VER && dirMode == HOR_IDX)
     {
       mvSubBlocks = true;
@@ -305,6 +360,9 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir )
       {
         const Area mvBlockV(cu.Y().x + off, cu.Y().y, pcv.minCUWidth, cu.Y().height);
         xSetEdgefilterMultiple(cu, EDGE_VER, mvBlockV, m_stLFCUParam.internalEdge, 1);
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+        edgeIdx.push_back( off / 4 );
+#endif
       }
     }
     else if (edgeDir == EDGE_HOR && dirMode == VER_IDX)
@@ -315,8 +373,16 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir )
       {
         const Area mvBlockH(cu.Y().x, cu.Y().y + off, cu.Y().width, pcv.minCUHeight);
         xSetEdgefilterMultiple(cu, EDGE_HOR, mvBlockH, m_stLFCUParam.internalEdge, 1);
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+        edgeIdx.push_back( off / 4 );
+#endif
       }
     }
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+    const PredictionUnit& currPU = *cu.firstPU;
+    const Area& areaPu = cu.Y().valid() ? currPU.block( COMPONENT_Y ) : area;
+    xSetMaxFilterLengthPQForCodingSubBlocks( edgeDir, cu, currPU, mvSubBlocks, subBlockSize, areaPu );
+#endif
   }
 
   const unsigned uiPelsInPart = pcv.minCUWidth;
@@ -347,6 +413,31 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir )
       return;
   }
 
+
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+  std::sort( edgeIdx.begin(), edgeIdx.end() );
+  int prevEdgeIdx = -1;
+  for ( const int& edge : edgeIdx )
+  {
+    if ( edge == prevEdgeIdx ) // skip duplicate edgeIdx marked by both transform and coding subblock processes
+    {
+      continue;
+    }
+    prevEdgeIdx = edge;
+
+    if ( cu.blocks[COMPONENT_Y].valid() )
+    {
+      xEdgeFilterLuma( cu, edgeDir, edge );
+    }
+    if ( cu.blocks[COMPONENT_Cb].valid() && pcv.chrFormat != CHROMA_400 )
+    {
+      if ( !cu.ispMode || edge == 0 )
+      {
+        xEdgeFilterChroma( cu, edgeDir, edge );
+      }
+    }
+  }
+#else
   unsigned int orthogonalLength = 1;
   unsigned int orthogonalIncrement = 1;
 #if FIX_DB_MAX_TRANSFORM_SIZE
@@ -451,8 +542,155 @@ void LoopFilter::xDeblockCU( CodingUnit& cu, const DeblockEdgeDir edgeDir )
       xEdgeFilterChroma(cu, edgeDir, edge);
     }
   }
+#endif
 }
 
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+void LoopFilter::xSetMaxFilterLengthPQFromTransformSizes( const DeblockEdgeDir edgeDir, const CodingUnit& cu, const TransformUnit& currTU )
+{
+  const TransformUnit& tuQ = currTU;
+
+  if ( edgeDir == EDGE_HOR )
+  {
+    for ( int cIdx = 0; cIdx < MAX_NUM_COMPONENT; cIdx++ ) // per component
+    {
+      const ComponentID comp = ComponentID(cIdx);
+      const ChannelType ch   = toChannelType(comp);
+      const int shiftHor     = ( ( ch == CH_L ) ? 0 : m_shiftHor );
+      const int shiftVer     = ( ( ch == CH_L ) ? 0 : m_shiftVer );
+      const int ctuXOff      = currTU.block(comp).x - ( m_ctuXLumaSamples >> shiftHor ); // x offset from left edge of CTU in respective channel sample units
+      const int ctuYOff      = currTU.block(comp).y - ( m_ctuYLumaSamples >> shiftVer ); // y offset from top edge of CTU in respective channel sample units
+      const int minCUWidth   = cu.cs->pcv->minCUWidth >> shiftHor;
+      if ( currTU.block(comp).valid() && ( ( currTU.block(comp).y == cu.block(comp).y ) ? m_stLFCUParam.topEdge : m_stLFCUParam.internalEdge ) ) // Edge deblocking needs to be recomputed since ISP contains whole CU chroma transforms in last TU of the CU
+      {
+        for ( int x = 0; x < currTU.blocks[cIdx].width; x += minCUWidth )
+        {
+          const Position  posQ     = Position( currTU.blocks[ch].x + x, currTU.blocks[ch].y );
+          const Position  posP     = posQ.offset( 0, -1 );
+          const int sizeQSide      = tuQ.block(comp).height;
+          const TransformUnit& tuP = *cu.cs->getTU( posP, ch );
+          const int sizePSide      = tuP.block(comp).height;
+          m_transformEdge[cIdx][ctuXOff+x][ctuYOff] = true;
+
+          if ( comp == COMPONENT_Y )
+          {
+            m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff] = ( sizeQSide >= 32 ) ? 7 : 3;
+            m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff] = ( sizePSide >= 32 ) ? 7 : 3;
+          }
+          else
+          {
+            m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff] = ( sizeQSide >= 8 && sizePSide >= 8 ) ? 3 : 1;
+            m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff] = ( sizeQSide >= 8 && sizePSide >= 8 ) ? 3 : 1;
+          }
+        }
+      }
+    }
+  }
+  if ( edgeDir == EDGE_VER )
+  {
+    for ( int cIdx = 0; cIdx < MAX_NUM_COMPONENT; cIdx++ ) // per component
+    {
+      const ComponentID comp = ComponentID(cIdx);
+      const ChannelType ch   = toChannelType(comp);
+      const int shiftHor     = ( ( ch == CH_L ) ? 0 : m_shiftHor );
+      const int shiftVer     = ( ( ch == CH_L ) ? 0 : m_shiftVer );
+      const int ctuXOff      = currTU.block(comp).x - ( m_ctuXLumaSamples >> shiftHor ); // x offset from left edge of CTU in respective channel sample units
+      const int ctuYOff      = currTU.block(comp).y - ( m_ctuYLumaSamples >> shiftVer ); // y offset from top edge of CTU in respective channel sample units
+      const int minCUHeight  = cu.cs->pcv->minCUHeight >> shiftVer;
+      if ( currTU.block(comp).valid() && ( ( currTU.block(comp).x == cu.block(comp).x ) ? m_stLFCUParam.leftEdge : m_stLFCUParam.internalEdge ) ) // Edge deblocking needs to be recomputed since ISP contains whole CU chroma transforms in last TU of the CU
+      {
+        for ( int y = 0; y < currTU.blocks[cIdx].height; y += minCUHeight )
+        {
+          const Position  posQ     = Position( currTU.blocks[ch].x, currTU.blocks[ch].y + y );
+          const Position  posP     = posQ.offset( -1, 0 );
+          const int sizeQSide      = tuQ.block(comp).width;
+          const TransformUnit& tuP = *cu.cs->getTU( posP, ch );
+          const int sizePSide      = tuP.block(comp).width;
+          m_transformEdge[cIdx][ctuXOff][ctuYOff+y] = true;
+
+          if ( comp == COMPONENT_Y )
+          {
+            m_maxFilterLengthQ[cIdx][ctuXOff][ctuYOff+y] = ( sizeQSide >= 32 ) ? 7 : 3;
+            m_maxFilterLengthP[cIdx][ctuXOff][ctuYOff+y] = ( sizePSide >= 32 ) ? 7 : 3;
+          }
+          else
+          {
+            m_maxFilterLengthQ[cIdx][ctuXOff][ctuYOff+y] = ( sizeQSide >= 8 && sizePSide >= 8 ) ? 3 : 1;
+            m_maxFilterLengthP[cIdx][ctuXOff][ctuYOff+y] = ( sizeQSide >= 8 && sizePSide >= 8 ) ? 3 : 1;
+          }
+        }
+      }
+    }
+  }
+}
+
+void LoopFilter::xSetMaxFilterLengthPQForCodingSubBlocks( const DeblockEdgeDir edgeDir, const CodingUnit& cu, const PredictionUnit& currPU, const bool& mvSubBlocks, const int& subBlockSize, const Area& areaPu )
+{
+  if ( mvSubBlocks && currPU.Y().valid() )
+  {
+    const int cIdx         = 0;
+    const ComponentID comp = ComponentID(cIdx);
+    const int ctuYOff      = currPU.block(comp).y - m_ctuYLumaSamples; // y offset from top edge of CTU in luma samples
+    const int ctuXOff      = currPU.block(comp).x - m_ctuXLumaSamples; // x offset from left edge of CTU in luma samples
+    const int minCUWidth   = cu.cs->pcv->minCUWidth;
+    const int minCUHeight  = cu.cs->pcv->minCUHeight;
+    if ( edgeDir == EDGE_HOR )
+    {
+      for ( int y = 0; y < areaPu.height; y += subBlockSize )
+      {
+        for ( int x = 0; x < areaPu.width; x += minCUWidth )
+        {
+          if ( m_transformEdge[cIdx][ctuXOff+x][ctuYOff+y] )
+          {
+            m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff+y] = std::min<int>(m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff+y], 5);
+            if ( y > 0 )
+            {
+              m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff+y] = std::min<int>(m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff+y], 5);
+            }
+          }
+          else if (y > 0 && ( m_transformEdge[cIdx][ctuXOff+x][ctuYOff+y-8] || (( y + 8 ) >= areaPu.height) || m_transformEdge[cIdx][ctuXOff+x][ctuYOff+y+8] )) // adjacent to transform edge on 8x8 grid
+          {
+            m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff+y] = 2;
+            m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff+y] = 2;
+          }
+          else
+          {
+            m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff+y] = 3;
+            m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff+y] = 3;
+          }
+        }
+      }
+    }
+    else // edgeDir == EDGE_VER
+    {
+      for ( int x = 0; x < areaPu.width; x += subBlockSize )
+      {
+        for ( int y = 0; y < areaPu.height; y += minCUHeight )
+        {
+          if ( m_transformEdge[cIdx][ctuXOff+x][ctuYOff+y] )
+          {
+            m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff+y] = std::min<int>(m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff+y], 5);
+            if ( x > 0 )
+            {
+              m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff+y] = std::min<int>(m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff+y], 5);
+            }
+          }
+          else if ( x > 0 && ( m_transformEdge[cIdx][ctuXOff+x-8][ctuYOff+y] || ( (x + 8) >= areaPu.width ) || m_transformEdge[cIdx][ctuXOff+x+8][ctuYOff+y] ) ) // adjacent to transform edge on 8x8 grid
+          {
+            m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff+y] = 2;
+            m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff+y] = 2;
+          }
+          else
+          {
+            m_maxFilterLengthQ[cIdx][ctuXOff+x][ctuYOff+y] = 3;
+            m_maxFilterLengthP[cIdx][ctuXOff+x][ctuYOff+y] = 3;
+          }
+        }
+      }
+    }
+  }
+}
+#endif
 
 void LoopFilter::xSetEdgefilterMultiple( const CodingUnit&    cu,
                                          const DeblockEdgeDir edgeDir,
@@ -492,7 +730,9 @@ void LoopFilter::xSetLoopfilterParam( const CodingUnit& cu )
   m_stLFCUParam.internalEdge = true;
   m_stLFCUParam.leftEdge     = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1,  0 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() );
   m_stLFCUParam.topEdge      = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset(  0, -1 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() );
+#if !JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
   m_stLFCUParam.internalEdge &= !cu.ispMode;
+#endif
 }
 
 unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const Position& localPos ) const
@@ -661,7 +901,11 @@ void LoopFilter::deriveLADFShift( const Pel* src, const int stride, int& shift,
 }
 #endif
 
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge )
+#else
 void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge, const int initialMaxFilterLengthP, const int initialMaxFilterLengthQ)
+#endif
 {
   const CompArea&  lumaArea = cu.block(COMPONENT_Y);
   const PreCalcValues& pcv = *cu.cs->pcv;
@@ -719,6 +963,18 @@ void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edge
     pos.x += xoffset;
     pos.y += yoffset;
 
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+    // Deblock luma boundaries on 8x8 grid only
+    if ( edgeDir == EDGE_HOR && ( pos.y % 8 ) != 0 )
+    {
+      continue;
+    }
+    if ( edgeDir == EDGE_VER && ( pos.x % 8 ) != 0 )
+    {
+      continue;
+    }
+#endif
+
     uiBsAbsIdx = getRasterIdx( pos, pcv );
     uiBs = BsGet(m_aapucBS[edgeDir][uiBsAbsIdx], COMPONENT_Y);
 
@@ -749,14 +1005,24 @@ void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edge
 
       bool sidePisLarge   = false;
       bool sideQisLarge   = false;
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+      int maxFilterLengthP = m_maxFilterLengthP[COMPONENT_Y][pos.x-m_ctuXLumaSamples][pos.y-m_ctuYLumaSamples];
+      int maxFilterLengthQ = m_maxFilterLengthQ[COMPONENT_Y][pos.x-m_ctuXLumaSamples][pos.y-m_ctuYLumaSamples];
+#else
       int maxFilterLengthP = initialMaxFilterLengthP;
       int maxFilterLengthQ = initialMaxFilterLengthQ;
+#endif
       if (maxFilterLengthP > 3)
       {
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+        sidePisLarge = true;
+        if ( maxFilterLengthP > 5 )
+#else
         sidePisLarge = (edgeDir == EDGE_VER && cuP.block(COMPONENT_Y).width >= 32)
           || (edgeDir == EDGE_HOR && cuP.block(COMPONENT_Y).height >= 32);
 
         if (sidePisLarge && maxFilterLengthP > 5)
+#endif
         {
           // restrict filter length if sub-blocks are used (e.g affine or ATMVP)
           bool ciipSubBlock = false;
@@ -773,8 +1039,12 @@ void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edge
       }
       if (maxFilterLengthQ > 3)
       {
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+        sideQisLarge = true;
+#else
         sideQisLarge = (edgeDir == EDGE_VER && cuQ.block(COMPONENT_Y).width >= 32)
           || (edgeDir == EDGE_HOR && cuQ.block(COMPONENT_Y).height >= 32);
+#endif
       }
 
       if (edgeDir == EDGE_HOR && pos.y % slice.getSPS()->getCTUSize() == 0)
@@ -1021,12 +1291,22 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed
         bPartQNoFilter = bPartQNoFilter || cuQ.transQuantBypass;
       }
 
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+      const int maxFilterLengthP = m_maxFilterLengthP[COMPONENT_Cb][(pos.x-m_ctuXLumaSamples)>>m_shiftHor][(pos.y-m_ctuYLumaSamples)>>m_shiftVer];
+      const int maxFilterLengthQ = m_maxFilterLengthQ[COMPONENT_Cb][(pos.x-m_ctuXLumaSamples)>>m_shiftHor][(pos.y-m_ctuYLumaSamples)>>m_shiftVer];
+      bool largeBoundary         = false;
+      if ( maxFilterLengthP >= 3 && maxFilterLengthQ >= 3 )
+      {
+        largeBoundary = true;
+      }
+#else
       const unsigned cuPWidth  = cuP.block(COMPONENT_Cb).width;
       const unsigned cuPHeight = cuP.block(COMPONENT_Cb).height;
       const unsigned cuQWidth  = cuQ.block(COMPONENT_Cb).width;
       const unsigned cuQHeight = cuQ.block(COMPONENT_Cb).height;
 
       bool largeBoundary = ((edgeDir == EDGE_VER && cuPWidth >= 8 && cuQWidth >= 8) || (edgeDir == EDGE_HOR && cuPHeight >= 8 && cuQHeight >= 8));
+#endif
 
       if (edgeDir == EDGE_HOR && pos.y % cuP.slice->getSPS()->getCTUSize() == 0)
       {
diff --git a/source/Lib/CommonLib/LoopFilter.h b/source/Lib/CommonLib/LoopFilter.h
index 6ff62b0ad5..a85f7b87ec 100644
--- a/source/Lib/CommonLib/LoopFilter.h
+++ b/source/Lib/CommonLib/LoopFilter.h
@@ -58,6 +58,13 @@ private:
   static_vector<char, MAX_NUM_PARTS_IN_CTU> m_aapucBS       [NUM_EDGE_DIR];         ///< Bs for [Ver/Hor][Y/U/V][Blk_Idx]
   static_vector<bool, MAX_NUM_PARTS_IN_CTU> m_aapbEdgeFilter[NUM_EDGE_DIR];
   LFCUParam m_stLFCUParam;                   ///< status structure
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+  int     m_ctuXLumaSamples, m_ctuYLumaSamples;                            // location of left-edge and top-edge of CTU
+  int     m_shiftHor, m_shiftVer;                                          // shift values to convert location from luma sample units to chroma sample units
+  uint8_t m_maxFilterLengthP[MAX_NUM_COMPONENT][MAX_CU_SIZE][MAX_CU_SIZE]; // maxFilterLengthP for [component][luma/chroma sample distance from left edge of CTU][luma/chroma sample distance from top edge of CTU]
+  uint8_t m_maxFilterLengthQ[MAX_NUM_COMPONENT][MAX_CU_SIZE][MAX_CU_SIZE]; // maxFilterLengthQ for [component][luma/chroma sample distance from left edge of CTU][luma/chroma sample distance from top edge of CTU]
+  bool    m_transformEdge[MAX_NUM_COMPONENT][MAX_CU_SIZE][MAX_CU_SIZE];    // transform edge flag for [component][luma/chroma sample distance from left edge of CTU][luma/chroma sample distance from top edge of CTU]
+#endif
   PelStorage                   m_encPicYuvBuffer;
   bool                         m_enc;
 private:
@@ -74,12 +81,20 @@ private:
                                     const Area&           area,
                                     const bool            bValue,
                                     const bool            EdgeIdx = false );
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+  void xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge );
+#else
   void xEdgeFilterLuma            ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge, const int initialMaxFilterLengthP, const int initialMaxFilterLengthQ );
+#endif
   void xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir edgeDir, const int iEdge);
 
 #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET
   void deriveLADFShift( const Pel* src, const int stride, int& shift, const DeblockEdgeDir edgeDir, const SPS sps );
 #endif
+#if JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
+  void xSetMaxFilterLengthPQFromTransformSizes( const DeblockEdgeDir edgeDir, const CodingUnit& cu, const TransformUnit& currTU );
+  void xSetMaxFilterLengthPQForCodingSubBlocks( const DeblockEdgeDir edgeDir, const CodingUnit& cu, const PredictionUnit& currPU, const bool& mvSubBlocks, const int& subBlockSize, const Area& areaPu );
+#endif
 
   inline void xBilinearFilter     ( Pel* srcP, Pel* srcQ, int offset, int refMiddle, int refP, int refQ, int numberPSide, int numberQSide, const int* dbCoeffsP, const int* dbCoeffsQ, int tc ) const;
   inline void xFilteringPandQ     ( Pel* src, int offset, int numberPSide, int numberQSide, int tc ) const;
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 267c1debad..101a7193a7 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -150,6 +150,7 @@
 
 #define JVET_N0492_NO_HIERARCH_CBF                        1 // Allow CBFs writing for leaf TU only
 
+#define JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES  1 // JVET-N0473, JVET-N0098: Deblocking of ISP/SBT TU boundaries
 
 #define JCTVC_Y0038_PARAMS                                1
 
-- 
GitLab