diff --git a/cfg/nonCTC-SliceConfigExamples/subpicture_4Slice2VerSubPic.cfg b/cfg/nonCTC-SliceConfigExamples/subpicture_4Slice2VerSubPic.cfg
index a1df9fbab047244ce6205435676acbccbf2b3e76..c37fa7de75f3b60f7ac4b66054483b6631e0cd1e 100644
--- a/cfg/nonCTC-SliceConfigExamples/subpicture_4Slice2VerSubPic.cfg
+++ b/cfg/nonCTC-SliceConfigExamples/subpicture_4Slice2VerSubPic.cfg
@@ -34,5 +34,5 @@ TileRowHeightArray            : 2                       # Tile row heights in un
 RasterScanSlices              : 0                       # Raster-scan or rectangular slices (0: rectangular, 1: raster-scan)
 RectSliceFixedWidth           : 1                       # Fixed rectangular slice width in units of tiles (0: disable this feature and use RectSlicePositions instead)
 RectSliceFixedHeight          : 1                       # Fixed rectangular slice height in units of tiles (0: disable this feature and use RectSlicePositions instead)
-DisableLoopFilterAcrossTiles  : 1                       # Loop filtering (DBLK/SAO/ALF) applied across tile boundaries or not (0: filter across tile boundaries  1: do not filter across tile boundaries)
-DisableLoopFilterAcrossSlices : 1                       # Loop filtering (DBLK/SAO/ALF) applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries)
+DisableLoopFilterAcrossTiles  : 0                       # Loop filtering (DBLK/SAO/ALF) applied across tile boundaries or not (0: filter across tile boundaries  1: do not filter across tile boundaries)
+DisableLoopFilterAcrossSlices : 0                       # Loop filtering (DBLK/SAO/ALF) applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries)
diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp
index f0428bff4987ad635fe28312f064fee908379dd4..dcbe8be97fd68fc1abf7762f29b5db94a266eef3 100644
--- a/source/App/DecoderApp/DecApp.cpp
+++ b/source/App/DecoderApp/DecApp.cpp
@@ -717,7 +717,7 @@ void DecApp::xCreateDecLib()
     std::ostream &os=m_seiMessageFileStream.is_open() ? m_seiMessageFileStream : std::cout;
     m_cDecLib.setDecodedSEIMessageOutputStream(&os);
   }
-#if SUBPIC_DECCHECK
+#if JVET_O1143_SUBPIC_DECCHECK
   m_cDecLib.m_targetSubPicIdx = this->m_targetSubPicIdx;
 #endif
   m_cDecLib.initScalingList();
diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp
index 63808add02c8f034a9c3c645afe4c65742a14cc4..f5e9ffda801182deb0c292a6b23190aab8055e29 100644
--- a/source/App/DecoderApp/DecAppCfg.cpp
+++ b/source/App/DecoderApp/DecAppCfg.cpp
@@ -117,7 +117,7 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] )
                                                                                    "\t3: enable bit and tool statistic\n")
 #endif
   ("MCTSCheck",                m_mctsCheck,                           false,       "If enabled, the decoder checks for violations of mc_exact_sample_value_match_flag in Temporal MCTS ")
-#if SUBPIC_DECCHECK
+#if JVET_O1143_SUBPIC_DECCHECK
   ("targetSubPicIdx",          m_targetSubPicIdx,                     0,           "Specify which subpicture shall be written to output, using subpic index\n" )
 #endif
   ( "UpscaledOutput",          m_upscaledOutput,                          0,       "Upscaled output for RPR" )
diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h
index c04f51c85fad022e42ded6df395dec7bd575aa32..e8e1af7e9eee5a1fdd13d535b5aaba47dd2b8bb9 100644
--- a/source/App/DecoderApp/DecAppCfg.h
+++ b/source/App/DecoderApp/DecAppCfg.h
@@ -83,7 +83,7 @@ protected:
   bool          m_mctsCheck;
 
   int          m_upscaledOutput;                     ////< Output upscaled (2), decoded but in full resolution buffer (1) or decoded cropped (0, default) picture for RPR.
-#if SUBPIC_DECCHECK
+#if JVET_O1143_SUBPIC_DECCHECK
   int           m_targetSubPicIdx;                    ///< Specify which subpicture shall be write to output, using subpicture index
 #endif
 public:
diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp
index 4d862ff95008c1b7543b0f1d53f480f329e066ea..04a4a5019c312818bf6059ce1b8656a533761bd6 100644
--- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp
+++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp
@@ -121,13 +121,21 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const CodingStructure& cs
   int   ctuSize = slice.getSPS()->getCTUSize();
   const Position currCtuPos(xPos, yPos);
   const CodingUnit *currCtu = cs.getCU(currCtuPos, CHANNEL_TYPE_LUMA);
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+  SubPic curSubPic = slice.getPPS()->getSubPicFromPos(currCtuPos);
+  bool loopFilterAcrossSubPicEnabledFlag = curSubPic.getloopFilterAcrossEnabledFlag();
+#endif
   //top
   if (yPos >= ctuSize && clipTop == false)
   {
     const Position prevCtuPos(xPos, yPos - ctuSize);
     const CodingUnit *prevCtu = cs.getCU(prevCtuPos, CHANNEL_TYPE_LUMA);
     if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *prevCtu)) || 
-        (!pps->getLoopFilterAcrossTilesEnabledFlag()  && !CU::isSameTile(*currCtu,  *prevCtu)))
+        (!pps->getLoopFilterAcrossTilesEnabledFlag()  && !CU::isSameTile(*currCtu,  *prevCtu))
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+      || (!loopFilterAcrossSubPicEnabledFlag && !CU::isSameSubPic(*currCtu, *prevCtu))
+#endif
+      )
     {
       clipTop = true;
     }
@@ -139,7 +147,11 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const CodingStructure& cs
     const Position nextCtuPos(xPos, yPos + ctuSize);
     const CodingUnit *nextCtu = cs.getCU(nextCtuPos, CHANNEL_TYPE_LUMA);
     if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *nextCtu)) || 
-        (!pps->getLoopFilterAcrossTilesEnabledFlag()  && !CU::isSameTile(*currCtu,  *nextCtu)))
+        (!pps->getLoopFilterAcrossTilesEnabledFlag()  && !CU::isSameTile(*currCtu,  *nextCtu))
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+      || (!loopFilterAcrossSubPicEnabledFlag && !CU::isSameSubPic(*currCtu, *nextCtu))
+#endif
+      )
     {
       clipBottom = true;
     }
