diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index 23639440535ce52013a5ac599f67ed8b52358429..27957a7f0e56384f4af6ea5f488d0fcd8ef38805 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -1614,9 +1614,9 @@ Specifies the maximum depth for CU chroma QP adjustment; if negative, CU chroma
 
 
 %%
-%% Slice coding parameters
+%% Slice/Tile/Brick coding parameters
 %%
-\begin{OptionTableNoShorthand}{Slice coding parameters}{tab:slice-coding}
+\begin{OptionTableNoShorthand}{Slice, tile and brick coding parameters}{tab:slice-coding}
 %\Option{SliceGranularity} &
 %\ShortOption{\None} &
 %\Default{0} &
@@ -1641,40 +1641,21 @@ SliceArgument.
 \par
 \begin{tabular}{cp{0.45\textwidth}}
  0 & Single slice \\
- 1 & Maximum number of CTUs per slice \\
- 2 & Maximum number of bytes per slice \\
+ 1 & (deprecated) Maximum number of CTUs per slice \\
+ 2 & (deprecated) Maximum number of bytes per slice \\
  3 & Maximum number of tiles per slice \\
+ 4 & One slice per brick
 \end{tabular}
 \\
 
 \Option{SliceArgument} &
 %\ShortOption{\None} &
 \Default{\NotSet} &
+(deprecated)
 Specifies the maximum number of CTUs, bytes or tiles in a slice depending on the
 SliceMode setting.
 \\
 
-\Option{SliceSegmentMode} &
-%\ShortOption{\None} &
-\Default{0} &
-Enables (dependent) slice segment coding in conjunction with 
-SliceSegmentArgument.
-\par
-\begin{tabular}{cp{0.45\textwidth}}
- 0 & Single slice \\
- 1 & Maximum number of CTUs per slice segment\\
- 2 & Maximum number of bytes per slice segment\\
- 3 & Maximum number of tiles per slice segment\\
-\end{tabular}
-\\
-
-\Option{SliceSegmentArgument} &
-%\ShortOption{\None} &
-\Default{\NotSet} &
-Defines the maximum number of CTUs, bytes or tiles a slice segment
-depending on the SliceSegmentMode setting.
-\\
-
 \Option{WaveFrontSynchro} &
 %\ShortOption{\None} &
 \Default{false} &
@@ -1712,6 +1693,35 @@ Specifies a space or comma separated list of widths and heights,
 respectively, of each tile column or tile row.  The first value in the
 list corresponds to the leftmost tile column or topmost tile row.
 \\
+
+\Option{BrickSplit1}%
+\Option{BrickSplit2} %
+\Option{BrickSplitN} &
+%\ShortOption{\None} &
+\Default{\NotSet} &
+Specifies the splitting of tiles into bricks, N can be in the range of 1 to 128 and has no further meaning except to distinguish different splitting parameters.
+
+The following options are supported:
+
+BrickSplitN tileIdx uniform (numsplits) heights
+
+\begin{tabular}{cp{0.45\textwidth}}
+ tileIdx & the index of the tile to be split in raster scan order starting with zero \\
+ uniform & specifies whether uniform splitting shall be used (1 for uniform, 0 non-uniform) \\
+ numsplits & specifies the number of splits, if uniform is not used \\
+ heights & specifies the height of the uniform splits or a list of heights for non-uniform splits \\
+\end{tabular}
+ 
+\\
+\Option{TileRowHeightArray} &
+%\ShortOption{\None} &
+\Default{\NotSet} &
+Specifies a space or comma separated list of widths and heights,
+respectively, of each tile column or tile row.  The first value in the
+list corresponds to the leftmost tile column or topmost tile row.
+\\
+
+
 \end{OptionTableNoShorthand}
 
 
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 4a309088d49ee563b9fd806a1977e0c0758d4a76..e198d86c9dec3a305504e87c608309dbcc92234c 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -517,6 +517,18 @@ void EncApp::xInitLibCfg()
     m_cEncLib.setColumnWidth                                     ( m_tileColumnWidth );
     m_cEncLib.setRowHeight                                       ( m_tileRowHeight );
   }
+#if JVET_N0857_TILES_BRICKS
+  m_cEncLib.setRectSliceFlag                                     ( m_rectSliceFlag );
+  m_cEncLib.setNumSlicesInPicMinus1                              ( m_numSlicesInPicMinus1 );
+  m_cEncLib.setTopLeftTileIdx                                    ( m_topLeftTileIdx );
+  m_cEncLib.setBottomRightTileIdx                                ( m_bottomRightTileIdx );
+  m_cEncLib.setLoopFilterAcrossSlicesEnabledFlag                 ( m_loopFilterAcrossSlicesEnabledFlag );
+  m_cEncLib.setSignalledSliceIdFlag                              ( m_signalledSliceIdFlag ),
+  m_cEncLib.setSignalledSliceIdLengthMinus1                      ( m_signalledSliceIdLengthMinus1 );
+  m_cEncLib.setSliceId                                           ( m_sliceId );
+  m_cEncLib.setBrickSplitMap                                     (m_brickSplitMap);
+#endif
+
   m_cEncLib.xCheckGSParameters();
   int uiTilesCount = (m_numTileRowsMinus1+1) * (m_numTileColumnsMinus1+1);
   if(uiTilesCount == 1)
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 863b17852d6349fb74fa24e82f38c0dbfa43c0a2..70465096dbda289862bbf321fac39718a866d2ec 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -217,6 +217,28 @@ std::istringstream &operator>>(std::istringstream &in, GOPEntry &entry)     //in
   return in;
 }
 
+#if JVET_N0857_TILES_BRICKS
+std::istringstream &operator>>(std::istringstream &in, BrickSplit &entry)     //input
+{
+  in>>entry.m_tileIdx;
+  in>>entry.m_uniformSplit;
+  if (entry.m_uniformSplit)
+  {
+    in>>entry.m_uniformHeight;
+  }
+  else
+  {
+    in>>entry.m_numSplits;
+    for ( int i = 0; i < entry.m_numSplits; i++ )
+    {
+      in>>entry.m_brickHeight[i];
+    }
+  }
+  return in;
+}
+
+#endif
+
 bool confirmPara(bool bflag, const char* message);
 
 static inline ChromaFormat numberToChromaFormat(const int val)
@@ -689,6 +711,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   SMultiValueInput<int>  cfg_codedPivotValue                 (std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), 0, 1<<16);
   SMultiValueInput<int>  cfg_targetPivotValue                (std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), 0, 1<<16);
 
+#if JVET_N0857_TILES_BRICKS
+  SMultiValueInput<uint32_t> cfg_TileGroupIdx                (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_SignalledTileGroupId        (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max());
+#endif
+
   SMultiValueInput<double> cfg_adIntraLambdaModifier         (0, std::numeric_limits<double>::max(), 0, MAX_TLAYER); ///< Lambda modifier for Intra pictures, one for each temporal layer. If size>temporalLayer, then use [temporalLayer], else if size>0, use [size()-1], else use m_adLambdaModifier.
 
 #if SHARP_LUMA_DELTA_QP
@@ -1076,7 +1103,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
 #if K0238_SAO_GREEDY_MERGE_ENCODING
   ("SAOGreedyEnc",                                    m_saoGreedyMergeEnc,                              false, "SAO greedy merge encoding algorithm")
 #endif
+#if JVET_N0857_TILES_BRICKS
+  ("SliceMode",                                       tmpSliceMode,                            int(NO_SLICES), "0: Disable all Recon slice limits, 1: (deprecated #CTU), 2: (deprecated #bytes), 3:specify tiles per slice, 4: one brick per slice")
+#else
   ("SliceMode",                                       tmpSliceMode,                            int(NO_SLICES), "0: Disable all Recon slice limits, 1: Enforce max # of CTUs, 2: Enforce max # of bytes, 3:specify tiles per dependent slice")
+#endif
   ("SliceArgument",                                   m_sliceArgument,                                      0, "Depending on SliceMode being:"
                                                                                                                "\t1: max number of CTUs per slice"
                                                                                                                "\t2: max number of bytes per slice"
@@ -1107,9 +1138,10 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("Log2ParallelMergeLevel",                          m_log2ParallelMergeLevel,                            2u, "Parallel merge estimation region")
     //deprecated copies of renamed tile parameters
   ("UniformSpacingIdc",                               m_tileUniformSpacingFlag,                         false,      "deprecated alias of TileUniformSpacing")
+#if !JVET_N0857_TILES_BRICKS
   ("ColumnWidthArray",                                cfg_ColumnWidth,                        cfg_ColumnWidth, "deprecated alias of TileColumnWidthArray")
   ("RowHeightArray",                                  cfg_RowHeight,                            cfg_RowHeight, "deprecated alias of TileRowHeightArray")
-
+#endif
   ("TileUniformSpacing",                              m_tileUniformSpacingFlag,                         false,      "Indicates that tile columns and rows are distributed uniformly")
   ("NumTileColumnsMinus1",                            m_numTileColumnsMinus1,                               0,          "Number of tile columns in a picture minus 1")
   ("NumTileRowsMinus1",                               m_numTileRowsMinus1,                                  0,          "Number of rows in a picture minus 1")
@@ -1117,6 +1149,17 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("TileRowHeightArray",                              cfg_RowHeight,                            cfg_RowHeight, "Array containing tile row height values in units of CTU")
   ("LFCrossTileBoundaryFlag",                         m_bLFCrossTileBoundaryFlag,                        true, "1: cross-tile-boundary loop filtering. 0:non-cross-tile-boundary loop filtering")
   ("WaveFrontSynchro",                                m_entropyCodingSyncEnabledFlag,                   false, "0: entropy coding sync disabled; 1 entropy coding sync enabled")
+
+#if JVET_N0857_TILES_BRICKS
+  ("RectTileGroupFlag",                               m_rectSliceFlag,                                  true, "Rectangular tile group flag")
+  ("SlicesInPicMinus1",                               m_numSlicesInPicMinus1,                               0, "Number tile groups in pic minus 1")
+  ("LoopFilterAcrossTileGroupsEnabledFlag",           m_loopFilterAcrossSlicesEnabledFlag,              false, "Loop Filter Across Tile Groups Flag")
+  ("SignalledIdFlag",                                 m_signalledSliceIdFlag,                           false, "Signalled Slice ID Flag")
+  ("SignalledSliceIdLengthMinus1",                    m_signalledSliceIdLengthMinus1,                       0, "Signalled Tile Group Length minus 1")
+  ("TileGroupsInPic",                                 cfg_TileGroupIdx,                      cfg_TileGroupIdx, "Tile Groups In Pic")
+  ("SignalledTileGroupId",                            cfg_SignalledTileGroupId,              cfg_TileGroupIdx, "Signalled Tile Group ID")
+#endif
+
 #if HEVC_USE_SCALING_LISTS
   ("ScalingList",                                     m_useScalingListId,                    SCALING_LIST_OFF, "0/off: no scaling list, 1/default: default scaling lists, 2/file: scaling lists specified in ScalingListFile")
   ("ScalingListFile",                                 m_scalingListFileName,                       string(""), "Scaling list file name. Use an empty string to produce help.")
@@ -1349,6 +1392,16 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
     cOSS<<"Frame"<<i;
     opts.addOptions()(cOSS.str(), m_GOPList[i-1], GOPEntry());
   }
+
+#if JVET_N0857_TILES_BRICKS
+  for(int i=1; i<MAX_TILES+1; i++)
+  {
+    std::ostringstream cOSS;
+    cOSS<<"BrickSplit"<<i;
+    opts.addOptions()(cOSS.str(), m_brickSplits[i-1], BrickSplit());
+  }
+#endif
+
   po::setDefaults(opts);
   po::ErrorReporter err;
   const list<const char*>& argv_unhandled = po::scanArgv(opts, argc, (const char**) argv, err);
@@ -1663,6 +1716,14 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
     EXIT( "Error: bad slice mode");
   }
   m_sliceMode = SliceConstraint(tmpSliceMode);
+#if JVET_N0857_TILES_BRICKS
+  if (m_sliceMode==FIXED_NUMBER_OF_CTU || m_sliceMode==FIXED_NUMBER_OF_BYTES)
+  {
+    // note: slice mode 2 can be re-enabled using scan order tiles
+    EXIT( "Error: slice mode 1 (fixed number of CTUs) and 2 (fixed number of bytes) are no longer supported");
+  }
+#endif
+
 
 #if HEVC_DEPENDENT_SLICES
   if (tmpSliceSegmentMode<0 || tmpSliceSegmentMode>=int(NUMBER_OF_SLICE_CONSTRAINT_MODES))
@@ -1672,6 +1733,64 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   m_sliceSegmentMode = SliceConstraint(tmpSliceSegmentMode);
 #endif
 
+#if JVET_N0857_TILES_BRICKS
+  m_topLeftTileIdx.clear();
+  m_bottomRightTileIdx.clear();
+  m_sliceId.clear();
+
+  bool singleTileInPicFlag = (m_numTileRowsMinus1 == 0 && m_numTileColumnsMinus1 == 0);
+
+  if (!singleTileInPicFlag)
+  {
+    //if (!m_singleBrickPerSliceFlag && m_rectSliceFlag)
+    if (m_sliceMode != 0 && m_sliceMode != 4 && m_rectSliceFlag)
+    {
+      int numTileGroupsInPic = m_numSlicesInPicMinus1 + 1;
+
+      if (cfg_TileGroupIdx.values.size() > numTileGroupsInPic * 2)
+      {
+        EXIT("Error: The number of Tile group indexs are greater than the numTileGroupsInPicMinus1.");
+      }
+      else if (cfg_TileGroupIdx.values.size() < numTileGroupsInPic * 2)
+      {
+        EXIT("Error: The number of Tile group indexs are less than the numTileGroupsInPicMinus1.");
+      }
+      else
+      {
+        m_topLeftTileIdx.resize(numTileGroupsInPic);
+        m_bottomRightTileIdx.resize(numTileGroupsInPic);
+        for (uint32_t i = 0; i < numTileGroupsInPic; ++i)
+        {
+          m_topLeftTileIdx[i] = cfg_TileGroupIdx.values[i * 2];
+          m_bottomRightTileIdx[i] = cfg_TileGroupIdx.values[i * 2 + 1];
+        }
+      }
+    }      // (!m_singleBrickPerSliceFlag && m_rectSliceFlag)
+  }        // !singleTileInPicFlag
+
+  if (m_rectSliceFlag && m_signalledSliceIdFlag)
+  {
+    int numTileGroupsInPic = m_numSlicesInPicMinus1 + 1;
+
+    if (cfg_SignalledTileGroupId.values.size() > numTileGroupsInPic)
+    {
+      EXIT("Error: The number of Tile group Ids are greater than the m_signalledTileGroupIdLengthMinus1.");
+    }
+    else if (cfg_SignalledTileGroupId.values.size() < numTileGroupsInPic)
+    {
+      EXIT("Error: The number of Tile group Ids are less than the m_signalledTileGroupIdLengthMinus1.");
+    }
+    else
+    {
+      m_sliceId.resize(numTileGroupsInPic);
+      for (uint32_t i = 0; i < cfg_SignalledTileGroupId.values.size(); ++i)
+      {
+        m_sliceId[i] = cfg_SignalledTileGroupId.values[i];
+      }
+    }
+  }
+#endif
+
   if (tmpDecodedPictureHashSEIMappedType<0 || tmpDecodedPictureHashSEIMappedType>=int(NUMBER_OF_HASHTYPES))
   {
     EXIT( "Error: bad checksum mode");
@@ -2858,6 +2977,17 @@ bool EncAppCfg::xCheckParameter()
     }
   }
 