@@ -151,7 +163,11 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const CodingStructure& cs
     const Position prevCtuPos(xPos - ctuSize, yPos);
     const CodingUnit *prevCtu = cs.getCU(prevCtuPos, CHANNEL_TYPE_LUMA);
     if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *prevCtu)) || 
-        (!pps->getLoopFilterAcrossTilesEnabledFlag()  && !CU::isSameTile(*currCtu,  *prevCtu)))
+        (!pps->getLoopFilterAcrossTilesEnabledFlag()  && !CU::isSameTile(*currCtu,  *prevCtu))
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+      || (!loopFilterAcrossSubPicEnabledFlag && !CU::isSameSubPic(*currCtu, *prevCtu))
+#endif
+      )
     {
       clipLeft = true;
     }
@@ -163,7 +179,11 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const CodingStructure& cs
     const Position nextCtuPos(xPos + ctuSize, yPos);
     const CodingUnit *nextCtu = cs.getCU(nextCtuPos, CHANNEL_TYPE_LUMA);
     if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *nextCtu)) || 
-        (!pps->getLoopFilterAcrossTilesEnabledFlag()  && !CU::isSameTile(*currCtu,  *nextCtu)))
+        (!pps->getLoopFilterAcrossTilesEnabledFlag()  && !CU::isSameTile(*currCtu,  *nextCtu))
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+      || (!loopFilterAcrossSubPicEnabledFlag && !CU::isSameSubPic(*currCtu, *nextCtu))
+#endif
+      )
     {
       clipRight = true;
     }
diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp
index a9e3a60c8eda3283e83e2dd86452e9a5f6d4c174..ba4ff56166652657e02a6680a27dda802dafdf74 100644
--- a/source/Lib/CommonLib/LoopFilter.cpp
+++ b/source/Lib/CommonLib/LoopFilter.cpp
@@ -81,15 +81,30 @@ inline static uint32_t getRasterIdx(const Position& pos, const PreCalcValues& pc
 // ====================================================================================================================
 // utility functions
 // ====================================================================================================================
-
-static bool isAvailableLeft( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction )
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+static bool isAvailableLeft( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction, const bool bEnforceSubPicRestriction)
+#else
+static bool isAvailableLeft( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction)
+#endif
 {
-  return ( ( !bEnforceSliceRestriction || CU::isSameSlice( cu, cu2 ) ) && ( !bEnforceTileRestriction || CU::isSameTile( cu, cu2 ) ) );
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+  return ((!bEnforceSliceRestriction || CU::isSameSlice(cu, cu2)) && (!bEnforceTileRestriction || CU::isSameTile(cu, cu2)) && (!bEnforceSubPicRestriction || CU::isSameSubPic(cu, cu2)));
+#else
+  return ((!bEnforceSliceRestriction || CU::isSameSlice(cu, cu2)) && (!bEnforceTileRestriction || CU::isSameTile(cu, cu2)));
+#endif    
 }
 
-static bool isAvailableAbove( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction )
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+static bool isAvailableAbove( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction, const bool bEnforceSubPicRestriction)
+#else
+static bool isAvailableAbove( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction)
+#endif
 {
-  return ( !bEnforceSliceRestriction || CU::isSameSlice( cu, cu2 ) ) && ( !bEnforceTileRestriction || CU::isSameTile( cu, cu2 ) );
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+  return ( !bEnforceSliceRestriction || CU::isSameSlice( cu, cu2 ) ) && ( !bEnforceTileRestriction || CU::isSameTile( cu, cu2 ) ) && (!bEnforceSubPicRestriction || CU::isSameSubPic(cu, cu2));
+#else
+  return ( !bEnforceSliceRestriction || CU::isSameSlice( cu, cu2 ) ) && ( !bEnforceTileRestriction || CU::isSameTile( cu, cu2 ) ) ;
+#endif
 }
 
 
@@ -680,8 +695,19 @@ 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 ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() );
-  m_stLFCUParam.topEdge      = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset(  0, -1 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() );
+
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+  m_stLFCUParam.leftEdge     = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1,  0 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag() );
+#else
+  m_stLFCUParam.leftEdge     = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1,  0 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag());  
+#endif
+
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+  m_stLFCUParam.topEdge      = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset(  0, -1 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag() );
+#else
+  m_stLFCUParam.topEdge      = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset(  0, -1 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag());  
+#endif
+
 }
 
 unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const Position& localPos ) const
@@ -937,7 +963,11 @@ void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edg
       // Derive neighboring PU index
       if (edgeDir == EDGE_VER)
       {
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+        if (!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag()))
+#else
         if (!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()))
+#endif        
         {
           m_aapucBS[edgeDir][uiBsAbsIdx] = uiBs = 0;
           continue;
@@ -945,7 +975,11 @@ void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edg
       }
       else  // (iDir == EDGE_HOR)
       {
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+        if (!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag()))
+#else
         if (!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()))
+#endif
         {
           m_aapucBS[edgeDir][uiBsAbsIdx] = uiBs = 0;
           continue;
@@ -1205,11 +1239,19 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed
 
       if (edgeDir == EDGE_VER)
       {
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+        CHECK(!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag()), "Neighbour not available");
+#else
         CHECK(!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available");
+#endif
       }
       else  // (iDir == EDGE_HOR)
       {
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+        CHECK(!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag()), "Neighbour not available");
+#else
         CHECK(!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available");
+#endif
       }
 
       bPartPNoFilter = bPartQNoFilter = false;
diff --git a/source/Lib/CommonLib/Mv.cpp b/source/Lib/CommonLib/Mv.cpp
index 386d0874680f79432ae174c44271c0a8cc11491b..598a26433cf80e965ac547c6388aa6cbc0ef19db 100644
--- a/source/Lib/CommonLib/Mv.cpp
+++ b/source/Lib/CommonLib/Mv.cpp
@@ -66,7 +66,17 @@ void clipMv( Mv& rcMv, const Position& pos, const struct Size& size, const SPS&
 
   int iVerMax = ( pps.getPicHeightInLumaSamples() + iOffset - (int)pos.y - 1 ) << iMvShift;
   int iVerMin = ( -( int ) sps.getMaxCUHeight()   - iOffset - ( int ) pos.y + 1 ) << iMvShift;
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY 
+  SubPic curSubPic = pps.getSubPicFromPos(pos);
+  if (curSubPic.getTreatedAsPicFlag()) 
+  {
+    iHorMax = (curSubPic.getSubPicWidthInLumaSample() + iOffset - (int)pos.x - 1 ) << iMvShift;
+    iHorMin = (-(int)sps.getMaxCUWidth() -  iOffset - ((int)pos.x - curSubPic.getSubPicLeft()) + 1) << iMvShift;
 
+    iVerMax = (curSubPic.getSubPicHeightInLumaSample()+ iOffset - (int)pos.y - 1) << iMvShift;
+    iVerMin = (-(int)sps.getMaxCUHeight() - iOffset - ((int)pos.y - curSubPic.getSubPicTop()) + 1) << iMvShift;
+  }
+#endif
   rcMv.setHor( std::min( iHorMax, std::max( iHorMin, rcMv.getHor() ) ) );
   rcMv.setVer( std::min( iVerMax, std::max( iVerMin, rcMv.getVer() ) ) );
 }
diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp
index 2821a7ef362fbbb8bf827976a1f04321ac4fe8ca..a74e5ed1e1ecf3e74d1116d80786b94552234ab6 100644
--- a/source/Lib/CommonLib/Picture.cpp
+++ b/source/Lib/CommonLib/Picture.cpp
@@ -173,6 +173,9 @@ int Scheduler::getNumPicInstances() const
 Picture::Picture()
 {
   cs                   = nullptr;
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+  m_isSubPicBorderSaved = false;
+#endif
   m_bIsBorderExtended  = false;
   usedByCurr           = false;
   longTerm             = false;
@@ -734,6 +737,219 @@ void Picture::rescalePicture( const std::pair<int, int> scalingRatio,
   }
 }
 
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+void Picture::saveSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight)
+{
+
+  // 1.1 set up margin for back up memory allocation
+  int xMargin = margin >> getComponentScaleX(COMPONENT_Y, cs->area.chromaFormat);
+  int yMargin = margin >> getComponentScaleY(COMPONENT_Y, cs->area.chromaFormat);
+
+  // 1.2 measure the size of back up memory
+  Area areaAboveBelow(0, 0, subPicWidth + 2 * xMargin, yMargin);
+  Area areaLeftRight(0, 0, xMargin, subPicHeight);
+  UnitArea unitAreaAboveBelow(cs->area.chromaFormat, areaAboveBelow);
+  UnitArea unitAreaLeftRight(cs->area.chromaFormat, areaLeftRight);
+
+  // 1.3 create back up memory
+  m_bufSubPicAbove.create(unitAreaAboveBelow);
+  m_bufSubPicBelow.create(unitAreaAboveBelow);
+  m_bufSubPicLeft.create(unitAreaLeftRight);
+  m_bufSubPicRight.create(unitAreaLeftRight);
+
+  for (int comp = 0; comp < getNumberValidComponents(cs->area.chromaFormat); comp++) 
+  {
+    ComponentID compID = ComponentID(comp);
+
+    // 2.1 measure the margin for each component
+    int xmargin = margin >> getComponentScaleX(compID, cs->area.chromaFormat);
+    int ymargin = margin >> getComponentScaleY(compID, cs->area.chromaFormat);
+
+    // 2.2 calculate the origin of the subpicture
+    int left = subPicX0 >> getComponentScaleX(compID, cs->area.chromaFormat);
+    int top = subPicY0 >> getComponentScaleY(compID, cs->area.chromaFormat);
+
+    // 2.3 calculate the width/height of the subPic
+    int width = subPicWidth >> getComponentScaleX(compID, cs->area.chromaFormat);
+    int height = subPicHeight >> getComponentScaleY(compID, cs->area.chromaFormat);
+
+
+    // 3.1.1 set reconstructed picture
+    PelBuf s = M_BUFS(0, PIC_RECONSTRUCTION).get(compID);
+    Pel *src = s.bufAt(left, top);
+
+    // 3.2.1 set back up buffer for left
+    PelBuf dBufLeft   = m_bufSubPicLeft.getBuf(compID);
+    Pel    *dstLeft   = dBufLeft.bufAt(0, 0);
+
+
+    // 3.2.2 set back up buffer for right
+    PelBuf dBufRight  = m_bufSubPicRight.getBuf(compID);
+    Pel    *dstRight  = dBufRight.bufAt(0, 0);
+
+    // 3.2.3 copy to recon picture to back up buffer
+    Pel *srcLeft  = src - xmargin;
+    Pel *srcRight = src + width;
+    for (int y = 0; y < height; y++) 
+    {
+      ::memcpy(dstLeft  + y *  dBufLeft.stride, srcLeft  + y * s.stride, sizeof(Pel) * xmargin);
+      ::memcpy(dstRight + y * dBufRight.stride, srcRight + y * s.stride, sizeof(Pel) * xmargin);
+    }
+
+    // 3.3.1 set back up buffer for above
+    PelBuf dBufTop = m_bufSubPicAbove.getBuf(compID);
+    Pel    *dstTop = dBufTop.bufAt(0, 0);
+
+    // 3.3.2 set back up buffer for below
+    PelBuf dBufBottom = m_bufSubPicBelow.getBuf(compID);
+    Pel    *dstBottom = dBufBottom.bufAt(0, 0);
+
+    // 3.3.3 copy to recon picture to back up buffer
+    Pel *srcTop    = src - xmargin - ymargin * s.stride;
+    Pel *srcBottom = src - xmargin +  height * s.stride;
+    for (int y = 0; y < ymargin; y++) 
+    {
+      ::memcpy(dstTop    + y *    dBufTop.stride, srcTop    + y * s.stride, sizeof(Pel) * (2 * xmargin + width));
+      ::memcpy(dstBottom + y * dBufBottom.stride, srcBottom + y * s.stride, sizeof(Pel) * (2 * xmargin + width));
+    }
+  }
+}
+
+void Picture::extendSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight)
+{
+
+  for (int comp = 0; comp < getNumberValidComponents(cs->area.chromaFormat); comp++) 
+  {
+    ComponentID compID = ComponentID(comp);
+
+    // 2.1 measure the margin for each component
+    int xmargin = margin >> getComponentScaleX(compID, cs->area.chromaFormat);
+    int ymargin = margin >> getComponentScaleY(compID, cs->area.chromaFormat);
+
+    // 2.2 calculate the origin of the Subpicture
+    int left = subPicX0 >> getComponentScaleX(compID, cs->area.chromaFormat);
+    int top = subPicY0 >> getComponentScaleY(compID, cs->area.chromaFormat);
+
+    // 2.3 calculate the width/height of the Subpicture
+    int width = subPicWidth >> getComponentScaleX(compID, cs->area.chromaFormat);
+    int height = subPicHeight >> getComponentScaleY(compID, cs->area.chromaFormat);
+
+    // 3.1 set reconstructed picture
+    PelBuf s = M_BUFS(0, PIC_RECONSTRUCTION).get(compID);
+    Pel *src = s.bufAt(left, top);
+
+    // 4.1 apply padding for left and right
+    {
+      Pel *dstLeft  = src - xmargin;
+      Pel *dstRight = src + width;
+      Pel *srcLeft  = src + 0;
+      Pel *srcRight = src + width - 1;
+
+      for (int y = 0; y < height; y++) 
+      {
+        for (int x = 0; x < xmargin; x++) 
+        {
+          dstLeft[x]  = *srcLeft;
+          dstRight[x] = *srcRight;
+        }
+        dstLeft += s.stride;
+        dstRight += s.stride;
+        srcLeft += s.stride;
+        srcRight += s.stride;
+      }
+    }
+
+    // 4.2 apply padding on bottom 
+    Pel *srcBottom = src + s.stride * (height - 1) - xmargin;
+    Pel *dstBottom = srcBottom + s.stride;
+    for (int y = 0; y < ymargin; y++)
+    {
+      ::memcpy(dstBottom, srcBottom, sizeof(Pel)*(2 * xmargin + width));
+      dstBottom += s.stride;
+    }
+
+    // 4.3 apply padding for top
+    // si is still (-marginX, SubpictureHeight-1)
+    Pel *srcTop = src - xmargin;
+    Pel *dstTop = srcTop - s.stride;
+    // si is now (-marginX, 0)
+    for (int y = 0; y < ymargin; y++)
+    {
+      ::memcpy(dstTop, srcTop, sizeof(Pel)*(2 * xmargin + width));
+      dstTop -= s.stride;
+    }
+  } // end of for  
+}
+
+void Picture::restoreSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight)
+{
+  for (int comp = 0; comp < getNumberValidComponents(cs->area.chromaFormat); comp++) 
+  {
+    ComponentID compID = ComponentID(comp);
+
+    // 2.1 measure the margin for each component
+    int xmargin = margin >> getComponentScaleX(compID, cs->area.chromaFormat);
+    int ymargin = margin >> getComponentScaleY(compID, cs->area.chromaFormat);
+
+    // 2.2 calculate the origin of the subpicture
+    int left = subPicX0 >> getComponentScaleX(compID, cs->area.chromaFormat);
+    int top = subPicY0 >> getComponentScaleY(compID, cs->area.chromaFormat);
+
+    // 2.3 calculate the width/height of the subpicture
+    int width = subPicWidth >> getComponentScaleX(compID, cs->area.chromaFormat);
+    int height = subPicHeight >> getComponentScaleY(compID, cs->area.chromaFormat);
+
+    // 3.1 set reconstructed picture
+    PelBuf s = M_BUFS(0, PIC_RECONSTRUCTION).get(compID);
+    Pel *src = s.bufAt(left, top);
+
+    // 4.2.1 copy from back up buffer to recon picture
+    PelBuf dBufLeft = m_bufSubPicLeft.getBuf(compID);
+    Pel    *dstLeft = dBufLeft.bufAt(0, 0);
+
+    // 4.2.2 set back up buffer for right
+    PelBuf dBufRight = m_bufSubPicRight.getBuf(compID);
+    Pel    *dstRight = dBufRight.bufAt(0, 0);
+
+    // 4.2.3 copy to recon picture to back up buffer
+    Pel *srcLeft  = src - xmargin;
+    Pel *srcRight = src + width;
+
+    for (int y = 0; y < height; y++) 
+    {
+      // the destination and source position is reversed on purpose
+      ::memcpy(srcLeft  + y * s.stride,  dstLeft + y *  dBufLeft.stride, sizeof(Pel) * xmargin);
+      ::memcpy(srcRight + y * s.stride, dstRight + y * dBufRight.stride, sizeof(Pel) * xmargin);
+    }
+
+
+    // 4.3.1 set back up buffer for above
+    PelBuf dBufTop = m_bufSubPicAbove.getBuf(compID);
+    Pel    *dstTop = dBufTop.bufAt(0, 0);
+
+    // 4.3.2 set back up buffer for below
+    PelBuf dBufBottom = m_bufSubPicBelow.getBuf(compID);
+    Pel    *dstBottom = dBufBottom.bufAt(0, 0);
+
+    // 4.3.3 copy to recon picture to back up buffer
+    Pel *srcTop = src - xmargin - ymargin * s.stride;
+    Pel *srcBottom = src - xmargin + height * s.stride;
+
+    for (int y = 0; y < ymargin; y++) 
+    {
+      ::memcpy(srcTop    + y * s.stride, dstTop    + y *    dBufTop.stride, sizeof(Pel) * (2 * xmargin + width));
+      ::memcpy(srcBottom + y * s.stride, dstBottom + y * dBufBottom.stride, sizeof(Pel) * (2 * xmargin + width));
+    }
+  }
+
+  // 5.0 destroy the back up memory
+  m_bufSubPicAbove.destroy();
+  m_bufSubPicBelow.destroy();
+  m_bufSubPicLeft.destroy();
+  m_bufSubPicRight.destroy();
+}
+#endif
+
 void Picture::extendPicBorder()
 {
   if ( m_bIsBorderExtended )
diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h
index aad5a47fc4b1f207ee4eb6919826411eba2fa8b1..911786f945524826c1f6640d28c03d5eb3353c98 100644
--- a/source/Lib/CommonLib/Picture.h
+++ b/source/Lib/CommonLib/Picture.h
@@ -172,6 +172,21 @@ private:
   Window        m_scalingWindow;
 
 public:
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY  
+  bool m_isSubPicBorderSaved;
+
+  PelStorage m_bufSubPicAbove;
+  PelStorage m_bufSubPicBelow;
+  PelStorage m_bufSubPicLeft;
+  PelStorage m_bufSubPicRight;
+
+  void    saveSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight);
+  void  extendSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight);
+  void restoreSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight);
+
+  bool getSubPicSaved()          { return m_isSubPicBorderSaved; }
+  void setSubPicSaved(bool bVal) { m_isSubPicBorderSaved = bVal; }
+#endif
   bool m_bIsBorderExtended;
   bool referenced;
   bool reconstructed;
diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
index 0953b569a4650468f729db30dff7a300d8d78aad..a910f8a468b2ffd40fdcd0f8a001d912d3fc0f24 100644
--- a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
+++ b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
@@ -726,6 +726,22 @@ void SampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructure&
     isBelowLeftAvail  = (!isBelowLeftAvail)  ? false : CU::isSameTile(*cuCurr, *cuBelowLeft);
     isBelowRightAvail = (!isBelowRightAvail) ? false : CU::isSameTile(*cuCurr, *cuBelowRight);
   }
+
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+  // check cross subpic flags
+  SubPic curSubPic = cs.pps->getSubPicFromCU(*cuCurr);
+  if (!curSubPic.getloopFilterAcrossEnabledFlag())
+  {
+    isLeftAvail       = (!isLeftAvail)       ? false : CU::isSameSubPic(*cuCurr, *cuLeft);
+    isAboveAvail      = (!isAboveAvail)      ? false : CU::isSameSubPic(*cuCurr, *cuAbove);
+    isRightAvail      = (!isRightAvail)      ? false : CU::isSameSubPic(*cuCurr, *cuRight);
+    isBelowAvail      = (!isBelowAvail)      ? false : CU::isSameSubPic(*cuCurr, *cuBelow);
+    isAboveLeftAvail  = (!isAboveLeftAvail)  ? false : CU::isSameSubPic(*cuCurr, *cuAboveLeft);
+    isAboveRightAvail = (!isAboveRightAvail) ? false : CU::isSameSubPic(*cuCurr, *cuAboveRight);
+    isBelowLeftAvail  = (!isBelowLeftAvail)  ? false : CU::isSameSubPic(*cuCurr, *cuBelowLeft);
+    isBelowRightAvail = (!isBelowRightAvail) ? false : CU::isSameSubPic(*cuCurr, *cuBelowRight);
+  }
+#endif
 }
 
 bool SampleAdaptiveOffset::isCrossedByVirtualBoundaries(const int xPos, const int yPos, const int width, const int height, int& numHorVirBndry, int& numVerVirBndry, int horVirBndryPos[], int verVirBndryPos[], const PicHeader* picHeader )
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index e852a1310783ef495a9be273a09ecb7d5c056926..c1fc4bd09a1be0aabeb02029217e23890176f570 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -2472,6 +2472,7 @@ void PPS::initSubPic(const SPS &sps)
   m_subPics.resize(getNumSubPics());
   for (int i=0; i< getNumSubPics(); i++)
   {
+    m_subPics[i].setSubPicIdx(i);
     m_subPics[i].setSubPicCtuTopLeftX(sps.getSubPicCtuTopLeftX(i));
     m_subPics[i].setSubPicCtuTopLeftY(sps.getSubPicCtuTopLeftY(i));
     m_subPics[i].setSubPicWidthInCTUs(sps.getSubPicWidth(i));
@@ -2488,10 +2489,15 @@ void PPS::initSubPic(const SPS &sps)
     uint32_t right = std::min(m_picWidthInLumaSamples - 1, (sps.getSubPicCtuTopLeftX(i) + sps.getSubPicWidth(i)) * m_ctuSize - 1);
     m_subPics[i].setSubPicRight(right);
     
+    m_subPics[i].setSubPicWidthInLumaSample(right - left + 1);
+
     uint32_t top = sps.getSubPicCtuTopLeftY(i) * m_ctuSize;
     m_subPics[i].setSubPicTop(top);
     
     uint32_t bottom = std::min(m_picHeightInLumaSamples - 1, (sps.getSubPicCtuTopLeftY(i) + sps.getSubPicHeight(i)) * m_ctuSize - 1);
+
+    m_subPics[i].setSubPicHeightInLumaSample(bottom - top + 1);
+
     m_subPics[i].setSubPicBottom(bottom);
     
     for (int j = 0; j < m_numSlicesInPic; j++)
@@ -2504,7 +2510,7 @@ void PPS::initSubPic(const SPS &sps)
           ctu_y >= sps.getSubPicCtuTopLeftY(i) &&
           ctu_y < (sps.getSubPicCtuTopLeftY(i) + sps.getSubPicHeight(i))) 
       {
-         // slice in the subpicture
+         // add ctus in a slice to the subpicture it belongs to
         m_subPics[i].addCTUsToSubPic(m_sliceMap[j].getCtuAddrList());
       }
     }