+#if JVET_N0857_TILES_BRICKS
+  for (int i=0; i<MAX_TILES; i++)
+  {
+    if (m_brickSplits[i].m_tileIdx>=0)
+    {
+      m_brickSplitMap[m_brickSplits[i].m_tileIdx] = m_brickSplits[i];
+      // ToDo: check that brick dimensions don't exceed tile dimensions
+    }
+  }
+#endif
+
   if ((m_MCTSEncConstraint) && (m_bLFCrossTileBoundaryFlag))
   {
     printf("Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling filtering across tile boundaries!\n");
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index e4afab344507ffc206564a877e9cbdcd2e7444ba..bc8d97e2e002fded998b397cdf8db98d4fcaa274 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -165,6 +165,10 @@ protected:
 #endif
   int       m_extraRPSs;                                      ///< extra RPSs added to handle CRA
   GOPEntry  m_GOPList[MAX_GOP];                               ///< the coding structure entries from the config file
+#if JVET_N0857_TILES_BRICKS
+  BrickSplit    m_brickSplits[MAX_TILES];
+  BrickSplitMap m_brickSplitMap;
+#endif
   int       m_numReorderPics[MAX_TLAYER];                     ///< total number of reorder pictures
   int       m_maxDecPicBuffering[MAX_TLAYER];                 ///< total number of pictures in the decoded picture buffer
   bool      m_crossComponentPredictionEnabledFlag;            ///< flag enabling the use of cross-component prediction
@@ -409,6 +413,7 @@ protected:
 #endif
 
   bool      m_bLFCrossSliceBoundaryFlag;  ///< 1: filter across slice boundaries 0: do not filter across slice boundaries
+
   bool      m_bLFCrossTileBoundaryFlag;   ///< 1: filter across tile boundaries  0: do not filter across tile boundaries
   bool      m_tileUniformSpacingFlag;
   int       m_numTileColumnsMinus1;
@@ -417,6 +422,17 @@ protected:
   std::vector<int> m_tileRowHeight;
   bool      m_entropyCodingSyncEnabledFlag;
 
+#if JVET_N0857_TILES_BRICKS
+  bool      m_rectSliceFlag;
+  int       m_numSlicesInPicMinus1;
+  std::vector<int> m_topLeftTileIdx;
+  std::vector<int> m_bottomRightTileIdx;
+  bool      m_loopFilterAcrossSlicesEnabledFlag;
+  bool      m_signalledSliceIdFlag;
+  int       m_signalledSliceIdLengthMinus1;
+  std::vector<int> m_sliceId;
+#endif
+
   bool      m_bUseConstrainedIntraPred;                       ///< flag for using constrained intra prediction
   bool      m_bFastUDIUseMPMEnabled;
   bool      m_bFastMEForGenBLowDelayEnabled;
diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index 801b34d52949d330580552cf132456edf018bde2..ab8ec6554b21ba644256d0a40ea3df75b245f37b 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -143,6 +143,11 @@ static const int MAX_NUM_REF =                                     16; ///< max.
 static const int MAX_QP =                                          63;
 static const int NOT_VALID =                                       -1;
 
+#if JVET_N0857_TILES_BRICKS
+static const int MAX_TILES =                                      128; ///< max. number of tiles for which a brick configuration can be read
+static const int MAX_NUM_BRICKS_PER_TILE =                          8; ///< max. number brick per tile, for which a configuration can be read
+#endif
+
 static const int AMVP_MAX_NUM_CANDS =                               2; ///< AMVP: advanced motion vector prediction - max number of final candidates
 static const int AMVP_MAX_NUM_CANDS_MEM =                           3; ///< AMVP: advanced motion vector prediction - max number of candidates
 static const int AMVP_DECIMATION_FACTOR =                           2;
diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp
index b2685cac426e6f54f1d1d4276e209d9e8c198f61..4f1b8e2959083ff2508a577c959679117798767f 100644
--- a/source/Lib/CommonLib/ContextModelling.cpp
+++ b/source/Lib/CommonLib/ContextModelling.cpp
@@ -179,7 +179,11 @@ void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, u
 {
   const Position pos         = partitioner.currArea().blocks[partitioner.chType];
   const unsigned curSliceIdx = cs.slice->getIndependentSliceIdx();
+#if JVET_N0857_TILES_BRICKS
+  const unsigned curTileIdx  = cs.picture->brickMap->getBrickIdxRsMap( partitioner.currArea().lumaPos() );
+#else
   const unsigned curTileIdx  = cs.picture->tileMap->getTileIdxMap( partitioner.currArea().lumaPos() );
+#endif
 
   // get left depth
   const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), curSliceIdx, curTileIdx, partitioner.chType );
diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp
index 76947802a2d8033dab41d012e60178dc23caf65e..2e3ed1c99bbe9dda9c8b5de7e3f207d5f0c56443 100644
--- a/source/Lib/CommonLib/LoopFilter.cpp
+++ b/source/Lib/CommonLib/LoopFilter.cpp
@@ -848,8 +848,8 @@ void LoopFilter::xSetLoopfilterParam( const CodingUnit& cu )
   const Position& pos = cu.blocks[cu.chType].pos();
 
   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() );
+  m_stLFCUParam.leftEdge     = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1,  0 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() );
+  m_stLFCUParam.topEdge      = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset(  0, -1 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() );
 #if !JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES
   m_stLFCUParam.internalEdge &= !cu.ispMode;
 #endif
@@ -1112,11 +1112,11 @@ void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edge
       // Derive neighboring PU index
       if (edgeDir == EDGE_VER)
       {
-        CHECK( !isAvailableLeft( cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ), "Neighbour not available" );
+        CHECK( !isAvailableLeft( cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() ), "Neighbour not available" );
       }
       else  // (iDir == EDGE_HOR)
       {
-        CHECK( !isAvailableAbove( cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ), "Neighbour not available" );
+        CHECK( !isAvailableAbove( cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() ), "Neighbour not available" );
       }
 
       iQP = (cuP.qp + cuQ.qp + 1) >> 1;