@@ -2512,6 +2518,24 @@ void PPS::initSubPic(const SPS &sps)
     m_subPics[i].setloopFilterAcrossEnabledFlag(sps.getLoopFilterAcrossSubpicEnabledFlag(i));
   }
 }
+
+SubPic PPS::getSubPicFromPos(const Position& pos)  const
+{
+  for (int i = 0; i< m_numSubPics; i++)
+  {
+    if (m_subPics[i].isContainingPos(pos))
+    {
+      return m_subPics[i];
+    }
+  }
+  return m_subPics[0];
+}
+
+SubPic  PPS::getSubPicFromCU(const CodingUnit& cu) const 
+{
+  const Position lumaPos = cu.Y().valid() ? cu.Y().pos() : recalcPosition(cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].pos());
+  return getSubPicFromPos(lumaPos);
+}
 #endif
 
 void PPS::initRasterSliceMap( std::vector<uint32_t> numTilesInSlice )
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 70fea19893c40bb0951b3e61855e63aadabbe19b..f148d808e700ebeb2dca0ea42f9b02094e899f48 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -689,11 +689,14 @@ class SubPic
 {
 private:
   uint32_t         m_subPicID;                                  //!< ID of subpicture
+  uint32_t         m_subPicIdx;                                 //!< Index of subpicture
   uint32_t         m_numCTUsInSubPic;                           //!< number of CTUs contained in this sub-picture
   uint32_t         m_subPicCtuTopLeftX;                         //!< horizontal position of top left CTU of the subpicture in unit of CTU
   uint32_t         m_subPicCtuTopLeftY;                         //!< vertical position of top left CTU of the subpicture in unit of CTU
   uint32_t         m_subPicWidth;                               //!< the width of subpicture in units of CTU
   uint32_t         m_subPicHeight;                              //!< the height of subpicture in units of CTU
+  uint32_t         m_subPicWidthInLumaSample;                   //!< the width of subpicture in units of luma sample
+  uint32_t         m_subPicHeightInLumaSample;                  //!< the height of subpicture in units of luma sample
   uint32_t         m_firstCtuInSubPic;                          //!< the raster scan index of the first CTU in a subpicture
   uint32_t         m_lastCtuInSubPic;                           //!< the raster scan index of the last CTU in a subpicture
   uint32_t         m_subPicLeft;                                //!< the position of left boundary 
@@ -711,6 +714,8 @@ public:
 
   void             setSubPicID (uint32_t u)                {         m_subPicID = u;       }
   uint32_t         getSubPicID   ()                  const { return  m_subPicID;           }
+  void             setSubPicIdx (uint32_t u)               {         m_subPicIdx = u;      }
+  uint32_t         getSubPicIdx ()                   const { return  m_subPicIdx;          }
   void             setNumCTUsInSubPic   (uint32_t u)       {         m_numCTUsInSubPic = u;       }
   uint32_t         getNumCTUsInSubPic   ()           const { return  m_numCTUsInSubPic;           }
   void             setSubPicCtuTopLeftX (uint32_t u)       {         m_subPicCtuTopLeftX = u;     }
@@ -734,16 +739,28 @@ public:
   void             setSubPicBottom      (uint32_t u)       {         m_subPicBottom = u;          }
   uint32_t         getSubPicBottom      ()           const { return  m_subPicBottom;              }
 
+  void             setSubPicWidthInLumaSample (uint32_t u) {         m_subPicWidthInLumaSample = u;   }
+  uint32_t         getSubPicWidthInLumaSample()      const { return  m_subPicWidthInLumaSample;       }
+  void             setSubPicHeightInLumaSample(uint32_t u) {         m_subPicHeightInLumaSample = u;  }
+  uint32_t         getSubPicHeightInLumaSample()     const { return  m_subPicHeightInLumaSample;      }
+
   std::vector<uint32_t> getCtuAddrList  ()           const { return  m_ctuAddrInSubPic;           }
   void                  addCTUsToSubPic(std::vector<uint32_t> ctuAddrInSlice)
   {
     for (auto ctu:ctuAddrInSlice)
       m_ctuAddrInSubPic.push_back(ctu);    
   }
+  bool                 isContainingPos(const Position& pos) const
+  {
+    return pos.x >= m_subPicLeft && pos.x <= m_subPicRight && pos.y >= m_subPicTop  && pos.y <= m_subPicBottom;
+  }
   void             setTreatedAsPicFlag           (bool u)  {         m_treatedAsPicFlag = u;   }
   bool             getTreatedAsPicFlag           ()  const { return  m_treatedAsPicFlag;       }
   void             setloopFilterAcrossEnabledFlag(bool u)  {         m_loopFilterAcrossSubPicEnabledFlag = u; }
   bool             getloopFilterAcrossEnabledFlag()  const { return  m_loopFilterAcrossSubPicEnabledFlag;     }
+
+  bool             isFirstCTUinSubPic(uint32_t ctuAddr)    { return  ctuAddr == m_firstCtuInSubPic;  }
+  bool              isLastCTUinSubPic(uint32_t ctuAddr)    { return  ctuAddr == m_lastCtuInSubPic;   }
 };
 #endif
 class DPS
@@ -1925,6 +1942,8 @@ public:
 #if JVET_O1143_SUBPIC_BOUNDARY
   std::vector<SubPic>    getSubPics()  const                                              {return m_subPics;          };
   void                   initSubPic(const SPS &sps);
+  SubPic                 getSubPicFromPos(const Position& pos)  const;
+  SubPic                 getSubPicFromCU (const CodingUnit& cu) const;
 #endif
   void                   initRasterSliceMap( std::vector<uint32_t> sizes );
   void                   checkSliceMap(); 
@@ -2616,7 +2635,11 @@ public:
   int                         getNumRefIdx( RefPicList e ) const                     { return m_aiNumRefIdx[e];                                      }
   Picture*                    getPic()                                               { return m_pcPic;                                               }
   const Picture*              getPic() const                                         { return m_pcPic;                                               }
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+        Picture*              getRefPic( RefPicList e, int iRefIdx) const            { return m_apcRefPicList[e][iRefIdx];                           }
+#else
   const Picture*              getRefPic( RefPicList e, int iRefIdx) const            { return m_apcRefPicList[e][iRefIdx];                           }
+#endif
   int                         getRefPOC( RefPicList e, int iRefIdx) const            { return m_aiRefPOCList[e][iRefIdx];                            }
   int                         getDepth() const                                       { return m_iDepth;                                              }
   bool                        getColFromL0Flag() const                               { return m_colFromL0Flag;                                       }
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index f848d07f47e43f7bffe7af8260a8151b971b0d82..bd2ecba44893536a6ea105816f4e538729a560b9 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -137,7 +137,9 @@
 
 #define JVET_O1143_SUBPIC_BOUNDARY                        1 // treat subpicture boundary as piucture boundary
 #if JVET_O1143_SUBPIC_BOUNDARY
-#define SUBPIC_DECCHECK                                   0
+#define JVET_O1143_SUBPIC_DECCHECK                        0
+#define JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY             1 
+#define JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY              1
 #endif
 
 #define JVET_Q0495_NLALF_CLIP_CLEANUP                     1 // JVET-Q0495: Cleanup of clipping table for NL-ALF
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 0b812f72b6b9da075ce28375c1f74901875949fe..00860acaf37a540cf64a0fe3a9a7ca6bf2db9c61 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -183,6 +183,13 @@ bool CU::isSameSliceAndTile(const CodingUnit& cu, const CodingUnit& cu2)
   return ( cu.slice->getIndependentSliceIdx() == cu2.slice->getIndependentSliceIdx() ) && ( cu.tileIdx == cu2.tileIdx );
 }
 