@@ -1401,11 +1401,11 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed
 
       if (edgeDir == EDGE_VER)
       {
-        CHECK(!isAvailableLeft(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available");
+        CHECK(!isAvailableLeft(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag()), "Neighbour not available");
       }
       else  // (iDir == EDGE_HOR)
       {
-        CHECK(!isAvailableAbove(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available");
+        CHECK(!isAvailableAbove(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag()), "Neighbour not available");
       }
 
       bPartPNoFilter = bPartQNoFilter = false;
diff --git a/source/Lib/CommonLib/MCTS.cpp b/source/Lib/CommonLib/MCTS.cpp
index dd87fb11bdc1c50df48be97763be4e8ba6522ebb..1c8aaca6627dac80b07a4cc074e7819c67608d12 100644
--- a/source/Lib/CommonLib/MCTS.cpp
+++ b/source/Lib/CommonLib/MCTS.cpp
@@ -90,17 +90,31 @@ void MCTSHelper::clipMvToArea( Mv& rcMv, const Area& block, const Area& clipArea
 
 Area MCTSHelper::getTileArea( const CodingStructure* cs, const int ctuAddr )
 {
+#if JVET_N0857_TILES_BRICKS
+  const BrickMap* tileMap = cs->picture->brickMap;
+  const int       tileIdx = tileMap->getBrickIdxRsMap( ctuAddr );
+#else
   const TileMap* tileMap = cs->picture->tileMap;
   const int      tileIdx = tileMap->getTileIdxMap( ctuAddr );
+#endif
+#if JVET_N0857_TILES_BRICKS
+  const Brick&  currentTile = tileMap->bricks[tileIdx];
+#else
   const Tile&    currentTile = tileMap->tiles[tileIdx];
+#endif
 
   const int      frameWidthInCtus = cs->pcv->widthInCtus;
   const int  firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr();
 
   const int tileXPosInCtus = firstCtuRsAddrOfTile % frameWidthInCtus;
   const int tileYPosInCtus = firstCtuRsAddrOfTile / frameWidthInCtus;
+#if JVET_N0857_TILES_BRICKS
+  const int tileWidthtInCtus = currentTile.getWidthInCtus();
+  const int tileHeightInCtus = currentTile.getHeightInCtus();
+#else
   const int tileWidthtInCtus = currentTile.getTileWidthInCtus();
   const int tileHeightInCtus = currentTile.getTileHeightInCtus();
+#endif
 
   const int  maxCUWidth  = cs->pcv->maxCUWidth;
   const int  maxCUHeight = cs->pcv->maxCUHeight;
diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp
index 9accbe45c18cab4c8e3c0874c2c8d4aa0780201c..786e2c58c6f6412706e0d5edf01a05d218877e15 100644
--- a/source/Lib/CommonLib/Picture.cpp
+++ b/source/Lib/CommonLib/Picture.cpp
@@ -436,7 +436,22 @@ bool Scheduler::getNextCtu( Position& pos, int ctuLine, int offset)
 // picture methods
 // ---------------------------------------------------------------------------
 
+#if JVET_N0857_TILES_BRICKS
+
+Brick::Brick()
+: m_widthInCtus     (0)
+, m_heightInCtus    (0)
+, m_colBd           (0)
+, m_rowBd           (0)
+, m_firstCtuRsAddr  (0)
+{
+}
+
+Brick::~Brick()
+{
+}
 
+#else
 Tile::Tile()
 : m_tileWidthInCtus     (0)
 , m_tileHeightInCtus    (0)
@@ -449,7 +464,9 @@ Tile::Tile()
 Tile::~Tile()
 {
 }
+#endif
 
+#if !JVET_N0857_TILES_BRICKS
 
 TileMap::TileMap()
   : pcv(nullptr)
@@ -509,7 +526,7 @@ void TileMap::initTileMap( const SPS& sps, const PPS& pps )
   const uint32_t frameWidthInCtus  = pcv->widthInCtus;
   const uint32_t frameHeightInCtus = pcv->heightInCtus;
 
-  if( pps.getTileUniformSpacingFlag() )
+  if( pps.getUniformTileSpacingFlag() )
   {
     //set width and height for each (uniform) tile
     for(int row=0; row < numTileRows; row++)
@@ -711,9 +728,286 @@ uint32_t TileMap::getSubstreamForCtuAddr(const uint32_t ctuAddr, const bool bAdd
   return subStrm;
 }
 
+#else
+BrickMap::BrickMap()
+  : pcv(nullptr)
+  , numTiles(0)
+  , numTileColumns(0)
+  , numTileRows(0)
+  , brickIdxRsMap(nullptr)
+  , brickIdxBsMap(nullptr)
+  , ctuBsToRsAddrMap(nullptr)
+  , ctuRsToBsAddrMap(nullptr)
+{
+}
+
+void BrickMap::create( const SPS& sps, const PPS& pps )
+{
+  pcv = pps.pcv;
+
+  numTileColumns = pps.getNumTileColumnsMinus1() + 1;
+  numTileRows    = pps.getNumTileRowsMinus1() + 1;
+  numTiles       = numTileColumns * numTileRows;
+
+  const uint32_t numCtusInFrame = pcv->sizeInCtus;
+  brickIdxRsMap    = new uint32_t[numCtusInFrame];
+  brickIdxBsMap    = new uint32_t[numCtusInFrame];
+  ctuBsToRsAddrMap = new uint32_t[numCtusInFrame+1];
+  ctuRsToBsAddrMap = new uint32_t[numCtusInFrame+1];
+
+  initBrickMap( sps, pps );
+
+  numTiles = (uint32_t) bricks.size();
+}
+
+void BrickMap::destroy()
+{
+  bricks.clear();
+
+  if ( brickIdxRsMap )
+  {
+    delete[] brickIdxRsMap;
+    brickIdxRsMap = nullptr;
+  }
+
+  if ( brickIdxBsMap )
+  {
+    delete[] brickIdxBsMap;
+    brickIdxBsMap = nullptr;
+  }
+
+  if ( ctuBsToRsAddrMap )
+  {
+    delete[] ctuBsToRsAddrMap;
+    ctuBsToRsAddrMap = nullptr;
+  }
+
+  if ( ctuRsToBsAddrMap )
+  {
+    delete[] ctuRsToBsAddrMap;
+    ctuRsToBsAddrMap = nullptr;
+  }
+}
+
+void BrickMap::initBrickMap( const SPS& sps, const PPS& pps )
+{
+  const uint32_t frameWidthInCtus  = pcv->widthInCtus;
+  const uint32_t frameHeightInCtus = pcv->heightInCtus;
+
+  std::vector<uint32_t> tileRowHeight (numTileRows);
+  std::vector<uint32_t> tileColWidth (numTileColumns);
+
+  if( pps.getUniformTileSpacingFlag() )
+  {
+    //set width and height for each (uniform) tile
+    for(int row=0; row < numTileRows; row++)
+    {
+      tileRowHeight[row] = (row+1)*frameHeightInCtus/numTileRows   - (row*frameHeightInCtus)/numTileRows;
+    }
+    for(int col=0; col < numTileColumns; col++)
+    {
+      tileColWidth[col] = (col+1)*frameWidthInCtus/numTileColumns - (col*frameWidthInCtus)/numTileColumns;
+    }
+  }
+  else
+  {
+    tileColWidth[ numTileColumns - 1 ] = frameWidthInCtus;
+    for( int i = 0; i < numTileColumns - 1; i++ ) 
+    {
+      tileColWidth[ i ] = pps.getTileColumnWidth(i);
+      tileColWidth[ numTileColumns - 1 ]  =  tileColWidth[ numTileColumns - 1 ] - pps.getTileColumnWidth(i);
+    }
+
+
+    tileRowHeight[ numTileRows-1 ] = frameHeightInCtus;
+    for( int j = 0; j < numTileRows-1; j++ ) 
+    {
+      tileRowHeight[ j ] = pps.getTileRowHeight( j );
+      tileRowHeight[ numTileRows-1 ]  =  tileRowHeight[ numTileRows-1 ] - pps.getTileRowHeight( j );
+    }
+  }
+
+
+  //initialize each tile of the current picture
+  std::vector<uint32_t> tileRowBd (numTileRows);
+  std::vector<uint32_t> tileColBd (numTileColumns);
+
+  tileColBd[ 0 ] = 0;
+  for( int i = 0; i  <  numTileColumns - 1; i++ )
+  {
+    tileColBd[ i + 1 ] = tileColBd[ i ] + tileColWidth[ i ];
+  }
+
+  tileRowBd[ 0 ] = 0;
+  for( int j = 0; j  <  numTileRows - 1; j++ )
+  {
+    tileRowBd[ j + 1 ] = tileRowBd[ j ] + tileRowHeight[ j ];
+  }
+
+  int brickIdx = 0;
+  for(int tileIdx=0; tileIdx< numTiles; tileIdx++)
+  {
+    int tileX = tileIdx % ( pps.getNumTileColumnsMinus1() + 1 );
+    int tileY = tileIdx / ( pps.getNumTileColumnsMinus1() + 1 );
+
+    if ( !pps.getBrickSplittingPresentFlag() || !pps.getBrickSplitFlag(tileIdx))
+    {
+      bricks.resize(bricks.size()+1);
+      bricks[ brickIdx ].setColBd (tileColBd[ tileX ]);
+      bricks[ brickIdx ].setRowBd (tileRowBd[ tileY ]);
+      bricks[ brickIdx ].setWidthInCtus (tileColWidth[ tileX ]);
+      bricks[ brickIdx ].setHeightInCtus(tileRowHeight[ tileY ]);
+      bricks[ brickIdx ].setFirstCtuRsAddr(bricks[ brickIdx ].getColBd() + bricks[ brickIdx ].getRowBd() * frameWidthInCtus);
+      brickIdx++;
+    }
+    else
+    {
+      std::vector<uint32_t> rowHeight2;
+      std::vector<uint32_t> rowBd2;
+      int numBrickRowsMinus1 = 0;
+      if (pps.getUniformBrickSpacingFlag(tileIdx))
+      {
+        int brickHeight= pps.getBrickHeightMinus1(tileIdx) + 1;
+        int remainingHeightInCtbsY  = tileRowHeight[ tileY ];
+        int brickInTile = 0;
+        while( remainingHeightInCtbsY > brickHeight ) 
+        {
+          rowHeight2.resize(brickInTile+1);
+          rowHeight2[ brickInTile++ ] = brickHeight;
+          remainingHeightInCtbsY -= brickHeight;
+        }
+        rowHeight2.resize(brickInTile+1);
+        rowHeight2[ brickInTile ] = remainingHeightInCtbsY;
+        numBrickRowsMinus1 = brickInTile;
+      }
+      else
+      {
+        numBrickRowsMinus1 = pps.getNumBrickRowsMinus1(tileIdx);
+        rowHeight2.resize(numBrickRowsMinus1 + 1);
+        rowHeight2[ numBrickRowsMinus1 ] = tileRowHeight[ tileY ];
+        for(int j = 0; j < numBrickRowsMinus1; j++ ) 
+        {
+          rowHeight2[ j ] = pps.getBrickRowHeightMinus1 ( tileIdx, j )+ 1;
+          rowHeight2[ numBrickRowsMinus1 ]  -=  rowHeight2[ j ];
+        }
+      }
+      rowBd2.resize(numBrickRowsMinus1 + 1);
+      rowBd2[ 0 ] = 0;
+      for( int j = 0; j  <  numBrickRowsMinus1; j++ )
+      {
+        rowBd2[ j + 1 ] = rowBd2[ j ] + rowHeight2[ j ];
+      }
+      for( int j = 0; j < numBrickRowsMinus1 + 1; j++ ) 
+      {
+        bricks.resize(bricks.size()+1);
+        bricks[ brickIdx ].setColBd (tileColBd[ tileX ]);
+        bricks[ brickIdx ].setRowBd (tileRowBd[ tileY ] + rowBd2[ j ]);
+        bricks[ brickIdx ].setWidthInCtus (tileColWidth[ tileX ]);
+        bricks[ brickIdx ].setHeightInCtus(rowHeight2[ j ]);
+        bricks[ brickIdx ].setFirstCtuRsAddr(bricks[ brickIdx ].getColBd() + bricks[ brickIdx ].getRowBd() * frameWidthInCtus);
+        brickIdx++;
+      }
+    }
+  }
+
+  initCtuBsRsAddrMap();
+
+  for( int i = 0; i < (int)bricks.size(); i++ )
+  {
+    for( int y = bricks[i].getRowBd(); y < bricks[i].getRowBd() + bricks[i].getHeightInCtus(); y++ ) 
+    {
+      for( int x = bricks[i].getColBd(); x < bricks[i].getColBd() + bricks[i].getWidthInCtus(); x++ )
+      {
+        // brickIdxBsMap in BS scan is brickIdxMap as defined in the draft text
+        brickIdxBsMap[ ctuRsToBsAddrMap[ y * frameWidthInCtus+ x ] ] = i;
+        // brickIdxRsMap in RS scan is usually required in the software
+        brickIdxRsMap[ y * frameWidthInCtus+ x ] = i;
+      }
+    }
+  }
+}
+
+
+void BrickMap::initCtuBsRsAddrMap()
+{
+  const uint32_t picWidthInCtbsY  = pcv->widthInCtus;
+  const uint32_t picHeightInCtbsY = pcv->heightInCtus;
+  const uint32_t picSizeInCtbsY    = picWidthInCtbsY * picHeightInCtbsY;
+  const int numBricksInPic         = (int) bricks.size();
+
+  for( uint32_t ctbAddrRs = 0; ctbAddrRs < picSizeInCtbsY; ctbAddrRs++ ) 
+  {
+    const uint32_t tbX = ctbAddrRs % picWidthInCtbsY;
+    const uint32_t tbY = ctbAddrRs / picWidthInCtbsY;
+    bool brickFound = false;
+    int bkIdx = (numBricksInPic - 1);
+    for( int i = 0; i < (numBricksInPic - 1)  &&  !brickFound; i++ ) 
+    {
+      brickFound = tbX  <  ( bricks[i].getColBd() + bricks[i].getWidthInCtus() )  &&
+                   tbY  <  ( bricks[i].getRowBd() + bricks[i].getHeightInCtus() );
+      if( brickFound )
+      {
+        bkIdx = i;
+      }
+    }
+    ctuRsToBsAddrMap[ ctbAddrRs ] = 0;
+
+    for( uint32_t i = 0; i < bkIdx; i++ )
+    {
+      ctuRsToBsAddrMap[ ctbAddrRs ]  +=  bricks[i].getHeightInCtus() * bricks[i].getWidthInCtus();
+    }
+    ctuRsToBsAddrMap[ ctbAddrRs ]  += ( tbY - bricks[ bkIdx ].getRowBd() ) * bricks[ bkIdx ].getWidthInCtus() + tbX - bricks[ bkIdx ].getColBd();
+  }
+  
+  
+  for( uint32_t ctbAddrRs = 0; ctbAddrRs < picSizeInCtbsY; ctbAddrRs++ )
+  {
+    ctuBsToRsAddrMap[ ctuRsToBsAddrMap[ ctbAddrRs ] ] = ctbAddrRs;
+  }
+}
+
+uint32_t BrickMap::getSubstreamForCtuAddr(const uint32_t ctuAddr, const bool addressInRaster, Slice *slice) const
+{
+  const bool wppEnabled = slice->getPPS()->getEntropyCodingSyncEnabledFlag();
+  uint32_t subStrm;
+
+  if( (wppEnabled && pcv->heightInCtus > 1) || (numTiles > 1) ) // wavefronts, and possibly tiles being used.
+  {
+    // needs to be checked
+    CHECK (false, "bricks and WPP needs to be checked");
+
+    const uint32_t ctuRsAddr = addressInRaster ? ctuAddr : getCtuBsToRsAddrMap(ctuAddr);
+    const uint32_t brickIndex = getBrickIdxRsMap(ctuRsAddr);
+
+    if (wppEnabled)
+    {
+      const uint32_t firstCtuRsAddrOfTile     = bricks[brickIndex].getFirstCtuRsAddr();
+      const uint32_t tileYInCtus              = firstCtuRsAddrOfTile / pcv->widthInCtus;
+      const uint32_t ctuLine                  = ctuRsAddr / pcv->widthInCtus;
+      const uint32_t startingSubstreamForTile = (tileYInCtus * numTileColumns) + (bricks[brickIndex].getHeightInCtus() * (brickIndex % numTileColumns));
+      subStrm = startingSubstreamForTile + (ctuLine - tileYInCtus);
+    }
+    else
+    {
+      subStrm = brickIndex;
+    }
+  }
+  else
+  {
+    subStrm = 0;
+  }
+  return subStrm;
+}
+
+#endif
+
 Picture::Picture()
 {
+#if JVET_N0857_TILES_BRICKS
+  brickMap             = nullptr;
+#else
   tileMap              = nullptr;
+#endif
   cs                   = nullptr;
   m_bIsBorderExtended  = false;
   usedByCurr           = false;
@@ -784,12 +1078,21 @@ void Picture::destroy()
   }
   SEIs.clear();
 
+#if JVET_N0857_TILES_BRICKS
+  if ( brickMap )
+  {
+    brickMap->destroy();
+    delete brickMap;
+    brickMap = nullptr;
+  }
+#else
   if ( tileMap )
   {
     tileMap->destroy();
     delete tileMap;
     tileMap = nullptr;
   }
+#endif
   if (m_spliceIdx)
   {
     delete[] m_spliceIdx;
@@ -884,12 +1187,21 @@ void Picture::finalInit(const SPS& sps, const PPS& pps, APS& aps)
   SEIs.clear();
   clearSliceBuffer();
 
+#if JVET_N0857_TILES_BRICKS
+  if( brickMap )
+  {
+    brickMap->destroy();
+    delete brickMap;
+    brickMap = nullptr;
+  }
+#else
   if( tileMap )
   {
     tileMap->destroy();
     delete tileMap;
     tileMap = nullptr;
   }
+#endif
 
   const ChromaFormat chromaFormatIDC = sps.getChromaFormatIdc();
   const int          iWidth = sps.getPicWidthInLumaSamples();
@@ -919,8 +1231,13 @@ void Picture::finalInit(const SPS& sps, const PPS& pps, APS& aps)
 #endif
   cs->pcv     = pps.pcv;
 
+#if JVET_N0857_TILES_BRICKS
+  brickMap = new BrickMap;
+  brickMap->create( sps, pps );
+#else
   tileMap = new TileMap;
   tileMap->create( sps, pps );
+#endif
   if (m_spliceIdx == NULL)
   {
     m_ctuNums = cs->pcv->sizeInCtus;
diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h
index 931e72868db1aedec902563fd7641961ca2c4847..c48eee6054c2499dad1bc552bb120cfdb85af07b 100644
--- a/source/Lib/CommonLib/Picture.h
+++ b/source/Lib/CommonLib/Picture.h
@@ -115,6 +115,35 @@ class AQpLayer;
 
 typedef std::list<SEI*> SEIMessages;
 
+#if JVET_N0857_TILES_BRICKS
+
+class Brick
+{
+private:
+  uint32_t      m_widthInCtus;
+  uint32_t      m_heightInCtus;
+  uint32_t      m_colBd;
+  uint32_t      m_rowBd;
+  uint32_t      m_firstCtuRsAddr;
+
+public:
+  Brick();
+  virtual ~Brick();
+
+  void      setWidthInCtus         ( uint32_t i )            { m_widthInCtus = i; }
+  uint32_t  getWidthInCtus         () const                  { return m_widthInCtus; }
+  void      setHeightInCtus        ( uint32_t i )            { m_heightInCtus = i; }
+  uint32_t  getHeightInCtus        () const                  { return m_heightInCtus; }
+  void      setColBd  ( uint32_t i )                         { m_colBd = i; }
+  uint32_t  getColBd  () const                               { return m_colBd; }
+  void      setRowBd ( uint32_t i )                          { m_rowBd = i; }
+  uint32_t  getRowBd () const                                { return m_rowBd; }
+
+  void      setFirstCtuRsAddr      ( uint32_t i )            { m_firstCtuRsAddr = i; }
+  uint32_t  getFirstCtuRsAddr      () const                  { return m_firstCtuRsAddr; }
+};
+
+#else
 class Tile
 {
 private:
@@ -139,8 +168,9 @@ public:
   void      setFirstCtuRsAddr      ( uint32_t i )            { m_firstCtuRsAddr = i; }
   uint32_t      getFirstCtuRsAddr      () const              { return m_firstCtuRsAddr; }
 };
+#endif
 
-
+#if !JVET_N0857_TILES_BRICKS
 struct TileMap
 {
   TileMap();
@@ -168,6 +198,41 @@ struct TileMap
   uint32_t calculateNextCtuRSAddr( const uint32_t currCtuRsAddr ) const;
 };
 
+#else
+struct BrickMap
+{
+  BrickMap();
+
+  void create( const SPS& sps, const PPS& pps );
+  void destroy();
+
+  uint32_t getBrickIdxRsMap( uint32_t ctuRsAddr )       const { return *(brickIdxRsMap + ctuRsAddr); }
+  uint32_t getBrickIdxRsMap( const Position& pos )      const { return getBrickIdxRsMap( ( pos.x / pcv->maxCUWidth ) + ( pos.y / pcv->maxCUHeight ) * pcv->widthInCtus ); };
+
+  uint32_t getBrickIdxBsMap( uint32_t ctuRsAddr )       const { return *(brickIdxBsMap + ctuRsAddr); }
+  uint32_t getBrickIdxBsMap( const Position& pos )      const { return getBrickIdxBsMap( ( pos.x / pcv->maxCUWidth ) + ( pos.y / pcv->maxCUHeight ) * pcv->widthInCtus ); };
+
+  uint32_t getCtuBsToRsAddrMap( uint32_t ctuTsAddr ) const { return *(ctuBsToRsAddrMap + (ctuTsAddr>=pcv->sizeInCtus ? pcv->sizeInCtus : ctuTsAddr)); }
+  uint32_t getCtuRsToBsAddrMap( uint32_t ctuRsAddr ) const { return *(ctuRsToBsAddrMap + (ctuRsAddr>=pcv->sizeInCtus ? pcv->sizeInCtus : ctuRsAddr)); }
+
+  uint32_t getSubstreamForCtuAddr(const uint32_t ctuAddr, const bool addressInRaster, Slice *slice) const;
+
+  const PreCalcValues* pcv;
+  std::vector<Brick> bricks;
+
+  uint32_t  numTiles;
+  uint32_t  numTileColumns;
+  uint32_t  numTileRows;
+  uint32_t* brickIdxRsMap;
+  uint32_t* brickIdxBsMap;
+  uint32_t* ctuBsToRsAddrMap;
+  uint32_t* ctuRsToBsAddrMap;
+
+  void initBrickMap( const SPS& sps, const PPS& pps );
+  void initCtuBsRsAddrMap();
+};
+#endif
+
 #if ENABLE_SPLIT_PARALLELISM
 #define M_BUFS(JID,PID) m_bufs[JID][PID]
 #else
@@ -281,7 +346,11 @@ public:
   Slice        *swapSliceObject(Slice * p, uint32_t i);
   void         clearSliceBuffer();
 
+#if !JVET_N0857_TILES_BRICKS
   TileMap*     tileMap;
+#else
+  BrickMap*     brickMap;
+#endif
   MCTSInfo     mctsInfo;
   std::vector<AQpLayer*> aqlayer;
 
diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
index ad8acae438cff63616060d6b871bdeb2187e465b..f699c3e8f55f95cb463909d4c162c07e91848ed0 100644
--- a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
+++ b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
@@ -840,7 +840,7 @@ void SampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructure&
   }
 
   // check cross tile flags
-  const bool isLoopFilterAcrossTilePPS = cs.pps->getLoopFilterAcrossTilesEnabledFlag();
+  const bool isLoopFilterAcrossTilePPS = cs.pps->getLoopFilterAcrossBricksEnabledFlag();
   if (!isLoopFilterAcrossTilePPS)
   {
     isLeftAvail       = (!isLeftAvail)       ? false : CU::isSameTile(*cuCurr, *cuLeft);
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index ebaf0b9d0c3f61ab38b38a03506e03f7b9961171..bc7d7f55f91969ace13039726efc78daafd8992a 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -1971,12 +1971,25 @@ PPS::PPS()
 #if HEVC_DEPENDENT_SLICES
 , m_dependentSliceSegmentsEnabledFlag(false)
 #endif
+#if !JVET_N0857_TILES_BRICKS
 , m_tilesEnabledFlag                 (false)
+#endif
 , m_entropyCodingSyncEnabledFlag     (false)
-, m_loopFilterAcrossTilesEnabledFlag (true)
-, m_uniformSpacingFlag               (false)
+, m_loopFilterAcrossBricksEnabledFlag (true)
+, m_uniformTileSpacingFlag           (false)
 , m_numTileColumnsMinus1             (0)
 , m_numTileRowsMinus1                (0)
+#if JVET_N0857_TILES_BRICKS
+, m_singleTileInPicFlag              (true)
+, m_tileColsWidthMinus1              (0)
+, m_tileRowsHeightMinus1             (0)
+, m_brickSplittingPresentFlag        (false)
+, m_singleBrickPerSliceFlag          (true)
+, m_rectSliceFlag                    (true)
+, m_numSlicesInPicMinus1             (0)
+, m_signalledSliceIdFlag             (false)
+,m_signalledSliceIdLengthMinus1      (0)
+#endif
 , m_cabacInitPresentFlag             (false)
 , m_sliceHeaderExtensionPresentFlag  (false)
 , m_loopFilterAcrossSlicesEnabledFlag(false)
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index b7d5a2a788281d7aa47aced6a0885c4d2da44487..6f8cc6f40c3481a80ff4047c26ea90aa5350116b 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -1582,16 +1582,38 @@ private:
 #if HEVC_DEPENDENT_SLICES
   bool             m_dependentSliceSegmentsEnabledFlag; //!< Indicates the presence of dependent slices
 #endif
+#if !JVET_N0857_TILES_BRICKS
   bool             m_tilesEnabledFlag;                  //!< Indicates the presence of tiles
+#endif
   bool             m_entropyCodingSyncEnabledFlag;      //!< Indicates the presence of wavefronts
 
-  bool             m_loopFilterAcrossTilesEnabledFlag;
-  bool             m_uniformSpacingFlag;
+  bool             m_loopFilterAcrossBricksEnabledFlag;
+  bool             m_uniformTileSpacingFlag;
   int              m_numTileColumnsMinus1;
   int              m_numTileRowsMinus1;
   std::vector<int> m_tileColumnWidth;
   std::vector<int> m_tileRowHeight;
 
+#if JVET_N0857_TILES_BRICKS
+  bool             m_singleTileInPicFlag;
+  int              m_tileColsWidthMinus1;
+  int              m_tileRowsHeightMinus1;
+  bool             m_brickSplittingPresentFlag;
+  std::vector<bool> m_brickSplitFlag;
+  std::vector<bool> m_uniformBrickSpacingFlag;
+  std::vector<int> m_brickHeightMinus1;
+  std::vector<int> m_numBrickRowsMinus1;
+  std::vector<std::vector<int>> m_brickRowHeightMinus1;
+  bool             m_singleBrickPerSliceFlag;
+  bool             m_rectSliceFlag;
+  int              m_numSlicesInPicMinus1;
+  std::vector<int> m_topLeftTileIdx;
+  std::vector<int> m_bottomRightTileIdx;
+  bool             m_signalledSliceIdFlag;
+  int              m_signalledSliceIdLengthMinus1;
+  std::vector<int> m_sliceId;
+#endif
+
   bool             m_cabacInitPresentFlag;
 
   bool             m_sliceHeaderExtensionPresentFlag;
@@ -1691,27 +1713,66 @@ public:
   bool                   getUseTransformSkip() const                                      { return m_useTransformSkip;                    }
   void                   setUseTransformSkip( bool b )                                    { m_useTransformSkip  = b;                      }
 
-  void                   setLoopFilterAcrossTilesEnabledFlag(bool b)                      { m_loopFilterAcrossTilesEnabledFlag = b;       }
-  bool                   getLoopFilterAcrossTilesEnabledFlag() const                      { return m_loopFilterAcrossTilesEnabledFlag;    }
+  void                   setLoopFilterAcrossBricksEnabledFlag(bool b)                     { m_loopFilterAcrossBricksEnabledFlag = b;      }
+  bool                   getLoopFilterAcrossBricksEnabledFlag() const                     { return m_loopFilterAcrossBricksEnabledFlag;   }
 #if HEVC_DEPENDENT_SLICES
   bool                   getDependentSliceSegmentsEnabledFlag() const                     { return m_dependentSliceSegmentsEnabledFlag;   }
   void                   setDependentSliceSegmentsEnabledFlag(bool val)                   { m_dependentSliceSegmentsEnabledFlag = val;    }
+#endif
+#if !JVET_N0857_TILES_BRICKS
+  void                   setTilesEnabledFlag(bool val)                                    { m_tilesEnabledFlag = val;                     }
+  bool                   getTilesEnabledFlag() const                                      { return m_tilesEnabledFlag;                    }
 #endif
   bool                   getEntropyCodingSyncEnabledFlag() const                          { return m_entropyCodingSyncEnabledFlag;        }
   void                   setEntropyCodingSyncEnabledFlag(bool val)                        { m_entropyCodingSyncEnabledFlag = val;         }
 
-  void                   setTilesEnabledFlag(bool val)                                    { m_tilesEnabledFlag = val;                     }
-  bool                   getTilesEnabledFlag() const                                      { return m_tilesEnabledFlag;                    }
-  void                   setTileUniformSpacingFlag(bool b)                                { m_uniformSpacingFlag = b;                     }
-  bool                   getTileUniformSpacingFlag() const                                { return m_uniformSpacingFlag;                  }
+  void                   setUniformTileSpacingFlag(bool b)                                { m_uniformTileSpacingFlag = b;                 }
+  bool                   getUniformTileSpacingFlag() const                                { return m_uniformTileSpacingFlag;              }
   void                   setNumTileColumnsMinus1(int i)                                   { m_numTileColumnsMinus1 = i;                   }
   int                    getNumTileColumnsMinus1() const                                  { return m_numTileColumnsMinus1;                }
   void                   setTileColumnWidth(const std::vector<int>& columnWidth )         { m_tileColumnWidth = columnWidth;              }
-  uint32_t                   getTileColumnWidth(uint32_t columnIdx) const                         { return  m_tileColumnWidth[columnIdx];         }
+  uint32_t               getTileColumnWidth(uint32_t columnIdx) const                     { return  m_tileColumnWidth[columnIdx];         }
   void                   setNumTileRowsMinus1(int i)                                      { m_numTileRowsMinus1 = i;                      }
   int                    getNumTileRowsMinus1() const                                     { return m_numTileRowsMinus1;                   }
   void                   setTileRowHeight(const std::vector<int>& rowHeight)              { m_tileRowHeight = rowHeight;                  }
-  uint32_t                   getTileRowHeight(uint32_t rowIdx) const                              { return m_tileRowHeight[rowIdx];               }
+  uint32_t               getTileRowHeight(uint32_t rowIdx) const                          { return m_tileRowHeight[rowIdx];               }
+
+#if JVET_N0857_TILES_BRICKS               
+  bool                   getSingleTileInPicFlag() const                                   { return m_singleTileInPicFlag;                 }
+  void                   setSingleTileInPicFlag(bool val)                                 { m_singleTileInPicFlag = val;                  }
+  int                    getTileColsWidthMinus1() const                                   { return m_tileColsWidthMinus1;                 }
+  void                   setTileColsWidthMinus1(int w)                                    { m_tileColsWidthMinus1 = w;                    }
+  int                    getTileRowsHeightMinus1() const                                  { return m_tileRowsHeightMinus1;                }
+  void                   setTileRowsHeightMinus1(int h)                                   { m_tileRowsHeightMinus1 = h;                   }
+  bool                   getBrickSplittingPresentFlag() const                             { return m_brickSplittingPresentFlag;           }
+  void                   setBrickSplittingPresentFlag(bool b)                             { m_brickSplittingPresentFlag = b;              }
+  bool                   getBrickSplitFlag(int i) const                                   { return m_brickSplitFlag[i];                   }
+  void                   setBrickSplitFlag(std::vector<bool>& val)                        { m_brickSplitFlag = val;                       }
+  bool                   getUniformBrickSpacingFlag(int i) const                          { return m_uniformBrickSpacingFlag[i];          }
+  void                   setUniformBrickSpacingFlag(std::vector<bool>& val)               { m_uniformBrickSpacingFlag = val;              }
+  int                    getBrickHeightMinus1(int i) const                                { return m_brickHeightMinus1[i];                }
+  void                   setBrickHeightMinus1(std::vector<int>& val)                      { m_brickHeightMinus1 = val;                    }
+  int                    getNumBrickRowsMinus1(int i) const                               { return m_numBrickRowsMinus1[i];               }
+  void                   setNumBrickRowsMinus1(std::vector<int>& val)                     { m_numBrickRowsMinus1 = val;                   }
+  int                    getBrickRowHeightMinus1(int i, int j) const                      { return m_brickRowHeightMinus1[i][j];          }
+  void                   setBrickRowHeightMinus1(std::vector<std::vector<int>>& val)      { m_brickRowHeightMinus1 = val;                 }
+  bool                   getSingleBrickPerSliceFlag() const                               { return m_singleBrickPerSliceFlag;             }
+  void                   setSingleBrickPerSliceFlag(bool val)                             { m_singleBrickPerSliceFlag = val;              }
+  bool                   getRectSliceFlag() const                                         { return m_rectSliceFlag;                       }
+  void                   setRectSliceFlag(bool val)                                       { m_rectSliceFlag = val;                        }
+  int                    getNumSlicesInPicMinus1() const                                  { return m_numSlicesInPicMinus1;                }
+  void                   setNumSlicesInPicMinus1(int val)                                 { m_numSlicesInPicMinus1 = val;                 }
+  int                    getTopLeftTileIdx(uint32_t columnIdx) const                      { return  m_topLeftTileIdx[columnIdx];          }
+  void                   setTopLeftTileIdx(const std::vector<int>& val)                   { m_topLeftTileIdx = val;                       }
+  int                    getBottomeRightTileIdx(uint32_t columnIdx) const                 { return  m_bottomRightTileIdx[columnIdx];      }
+  void                   setBottomRightTileIdx(const std::vector<int>& val)               { m_bottomRightTileIdx = val;                   }
+  bool                   getSignalledSliceIdFlag() const                                  { return m_signalledSliceIdFlag;                }
+  void                   setSignalledSliceIdFlag(bool val)                                { m_signalledSliceIdFlag = val;                 }
+  int                    getSignalledSliceIdLengthMinus1() const                          { return m_signalledSliceIdLengthMinus1;        }
+  void                   setSignalledSliceIdLengthMinus1(int val)                         { m_signalledSliceIdLengthMinus1 = val;         }
+  int                    getSliceId(uint32_t columnIdx) const                             { return  m_sliceId[columnIdx];                 }
+  void                   setSliceId(const std::vector<int>& val)                          { m_sliceId = val;                              }
+#endif
 
   void                   setCabacInitPresentFlag( bool flag )                             { m_cabacInitPresentFlag = flag;                }
   bool                   getCabacInitPresentFlag() const                                  { return m_cabacInitPresentFlag;                }
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 354d06143853bf46e55a0a2dc9e051eeece97648..a23b6af87d00953cfcfc77e2bf0b5c363daebc16 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -87,6 +87,8 @@
 
 #define JVET_N0308_MAX_CU_SIZE_FOR_ISP                    1
 
+#define JVET_N0857_TILES_BRICKS                           1 // VTM-5 basic Slices/Tiles/Bricks design, rectangular slices not supported yet
+
 #define JVET_N0280_RESIDUAL_CODING_TS                     1
 
 #define JVET_N0103_CGSIZE_HARMONIZATION                   1 // Chroma CG sizes aligned to luma CG sizes
@@ -793,7 +795,12 @@ enum SliceConstraint
   FIXED_NUMBER_OF_CTU    = 1,          ///< Limit maximum number of largest coding tree units in a slice / slice segments
   FIXED_NUMBER_OF_BYTES  = 2,          ///< Limit maximum number of bytes in a slice / slice segment
   FIXED_NUMBER_OF_TILES  = 3,          ///< slices / slice segments span an integer number of tiles
+#if !JVET_N0857_TILES_BRICKS
   NUMBER_OF_SLICE_CONSTRAINT_MODES = 4
+#else
+  SINGLE_BRICK_PER_SLICE = 4,          ///< each brick is coded as separate NAL unit (slice)
+  NUMBER_OF_SLICE_CONSTRAINT_MODES = 5
+#endif
 };
 
 // For use with decoded picture hash SEI messages, generated by encoder.
diff --git a/source/Lib/CommonLib/UnitPartitioner.cpp b/source/Lib/CommonLib/UnitPartitioner.cpp
index c300bc224c680cd6ce717de729cdedeea096afdb..556d4c9282bde2a8f4a37eead6d60423c4d73bb2 100644
--- a/source/Lib/CommonLib/UnitPartitioner.cpp
+++ b/source/Lib/CommonLib/UnitPartitioner.cpp
@@ -144,7 +144,11 @@ void AdaptiveDepthPartitioner::setMaxMinDepth( unsigned& minDepth, unsigned& max
   unsigned          stdMaxDepth = ( g_aucLog2[cs.sps->getCTUSize()] - g_aucLog2[cs.sps->getMinQTSize( cs.slice->getSliceType(), chType )]);
   const Position    pos         = currArea().blocks[chType].pos();
   const unsigned    curSliceIdx = cs.slice->getIndependentSliceIdx();
+#if JVET_N0857_TILES_BRICKS
+  const unsigned    curTileIdx  = cs.picture->brickMap->getBrickIdxRsMap( currArea().lumaPos() );
+#else
   const unsigned    curTileIdx  = cs.picture->tileMap->getTileIdxMap( currArea().lumaPos() );
+#endif
 
   const CodingUnit* cuLeft        = cs.getCURestricted( pos.offset( -1,                               0 ), curSliceIdx, curTileIdx, chType );
   const CodingUnit* cuBelowLeft   = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), curSliceIdx, curTileIdx, chType );
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 9e43d182ffed6b1e8413de61e6d3c0b8ae6bc7e6..62915cedc6340a45ac111cbe83626b43ed1d610d 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -5430,11 +5430,19 @@ int CU::getMaxNeighboriMVCandNum( const CodingStructure& cs, const Position& pos
   int        maxImvNumCand  = 0;
 
   // Get BCBP of left PU
+#if JVET_N0857_TILES_BRICKS
+  const CodingUnit *cuLeft  = cs.getCURestricted( pos.offset( -1, 0 ), cs.slice->getIndependentSliceIdx(), cs.picture->brickMap->getBrickIdxRsMap( pos ), CH_L );
+#else
   const CodingUnit *cuLeft  = cs.getCURestricted( pos.offset( -1, 0 ), cs.slice->getIndependentSliceIdx(), cs.picture->tileMap->getTileIdxMap( pos ), CH_L );
+#endif
   maxImvNumCand = ( cuLeft ) ? cuLeft->imvNumCand : numDefault;
 
   // Get BCBP of above PU
+#if JVET_N0857_TILES_BRICKS
+  const CodingUnit *cuAbove = cs.getCURestricted( pos.offset( 0, -1 ), cs.slice->getIndependentSliceIdx(), cs.picture->brickMap->getBrickIdxRsMap( pos ), CH_L );
+#else
   const CodingUnit *cuAbove = cs.getCURestricted( pos.offset( 0, -1 ), cs.slice->getIndependentSliceIdx(), cs.picture->tileMap->getTileIdxMap( pos ), CH_L );
+#endif
   maxImvNumCand = std::max( maxImvNumCand, ( cuAbove ) ? cuAbove->imvNumCand : numDefault );
 
   return maxImvNumCand;
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index f68fe091c75241d5cf2fcb07540ebae330fcbb09..f7adbf2627647854dfcc787ff5d72f8f1d99cf98 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -157,7 +157,11 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i
     int                 rx = ctuRsAddr - ry * frame_width_in_ctus;
     const Position      pos( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight );
     const uint32_t          curSliceIdx = cs.slice->getIndependentSliceIdx();
+#if JVET_N0857_TILES_BRICKS
+    const uint32_t          curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( pos );
+#else
     const uint32_t          curTileIdx = cs.picture->tileMap->getTileIdxMap( pos );
+#endif
     bool                leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
     bool                aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
 
@@ -301,7 +305,11 @@ void CABACReader::sao( CodingStructure& cs, unsigned ctuRsAddr )
 
   RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__SAO );
 
+#if JVET_N0857_TILES_BRICKS
+  const unsigned  curTileIdx  = cs.picture->brickMap->getBrickIdxRsMap( pos );
+#else
   const unsigned  curTileIdx  = cs.picture->tileMap->getTileIdxMap( pos );
+#endif
   if( cs.getCURestricted( pos.offset(-(int)cs.pcv->maxCUWidth, 0), curSliceIdx, curTileIdx, CH_L ) )
   {
     // sao_merge_left_flag
@@ -583,7 +591,11 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU
 
   partitioner.setCUData( cu );
   cu.slice   = cs.slice;
+#if JVET_N0857_TILES_BRICKS
+  cu.tileIdx = cs.picture->brickMap->getBrickIdxRsMap( currArea.lumaPos() );
+#else
   cu.tileIdx = cs.picture->tileMap->getTileIdxMap( currArea.lumaPos() );
+#endif
 
   // Predict QP on start of quantization group
   if( cuCtx.qgStart )
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index 7c8a32853d7f64db9cde51d7efac749d7180ab51..8308a1fdbe4f9b691cd41f38ae7ee2de7bd43dd3 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -1247,15 +1247,24 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl
 
   // When decoding the slice header, the stored start and end addresses were actually RS addresses, not TS addresses.
   // Now, having set up the maps, convert them to the correct form.
+#if JVET_N0857_TILES_BRICKS
+  const BrickMap& tileMap = *(m_pcPic->brickMap);
+#else
   const TileMap& tileMap = *(m_pcPic->tileMap);
+#endif
 #if HEVC_DEPENDENT_SLICES
   pcSlice->setSliceSegmentCurStartCtuTsAddr( tileMap.getCtuRsToTsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr()) );
   pcSlice->setSliceSegmentCurEndCtuTsAddr( tileMap.getCtuRsToTsAddrMap(pcSlice->getSliceSegmentCurEndCtuTsAddr()) );
   if(!pcSlice->getDependentSliceSegmentFlag())
   {
 #endif
+#if JVET_N0857_TILES_BRICKS
+    pcSlice->setSliceCurStartCtuTsAddr( tileMap.getCtuRsToBsAddrMap(pcSlice->getSliceCurStartCtuTsAddr()) );
+    pcSlice->setSliceCurEndCtuTsAddr( tileMap.getCtuRsToBsAddrMap(pcSlice->getSliceCurEndCtuTsAddr()) );
+#else
     pcSlice->setSliceCurStartCtuTsAddr( tileMap.getCtuRsToTsAddrMap(pcSlice->getSliceCurStartCtuTsAddr()) );
     pcSlice->setSliceCurEndCtuTsAddr( tileMap.getCtuRsToTsAddrMap(pcSlice->getSliceCurEndCtuTsAddr()) );
+#endif
 #if HEVC_DEPENDENT_SLICES
   }
 #endif
diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp
index f094bceb72c03b51736938605b64419cfce9a690..8c2e86b3c4a75da81dea64d773d1abab351ca50b 100644
--- a/source/Lib/DecoderLib/DecSlice.cpp
+++ b/source/Lib/DecoderLib/DecSlice.cpp
@@ -77,7 +77,11 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
 
   const SPS*     sps          = slice->getSPS();
   Picture*       pic          = slice->getPic();
+#if JVET_N0857_TILES_BRICKS
+  const BrickMap& tileMap     = *pic->brickMap;
+#else
   const TileMap& tileMap      = *pic->tileMap;
+#endif
   CABACReader&   cabacReader  = *m_CABACDecoder->getCABACReader( 0 );
 
   // setup coding structure
@@ -123,8 +127,13 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
 #endif
 #if HEVC_DEPENDENT_SLICES
   const int       startCtuRsAddr          = startCtuTsAddr;
+#else
+#if JVET_N0857_TILES_BRICKS
+  const int       startCtuRsAddr          = tileMap.getCtuBsToRsAddrMap(startCtuTsAddr);
 #else
   const int       startCtuRsAddr          = tileMap.getCtuTsToRsAddrMap(startCtuTsAddr);
+#endif
+
 #endif
   const unsigned  numCtusInFrame          = cs.pcv->sizeInCtus;
   const unsigned  widthInCtus             = cs.pcv->widthInCtus;
@@ -177,8 +186,13 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
   bool isLastCtuOfSliceSegment = false;
   for( unsigned ctuTsAddr = startCtuTsAddr; !isLastCtuOfSliceSegment && ctuTsAddr < numCtusInFrame; ctuTsAddr++ )
   {
+#if JVET_N0857_TILES_BRICKS
+    const unsigned  ctuRsAddr             = tileMap.getCtuBsToRsAddrMap(ctuTsAddr);
+    const Brick&  currentTile             = tileMap.bricks[ tileMap.getBrickIdxRsMap(ctuRsAddr) ];
+#else
     const unsigned  ctuRsAddr             = tileMap.getCtuTsToRsAddrMap(ctuTsAddr);
     const Tile&     currentTile           = tileMap.tiles[ tileMap.getTileIdxMap(ctuRsAddr) ];
+#endif
     const unsigned  firstCtuRsAddrOfTile  = currentTile.getFirstCtuRsAddr();
     const unsigned  tileXPosInCtus        = firstCtuRsAddrOfTile % widthInCtus;
     const unsigned  tileYPosInCtus        = firstCtuRsAddrOfTile / widthInCtus;
@@ -209,7 +223,11 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
       {
         cabacReader.initCtxModels( *slice );
       }
+#if JVET_N0857_TILES_BRICKS
+      if( cs.getCURestricted( pos.offset(maxCUSize, -1), slice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) )
+#else
       if( cs.getCURestricted( pos.offset(maxCUSize, -1), slice->getIndependentSliceIdx(), tileMap.getTileIdxMap( pos ), CH_L ) )
+#endif
       {
         // Top-right is available, so use it.
         cabacReader.getCtx() = m_entropyCodingSyncContextState;
@@ -268,8 +286,13 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
       slice->setSliceSegmentCurEndCtuTsAddr( ctuTsAddr+1 );
 #endif
     }
+#if JVET_N0857_TILES_BRICKS
+    else if( ( ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getWidthInCtus () ) &&
+             ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getHeightInCtus() || wavefrontsEnabled ) )
+#else
     else if( ( ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getTileWidthInCtus () ) &&
              ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getTileHeightInCtus() || wavefrontsEnabled ) )
+#endif
     {
       // The sub-stream/stream should be terminated after this CTU.
       // (end of slice-segment, end of tile, end of wavefront-CTU-row)
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 6cff2f0ea5d4249c34ada2b0efb9f3ebf30936dd..9b9a57caf38ce533101b5d8ba8548a3fb6718c6b 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -452,26 +452,33 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS )
 
   READ_FLAG( uiCode, "transquant_bypass_enabled_flag");
   pcPPS->setTransquantBypassEnabledFlag(uiCode ? true : false);
-  READ_FLAG( uiCode, "tiles_enabled_flag" );    pcPPS->setTilesEnabledFlag( uiCode == 1 );
-  READ_FLAG( uiCode, "entropy_coding_sync_enabled_flag" );    pcPPS->setEntropyCodingSyncEnabledFlag( uiCode == 1 );
+  
+#if JVET_N0857_TILES_BRICKS
+  READ_FLAG( uiCode, "single_tile_in_pic_flag" );                 pcPPS->setSingleTileInPicFlag(uiCode == 1);
 
-  if( pcPPS->getTilesEnabledFlag() )
+  if(!pcPPS->getSingleTileInPicFlag())
   {
-    READ_UVLC ( uiCode, "num_tile_columns_minus1" );                pcPPS->setNumTileColumnsMinus1( uiCode );
-    READ_UVLC ( uiCode, "num_tile_rows_minus1" );                   pcPPS->setNumTileRowsMinus1( uiCode );
-    READ_FLAG ( uiCode, "uniform_spacing_flag" );                   pcPPS->setTileUniformSpacingFlag( uiCode == 1 );
+    READ_FLAG ( uiCode, "uniform_tile_spacing_flag" );            pcPPS->setUniformTileSpacingFlag( uiCode == 1 );
+    if (pcPPS->getUniformTileSpacingFlag())
+    {
+      READ_UVLC ( uiCode, "tile_cols_width_minus1" );               pcPPS->setTileColsWidthMinus1( uiCode );
+      READ_UVLC ( uiCode, "tile_rows_height_minus1" );              pcPPS->setTileRowsHeightMinus1( uiCode );
+    }
+    else
+    {
+      READ_UVLC ( uiCode, "num_tile_columns_minus1" );                pcPPS->setNumTileColumnsMinus1( uiCode );
+      READ_UVLC ( uiCode, "num_tile_rows_minus1" );                   pcPPS->setNumTileRowsMinus1( uiCode );
 
-    const uint32_t tileColumnsMinus1 = pcPPS->getNumTileColumnsMinus1();
-    const uint32_t tileRowsMinus1    = pcPPS->getNumTileRowsMinus1();
+      const int tileColumnsMinus1 = pcPPS->getNumTileColumnsMinus1();
+      const int tileRowsMinus1    = pcPPS->getNumTileRowsMinus1();
+      CHECK( ((tileColumnsMinus1 + 1) * (tileColumnsMinus1 + 1)) < 2, "tile colums * rows must be > 1 when explicitly signalled.");
 
-    if ( !pcPPS->getTileUniformSpacingFlag())
-    {
       if (tileColumnsMinus1 > 0)
       {
         std::vector<int> columnWidth(tileColumnsMinus1);
-        for(uint32_t i = 0; i < tileColumnsMinus1; i++)
+        for(int i = 0; i < tileColumnsMinus1; i++)
         {
-          READ_UVLC( uiCode, "column_width_minus1" );
+          READ_UVLC( uiCode, "tile_column_width_minus1" );
           columnWidth[i] = uiCode+1;
         }
         pcPPS->setTileColumnWidth(columnWidth);
@@ -480,18 +487,175 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS )
       if (tileRowsMinus1 > 0)
       {
         std::vector<int> rowHeight (tileRowsMinus1);
-        for(uint32_t i = 0; i < tileRowsMinus1; i++)
+        for(int i = 0; i < tileRowsMinus1; i++)
+        {
+          READ_UVLC( uiCode, "tile_row_height_minus1" );
+          rowHeight[i] = uiCode + 1;
+        }
+        pcPPS->setTileRowHeight(rowHeight);
+      }
+      CHECK( ( tileColumnsMinus1 + tileRowsMinus1 ) == 0, "Invalid tile configuration" );
+    }
+
+    READ_FLAG( uiCode, "brick_splitting_present_flag" );                 pcPPS->setBrickSplittingPresentFlag(uiCode == 1);
+
+    int numTilesInPic = pcPPS->getUniformTileSpacingFlag() ? 0 : (pcPPS->getNumTileColumnsMinus1() + 1) * (pcPPS->getNumTileRowsMinus1() + 1);
+
+    if (pcPPS->getBrickSplittingPresentFlag())
+    {
+      std::vector<bool> brickSplitFlag (numTilesInPic);
+      std::vector<bool> uniformBrickSpacingFlag (numTilesInPic);
+      std::vector<int>  brickHeightMinus1 (numTilesInPic);
+      std::vector<int>  numBrickRowsMinus1 (numTilesInPic);
+      std::vector<std::vector<int>>  brickRowHeightMinus1 (numTilesInPic);
+      for( int i = 0; i < numTilesInPic; i++ )
+      {
+        READ_FLAG( uiCode, "brick_split_flag [i]" );
+        brickSplitFlag[i] = (uiCode == 1);
+
+        if( brickSplitFlag[i] )
+        {
+          READ_FLAG( uiCode, "uniform_brick_spacing_flag [i]" );
+          uniformBrickSpacingFlag[i] = (uiCode == 1);
+          if( uniformBrickSpacingFlag[i] )
+          {
+            READ_UVLC( uiCode, "brick_height_minus1" );
+            brickHeightMinus1[i] = uiCode;
+          }
+          else
+          {
+            READ_UVLC( uiCode, "num_brick_rows_minus1 [i]" );
+            numBrickRowsMinus1[i] = uiCode;
+            for(int j = 0; j < numBrickRowsMinus1[i]; j++ )
+            {
+              brickRowHeightMinus1[i].resize(numBrickRowsMinus1[i]);
+              READ_UVLC( uiCode, "brick_row_height_minus1 [i][j]" );
+              brickRowHeightMinus1[i][j]=uiCode;
+            }
+          }
+        }
+      }
+      pcPPS->setBrickSplitFlag(brickSplitFlag);
+      pcPPS->setUniformBrickSpacingFlag(uniformBrickSpacingFlag);
+      pcPPS->setBrickHeightMinus1(brickHeightMinus1);
+      pcPPS->setNumBrickRowsMinus1(numBrickRowsMinus1);
+      pcPPS->setBrickRowHeightMinus1(brickRowHeightMinus1);
+    }
+    READ_FLAG (uiCode, "single_brick_per_slice_flag" );         pcPPS->setSingleBrickPerSliceFlag(uiCode == 1);
+    if (!pcPPS->getSingleBrickPerSliceFlag())
+    {
+      READ_FLAG( uiCode, "rect_slice_flag" );                  pcPPS->setRectSliceFlag(uiCode == 1);
+    }
+    else
+    {
+      pcPPS->setRectSliceFlag(true);
+    }
+
+    if(pcPPS->getRectSliceFlag() && !pcPPS->getSingleBrickPerSliceFlag())
+    {
+      READ_UVLC (uiCode, "num_slices_in_pic_minus1" );          pcPPS->setNumSlicesInPicMinus1(uiCode);
+      const uint32_t tileColumnsMinus1 = pcPPS->getNumTileColumnsMinus1();
+      const uint32_t tileRowsMinus1 = pcPPS->getNumTileRowsMinus1();
+      const uint32_t numSlicesInPic = pcPPS->getNumSlicesInPicMinus1() + 1;
+      const uint32_t numTilesInPic = (tileColumnsMinus1 + 1) * (tileRowsMinus1 + 1);
+      int codeLength = (int)ceil(log2(numTilesInPic));
+      if (numSlicesInPic > 0)
+      {
+        std::vector<int> topLeft(numSlicesInPic);
+        std::vector<int> bottomRight(numSlicesInPic);
+        topLeft[0] = 0;
+        for (uint32_t i = 0; i < numSlicesInPic; i++)
+        {
+          if (i > 0)
+          {
+            READ_CODE( codeLength, uiCode, "top_left_brick_idx" );
+            topLeft[i] = uiCode;
+          }
+          READ_CODE( codeLength, uiCode, "bottom_right_brick_idx_delta" );
+          bottomRight[i] = topLeft[i] + uiCode;
+        }
+        pcPPS->setTopLeftTileIdx(topLeft);
+        pcPPS->setBottomRightTileIdx(bottomRight);
+      }
+    }
+
+    READ_FLAG( uiCode, "loop_filter_across_bricks_enabled_flag ");        pcPPS->setLoopFilterAcrossBricksEnabledFlag(uiCode ? true : false);
+    if (pcPPS->getLoopFilterAcrossBricksEnabledFlag())
+    {
+      READ_FLAG( uiCode, "loop_filter_across_slices_enabled_flag" );      pcPPS->setLoopFilterAcrossSlicesEnabledFlag(uiCode == 1);
+    }
+  }
+  else
+  {
+    pcPPS->setRectSliceFlag(true);
+  }
+
+  if (pcPPS->getRectSliceFlag())
+  {
+    READ_FLAG( uiCode, "signalled_slice_id_flag ");                        pcPPS->setSignalledSliceIdFlag(uiCode == 1);
+    if (pcPPS->getSignalledSliceIdFlag())
+    {
+      READ_UVLC( uiCode, "signalled_slice_id_length_minus1" );             pcPPS->setSignalledSliceIdLengthMinus1(uiCode);
+      const uint32_t numTileGroups = pcPPS->getNumSlicesInPicMinus1() + 1;
+      int codeLength = pcPPS->getSignalledSliceIdLengthMinus1() + 1;
+      if (numTileGroups > 0)
+      {
+        std::vector<int> tileGroupID(numTileGroups);
+        for (uint32_t i = 0; i < numTileGroups; i++)
+        {
+          READ_CODE( codeLength, uiCode, "slice_id" );
+          tileGroupID[i] = uiCode;
+        }
+        pcPPS->setSliceId(tileGroupID);
+      }
+    }
+  }
+#endif
+
+#if !JVET_N0857_TILES_BRICKS
+  READ_FLAG(uiCode, "tiles_enabled_flag");                       pcPPS->setTilesEnabledFlag(uiCode == 1);
+
+  if (pcPPS->getTilesEnabledFlag())
+  {
+    READ_UVLC(uiCode, "num_tile_columns_minus1");                pcPPS->setNumTileColumnsMinus1(uiCode);
+    READ_UVLC(uiCode, "num_tile_rows_minus1");                   pcPPS->setNumTileRowsMinus1(uiCode);
+    READ_FLAG(uiCode, "uniform_spacing_flag");                   pcPPS->setUniformTileSpacingFlag(uiCode == 1);
+
+    const uint32_t tileColumnsMinus1 = pcPPS->getNumTileColumnsMinus1();
+    const uint32_t tileRowsMinus1 = pcPPS->getNumTileRowsMinus1();
+
+    if (!pcPPS->getUniformTileSpacingFlag())
+    {
+      if (tileColumnsMinus1 > 0)
+      {
+        std::vector<int> columnWidth(tileColumnsMinus1);
+        for (uint32_t i = 0; i < tileColumnsMinus1; i++)
         {
-          READ_UVLC( uiCode, "row_height_minus1" );
+          READ_UVLC(uiCode, "column_width_minus1");
+          columnWidth[i] = uiCode + 1;
+        }
+        pcPPS->setTileColumnWidth(columnWidth);
+      }
+
+      if (tileRowsMinus1 > 0)
+      {
+        std::vector<int> rowHeight(tileRowsMinus1);
+        for (uint32_t i = 0; i < tileRowsMinus1; i++)
+        {
+          READ_UVLC(uiCode, "row_height_minus1");
           rowHeight[i] = uiCode + 1;
         }
         pcPPS->setTileRowHeight(rowHeight);
       }
     }
     CHECK((tileColumnsMinus1 + tileRowsMinus1) == 0, "Invalid tile configuration");
-    READ_FLAG ( uiCode, "loop_filter_across_tiles_enabled_flag" );     pcPPS->setLoopFilterAcrossTilesEnabledFlag( uiCode ? true : false );
+    READ_FLAG ( uiCode, "loop_filter_across_tiles_enabled_flag" );     pcPPS->setLoopFilterAcrossBricksEnabledFlag( uiCode ? true : false );
   }
+ 
   READ_FLAG( uiCode, "pps_loop_filter_across_slices_enabled_flag" );   pcPPS->setLoopFilterAcrossSlicesEnabledFlag( uiCode ? true : false );
+#endif
+  READ_FLAG(uiCode, "entropy_coding_sync_enabled_flag");         pcPPS->setEntropyCodingSyncEnabledFlag(uiCode == 1);
+
   READ_FLAG( uiCode, "deblocking_filter_control_present_flag" );       pcPPS->setDeblockingFilterControlPresentFlag( uiCode ? true : false );
   if(pcPPS->getDeblockingFilterControlPresentFlag())
   {
@@ -2215,7 +2379,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
 
 
   std::vector<uint32_t> entryPointOffset;
+#if JVET_N0857_TILES_BRICKS
+  if( !pps->getSingleTileInPicFlag() || pps->getEntropyCodingSyncEnabledFlag() )
+#else
   if( pps->getTilesEnabledFlag() || pps->getEntropyCodingSyncEnabledFlag() )
+#endif
   {
     uint32_t numEntryPointOffsets;
     uint32_t offsetLenMinus1;
@@ -2240,7 +2408,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
 
   pcSlice->clearSubstreamSizes();
 
+#if !JVET_N0857_TILES_BRICKS
   if( pps->getTilesEnabledFlag() || pps->getEntropyCodingSyncEnabledFlag() )
+#else
+  if( !pps->getSingleTileInPicFlag() || pps->getEntropyCodingSyncEnabledFlag() )
+#endif
   {
     int endOfSliceHeaderLocation = m_pcBitstream->getByteLocation();
 
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index e3878da068e8c27d3193d47ea2f40023d8804a0e..7bc3cfb5b1229d8a03d7d43d76084fe1a0ecbb6c 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -241,7 +241,11 @@ void CABACWriter::sao( const Slice& slice, unsigned ctuRsAddr )
   int                 rx                      = ctuRsAddr - ry * frame_width_in_ctus;
   const Position      pos                     ( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight );
   const unsigned      curSliceIdx             = slice.getIndependentSliceIdx();
+#if JVET_N0857_TILES_BRICKS
+  const unsigned      curTileIdx              = cs.picture->brickMap->getBrickIdxRsMap( pos );
+#else
   const unsigned      curTileIdx              = cs.picture->tileMap->getTileIdxMap( pos );
+#endif
   bool                leftMergeAvail          = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0  ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
   bool                aboveMergeAvail         = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
   sao_block_pars( sao_ctu_pars, sps.getBitDepths(), sliceEnabled, leftMergeAvail, aboveMergeAvail, false );
@@ -1453,8 +1457,12 @@ void CABACWriter::sbt_mode( const CodingUnit& cu )
 void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx )
 {
   const Slice*  slice             = cu.cs->slice;
+#if JVET_N0857_TILES_BRICKS
+  const int     currentCTUTsAddr  = cu.cs->picture->brickMap->getCtuRsToBsAddrMap( CU::getCtuAddr( cu ) );
+#else
   const TileMap& tileMap          = *cu.cs->picture->tileMap;
   const int     currentCTUTsAddr  = tileMap.getCtuRsToTsAddrMap( CU::getCtuAddr( cu ) );
+#endif
   const bool    isLastSubCUOfCtu  = CU::isLastSubCUOfCtu( cu );
 
   if ( isLastSubCUOfCtu
@@ -3460,7 +3468,11 @@ void CABACWriter::codeAlfCtuEnableFlag( CodingStructure& cs, uint32_t ctuRsAddr,
     int                 rx = ctuRsAddr - ry * frame_width_in_ctus;
     const Position      pos( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight );
     const uint32_t          curSliceIdx = cs.slice->getIndependentSliceIdx();
+#if JVET_N0857_TILES_BRICKS
+    const uint32_t      curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( pos );
+#else
     const uint32_t          curTileIdx = cs.picture->tileMap->getTileIdxMap( pos );
+#endif
     bool                leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
     bool                aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
 
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 66719184b807852c01cf210beef80d6493b6803c..815077c508e8547efcf4ae1acbbb7c8312fa4026 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -105,6 +105,31 @@ struct GOPEntry
 };
 
 std::istringstream &operator>>(std::istringstream &in, GOPEntry &entry);     //input
+
+#if JVET_N0857_TILES_BRICKS
+struct BrickSplit
+{
+  int     m_tileIdx;
+  bool    m_uniformSplit;
+  int     m_uniformHeight;
+  int     m_numSplits;
+  int     m_brickHeight[MAX_NUM_BRICKS_PER_TILE];
+  BrickSplit()
+    : m_tileIdx(-1)
+    , m_uniformSplit(true)
+    , m_uniformHeight(0)
+    , m_numSplits(0)
+  {
+    ::memset( m_brickHeight, 0, sizeof(m_brickHeight) );
+  }
+};
+
+typedef std::map<int, BrickSplit> BrickSplitMap;
+
+std::istringstream &operator>>(std::istringstream &in, BrickSplit &entry);     //input
+#endif
+
+
 //! \ingroup EncoderLib
 //! \{
 
@@ -418,7 +443,7 @@ protected:
   bool      m_bPCMInputBitDepthFlag;
   bool      m_bPCMFilterDisableFlag;
   bool      m_intraSmoothingDisabledFlag;
-  bool      m_loopFilterAcrossTilesEnabledFlag;
+  bool      m_loopFilterAcrossBricksEnabledFlag;
   bool      m_tileUniformSpacingFlag;
   int       m_iNumColumnsMinus1;
   int       m_iNumRowsMinus1;
@@ -426,6 +451,18 @@ protected:
   std::vector<int> m_tileRowHeight;
 
   bool      m_entropyCodingSyncEnabledFlag;
+ 
+#if JVET_N0857_TILES_BRICKS
+  bool      m_rectSliceFlag;
+  int       m_numSlicesInPicMinus1;
+  std::vector<int> m_topLeftTileIdx;
+  std::vector<int> m_bottomRightTileIdx;
+  bool      m_loopFilterAcrossSlicesEnabledFlag;
+  bool      m_signalledSliceIdFlag;
+  int       m_signalledSliceIdLengthMinus1;
+  std::vector<int> m_sliceId;
+  BrickSplitMap m_brickSplitMap;
+#endif
 
   HashType  m_decodedPictureHashSEIType;
   bool      m_bufferingPeriodSEIEnabled;
@@ -1166,8 +1203,8 @@ public:
   void  setSaoGreedyMergeEnc           (bool val)                    { m_saoGreedyMergeEnc = val; }
   bool  getSaoGreedyMergeEnc           ()                            { return m_saoGreedyMergeEnc; }
 #endif
-  void  setLFCrossTileBoundaryFlag               ( bool   val  )     { m_loopFilterAcrossTilesEnabledFlag = val; }
-  bool  getLFCrossTileBoundaryFlag               ()                  { return m_loopFilterAcrossTilesEnabledFlag;   }
+  void  setLFCrossTileBoundaryFlag               ( bool   val  )     { m_loopFilterAcrossBricksEnabledFlag = val; }
+  bool  getLFCrossTileBoundaryFlag               ()                  { return m_loopFilterAcrossBricksEnabledFlag;   }
   void  setTileUniformSpacingFlag      ( bool b )                    { m_tileUniformSpacingFlag = b; }
   bool  getTileUniformSpacingFlag      ()                            { return m_tileUniformSpacingFlag; }
   void  setNumColumnsMinus1            ( int i )                     { m_iNumColumnsMinus1 = i; }
@@ -1178,6 +1215,28 @@ public:
   int   getNumRowsMinus1               ()                            { return m_iNumRowsMinus1; }
   void  setRowHeight ( const std::vector<int>& rowHeight)            { m_tileRowHeight = rowHeight; }
   uint32_t  getRowHeight                   ( uint32_t rowIdx )               { return m_tileRowHeight[rowIdx]; }
+
+#if JVET_N0857_TILES_BRICKS
+  bool  getRectSliceFlag() const                                     { return m_rectSliceFlag; }
+  void  setRectSliceFlag(bool val)                                   { m_rectSliceFlag = val; }
+  int   getNumSlicesInPicMinus1() const                              { return m_numSlicesInPicMinus1; }
+  void  setNumSlicesInPicMinus1(int val)                             { m_numSlicesInPicMinus1 = val; }
+  int   getTopLeftTileIdx(uint32_t columnIdx) const                  { return  m_topLeftTileIdx[columnIdx]; }
+  void  setTopLeftTileIdx(const std::vector<int>& val)               { m_topLeftTileIdx = val; }
+  int   getBottomeRightTileIdx(uint32_t columnIdx) const             { return  m_bottomRightTileIdx[columnIdx]; }
+  void  setBottomRightTileIdx(const std::vector<int>& val)           { m_bottomRightTileIdx = val; }
+  bool  getLoopFilterAcrossSlicesEnabledFlag() const                 { return m_loopFilterAcrossSlicesEnabledFlag; }
+  void  setLoopFilterAcrossSlicesEnabledFlag(bool val)               { m_loopFilterAcrossSlicesEnabledFlag = val; }
+  bool  getSignalledSliceIdFlag() const                              { return m_signalledSliceIdFlag; }
+  void  setSignalledSliceIdFlag(bool val)                            { m_signalledSliceIdFlag = val; }
+  int   getSignalledSliceIdLengthMinus1() const                      { return m_signalledSliceIdLengthMinus1; }
+  void  setSignalledSliceIdLengthMinus1(int val)                     { m_signalledSliceIdLengthMinus1 = val; }
+  int   getSliceId(uint32_t columnIdx) const                         { return  m_sliceId[columnIdx]; }
+  void  setSliceId(const std::vector<int>& val)                      { m_sliceId = val; }
+  BrickSplitMap getBrickSplitMap() const                             { return  m_brickSplitMap; }
+  void  setBrickSplitMap(const BrickSplitMap& val)                   { m_brickSplitMap = val; }
+#endif
+
   void  xCheckGSParameters();
   void  setEntropyCodingSyncEnabledFlag(bool b)                      { m_entropyCodingSyncEnabledFlag = b; }
   bool  getEntropyCodingSyncEnabledFlag() const                      { return m_entropyCodingSyncEnabledFlag; }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 05a7d018dc1e7829ded70a5f93095de4254df5b1..c9e6a0afb64fbb6e6d096d03f35c0181bd5bccde 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -1321,6 +1321,13 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS,
   // The exception is each slice / slice-segment must have at least one CTU.
   if (bestCS->cost != MAX_DOUBLE)
   {
+#if JVET_N0857_TILES_BRICKS
+    const BrickMap& tileMap = *tempCS->picture->brickMap;
+    const uint32_t CtuAddr  = CU::getCtuAddr( *bestCS->getCU( partitioner.chType ) );
+    const bool isEndOfSlice = slice.getSliceMode() == FIXED_NUMBER_OF_BYTES
+                              && ((slice.getSliceBits() + CS::getEstBits(*bestCS)) > slice.getSliceArgument() << 3)
+                              && CtuAddr != tileMap.getCtuBsToRsAddrMap(slice.getSliceCurStartCtuTsAddr());
+#else
     const TileMap& tileMap = *tempCS->picture->tileMap;
     const uint32_t CtuAddr             = CU::getCtuAddr( *bestCS->getCU( partitioner.chType ) );
     const bool isEndOfSlice        =    slice.getSliceMode() == FIXED_NUMBER_OF_BYTES
@@ -1331,6 +1338,7 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS,
 #else
                                       ;
 #endif
+#endif
 
 #if HEVC_DEPENDENT_SLICES
     const bool isEndOfSliceSegment =    slice.getSliceSegmentMode() == FIXED_NUMBER_OF_BYTES
@@ -1428,7 +1436,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
 
           partitioner.setCUData( cu );
           cu.slice            = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+          cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
           cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
           cu.skip             = false;
           cu.mmvdSkip = false;
           cu.predMode         = MODE_INTRA;
@@ -1697,7 +1709,11 @@ void EncCu::xCheckIntraPCM(CodingStructure *&tempCS, CodingStructure *&bestCS, P
 
   partitioner.setCUData( cu );
   cu.slice            = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+  cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
   cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
   cu.skip             = false;
   cu.mmvdSkip = false;
   cu.predMode         = MODE_INTRA;
@@ -1927,7 +1943,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
     cu.cs       = tempCS;
     cu.predMode = MODE_INTER;
     cu.slice    = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+    cu.tileIdx  = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
     cu.tileIdx  = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
+#endif
 
     PredictionUnit pu( tempCS->area );
     pu.cu = &cu;
@@ -2036,7 +2056,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #endif
       partitioner.setCUData( cu );
       cu.slice            = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+      cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
       cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
       cu.skip             = false;
       cu.mmvdSkip = false;
       cu.triangle         = false;
@@ -2483,7 +2507,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 
       partitioner.setCUData( cu );
       cu.slice            = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+      cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
       cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
       cu.skip             = false;
       cu.mmvdSkip = false;
       cu.triangle         = false;
@@ -2704,7 +2732,11 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
     cu.cs       = tempCS;
     cu.predMode = MODE_INTER;
     cu.slice    = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+    cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
     cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
     cu.triangle = true;
     cu.mmvdSkip = false;
     cu.GBiIdx   = GBI_DEFAULT;
@@ -2760,7 +2792,11 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
 
     partitioner.setCUData( cu );
     cu.slice            = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+    cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
     cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
     cu.skip             = false;
     cu.predMode         = MODE_INTER;
     cu.transQuantBypass = encTestMode.lossless;
@@ -2892,7 +2928,11 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
 
         partitioner.setCUData(cu);
         cu.slice = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+        cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
         cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
         cu.skip = false;
         cu.predMode = MODE_INTER;
         cu.transQuantBypass = encTestMode.lossless;
@@ -2981,7 +3021,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
     cu.cs = tempCS;
     cu.predMode = MODE_INTER;
     cu.slice = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+    cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
     cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
     cu.mmvdSkip = false;
 
     PredictionUnit pu( tempCS->area );
@@ -3038,7 +3082,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
 
       partitioner.setCUData( cu );
       cu.slice = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+      cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
       cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
       cu.skip = false;
       cu.affine = true;
       cu.predMode = MODE_INTER;
@@ -3155,7 +3203,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
 
       partitioner.setCUData( cu );
       cu.slice = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+      cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
       cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
       cu.skip = false;
       cu.affine = true;
       cu.predMode = MODE_INTER;
@@ -3281,7 +3333,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     cu.cs = tempCS;
     cu.predMode = MODE_IBC;
     cu.slice = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+    cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
     cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
+#endif
     PredictionUnit pu(tempCS->area);
     pu.cu = &cu;
     pu.cs = tempCS;
@@ -3320,7 +3376,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
 
       partitioner.setCUData(cu);
       cu.slice = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+      cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
       cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
+#endif
       cu.skip = false;
       cu.predMode = MODE_IBC;
       cu.transQuantBypass = encTestMode.lossless;
@@ -3443,7 +3503,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
 
             partitioner.setCUData(cu);
             cu.slice = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+            cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
             cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
+#endif
             cu.skip = false;
             cu.predMode = MODE_IBC;
             cu.transQuantBypass = encTestMode.lossless;
@@ -3529,7 +3593,11 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
 
     partitioner.setCUData(cu);
     cu.slice = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+    cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
     cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
+#endif
     cu.skip = false;
     cu.predMode = MODE_IBC;
     cu.transQuantBypass = encTestMode.lossless;
@@ -3732,7 +3800,11 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC
 
   partitioner.setCUData( cu );
   cu.slice            = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+  cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
   cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
   cu.skip             = false;
   cu.mmvdSkip = false;
 //cu.affine
@@ -3869,7 +3941,11 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be
 
   partitioner.setCUData( cu );
   cu.slice            = tempCS->slice;
+#if JVET_N0857_TILES_BRICKS
+  cu.tileIdx          = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() );
+#else
   cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
   cu.skip             = false;
   cu.mmvdSkip = false;
 //cu.affine
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index 4a4cb0f499534c09cb5e7a70613b263636b33612..104e3ed02d205da0c77a7ee9172d0f979b0251fb 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -2173,7 +2173,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
     const uint32_t numberOfCtusInFrame = pcPic->cs->pcv->sizeInCtus;
     const int numSubstreamsColumns = (pcSlice->getPPS()->getNumTileColumnsMinus1() + 1);
     const int numSubstreamRows     = pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag() ? pcPic->cs->pcv->heightInCtus : (pcSlice->getPPS()->getNumTileRowsMinus1() + 1);
+#if JVET_N0857_TILES_BRICKS
+    const int numSubstreams        = std::max<int> (numSubstreamRows * numSubstreamsColumns, (int) pcPic->brickMap->bricks.size());
+#else
     const int numSubstreams        = numSubstreamRows * numSubstreamsColumns;
+#endif
     std::vector<OutputBitstream> substreamsOut(numSubstreams);
 
 #if ENABLE_QPA
@@ -2679,11 +2683,15 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
 
           // Append substreams...
           OutputBitstream *pcOut = pcBitstreamRedirect;
+#if JVET_N0857_TILES_BRICKS
+          const int numZeroSubstreamsAtStartOfSlice  = pcPic->brickMap->getSubstreamForCtuAddr(pcSlice->getSliceCurStartCtuTsAddr(), false, pcSlice);
+#else
 #if HEVC_DEPENDENT_SLICES
 
           const int numZeroSubstreamsAtStartOfSlice = pcPic->tileMap->getSubstreamForCtuAddr(pcSlice->getSliceSegmentCurStartCtuTsAddr(), false, pcSlice);
 #else
           const int numZeroSubstreamsAtStartOfSlice  = pcPic->tileMap->getSubstreamForCtuAddr(pcSlice->getSliceCurStartCtuTsAddr(), false, pcSlice);
+#endif
 #endif
           const int numSubstreamsToCode  = pcSlice->getNumberOfSubstreamSizes()+1;
           for ( uint32_t ui = 0 ; ui < numSubstreamsToCode; ui++ )
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index b30103a4983739af61ad583e22112e1314793158..f4532e2bb57ec71620eddacf1cff94c061624700 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1480,7 +1480,13 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps)
   }
 
   pps.setEntropyCodingSyncEnabledFlag( m_entropyCodingSyncEnabledFlag );
+
+#if JVET_N0857_TILES_BRICKS
+  pps.setSingleTileInPicFlag((m_iNumColumnsMinus1 == 0 && m_iNumRowsMinus1 == 0));
+#else
   pps.setTilesEnabledFlag( (m_iNumColumnsMinus1 > 0 || m_iNumRowsMinus1 > 0) );
+#endif
+
   pps.setUseWP( m_useWeightedPred );
   pps.setWPBiPred( m_useWeightedBiPred );
   pps.setOutputFlagPresentFlag( false );
@@ -1870,7 +1876,22 @@ int EncLib::getReferencePictureSetIdxForSOP(int POCCurr, int GOPid )
 
 void  EncLib::xInitPPSforTiles(PPS &pps)
 {
-  pps.setTileUniformSpacingFlag( m_tileUniformSpacingFlag );
+#if JVET_N0857_TILES_BRICKS
+  if ( (m_iNumColumnsMinus1==0) && (m_iNumRowsMinus1==0) )
+  {
+    // one, no bricks
+    pps.setSingleTileInPicFlag(true);
+    pps.setSingleBrickPerSliceFlag(true);
+    pps.setRectSliceFlag(true);
+  }
+  else
+  {
+    pps.setSingleTileInPicFlag(false);
+    pps.setSingleBrickPerSliceFlag( m_sliceMode==SINGLE_BRICK_PER_SLICE );
+    pps.setRectSliceFlag( m_sliceMode==SINGLE_BRICK_PER_SLICE );
+  }
+#endif
+  pps.setUniformTileSpacingFlag( m_tileUniformSpacingFlag );
   pps.setNumTileColumnsMinus1( m_iNumColumnsMinus1 );
   pps.setNumTileRowsMinus1( m_iNumRowsMinus1 );
   if( !m_tileUniformSpacingFlag )
@@ -1878,9 +1899,114 @@ void  EncLib::xInitPPSforTiles(PPS &pps)
     pps.setTileColumnWidth( m_tileColumnWidth );
     pps.setTileRowHeight( m_tileRowHeight );
   }
-  pps.setLoopFilterAcrossTilesEnabledFlag( m_loopFilterAcrossTilesEnabledFlag );
+  pps.setLoopFilterAcrossBricksEnabledFlag( m_loopFilterAcrossBricksEnabledFlag );
+
+#if JVET_N0857_TILES_BRICKS
+  //pps.setRectSliceFlag( m_rectSliceFlag );
+  pps.setNumSlicesInPicMinus1( m_numSlicesInPicMinus1 );
+  pps.setTopLeftTileIdx( m_topLeftTileIdx );
+  pps.setBottomRightTileIdx( m_bottomRightTileIdx );
+  pps.setLoopFilterAcrossBricksEnabledFlag( m_loopFilterAcrossBricksEnabledFlag );
+  pps.setLoopFilterAcrossSlicesEnabledFlag( m_loopFilterAcrossSlicesEnabledFlag );
+  pps.setSignalledSliceIdFlag( m_signalledSliceIdFlag );
+  pps.setSignalledSliceIdLengthMinus1( m_signalledSliceIdLengthMinus1 );
+  pps.setSignalledSliceIdFlag( m_signalledSliceIdFlag );
+  pps.setSignalledSliceIdLengthMinus1( m_signalledSliceIdLengthMinus1 );
+  pps.setSliceId( m_sliceId );
+
+  int numTiles= (m_iNumColumnsMinus1 + 1) * (m_iNumRowsMinus1 + 1);
+  
+  if (m_brickSplitMap.empty())
+  {
+    pps.setBrickSplittingPresentFlag(false);
+  }
+  else
+  {
+    pps.setBrickSplittingPresentFlag(true);
+
+    std::vector<bool> brickSplitFlag (numTiles, false);
+    std::vector<bool> uniformBrickSpacingFlag (numTiles, false);
+    std::vector<int>  brickHeightMinus1 (numTiles, 0);
+    std::vector<int>  numBrickRowsMinus1 (numTiles, 0);
+    std::vector<std::vector<int>>  brickRowHeightMinus1 (numTiles);
+
+    for (auto &brickSplit: m_brickSplitMap)
+    {
+      int tileIdx = brickSplit.first;
+      CHECK ( tileIdx >= numTiles, "Brick split specified for undefined tile");
+
+      brickSplitFlag[tileIdx]           = true;
+      uniformBrickSpacingFlag [tileIdx] = brickSplit.second.m_uniformSplit;
+      if (uniformBrickSpacingFlag [tileIdx])
+      {
+        brickHeightMinus1[tileIdx]=brickSplit.second.m_uniformHeight - 1;
+      }
+      else
+      {
+        numBrickRowsMinus1[tileIdx]=brickSplit.second.m_numSplits;
+        brickRowHeightMinus1[tileIdx].resize(brickSplit.second.m_numSplits);
+        for (int i=0; i<brickSplit.second.m_numSplits; i++)
+        {
+          brickRowHeightMinus1[tileIdx][i]=brickSplit.second.m_brickHeight[i] - 1;
+        }
+      }
+    }
+    pps.setBrickSplitFlag(brickSplitFlag);
+    pps.setUniformBrickSpacingFlag(uniformBrickSpacingFlag);
+    pps.setBrickHeightMinus1(brickHeightMinus1);
+    pps.setNumBrickRowsMinus1(numBrickRowsMinus1);
+    pps.setBrickRowHeightMinus1(brickRowHeightMinus1);
+
+    // check brick dimensions
+    std::vector<uint32_t> tileRowHeight (m_iNumRowsMinus1+1);
+    int picHeightInCtus = (getSourceHeight() + m_maxCUHeight - 1) / m_maxCUHeight;
+
+    // calculate all tile row heights
+    if( pps.getUniformTileSpacingFlag() )
+    {
+      //set width and height for each (uniform) tile
+      for(int row=0; row < m_iNumRowsMinus1 + 1; row++)
+      {
+        tileRowHeight[row] = (row+1)*picHeightInCtus/(m_iNumRowsMinus1+1)   - (row*picHeightInCtus)/(m_iNumRowsMinus1 + 1);
+      }
+    }
+    else
+    {
+      tileRowHeight[ m_iNumRowsMinus1 ] = picHeightInCtus;
+      for( int j = 0; j < m_iNumRowsMinus1; j++ ) 
+      {
+        tileRowHeight[ j ] = pps.getTileRowHeight( j );
+        tileRowHeight[ m_iNumRowsMinus1 ]  =  tileRowHeight[ m_iNumRowsMinus1 ] - pps.getTileRowHeight( j );
+      }
+    }
+
+    // check brick splits for each tile
+    for (int tileIdx=0; tileIdx < numTiles; tileIdx++)
+    {
+      if (pps.getBrickSplitFlag(tileIdx))
+      {
+        const int tileY = tileIdx / (m_iNumColumnsMinus1+1);
+
+        int tileHeight = tileRowHeight [tileY];
+
+        if (pps.getUniformBrickSpacingFlag(tileIdx))
+        {
+          CHECK((pps.getBrickHeightMinus1(tileIdx) + 1) >= tileHeight, "Brick height larger than or equal to tile height");
+        }
+        else
+        {
+          int cumulativeHeight=0;
+          for (int i = 0; i < pps.getNumBrickRowsMinus1(tileIdx); i++)
+          {
+            cumulativeHeight += pps.getBrickRowHeightMinus1(tileIdx, i) + 1;
+          }
+          CHECK(cumulativeHeight >= tileHeight, "Cumulative brick height larger than or equal to tile height");
+        }
+      }
+    }
+  }
 
-  // # substreams is "per tile" when tiles are independent.
+#endif
 }
 
 void  EncCfg::xCheckGSParameters()
diff --git a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp
index 1a90c2ec66372cf41527d5c72a9206be4a03e26e..c4b69280bc6a2d5147965015a36cb1ed274a75bf 100644
--- a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp
+++ b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp
@@ -1592,7 +1592,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c
 
 void EncSampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructure& cs, const Position &pos, bool& isLeftAvail, bool& isAboveAvail, bool& isAboveLeftAvail) const
 {
-  bool isLoopFiltAcrossTilePPS = cs.pps->getLoopFilterAcrossTilesEnabledFlag();
+  bool isLoopFiltAcrossTilePPS = cs.pps->getLoopFilterAcrossBricksEnabledFlag();
 
   const int width = cs.pcv->maxCUWidth;
   const int height = cs.pcv->maxCUHeight;
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index be6ec8168ce69b2b1b661db0423d4e27d18172b2..caa1e0ba99ea4bcd90ffca97ade72709cee5e9bd 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -222,8 +222,11 @@ static int getGlaringColorQPOffset (Picture* const pcPic, const int ctuAddr, con
   {
     for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++)
     {
+#if JVET_N0857_TILES_BRICKS
+      const uint32_t ctuRsAddr = pcPic->brickMap->getCtuBsToRsAddrMap (ctuTsAddr);
+#else
       const uint32_t ctuRsAddr = pcPic->tileMap->getCtuTsToRsAddrMap (ctuTsAddr);
-
+#endif
       avgLumaValue += pcPic->m_iOffsetCtu[ctuRsAddr];
     }
     avgLumaValue = (avgLumaValue + ((boundingAddr - startAddr) >> 1)) / (boundingAddr - startAddr);
@@ -869,7 +872,11 @@ static bool applyQPAdaptation (Picture* const pcPic,       Slice* const pcSlice,
 {
   const int  bitDepth    = pcSlice->getSPS()->getBitDepth (CHANNEL_TYPE_LUMA);
   const int  iQPIndex    = pcSlice->getSliceQp(); // initial QP index for current slice, used in following loops
+#if JVET_N0857_TILES_BRICKS
+  const BrickMap& tileMap = *pcPic->brickMap;
+#else
   const TileMap& tileMap = *pcPic->tileMap;
+#endif
   bool   sliceQPModified = false;
   uint32_t   meanLuma    = MAX_UINT;
   double     hpEnerAvg   = 0.0;
@@ -880,7 +887,11 @@ static bool applyQPAdaptation (Picture* const pcPic,       Slice* const pcSlice,
   {
     for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++)
     {
+#if JVET_N0857_TILES_BRICKS
+      const uint32_t ctuRsAddr  = tileMap.getCtuBsToRsAddrMap (ctuTsAddr);
+#else
       const uint32_t ctuRsAddr  = tileMap.getCtuTsToRsAddrMap (ctuTsAddr);
+#endif
       const Position pos ((ctuRsAddr % pcv.widthInCtus) * pcv.maxCUWidth, (ctuRsAddr / pcv.widthInCtus) * pcv.maxCUHeight);
       const CompArea ctuArea    = clipArea (CompArea (COMPONENT_Y, pcPic->chromaFormat, Area (pos.x, pos.y, pcv.maxCUWidth, pcv.maxCUHeight)), pcPic->Y());
       const CompArea fltArea    = clipArea (CompArea (COMPONENT_Y, pcPic->chromaFormat, Area (pos.x > 0 ? pos.x - 1 : 0, pos.y > 0 ? pos.y - 1 : 0, pcv.maxCUWidth + (pos.x > 0 ? 2 : 1), pcv.maxCUHeight + (pos.y > 0 ? 2 : 1))), pcPic->Y());
@@ -927,7 +938,11 @@ static bool applyQPAdaptation (Picture* const pcPic,       Slice* const pcSlice,
 
         for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++)
         {
+#if JVET_N0857_TILES_BRICKS
+          const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr);
+#else
           const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap (ctuTsAddr);
+#endif
 
           meanLuma += pcPic->m_iOffsetCtu[ctuRsAddr];  // CTU mean
         }
@@ -955,7 +970,11 @@ static bool applyQPAdaptation (Picture* const pcPic,       Slice* const pcSlice,
 
     for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++)
     {
+#if JVET_N0857_TILES_BRICKS
+      const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr);
+#else
       const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap (ctuTsAddr);
+#endif
 
       pcPic->m_iOffsetCtu[ctuRsAddr] = (Pel)iQPFixed; // fixed QPs
     }
@@ -964,7 +983,11 @@ static bool applyQPAdaptation (Picture* const pcPic,       Slice* const pcSlice,
   {
     for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++)
     {
+#if JVET_N0857_TILES_BRICKS
+      const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr);
+#else
       const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap (ctuTsAddr);
+#endif
 
       int iQPAdapt = Clip3 (0, MAX_QP, iQPIndex + apprI3Log2 (pcPic->m_uEnerHpCtu[ctuRsAddr] * hpEnerPic));
 
@@ -1296,7 +1319,11 @@ void EncSlice::calCostSliceI(Picture* pcPic) // TODO: this only analyses the fir
 {
   double         iSumHadSlice      = 0;
   Slice * const  pcSlice           = pcPic->slices[getSliceSegmentIdx()];
+#if JVET_N0857_TILES_BRICKS
+  const BrickMap &tileMap          = *pcPic->brickMap;
+#else
   const TileMap &tileMap           = *pcPic->tileMap;
+#endif
   const PreCalcValues& pcv         = *pcPic->cs->pcv;
   const SPS     &sps               = *(pcSlice->getSPS());
   const int      shift             = sps.getBitDepth(CHANNEL_TYPE_LUMA)-8;
@@ -1308,10 +1335,15 @@ void EncSlice::calCostSliceI(Picture* pcPic) // TODO: this only analyses the fir
 
   uint32_t startCtuTsAddr, boundingCtuTsAddr;
   xDetermineStartAndBoundingCtuTsAddr ( startCtuTsAddr, boundingCtuTsAddr, pcPic );
-
+#if JVET_N0857_TILES_BRICKS
+  for( uint32_t ctuTsAddr = startCtuTsAddr, ctuRsAddr = tileMap.getCtuBsToRsAddrMap( startCtuTsAddr);
+       ctuTsAddr < boundingCtuTsAddr;
+       ctuRsAddr = tileMap.getCtuBsToRsAddrMap(++ctuTsAddr) )
+#else
   for( uint32_t ctuTsAddr = startCtuTsAddr, ctuRsAddr = tileMap.getCtuTsToRsAddrMap( startCtuTsAddr);
        ctuTsAddr < boundingCtuTsAddr;
        ctuRsAddr = tileMap.getCtuTsToRsAddrMap(++ctuTsAddr) )
+#endif
   {
     Position pos( (ctuRsAddr % pcv.widthInCtus) * pcv.maxCUWidth, (ctuRsAddr / pcv.widthInCtus) * pcv.maxCUHeight);
 
@@ -1521,7 +1553,11 @@ void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32
   Slice* pcSlice                  = cs.slice;
   const PreCalcValues& pcv        = *cs.pcv;
   const uint32_t    widthInCtus   = pcv.widthInCtus;
+#if JVET_N0857_TILES_BRICKS
+  const BrickMap&  tileMap         = *pcPic->brickMap;
+#else
   const TileMap&  tileMap         = *pcPic->tileMap;
+#endif
   const uint32_t hashThreshold    = 20;
   uint32_t totalCtu               = 0;
   uint32_t hashRatio              = 0;
@@ -1533,7 +1569,11 @@ void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32
 
   for ( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ )
   {
+#if JVET_N0857_TILES_BRICKS
+    const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap( ctuTsAddr );
+#else
     const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap( ctuTsAddr );
+#endif
     const uint32_t ctuXPosInCtus        = ctuRsAddr % widthInCtus;
     const uint32_t ctuYPosInCtus        = ctuRsAddr / widthInCtus;
 
@@ -1560,7 +1600,11 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
   Slice* pcSlice                  = cs.slice;
   const PreCalcValues& pcv        = *cs.pcv;
   const uint32_t        widthInCtus   = pcv.widthInCtus;
+#if JVET_N0857_TILES_BRICKS
+  const BrickMap&  tileMap        = *pcPic->brickMap;
+#else
   const TileMap&  tileMap         = *pcPic->tileMap;
+#endif
 #if ENABLE_QPA
   const int iQPIndex              = pcSlice->getSliceQpBase();
 #endif
@@ -1621,10 +1665,18 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
   // for every CTU in the slice segment (may terminate sooner if there is a byte limit on the slice-segment)
   for( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ )
   {
+#if JVET_N0857_TILES_BRICKS
+    const int32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap( ctuTsAddr );
+#else
     const int32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap( ctuTsAddr );
+#endif
 
     // update CABAC state
+#if JVET_N0857_TILES_BRICKS
+    const uint32_t firstCtuRsAddrOfTile = tileMap.bricks[tileMap.getBrickIdxRsMap(ctuRsAddr)].getFirstCtuRsAddr();
+#else
     const uint32_t firstCtuRsAddrOfTile = tileMap.tiles[tileMap.getTileIdxMap(ctuRsAddr)].getFirstCtuRsAddr();
+#endif
     const uint32_t tileXPosInCtus       = firstCtuRsAddrOfTile % widthInCtus;
     const uint32_t ctuXPosInCtus        = ctuRsAddr % widthInCtus;
     const uint32_t ctuYPosInCtus        = ctuRsAddr / widthInCtus;
@@ -1657,7 +1709,11 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
     {
       // reset and then update contexts to the state at the end of the top-right CTU (if within current slice and tile).
       pCABACWriter->initCtxModels( *pcSlice );
+#if JVET_N0857_TILES_BRICKS
+      if( cs.getCURestricted( pos.offset(pcv.maxCUWidth, -1), pcSlice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) )
+#else
       if( cs.getCURestricted( pos.offset(pcv.maxCUWidth, -1), pcSlice->getIndependentSliceIdx(), tileMap.getTileIdxMap( pos ), CH_L ) )
+#endif
       {
         // Top-right is available, we use it.
         pCABACWriter->getCtx() = pEncLib->m_entropyCodingSyncContextState;
@@ -1903,7 +1959,11 @@ void EncSlice::encodeSlice   ( Picture* pcPic, OutputBitstream* pcSubstreams, ui
 {
 
   Slice *const pcSlice               = pcPic->slices[getSliceSegmentIdx()];
+#if JVET_N0857_TILES_BRICKS
+  const BrickMap& tileMap            = *pcPic->brickMap;
+#else
   const TileMap& tileMap             = *pcPic->tileMap;
+#endif
 #if HEVC_DEPENDENT_SLICES
   const uint32_t startCtuTsAddr          = pcSlice->getSliceSegmentCurStartCtuTsAddr();
   const uint32_t boundingCtuTsAddr       = pcSlice->getSliceSegmentCurEndCtuTsAddr();
@@ -1956,8 +2016,13 @@ void EncSlice::encodeSlice   ( Picture* pcPic, OutputBitstream* pcSubstreams, ui
 
   for( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ )
   {
+#if JVET_N0857_TILES_BRICKS
+    const uint32_t ctuRsAddr            = tileMap.getCtuBsToRsAddrMap(ctuTsAddr);
+    const Brick& currentTile            = tileMap.bricks[tileMap.getBrickIdxRsMap(ctuRsAddr)];
+#else
     const uint32_t ctuRsAddr            = tileMap.getCtuTsToRsAddrMap(ctuTsAddr);
     const Tile& currentTile         = tileMap.tiles[tileMap.getTileIdxMap(ctuRsAddr)];
+#endif
     const uint32_t firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr();
     const uint32_t tileXPosInCtus       = firstCtuRsAddrOfTile % widthInCtus;
     const uint32_t tileYPosInCtus       = firstCtuRsAddrOfTile / widthInCtus;
@@ -1986,7 +2051,11 @@ void EncSlice::encodeSlice   ( Picture* pcPic, OutputBitstream* pcSubstreams, ui
       {
         m_CABACWriter->initCtxModels( *pcSlice );
       }
+#if JVET_N0857_TILES_BRICKS
+      if( cs.getCURestricted( pos.offset( pcv.maxCUWidth, -1 ), pcSlice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) )
+#else
       if( cs.getCURestricted( pos.offset( pcv.maxCUWidth, -1 ), pcSlice->getIndependentSliceIdx(), tileMap.getTileIdxMap( pos ), CH_L ) )
+#endif
       {
         // Top-right is available, so use it.
         m_CABACWriter->getCtx() = m_entropyCodingSyncContextState;
@@ -2008,11 +2077,18 @@ void EncSlice::encodeSlice   ( Picture* pcPic, OutputBitstream* pcSubstreams, ui
     }
 
     // terminate the sub-stream, if required (end of slice-segment, end of tile, end of wavefront-CTU-row):
+#if JVET_N0857_TILES_BRICKS
+    if( ctuTsAddr + 1 == boundingCtuTsAddr ||
+        (  ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getWidthInCtus () &&
+        ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getHeightInCtus() || wavefrontsEnabled ) )
+      )
+#else
     if( ctuTsAddr + 1 == boundingCtuTsAddr ||
          (  ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getTileWidthInCtus () &&
           ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getTileHeightInCtus() || wavefrontsEnabled )
          )
        )
+#endif
     {
       m_CABACWriter->end_of_slice();
 
@@ -2054,7 +2130,11 @@ void EncSlice::calculateBoundingCtuTsAddrForSlice(uint32_t &startCtuTSAddrSlice,
                                                    Picture* pcPic, const int sliceMode, const int sliceArgument)
 {
   Slice* pcSlice = pcPic->slices[getSliceSegmentIdx()];
+#if JVET_N0857_TILES_BRICKS
+  const BrickMap& tileMap = *( pcPic->brickMap );
+#else
   const TileMap& tileMap = *( pcPic->tileMap );
+#endif
   const PPS &pps         = *( pcSlice->getPPS() );
   const uint32_t numberOfCtusInFrame = pcPic->cs->pcv->sizeInCtus;
   boundingCtuTSAddrSlice=0;
@@ -2073,16 +2153,26 @@ void EncSlice::calculateBoundingCtuTsAddrForSlice(uint32_t &startCtuTSAddrSlice,
       break;
     case FIXED_NUMBER_OF_TILES:
       {
+#if JVET_N0857_TILES_BRICKS
+      const uint32_t tileIdx        = tileMap.getBrickIdxRsMap( tileMap.getCtuBsToRsAddrMap(startCtuTSAddrSlice) );
+      const uint32_t tileTotalCount = (uint32_t) tileMap.bricks.size();
+#else
         const uint32_t tileIdx        = tileMap.getTileIdxMap( tileMap.getCtuTsToRsAddrMap(startCtuTSAddrSlice) );
         const uint32_t tileTotalCount = (pps.getNumTileColumnsMinus1()+1) * (pps.getNumTileRowsMinus1()+1);
+#endif
         uint32_t ctuAddrIncrement   = 0;
 
         for(uint32_t tileIdxIncrement = 0; tileIdxIncrement < sliceArgument; tileIdxIncrement++)
         {
           if((tileIdx + tileIdxIncrement) < tileTotalCount)
           {
+#if JVET_N0857_TILES_BRICKS
+            uint32_t tileWidthInCtus    = tileMap.bricks[tileIdx + tileIdxIncrement].getWidthInCtus();
+            uint32_t tileHeightInCtus   = tileMap.bricks[tileIdx + tileIdxIncrement].getHeightInCtus();
+#else
             uint32_t tileWidthInCtus    = tileMap.tiles[tileIdx + tileIdxIncrement].getTileWidthInCtus();
             uint32_t tileHeightInCtus   = tileMap.tiles[tileIdx + tileIdxIncrement].getTileHeightInCtus();
+#endif
             ctuAddrIncrement       += (tileWidthInCtus * tileHeightInCtus);
           }
         }
@@ -2090,6 +2180,17 @@ void EncSlice::calculateBoundingCtuTsAddrForSlice(uint32_t &startCtuTSAddrSlice,
         boundingCtuTSAddrSlice  = ((startCtuTSAddrSlice + ctuAddrIncrement) < numberOfCtusInFrame) ? (startCtuTSAddrSlice + ctuAddrIncrement) : numberOfCtusInFrame;
       }
       break;
+#if JVET_N0857_TILES_BRICKS
+    case SINGLE_BRICK_PER_SLICE:
+      {
+        const uint32_t brickIdx           = tileMap.getBrickIdxRsMap( tileMap.getCtuBsToRsAddrMap(startCtuTSAddrSlice) );
+        const uint32_t brickWidthInCtus   = tileMap.bricks[brickIdx].getWidthInCtus();
+        const uint32_t brickHeightInCtus  = tileMap.bricks[brickIdx].getHeightInCtus();
+        const uint32_t ctuAddrIncrement   = brickWidthInCtus * brickHeightInCtus;
+        boundingCtuTSAddrSlice  = ((startCtuTSAddrSlice + ctuAddrIncrement) < numberOfCtusInFrame) ? (startCtuTSAddrSlice + ctuAddrIncrement) : numberOfCtusInFrame;
+      }
+      break;
+#endif
     default:
       boundingCtuTSAddrSlice    = numberOfCtusInFrame;
       break;
@@ -2101,12 +2202,21 @@ void EncSlice::calculateBoundingCtuTsAddrForSlice(uint32_t &startCtuTSAddrSlice,
   if ((sliceMode == FIXED_NUMBER_OF_CTU || sliceMode == FIXED_NUMBER_OF_BYTES) &&
       (pps.getNumTileRowsMinus1() > 0 || pps.getNumTileColumnsMinus1() > 0))
   {
+#if JVET_N0857_TILES_BRICKS
+    const uint32_t  ctuRsAddr                  = tileMap.getCtuBsToRsAddrMap(startCtuTSAddrSlice);
+    const uint32_t  startTileIdx               = tileMap.getBrickIdxRsMap(ctuRsAddr);
+    const Brick&    startingTile               = tileMap.bricks[startTileIdx];
+    const uint32_t  tileStartTsAddr            = tileMap.getCtuRsToBsAddrMap(startingTile.getFirstCtuRsAddr());
+    const uint32_t  tileStartWidth             = startingTile.getWidthInCtus();
+    const uint32_t  tileStartHeight            = startingTile.getHeightInCtus();
+#else
     const uint32_t ctuRsAddr                   = tileMap.getCtuTsToRsAddrMap(startCtuTSAddrSlice);
     const uint32_t startTileIdx                = tileMap.getTileIdxMap(ctuRsAddr);
     const Tile& startingTile               = tileMap.tiles[startTileIdx];
     const uint32_t  tileStartTsAddr            = tileMap.getCtuRsToTsAddrMap(startingTile.getFirstCtuRsAddr());
     const uint32_t  tileStartWidth             = startingTile.getTileWidthInCtus();
     const uint32_t  tileStartHeight            = startingTile.getTileHeightInCtus();
+#endif
     const uint32_t tileLastTsAddr_excl        = tileStartTsAddr + tileStartWidth*tileStartHeight;
     const uint32_t tileBoundingCtuTsAddrSlice = tileLastTsAddr_excl;
     const uint32_t ctuColumnOfStartingTile     = ((startCtuTSAddrSlice-tileStartTsAddr)%tileStartWidth);
diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp
index cc4e16ce4ecb78f73755c28475c51fc55e44ea26..1af9069e97ad0f3036e147df664d812dad063ee0 100644
--- a/source/Lib/EncoderLib/SEIEncoder.cpp
+++ b/source/Lib/EncoderLib/SEIEncoder.cpp
@@ -356,7 +356,11 @@ void SEIEncoder::initSEITempMotionConstrainedTileSets (SEITempMotionConstrainedT
   CHECK(!(sei!=NULL), "Unspecified error");
   CHECK(!(pps!=NULL), "Unspecified error");
 
+#if !JVET_N0857_TILES_BRICKS
   if(pps->getTilesEnabledFlag())
+#else
+  if(!pps->getSingleTileInPicFlag())
+#endif
   {
     if (m_pcCfg->getMCTSEncConstraint())
     {
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 89ee5002072e259f9b90e10863d2ed4347595840..9bda97fafa69a929c26a248e31d830c5a2e01490 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -247,14 +247,119 @@ void HLSWriter::codePPS( const PPS* pcPPS )
   WRITE_FLAG( pcPPS->getUseWP() ? 1 : 0,  "weighted_pred_flag" );   // Use of Weighting Prediction (P_SLICE)
   WRITE_FLAG( pcPPS->getWPBiPred() ? 1 : 0, "weighted_bipred_flag" );  // Use of Weighting Bi-Prediction (B_SLICE)
   WRITE_FLAG( pcPPS->getTransquantBypassEnabledFlag()  ? 1 : 0, "transquant_bypass_enabled_flag" );
+
+#if JVET_N0857_TILES_BRICKS
+  WRITE_FLAG( pcPPS->getSingleTileInPicFlag() ? 1 : 0, "single_tile_in_pic_flag" );
+  if (!pcPPS->getSingleTileInPicFlag())
+  {
+    WRITE_FLAG( pcPPS->getUniformTileSpacingFlag() ? 1 : 0, "uniform_tile_spacing_flag" );
+    if (pcPPS->getUniformTileSpacingFlag())
+    {
+      WRITE_UVLC( pcPPS->getTileColsWidthMinus1(),   "tile_cols_width_minus1" );
+      WRITE_UVLC( pcPPS->getTileRowsHeightMinus1(),  "tile_rows_height_minus1" );
+    }
+    else
+    {
+      WRITE_UVLC( pcPPS->getNumTileColumnsMinus1(), "num_tile_columns_minus1" );
+      WRITE_UVLC( pcPPS->getNumTileRowsMinus1(),    "num_tile_rows_minus1" );
+
+      CHECK( ((pcPPS->getNumTileColumnsMinus1() + 1) * (pcPPS->getNumTileRowsMinus1() + 1)) < 2, "tile colums * rows must be > 1 when explicitly signalled.");
+
+      for (int i = 0; i < pcPPS->getNumTileColumnsMinus1(); i++)
+      {
+        WRITE_UVLC( pcPPS->getTileColumnWidth(i) - 1, "tile_column_width_minus1" );
+      }
+      for (int i = 0; i < pcPPS->getNumTileRowsMinus1(); i++)
+      {
+        WRITE_UVLC( pcPPS->getTileRowHeight(i) - 1, "tile_row_height_minus1" );
+      }
+    }
+    WRITE_FLAG( pcPPS->getBrickSplittingPresentFlag() ? 1 : 0, "brick_splitting_present_flag" );
+
+    int numTilesInPic = pcPPS->getUniformTileSpacingFlag() ? 0 : (pcPPS->getNumTileColumnsMinus1() + 1) * (pcPPS->getNumTileRowsMinus1() + 1);
+
+    for( int i = 0; pcPPS->getBrickSplittingPresentFlag()  &&  i < numTilesInPic; i++ )
+    {
+      WRITE_FLAG( pcPPS->getBrickSplitFlag(i) ? 1 : 0, "brick_split_flag [i]" );
+      if( pcPPS->getBrickSplitFlag(i) )
+      {
+        WRITE_FLAG( pcPPS->getUniformBrickSpacingFlag(i) ? 1 : 0, "uniform_brick_spacing_flag [i]" );
+        if( pcPPS->getUniformBrickSpacingFlag(i) )
+          WRITE_UVLC( pcPPS->getBrickHeightMinus1(i), "brick_height_minus1" );
+        else
+        {
+          WRITE_UVLC( pcPPS->getNumBrickRowsMinus1(i), "num_brick_rows_minus1 [i]" );
+          for(int j = 0; j < pcPPS->getNumBrickRowsMinus1(i); j++ )
+            WRITE_UVLC( pcPPS->getBrickRowHeightMinus1(i,j), "brick_row_height_minus1 [i][j]" );
+        }
+      }
+    }
+
+    WRITE_FLAG( pcPPS->getSingleBrickPerSliceFlag() ? 1 : 0, "single_brick_per_slice_flag" );
+    if (!pcPPS->getSingleBrickPerSliceFlag())
+    {
+      WRITE_FLAG( pcPPS->getRectSliceFlag() ? 1 : 0, "rect_slice_flag" );
+    }
+    else
+    {
+      // make sure rect_slice_flag is set
+      CHECK (pcPPS->getRectSliceFlag()!=true, "RectSliceFlag must be equal to 1 for single_brick_per_slice_flag equal to 1");
+    }
+
+    if (pcPPS->getRectSliceFlag() && !pcPPS->getSingleBrickPerSliceFlag())
+    {
+      WRITE_UVLC( pcPPS->getNumSlicesInPicMinus1(), "num_slices_in_pic_minus1" );
+      int numSlicesInPic = pcPPS->getNumSlicesInPicMinus1() + 1;
+      int numTilesInPic = (pcPPS->getNumTileColumnsMinus1() + 1) * (pcPPS->getNumTileRowsMinus1() + 1);
+      int codeLength = (int)ceil(log2(numTilesInPic));
+      for (int i = 0; i < numSlicesInPic; ++i)
+      {
+        if (i > 0)
+        {
+          WRITE_CODE( pcPPS->getTopLeftTileIdx(i), codeLength, "top_left_brick_idx ");
+        }
+        WRITE_CODE( pcPPS->getBottomeRightTileIdx(i)-pcPPS->getTopLeftTileIdx(i), codeLength, "bottom_right_brick_idx_delta" );
+
+      }
+    }
+
+    WRITE_FLAG( pcPPS->getLoopFilterAcrossBricksEnabledFlag() ? 1 : 0, "loop_filter_across_bricks_enabled_flag" );
+    if (pcPPS->getLoopFilterAcrossBricksEnabledFlag())
+    {
+      WRITE_FLAG( pcPPS->getLoopFilterAcrossSlicesEnabledFlag() ? 1 : 0, "loop_filter_across_slices_enabled_flag" );
+    }
+  }
+  else
+  {
+    // make sure rect_slice_flag is set
+    CHECK (pcPPS->getRectSliceFlag()!=true, "RectSliceFlag must be equalt to 1 for single_tile_in_pic_flag equal to 1");
+  }
+
+  if (pcPPS->getRectSliceFlag())
+  {
+    WRITE_FLAG( pcPPS->getSignalledSliceIdFlag() ? 1 : 0, "signalled_slice_id_flag" );
+    if (pcPPS->getSignalledSliceIdFlag())
+    {
+      WRITE_UVLC( pcPPS->getSignalledSliceIdLengthMinus1(), "signalled_slice_id_length_minus1" );
+      int signalledTileGroupIdLength = pcPPS->getSignalledSliceIdLengthMinus1() + 1;
+      int numTileGroupsInPic = pcPPS->getNumSlicesInPicMinus1() + 1;
+      for (int i = 0; i < numTileGroupsInPic; ++i)
+      {
+        WRITE_CODE (pcPPS->getSliceId(i), signalledTileGroupIdLength, "slice_id" );
+      }
+    }
+  }
+#endif
+
+
+#if !JVET_N0857_TILES_BRICKS
   WRITE_FLAG( pcPPS->getTilesEnabledFlag() ? 1 : 0, "tiles_enabled_flag" );
-  WRITE_FLAG( pcPPS->getEntropyCodingSyncEnabledFlag() ? 1 : 0, "entropy_coding_sync_enabled_flag" );
   if( pcPPS->getTilesEnabledFlag() )
   {
     WRITE_UVLC( pcPPS->getNumTileColumnsMinus1(),                                    "num_tile_columns_minus1" );
     WRITE_UVLC( pcPPS->getNumTileRowsMinus1(),                                       "num_tile_rows_minus1" );
-    WRITE_FLAG( pcPPS->getTileUniformSpacingFlag(),                                  "uniform_spacing_flag" );
-    if( !pcPPS->getTileUniformSpacingFlag() )
+    WRITE_FLAG( pcPPS->getUniformTileSpacingFlag(),                                  "uniform_spacing_flag" );
+    if( !pcPPS->getUniformTileSpacingFlag() )
     {
       for(uint32_t i=0; i<pcPPS->getNumTileColumnsMinus1(); i++)
       {
@@ -266,9 +371,12 @@ void HLSWriter::codePPS( const PPS* pcPPS )
       }
     }
     CHECK ((pcPPS->getNumTileColumnsMinus1() + pcPPS->getNumTileRowsMinus1()) == 0, "Invalid tile parameters read");
-    WRITE_FLAG( pcPPS->getLoopFilterAcrossTilesEnabledFlag()?1 : 0,       "loop_filter_across_tiles_enabled_flag");
+    WRITE_FLAG( pcPPS->getLoopFilterAcrossBricksEnabledFlag()?1 : 0,       "loop_filter_across_tiles_enabled_flag");
   }
   WRITE_FLAG( pcPPS->getLoopFilterAcrossSlicesEnabledFlag()?1 : 0,        "pps_loop_filter_across_slices_enabled_flag");
+#endif
+  WRITE_FLAG( pcPPS->getEntropyCodingSyncEnabledFlag() ? 1 : 0, "entropy_coding_sync_enabled_flag" );
+
   WRITE_FLAG( pcPPS->getDeblockingFilterControlPresentFlag()?1 : 0,       "deblocking_filter_control_present_flag");
   if(pcPPS->getDeblockingFilterControlPresentFlag())
   {
@@ -1127,7 +1235,11 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
 #endif
 
   //write slice address
+#if JVET_N0857_TILES_BRICKS
+  const int sliceSegmentRsAddress = pcSlice->getPic()->brickMap->getCtuBsToRsAddrMap(ctuTsAddress);
+#else
   const int sliceSegmentRsAddress = pcSlice->getPic()->tileMap->getCtuTsToRsAddrMap(ctuTsAddress);
+#endif
 
   WRITE_FLAG( sliceSegmentRsAddress==0, "first_slice_segment_in_pic_flag" );
   if ( pcSlice->getRapPicFlag() )
@@ -1752,7 +1864,11 @@ void HLSWriter::codeProfileTier( const ProfileTierLevel* ptl, const bool /*bIsSu
 */
 void  HLSWriter::codeTilesWPPEntryPoint( Slice* pSlice )
 {
+#if !JVET_N0857_TILES_BRICKS
   if (!pSlice->getPPS()->getTilesEnabledFlag() && !pSlice->getPPS()->getEntropyCodingSyncEnabledFlag())
+#else
+  if (pSlice->getPPS()->getSingleTileInPicFlag() && !pSlice->getPPS()->getEntropyCodingSyncEnabledFlag())
+#endif
   {
     return;
   }