+#if JVET_O1143_SUBPIC_BOUNDARY
+bool CU::isSameSubPic(const CodingUnit& cu, const CodingUnit& cu2)
+{
+  return (cu.slice->getPPS()->getSubPicFromCU(cu).getSubPicIdx() == cu2.slice->getPPS()->getSubPicFromCU(cu2).getSubPicIdx()) ;
+}
+#endif 
+
 bool CU::isSameCtu(const CodingUnit& cu, const CodingUnit& cu2)
 {
   uint32_t ctuSizeBit = floorLog2(cu.cs->sps->getMaxCUWidth());
@@ -1080,7 +1087,18 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
     Position posC0;
     Position posC1 = pu.Y().center();
     bool C0Avail = false;
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+    bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
+    SubPic curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
+    if (curSubPic.getTreatedAsPicFlag())
+    {
+      boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
+                      (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
+    }    
+    if (boundaryCond)
+#else
     if (((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight))
+#endif
     {
       int posYInCtu = posRB.y & pcv.maxCUHeightMask;
       if (posYInCtu + 4 < pcv.maxCUHeight)
@@ -1413,6 +1431,15 @@ bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList
     return false;
   }
 
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+  // Check the position of colocated block is within a subpicture
+  SubPic curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
+  if (curSubPic.getTreatedAsPicFlag())
+  {
+    if (!curSubPic.isContainingPos(pos))
+      return false;
+  }
+#endif
   RefPicList eColRefPicList = slice.getCheckLDC() ? eRefPicList : RefPicList(slice.getColFromL0Flag());
 
   const MotionInfo& mi = pColPic->cs->getMotionInfo( pos );
@@ -1789,7 +1816,18 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in
     Position posC1 = pu.Y().center();
     Mv cColMv;
 
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+    bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
+    SubPic curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
+    if (curSubPic.getTreatedAsPicFlag())
+    {
+      boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
+                      (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
+    }    
+    if (boundaryCond)
+#else
     if( ( ( posRB.x + pcv.minCUWidth ) < pcv.lumaWidth ) && ( ( posRB.y + pcv.minCUHeight ) < pcv.lumaHeight ) )
+#endif
     {
       int posYInCtu = posRB.y & pcv.maxCUHeightMask;
       if (posYInCtu + 4 < pcv.maxCUHeight)
@@ -2104,7 +2142,18 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co
       bool C0Avail = false;
       Position posC1 = pu.Y().center();
       Mv cColMv;
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+      bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
+      SubPic curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
+      if (curSubPic.getTreatedAsPicFlag())
+      {
+        boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
+          (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
+      }
+      if (boundaryCond)
+#else
       if ( ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight) )
+#endif
       {
         int posYInCtu = posRB.y & pcv.maxCUHeightMask;
         if (posYInCtu + 4 < pcv.maxCUHeight)
@@ -2681,7 +2730,18 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
         Position posC0;
         bool C0Avail = false;
 
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+        bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
+        SubPic curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
+        if (curSubPic.getTreatedAsPicFlag())
+        {
+          boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
+            (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
+        }
+        if (boundaryCond)
+#else
         if ( ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight) )
+#endif
         {
           int posYInCtu = posRB.y & pcv.maxCUHeightMask;
           if (posYInCtu + 4 < pcv.maxCUHeight)
@@ -2871,7 +2931,20 @@ void clipColPos(int& posX, int& posY, const PredictionUnit& pu)
   int log2CtuSize = floorLog2(pu.cs->sps->getCTUSize());
   int ctuX = ((puPos.x >> log2CtuSize) << log2CtuSize);
   int ctuY = ((puPos.y >> log2CtuSize) << log2CtuSize);
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+  int horMax;
+  SubPic curSubPic = pu.cu->slice->getPPS()->getSubPicFromPos(puPos);
+  if (curSubPic.getTreatedAsPicFlag())
+  {
+    horMax = std::min((int)curSubPic.getSubPicRight(), ctuX + (int)pu.cs->sps->getCTUSize() + 3);
+  }
+  else
+  {
+    horMax = std::min((int)pu.cs->pps->getPicWidthInLumaSamples() - 1, ctuX + (int)pu.cs->sps->getCTUSize() + 3);
+  }
+#else
   int horMax = std::min( (int)pu.cs->pps->getPicWidthInLumaSamples() - 1, ctuX + (int)pu.cs->sps->getCTUSize() + 3 );
+#endif
   int horMin = std::max((int)0, ctuX);
   int verMax = std::min( (int)pu.cs->pps->getPicHeightInLumaSamples() - 1, ctuY + (int)pu.cs->sps->getCTUSize() - 1 );
   int verMin = std::max((int)0, ctuY);
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index e13475ef6c10886d9562969009bae48d6abc9ca5..3807321f851979aa4cdd2aa63b62ca1156880703 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -66,6 +66,9 @@ namespace CU
   bool isSameSlice                    (const CodingUnit &cu, const CodingUnit &cu2);
   bool isSameTile                     (const CodingUnit &cu, const CodingUnit &cu2);
   bool isSameSliceAndTile             (const CodingUnit &cu, const CodingUnit &cu2);
+#if JVET_O1143_SUBPIC_BOUNDARY
+  bool isSameSubPic                   (const CodingUnit &cu, const CodingUnit &cu2);
+#endif
   bool isLastSubCUOfCtu               (const CodingUnit &cu);
   uint32_t getCtuAddr                     (const CodingUnit &cu);
   int  predictQP                      (const CodingUnit& cu, const int prevQP );
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index f44ebb6b39c0b3abeac9da257e54ce167de055e1..b7560efd5a32ccc677763d85285d277c2fc8f4ca 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -599,7 +599,7 @@ void DecLib::executeLoopFilters()
     m_cALF.ALFProcess(cs);
   }
 
-#if SUBPIC_DECCHECK 
+#if JVET_O1143_SUBPIC_DECCHECK 
   for (int i = 0; i < cs.pps->getNumSubPics(); i++)
   {
     // keep target subpic samples untouched, for other subpics mask their output sample value to 0
diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h
index 5e8aef4978aed58794f72011d935bf6f67076a0c..31cd21d3b9c6a41abf69e6e526ffe0c1aec597d6 100644
--- a/source/Lib/DecoderLib/DecLib.h
+++ b/source/Lib/DecoderLib/DecLib.h
@@ -147,7 +147,7 @@ private:
   bool                    m_scalingListUpdateFlag;
   int                     m_PreScalingListAPSId;
 
-#if SUBPIC_DECCHECK
+#if JVET_O1143_SUBPIC_DECCHECK
 public:
   int                     m_targetSubPicIdx;
 #endif
diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp
index 9e4d1360f7ecba1201d193cf282e85e70cf90cac..762ddf16bca5d86ccdbebbc7df5b389a339a2021 100644
--- a/source/Lib/DecoderLib/DecSlice.cpp
+++ b/source/Lib/DecoderLib/DecSlice.cpp
@@ -143,6 +143,31 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
     const unsigned  maxCUSize             = sps->getMaxCUWidth();
     Position pos( ctuXPosInCtus*maxCUSize, ctuYPosInCtus*maxCUSize) ;
     UnitArea ctuArea(cs.area.chromaFormat, Area( pos.x, pos.y, maxCUSize, maxCUSize ) );
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+    SubPic curSubPic = slice->getPPS()->getSubPicFromPos(pos);
+    // padding/restore at slice level
+    if (curSubPic.getTreatedAsPicFlag() && ctuIdx==0)
+    {
+      int subPicX      = (int)curSubPic.getSubPicLeft();
+      int subPicY      = (int)curSubPic.getSubPicTop();
+      int subPicWidth  = (int)curSubPic.getSubPicWidthInLumaSample();
+      int subPicHeight = (int)curSubPic.getSubPicHeightInLumaSample();
+      for (int rlist = REF_PIC_LIST_0; rlist < NUM_REF_PIC_LIST_01; rlist++) 
+      {
+        int n = slice->getNumRefIdx((RefPicList)rlist);
+        for (int idx = 0; idx < n; idx++) 
+        {
+          Picture *refPic = slice->getRefPic((RefPicList)rlist, idx);
+          if (!refPic->getSubPicSaved()) 
+          {
+            refPic->saveSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight);
+            refPic->extendSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight);
+            refPic->setSubPicSaved(true);
+          }
+        }
+      }
+    }
+#endif
 
     DTRACE_UPDATE( g_trace_ctx, std::make_pair( "ctu", ctuRsAddr ) );
 
@@ -232,6 +257,29 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
 #endif
       subStrmId++;
     }
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+    if (curSubPic.getTreatedAsPicFlag() && ctuIdx == (slice->getNumCtuInSlice() - 1))
+    // for last Ctu in the slice
+    {
+      int subPicX = (int)curSubPic.getSubPicLeft();
+      int subPicY = (int)curSubPic.getSubPicTop();
+      int subPicWidth = (int)curSubPic.getSubPicWidthInLumaSample();
+      int subPicHeight = (int)curSubPic.getSubPicHeightInLumaSample();
+      for (int rlist = REF_PIC_LIST_0; rlist < NUM_REF_PIC_LIST_01; rlist++) 
+      {
+        int n = slice->getNumRefIdx((RefPicList)rlist);
+        for (int idx = 0; idx < n; idx++) 
+        {
+          Picture *refPic = slice->getRefPic((RefPicList)rlist, idx);
+          if (refPic->getSubPicSaved()) 
+          {
+            refPic->restoreSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight);
+            refPic->setSubPicSaved(false);
+          }
+        }
+      }
+    }
+#endif
   }
 
   // deallocate all created substreams, including internal buffers.
diff --git a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp
index 15ed5b0e24d0cf823d5a44eeb7d3cb83702b4fbe..44e214ff819d20d2b6a28fbe354fe48ca805ea44 100644
--- a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp
+++ b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp
@@ -1569,6 +1569,16 @@ void EncSampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructu
     isAboveAvail     = (!isAboveAvail)     ? false : CU::isSameTile(*cuCurr, *cuAbove);
     isAboveLeftAvail = (!isAboveLeftAvail) ? false : CU::isSameTile(*cuCurr, *cuAboveLeft);
   }
+
+#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY
+  SubPic curSubPic = cs.pps->getSubPicFromCU(*cuCurr);
+  if (!curSubPic.getloopFilterAcrossEnabledFlag())
+  {
+    isLeftAvail      = (!isLeftAvail)      ? false : CU::isSameSubPic(*cuCurr, *cuLeft);
+    isAboveAvail     = (!isAboveAvail)     ? false : CU::isSameSubPic(*cuCurr, *cuAbove);
+    isAboveLeftAvail = (!isAboveLeftAvail) ? false : CU::isSameSubPic(*cuCurr, *cuAboveLeft);
+  }
+#endif
 }
 
 //! \}
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index 525656424605f6c1b197df535824366f7e4fa894..449ba3af1d9f82708e8c138b0e5abecb2f179312 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -1462,7 +1462,32 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
       cs.motionLut.lutIbc.resize(0);
     }
 
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+    SubPic curSubPic = pcSlice->getPPS()->getSubPicFromPos(pos);
+    // padding/restore at slice level
+    if (curSubPic.getTreatedAsPicFlag() && ctuIdx == 0)
+    {
+      int subPicX = (int)curSubPic.getSubPicLeft();
+      int subPicY = (int)curSubPic.getSubPicTop();
+      int subPicWidth = (int)curSubPic.getSubPicWidthInLumaSample();
+      int subPicHeight = (int)curSubPic.getSubPicHeightInLumaSample();
 
+      for (int rlist = REF_PIC_LIST_0; rlist < NUM_REF_PIC_LIST_01; rlist++) 
+      {
+        int n = pcSlice->getNumRefIdx((RefPicList)rlist);
+        for (int idx = 0; idx < n; idx++) 
+        {
+          Picture *refPic = pcSlice->getRefPic((RefPicList)rlist, idx);
+          if (!refPic->getSubPicSaved()) 
+          {
+            refPic->saveSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight);
+            refPic->extendSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight);
+            refPic->setSubPicSaved(true);
+          }
+        }
+      }
+    }
+#endif
     if (cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && cs.pps->ctuIsTileRowBd( ctuYPosInCtus ))
     {
       pCABACWriter->initCtxModels( *pcSlice );
@@ -1659,6 +1684,31 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
 
     m_uiPicTotalBits += actualBits;
     m_uiPicDist       = cs.dist;
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+    // for last Ctu in the slice    
+    if (curSubPic.getTreatedAsPicFlag() && ctuIdx == (pcSlice->getNumCtuInSlice() - 1))
+    {
+
+      int subPicX = (int)curSubPic.getSubPicLeft();
+      int subPicY = (int)curSubPic.getSubPicTop();
+      int subPicWidth = (int)curSubPic.getSubPicWidthInLumaSample();
+      int subPicHeight = (int)curSubPic.getSubPicHeightInLumaSample();
+
+      for (int rlist = REF_PIC_LIST_0; rlist < NUM_REF_PIC_LIST_01; rlist++) 
+      {
+        int n = pcSlice->getNumRefIdx((RefPicList)rlist);
+        for (int idx = 0; idx < n; idx++) 
+        {
+          Picture *refPic = pcSlice->getRefPic((RefPicList)rlist, idx);
+          if (refPic->getSubPicSaved()) 
+          {
+            refPic->restoreSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight);
+            refPic->setSubPicSaved(false);
+          }
+        }
+      }
+    }
+#endif
   }
 
   // this is wpp exclusive section
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index 51ff99a7861f2842f10a4c8d09697415c6867e40..91fcfd1333db435b5df1dd5532b29c05c5ff5cd6 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -7984,7 +7984,17 @@ void InterSearch::xClipMv( Mv& rcMv, const Position& pos, const struct Size& siz
 
   int verMax = ( pps.getPicHeightInLumaSamples() + offset - (int)pos.y - 1 ) << mvShift;
   int verMin = ( -( int ) sps.getMaxCUHeight()   - offset - ( int ) pos.y + 1 ) << mvShift;
+#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY
+  SubPic curSubPic = pps.getSubPicFromPos(pos);
+  if (curSubPic.getTreatedAsPicFlag()) 
+  {
+    horMax = (curSubPic.getSubPicWidthInLumaSample() + offset - (int)pos.x - 1) << mvShift;
+    horMin = (-(int)sps.getMaxCUWidth()  - offset - ((int)pos.x - curSubPic.getSubPicLeft()) + 1) << mvShift;
 
+    verMax = (curSubPic.getSubPicHeightInLumaSample()+ offset -  (int)pos.y - 1) << mvShift;
+    verMin = (-(int)sps.getMaxCUHeight() - offset - ((int)pos.y - curSubPic.getSubPicTop()) + 1) << mvShift;
+  }
+#endif
   if( sps.getWrapAroundEnabledFlag() )
   {
     int horMax = ( pps.getPicWidthInLumaSamples() + sps.getMaxCUWidth() - size.width + offset - (int)pos.x - 1 ) << mvShift;