diff --git a/source/Lib/CommonLib/BilateralFilter.cpp b/source/Lib/CommonLib/BilateralFilter.cpp
index e305dffca256e3a2a649aeb1ab9f7a3b79f81c0d..ca9dca23e1e9f3390603198e8d508c35f2d185f5 100644
--- a/source/Lib/CommonLib/BilateralFilter.cpp
+++ b/source/Lib/CommonLib/BilateralFilter.cpp
@@ -2956,8 +2956,8 @@ void BilateralFilter::bilateralFilterPicRDOperCTUChroma(CodingStructure& cs, Pel
             CompArea &myArea                         = (isCb ? currTU.block(COMPONENT_Cb) : currTU.block(COMPONENT_Cr));
             const int chromaScaleX                   = getComponentScaleX(COMPONENT_Cb, currTU.cu->cs->pcv->chrFormat);
             const int chromaScaleY                   = getComponentScaleY(COMPONENT_Cb, currTU.cu->cs->pcv->chrFormat);
-            int       yPos                           = myArea.y << chromaScaleX;
-            int       xPos                           = myArea.x << chromaScaleY;
+            int       yPos                           = myArea.y << chromaScaleY;
+            int       xPos                           = myArea.x << chromaScaleX;
             bool      isTUCrossedByVirtualBoundaries = isCrossedByVirtualBoundaries(
               cs, xPos, yPos, myArea.width << chromaScaleX, myArea.height << chromaScaleY, clipTop, clipBottom,
               clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos);
diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
index 392849eb70c07dd29abc74188813bdc3abba8042..28e69d7e756fc73a7a53e8c04b920c58a7c0d351 100644
--- a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
+++ b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
@@ -1227,8 +1227,8 @@ void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkP
                 CompArea &myArea                         = currTU.block(compID);
                 const int chromaScaleX                   = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat);
                 const int chromaScaleY                   = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat);
-                int       yPos                           = myArea.y << chromaScaleX;
-                int       xPos                           = myArea.x << chromaScaleY;
+                int       yPos                           = myArea.y << chromaScaleY;
+                int       xPos                           = myArea.x << chromaScaleX;
                 bool      isTUCrossedByVirtualBoundaries = m_bilateralFilter.isCrossedByVirtualBoundaries(
                   cs, xPos, yPos, myArea.width << chromaScaleX, myArea.height << chromaScaleY, clipTop, clipBottom,
                   clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos);
@@ -1385,8 +1385,8 @@ void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkP
                   CompArea &myArea                         = currTU.block(compID);
                   const int chromaScaleX                   = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat);
                   const int chromaScaleY                   = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat);
-                  int       yPos                           = myArea.y << chromaScaleX;
-                  int       xPos                           = myArea.x << chromaScaleY;
+                  int       yPos                           = myArea.y << chromaScaleY;
+                  int       xPos                           = myArea.x << chromaScaleX;
                   bool      isTUCrossedByVirtualBoundaries = m_bilateralFilter.isCrossedByVirtualBoundaries(
                     cs, xPos, yPos, myArea.width << chromaScaleX, myArea.height << chromaScaleY, clipTop, clipBottom,
                     clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos);
@@ -1536,8 +1536,8 @@ void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkP
                   CompArea &myArea                         = currTU.block(compID);
                   const int chromaScaleX                   = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat);
                   const int chromaScaleY                   = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat);
-                  int       yPos                           = myArea.y << chromaScaleX;
-                  int       xPos                           = myArea.x << chromaScaleY;
+                  int       yPos                           = myArea.y << chromaScaleY;
+                  int       xPos                           = myArea.x << chromaScaleX;
                   bool      isTUCrossedByVirtualBoundaries = m_bilateralFilter.isCrossedByVirtualBoundaries(
                     cs, xPos, yPos, myArea.width << chromaScaleX, myArea.height << chromaScaleY, clipTop, clipBottom,
                     clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos);
@@ -1870,18 +1870,15 @@ void SampleAdaptiveOffset::offsetCTUCcSaoNoClip(CodingStructure& cs, const UnitA
         {
           verVirBndryPosComp[i] = (verVirBndryPos[i] >> ::getComponentScaleX(compID, area.chromaFormat)) - compArea.x;
         }
-        const int chromaScaleX = getComponentScaleX(compID, cs.pcv->chrFormat);
-        const int chromaScaleY = getComponentScaleY(compID, cs.pcv->chrFormat);
 #endif
 
-          offsetBlockCcSaoNoClipEdge(compID, cs.sps->getBitDepth(toChannelType(compID)), cs.slice->clpRng(compID),
+          offsetBlockCcSaoNoClipEdge(compID, cs.sps->getChromaFormatIdc(), cs.sps->getBitDepth(toChannelType(compID)), cs.slice->clpRng(compID),
                                      candPosY, bandNumY, bandNumU, bandNumV, offset, srcBlkY, srcBlkU, srcBlkV, dstBlk,
                                      srcStrideY, srcStrideU, srcStrideV, dstStride, compArea.width, compArea.height,
                                      isLeftAvail, isRightAvail, isAboveAvail, isBelowAvail, isAboveLeftAvail,
                                      isAboveRightAvail, isBelowLeftAvail, isBelowRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
             , isCtuCrossedByVirtualBoundaries, horVirBndryPosComp, verVirBndryPosComp, numHorVirBndry, numVerVirBndry
-            , chromaScaleX, chromaScaleY
 #endif
           );
         }
@@ -1917,18 +1914,15 @@ void SampleAdaptiveOffset::offsetCTUCcSaoNoClip(CodingStructure& cs, const UnitA
         {
           verVirBndryPosComp[i] = (verVirBndryPos[i] >> ::getComponentScaleX(compID, area.chromaFormat)) - compArea.x;
         }
-        const int chromaScaleX = getComponentScaleX(compID, cs.pcv->chrFormat);
-        const int chromaScaleY = getComponentScaleY(compID, cs.pcv->chrFormat);
 #endif
       
-          offsetBlockCcSaoNoClip(compID, cs.sps->getBitDepth(toChannelType(compID)), cs.slice->clpRng(compID), candPosY,
+          offsetBlockCcSaoNoClip(compID, cs.sps->getChromaFormatIdc(), cs.sps->getBitDepth(toChannelType(compID)), cs.slice->clpRng(compID), candPosY,
                                  bandNumY, bandNumU, bandNumV, offset, srcBlkY, srcBlkU, srcBlkV, dstBlk, srcStrideY,
                                  srcStrideU, srcStrideV, dstStride, compArea.width, compArea.height, isLeftAvail,
                                  isRightAvail, isAboveAvail, isBelowAvail, isAboveLeftAvail, isAboveRightAvail,
                                  isBelowLeftAvail, isBelowRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                                  , isCtuCrossedByVirtualBoundaries, horVirBndryPosComp, verVirBndryPosComp, numHorVirBndry, numVerVirBndry
-                                 , chromaScaleX, chromaScaleY
 #endif
                               );
         }
@@ -2000,11 +1994,9 @@ void SampleAdaptiveOffset::offsetCTUCcSao(CodingStructure& cs, const UnitArea& a
         {
           verVirBndryPosComp[i] = (verVirBndryPos[i] >> ::getComponentScaleX(compID, area.chromaFormat)) - compArea.x;
         }
-        const int chromaScaleX = getComponentScaleX(compID, cs.pcv->chrFormat);
-        const int chromaScaleY = getComponentScaleY(compID, cs.pcv->chrFormat);
 #endif
 
-        offsetBlockCcSao( compID, cs.sps->getBitDepth(toChannelType(compID)), cs.slice->clpRng(compID)
+        offsetBlockCcSao( compID, cs.sps->getChromaFormatIdc(), cs.sps->getBitDepth(toChannelType(compID)), cs.slice->clpRng(compID)
                         , candPosY, bandNumY, bandNumU, bandNumV
                         , offset
                         , srcBlkY, srcBlkU, srcBlkV, dstBlk
@@ -2016,7 +2008,6 @@ void SampleAdaptiveOffset::offsetCTUCcSao(CodingStructure& cs, const UnitArea& a
                         , isBelowLeftAvail, isBelowRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                         , isCtuCrossedByVirtualBoundaries, horVirBndryPosComp, verVirBndryPosComp, numHorVirBndry, numVerVirBndry
-                        , chromaScaleX, chromaScaleY
 #endif
                         );
       }
@@ -2056,14 +2047,13 @@ int calcDiffRange(Pel a, Pel b, int th)
 }
 
 void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
-  const ComponentID compID, const int bitDepth, const ClpRng &clpRng, const uint16_t candPosY, const uint16_t bandNumY,
+  const ComponentID compID, const ChromaFormat chromaFormat, const int bitDepth, const ClpRng &clpRng, const uint16_t candPosY, const uint16_t bandNumY,
   const uint16_t bandNumU, const uint16_t bandNumV, const short *offset, const Pel *srcY, const Pel *srcU,
   const Pel *srcV, Pel *dst, const int srcStrideY, const int srcStrideU, const int srcStrideV, const int dstStride,
   const int width, const int height, bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail,
   bool isAboveLeftAvail, bool isAboveRightAvail, bool isBelowLeftAvail, bool isBelowRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
   ,bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-  , const int chromaScaleX, const int chromaScaleY 
 #endif
 )
 {
@@ -2074,6 +2064,10 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
   int       signa, signb, band;
   int       th = bandNumU - 1;
 
+  const int chromaScaleX = getChannelTypeScaleX( CHANNEL_TYPE_CHROMA, chromaFormat );
+  const int chromaScaleY = getChannelTypeScaleY( CHANNEL_TYPE_CHROMA, chromaFormat );
+  const int chromaScaleYM1 = 1 - chromaScaleY;
+
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
   int x, y, startX, startY, endX, endY;
   int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX;
@@ -2131,8 +2125,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
           }
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
     }
@@ -2145,8 +2139,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
       if (!isAboveAvail)
       {
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         dst += dstStride;
       }
       for (y = startY; y < endY; y++)
@@ -2193,8 +2187,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
           }
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
     }
@@ -2250,8 +2244,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
         }
       }
       srcY += srcStrideY;
-      srcU += srcStrideU * (0 & 0x1);
-      srcV += srcStrideV * (0 & 0x1);
+      srcU += srcStrideU * chromaScaleYM1;
+      srcV += srcStrideV * chromaScaleYM1;
       dst += dstStride;
 
       // middle lines
@@ -2299,8 +2293,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
           }
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
 
@@ -2400,9 +2394,10 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
         }
       }
       srcY += srcStrideY;
-      srcU += srcStrideU * (0 & 0x1);
-      srcV += srcStrideV * (0 & 0x1);
+      srcU += srcStrideU * chromaScaleYM1;
+      srcV += srcStrideV * chromaScaleYM1;
       dst += dstStride;
+
       // middle lines
       for (y = 1; y < height - 1; y++)
       {
@@ -2448,8 +2443,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
           }
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
 
@@ -2556,7 +2551,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
             dst[x]             = dst[x] + offset[classIdx];
           }
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -2570,7 +2565,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
       endY   = isBelowAvail ? height : height - 1;
       if (!isAboveAvail)
       {
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -2619,7 +2614,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
             dst[x]             = dst[x] + offset[classIdx];
           }
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -2677,7 +2672,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
           dst[x]             = dst[x] + offset[classIdx];
         }
       }
-      srcY += srcStrideY << 1;
+      srcY += srcStrideY << chromaScaleY;
       srcU += srcStrideU;
       srcV += srcStrideV;
       dst += dstStride;
@@ -2727,7 +2722,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
             dst[x]             = dst[x] + offset[classIdx];
           }
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -2830,10 +2825,11 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
           dst[x]             = dst[x] + offset[classIdx];
         }
       }
-      srcY += srcStrideY << 1;
+      srcY += srcStrideY << chromaScaleY;
       srcU += srcStrideU;
       srcV += srcStrideV;
       dst += dstStride;
+
       // middle lines
       for (y = 1; y < height - 1; y++)
       {
@@ -2879,7 +2875,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
             dst[x]             = dst[x] + offset[classIdx];
           }
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -2985,8 +2981,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
         }
       }
       srcY += srcStrideY;
-      srcU += srcStrideU * (y & 0x1);
-      srcV += srcStrideV * (y & 0x1);
+      srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+      srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
       dst += dstStride;
     }
   }
@@ -3033,7 +3029,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
           dst[x]             = dst[x] + offset[classIdx];
         }
       }
-      srcY += srcStrideY << 1;
+      srcY += srcStrideY << chromaScaleY;
       srcU += srcStrideU;
       srcV += srcStrideV;
       dst += dstStride;
@@ -3048,7 +3044,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClipEdge(
 #endif
 }
 #endif
-void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, const int bitDepth, const ClpRng& clpRng
+void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, const ChromaFormat chromaFormat, const int bitDepth, const ClpRng& clpRng
                                                 , const uint16_t candPosY
                                                 , const uint16_t bandNumY, const uint16_t bandNumU, const uint16_t bandNumV
                                                 , const short* offset
@@ -3058,13 +3054,16 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
                                                 , bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail, bool isBelowLeftAvail, bool isBelowRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                                                 , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-                                                , const int chromaScaleX, const int chromaScaleY 
 #endif
                                                  )
 {
   const int candPosYX = g_ccSaoCandPosX[COMPONENT_Y][candPosY];
   const int candPosYY = g_ccSaoCandPosY[COMPONENT_Y][candPosY];
 
+  const int chromaScaleX = getChannelTypeScaleX( CHANNEL_TYPE_CHROMA, chromaFormat );
+  const int chromaScaleY = getChannelTypeScaleY( CHANNEL_TYPE_CHROMA, chromaFormat );
+  const int chromaScaleYM1 = 1 - chromaScaleY;
+
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
   int x, y, startX, startY, endX, endY;
   int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX;
@@ -3105,8 +3104,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           dst[x] = dst[x] + offset[classIdx];
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         dst += dstStride;
 
         // middle lines
@@ -3132,8 +3131,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
             dst[x] = dst[x] + offset[classIdx];
           }
           srcY += srcStrideY;
-          srcU += srcStrideU * (y & 0x1);
-          srcV += srcStrideV * (y & 0x1);
+          srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+          srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
           dst += dstStride;
         }
       }
@@ -3145,8 +3144,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
       if (!isAboveAvail)
       {
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         dst += dstStride;
       }
       for (y = startY; y < endY; y++)
@@ -3172,8 +3171,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
         }
 
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -3206,8 +3205,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
       }
 
       srcY += srcStrideY;
-      srcU += srcStrideU * (0 & 0x1);
-      srcV += srcStrideV * (0 & 0x1);
+      srcU += srcStrideU * chromaScaleYM1;
+      srcV += srcStrideV * chromaScaleYM1;
       dst += dstStride;
 
       // middle lines
@@ -3234,8 +3233,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
         }
 
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -3267,8 +3266,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           dst[x] = dst[x] + offset[classIdx];
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -3294,8 +3293,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           dst[x] = dst[x] + offset[classIdx];
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -3327,8 +3326,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           dst[x] = dst[x] + offset[classIdx];
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -3360,8 +3359,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           dst[x] = dst[x] + offset[classIdx];
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
 
@@ -3417,8 +3416,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           dst[x] = dst[x] + offset[classIdx];
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -3450,10 +3449,11 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           dst[x] = dst[x] + offset[classIdx];
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
+
       // last line
       lastLineStartX = isBelowAvail ? startX : (width - 1);
       lastLineEndX   = isBelowRightAvail ? width : (width - 1);
@@ -3515,7 +3515,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           // dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);
           dst[x] = dst[x] + offset[classIdx];
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -3542,7 +3542,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
             // dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);
             dst[x] = dst[x] + offset[classIdx];
           }
-          srcY += srcStrideY << 1;
+          srcY += srcStrideY << chromaScaleY;
           srcU += srcStrideU;
           srcV += srcStrideV;
           dst += dstStride;
@@ -3556,8 +3556,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
       if (!isAboveAvail)
       {
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         dst += dstStride;
       }
       for (y = startY; y < endY; y++)
@@ -3582,7 +3582,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           dst[x] = dst[x] + offset[classIdx];
         }
 
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -3616,7 +3616,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
         dst[x] = dst[x] + offset[classIdx];
       }
 
-      srcY += srcStrideY << 1;
+      srcY += srcStrideY << chromaScaleY;
       srcU += srcStrideU;
       srcV += srcStrideV;
       dst += dstStride;
@@ -3644,7 +3644,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           dst[x] = dst[x] + offset[classIdx];
         }
 
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -3677,7 +3677,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           // dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);
           dst[x] = dst[x] + offset[classIdx];
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -3704,7 +3704,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           // dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);
           dst[x] = dst[x] + offset[classIdx];
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -3737,7 +3737,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           // dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);
           dst[x] = dst[x] + offset[classIdx];
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -3770,7 +3770,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           // dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);
           dst[x] = dst[x] + offset[classIdx];
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -3827,7 +3827,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           // dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);
           dst[x] = dst[x] + offset[classIdx];
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -3860,7 +3860,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
           // dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);
           dst[x] = dst[x] + offset[classIdx];
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -3922,8 +3922,8 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
       }
 
       srcY += srcStrideY;
-      srcU += srcStrideU * (y & 0x1);
-      srcV += srcStrideV * (y & 0x1);
+      srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+      srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
       dst += dstStride;
     }
   }
@@ -3948,7 +3948,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
         // dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);
         dst[x] = dst[x] + offset[classIdx];
       }
-      srcY += srcStrideY << 1;
+      srcY += srcStrideY << chromaScaleY;
       srcU += srcStrideU;
       srcV += srcStrideV;
       dst += dstStride;
@@ -3963,7 +3963,7 @@ void SampleAdaptiveOffset::offsetBlockCcSaoNoClip(const ComponentID compID, cons
 #endif
 }
 
-void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int bitDepth, const ClpRng& clpRng
+void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const ChromaFormat chromaFormat, const int bitDepth, const ClpRng& clpRng
                                           , const uint16_t candPosY
                                           , const uint16_t bandNumY, const uint16_t bandNumU, const uint16_t bandNumV
                                           , const short* offset
@@ -3973,12 +3973,16 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
                                           , bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail, bool isBelowLeftAvail, bool isBelowRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                                           , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-                                          , const int chromaScaleX, const int chromaScaleY 
 #endif
                                            )
 {
   const int candPosYX = g_ccSaoCandPosX[COMPONENT_Y][candPosY];
   const int candPosYY = g_ccSaoCandPosY[COMPONENT_Y][candPosY];
+
+  const int chromaScaleX = getChannelTypeScaleX( CHANNEL_TYPE_CHROMA, chromaFormat );
+  const int chromaScaleY = getChannelTypeScaleY( CHANNEL_TYPE_CHROMA, chromaFormat );
+  const int chromaScaleYM1 = 1 - chromaScaleY;
+
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
   int x, y, startX, startY, endX, endY;
   int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX;
@@ -4017,8 +4021,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         dst += dstStride;
 
         // middle lines
@@ -4043,8 +4047,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
             dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);            
           }
           srcY += srcStrideY;
-          srcU += srcStrideU * (y & 0x1);
-          srcV += srcStrideV * (y & 0x1);
+          srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+          srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
           dst += dstStride;
         }
       }
@@ -4056,8 +4060,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
       if (!isAboveAvail)
       {
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         dst += dstStride;
       }
       for (y = startY; y < endY; y++)
@@ -4082,8 +4086,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
         }
 
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -4115,8 +4119,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
       }
 
       srcY += srcStrideY;
-      srcU += srcStrideU * (0 & 0x1);
-      srcV += srcStrideV * (0 & 0x1);
+      srcU += srcStrideU * chromaScaleYM1;
+      srcV += srcStrideV * chromaScaleYM1;
       dst += dstStride;
 
       // middle lines
@@ -4142,8 +4146,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
         }
 
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -4174,8 +4178,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -4200,8 +4204,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -4232,8 +4236,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -4264,8 +4268,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
 
@@ -4319,8 +4323,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
       break;
@@ -4351,10 +4355,11 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         dst += dstStride;
       }
+
       // last line
       lastLineStartX = isBelowAvail ? startX : (width - 1);
       lastLineEndX   = isBelowRightAvail ? width : (width - 1);
@@ -4414,7 +4419,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
 
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -4440,7 +4445,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
 
             dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);            
           }
-          srcY += srcStrideY << 1;
+          srcY += srcStrideY << chromaScaleY;
           srcU += srcStrideU;
           srcV += srcStrideV;
           dst += dstStride;
@@ -4454,8 +4459,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
       if (!isAboveAvail)
       {
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         dst += dstStride;
       }
       for (y = startY; y < endY; y++)
@@ -4479,7 +4484,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
 
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -4512,7 +4517,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
         dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);        
       }
 
-      srcY += srcStrideY << 1;
+      srcY += srcStrideY << chromaScaleY;
       srcU += srcStrideU;
       srcV += srcStrideV;
       dst += dstStride;
@@ -4539,7 +4544,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
 
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -4571,7 +4576,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
 
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -4597,7 +4602,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
 
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -4629,7 +4634,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
 
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -4661,7 +4666,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
 
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -4716,7 +4721,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
 
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
@@ -4748,11 +4753,12 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
 
           dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);          
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         dst += dstStride;
       }
+
       // last line
       lastLineStartX = isBelowAvail ? startX : (width - 1);
       lastLineEndX   = isBelowRightAvail ? width : (width - 1);
@@ -4809,8 +4815,8 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
       }
 
       srcY += srcStrideY;
-      srcU += srcStrideU * (y & 0x1);
-      srcV += srcStrideV * (y & 0x1);
+      srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+      srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
       dst += dstStride;
     }
   }
@@ -4835,7 +4841,7 @@ void SampleAdaptiveOffset::offsetBlockCcSao(const ComponentID compID, const int
         dst[x] = ClipPel<int>(dst[x] + offset[classIdx], clpRng);
       }
 
-      srcY += srcStrideY << 1;
+      srcY += srcStrideY << chromaScaleY;
       srcU += srcStrideU;
       srcV += srcStrideV;
       dst += dstStride;
diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.h b/source/Lib/CommonLib/SampleAdaptiveOffset.h
index f52b86c35f0c128c2c2457378af868d5d1cc2ee1..a283dc34ca487deb1dbff1765db457b2acda0618 100644
--- a/source/Lib/CommonLib/SampleAdaptiveOffset.h
+++ b/source/Lib/CommonLib/SampleAdaptiveOffset.h
@@ -152,7 +152,7 @@ protected:
   void applyCcSao(CodingStructure &cs, const PreCalcValues& pcv, const CPelUnitBuf& srcYuv, PelUnitBuf& dstYuv);
   void offsetCTUCcSao(CodingStructure& cs, const UnitArea& area, const CPelUnitBuf& srcYuv, PelUnitBuf& dstYuv, const int ctuRsAddr);
 #if JVET_Y0106_CCSAO_EDGE_CLASSIFIER
-  void offsetBlockCcSaoNoClipEdge(const ComponentID compID, const int bitDepth, const ClpRng &clpRng,
+  void offsetBlockCcSaoNoClipEdge(const ComponentID compID, const ChromaFormat chromaFormat, const int bitDepth, const ClpRng &clpRng,
                                   const uint16_t candPosY, const uint16_t bandNumY, const uint16_t bandNumU,
                                   const uint16_t bandNumV, const short *offset, const Pel *srcY, const Pel *srcU,
                                   const Pel *srcV, Pel *dst, const int srcStrideY, const int srcStrideU,
@@ -161,12 +161,11 @@ protected:
                                   bool isAboveLeftAvail, bool isAboveRightAvail, bool isBelowLeftAvail, bool isBelowRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                                 , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-                                , const int chromaScaleX, const int chromaScaleY 
 #endif
                                   );
 #endif
   void offsetCTUCcSaoNoClip(CodingStructure& cs, const UnitArea& area, const CPelUnitBuf& srcYuv, PelUnitBuf& dstYuv, const int ctuRsAddr);
-  void offsetBlockCcSao(const ComponentID compID, const int bitDepth, const ClpRng& clpRng
+  void offsetBlockCcSao(const ComponentID compID, const ChromaFormat chromaFormat, const int bitDepth, const ClpRng& clpRng
                       , const uint16_t candPosY
                       , const uint16_t bandNumY, const uint16_t bandNumU, const uint16_t bandNumV
                       , const short* offset
@@ -176,10 +175,9 @@ protected:
                       , bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail, bool isBelowLeftAvail, bool isBelowRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                       , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-                      , const int chromaScaleX, const int chromaScaleY 
 #endif
                        );
-  void offsetBlockCcSaoNoClip(const ComponentID compID, const int bitDepth, const ClpRng& clpRng
+  void offsetBlockCcSaoNoClip(const ComponentID compID, const ChromaFormat chromaFormat, const int bitDepth, const ClpRng& clpRng
                             , const uint16_t candPosY
                             , const uint16_t bandNumY, const uint16_t bandNumU, const uint16_t bandNumV
                             , const short* offset
@@ -189,7 +187,6 @@ protected:
                             , bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail, bool isBelowLeftAvail, bool isBelowRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                             , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-                            , const int chromaScaleX, const int chromaScaleY
 #endif
                              );
 #endif
diff --git a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp
index 44f4a0ef88a971f8d54c567aca8e0a427d607705..3283f33e58950ab8e70a21e3d26f924135e2d6b9 100644
--- a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp
+++ b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp
@@ -1493,8 +1493,8 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn
                 CompArea &myArea                         = currTU.block(compID);
                 const int chromaScaleX                   = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat);
                 const int chromaScaleY                   = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat);
-                int       yPos                           = myArea.y << chromaScaleX;
-                int       xPos                           = myArea.x << chromaScaleY;
+                int       yPos                           = myArea.y << chromaScaleY;
+                int       xPos                           = myArea.x << chromaScaleX;
                 bool      isTUCrossedByVirtualBoundaries = m_bilateralFilter.isCrossedByVirtualBoundaries(
                   cs, xPos, yPos, myArea.width << chromaScaleX, myArea.height << chromaScaleY, clipTop, clipBottom,
                   clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos);
@@ -1649,8 +1649,8 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn
                     CompArea &myArea           = currTU.block(compID);
                     const int chromaScaleX     = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat);
                     const int chromaScaleY     = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat);
-                    int       yPos             = myArea.y << chromaScaleX;
-                    int       xPos             = myArea.x << chromaScaleY;
+                    int       yPos             = myArea.y << chromaScaleY;
+                    int       xPos             = myArea.x << chromaScaleX;
                     bool      isTUCrossedByVirtualBoundaries = m_bilateralFilter.isCrossedByVirtualBoundaries(
                       cs, xPos, yPos, myArea.width << chromaScaleX, myArea.height << chromaScaleY, clipTop, clipBottom,
                       clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos);
@@ -1794,8 +1794,8 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn
                   CompArea &myArea                         = currTU.block(compID);
                   const int chromaScaleX                   = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat);
                   const int chromaScaleY                   = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat);
-                  int       yPos                           = myArea.y << chromaScaleX;
-                  int       xPos                           = myArea.x << chromaScaleY;
+                  int       yPos                           = myArea.y << chromaScaleY;
+                  int       xPos                           = myArea.x << chromaScaleX;
                   bool      isTUCrossedByVirtualBoundaries = m_bilateralFilter.isCrossedByVirtualBoundaries(
                     cs, xPos, yPos, myArea.width << chromaScaleX, myArea.height << chromaScaleY, clipTop, clipBottom,
                     clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos);
@@ -1993,8 +1993,8 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn
                   CompArea &myArea                         = currTU.block(compID);
                   const int chromaScaleX                   = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat);
                   const int chromaScaleY                   = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat);
-                  int       yPos                           = myArea.y << chromaScaleX;
-                  int       xPos                           = myArea.x << chromaScaleY;
+                  int       yPos                           = myArea.y << chromaScaleY;
+                  int       xPos                           = myArea.x << chromaScaleX;
                   bool      isTUCrossedByVirtualBoundaries = m_bilateralFilter.isCrossedByVirtualBoundaries(
                     cs, xPos, yPos, myArea.width << chromaScaleX, myArea.height << chromaScaleY, clipTop, clipBottom,
                     clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos);
@@ -2141,8 +2141,8 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn
                     CompArea &myArea           = currTU.block(compID);
                     const int chromaScaleX     = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat);
                     const int chromaScaleY     = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat);
-                    int       yPos             = myArea.y << chromaScaleX;
-                    int       xPos             = myArea.x << chromaScaleY;
+                    int       yPos             = myArea.y << chromaScaleY;
+                    int       xPos             = myArea.x << chromaScaleX;
                     bool      isTUCrossedByVirtualBoundaries = m_bilateralFilter.isCrossedByVirtualBoundaries(
                       cs, xPos, yPos, myArea.width << chromaScaleX, myArea.height << chromaScaleY, clipTop, clipBottom,
                       clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos);
@@ -2342,8 +2342,8 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn
                   CompArea &myArea                         = currTU.block(compID);
                   const int chromaScaleX                   = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat);
                   const int chromaScaleY                   = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat);
-                  int       yPos                           = myArea.y << chromaScaleX;
-                  int       xPos                           = myArea.x << chromaScaleY;
+                  int       yPos                           = myArea.y << chromaScaleY;
+                  int       xPos                           = myArea.x << chromaScaleX;
                   bool      isTUCrossedByVirtualBoundaries = m_bilateralFilter.isCrossedByVirtualBoundaries(
                     cs, xPos, yPos, myArea.width << chromaScaleX, myArea.height << chromaScaleY, clipTop, clipBottom,
                     clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos);
@@ -3371,8 +3371,6 @@ void EncSampleAdaptiveOffset::getCcSaoStatistics(CodingStructure& cs, const Comp
         {
           verVirBndryPosComp[i] = (verVirBndryPos[i] >> ::getComponentScaleX(compID, area.chromaFormat)) - compArea.x;
         }
-        const int chromaScaleX = getComponentScaleX(compID, cs.pcv->chrFormat);
-        const int chromaScaleY = getComponentScaleY(compID, cs.pcv->chrFormat);
 #endif
 
         const uint16_t    candPosY   = ccSaoParam.candPos[setIdx][COMPONENT_Y ];
@@ -3388,7 +3386,6 @@ void EncSampleAdaptiveOffset::getCcSaoStatistics(CodingStructure& cs, const Comp
                        , isLeftAvail, isRightAvail, isAboveAvail, isBelowAvail, isAboveLeftAvail, isAboveRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                        , isCtuCrossedByVirtualBoundaries, horVirBndryPosComp, verVirBndryPosComp, numHorVirBndry, numVerVirBndry
-                       , chromaScaleX, chromaScaleY
 #endif
                        );
       }
@@ -3477,8 +3474,6 @@ void EncSampleAdaptiveOffset::getCcSaoStatisticsEdgeNew(CodingStructure &cs, con
         {
           verVirBndryPosComp[i] = (verVirBndryPos[i] >> ::getComponentScaleX(compID, area.chromaFormat)) - compArea.x;
         }
-        const int chromaScaleX = getComponentScaleX(compID, cs.pcv->chrFormat);
-        const int chromaScaleY = getComponentScaleY(compID, cs.pcv->chrFormat);
 #endif
 
         const uint16_t candPosY = 0;
@@ -3493,7 +3488,6 @@ void EncSampleAdaptiveOffset::getCcSaoStatisticsEdgeNew(CodingStructure &cs, con
                                 isAboveLeftAvail, isAboveRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                               , isCtuCrossedByVirtualBoundaries, horVirBndryPosComp, verVirBndryPosComp, numHorVirBndry, numVerVirBndry
-                              , chromaScaleX, chromaScaleY
 #endif
         );
       }
@@ -3592,11 +3586,15 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
   bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
   , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-  , const int chromaScaleX, const int chromaScaleY 
 #endif
 )
 {
   int signa, signb, band;
+
+  const int chromaScaleX = getChannelTypeScaleX( CHANNEL_TYPE_CHROMA, chromaFormat );
+  const int chromaScaleY = getChannelTypeScaleY( CHANNEL_TYPE_CHROMA, chromaFormat );
+  const int chromaScaleYM1 = 1 - chromaScaleY;
+
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
   int        x, y, startX, startY, endX, endY;
   int        firstLineStartX, firstLineEndX;
@@ -3605,8 +3603,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
   const Pel *srcVT = srcV;
   const Pel *orgT  = org;
   const Pel *dstT  = dst;
-  #endif
-#if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
+
   switch (compID)
   {
   case COMPONENT_Y:
@@ -3679,8 +3676,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
             }     // th
           }       // x
           srcY += srcStrideY;
-          srcU += srcStrideU * (y & 0x1);
-          srcV += srcStrideV * (y & 0x1);
+          srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+          srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
           org += orgStride;
           dst += dstStride;
         }   // y
@@ -3693,8 +3690,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
         if (!isAboveAvail)
         {
           srcY += srcStrideY;
-          srcU += srcStrideU * (0 & 0x1);
-          srcV += srcStrideV * (0 & 0x1);
+          srcU += srcStrideU * chromaScaleYM1;
+          srcV += srcStrideV * chromaScaleYM1;
           org += orgStride;
           dst += dstStride;
         }
@@ -3748,8 +3745,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
             }     // th
           }       // x
           srcY += srcStrideY;
-          srcU += srcStrideU * (y & 0x1);
-          srcV += srcStrideV * (y & 0x1);
+          srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+          srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
           org += orgStride;
           dst += dstStride;
         }   // y
@@ -3810,8 +3807,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
           }     // th
         }       // x
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         org += orgStride;
         dst += dstStride;
 
@@ -3866,8 +3863,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
             }     // th
           }       // x
           srcY += srcStrideY;
-          srcU += srcStrideU * (y & 0x1);
-          srcV += srcStrideV * (y & 0x1);
+          srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+          srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
           org += orgStride;
           dst += dstStride;
         }   // y
@@ -3929,8 +3926,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
           }     // th
         }       // x
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         org += orgStride;
         dst += dstStride;
         // middle lines
@@ -3984,8 +3981,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
             }     // th
           }       // x
           srcY += srcStrideY;
-          srcU += srcStrideU * (y & 0x1);
-          srcV += srcStrideV * (y & 0x1);
+          srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+          srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
           org += orgStride;
           dst += dstStride;
         }   // y
@@ -4069,7 +4066,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
               }   // modeY
             }     // th
           }       // x
-          srcY += srcStrideY << 1;
+          srcY += srcStrideY << chromaScaleY;
           srcU += srcStrideU;
           srcV += srcStrideV;
           org += orgStride;
@@ -4083,7 +4080,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
         endY   = isBelowAvail ? height : height - 1;
         if (!isAboveAvail)
         {
-          srcY += srcStrideY << 1;
+          srcY += srcStrideY << chromaScaleY;
           srcU += srcStrideU;
           srcV += srcStrideV;
           org += orgStride;
@@ -4141,7 +4138,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
               }   // mode
             }     // th
           }       // x
-          srcY += srcStrideY << 1;
+          srcY += srcStrideY << chromaScaleY;
           srcU += srcStrideU;
           srcV += srcStrideV;
           org += orgStride;
@@ -4206,7 +4203,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
             }   // mode
           }     // th
         }       // x
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -4265,7 +4262,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
               }   // mode
             }     // th
           }       // x
-          srcY += srcStrideY << 1;
+          srcY += srcStrideY << chromaScaleY;
           srcU += srcStrideU;
           srcV += srcStrideV;
           org += orgStride;
@@ -4331,7 +4328,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
             }   // mode
           }     // th
         }       // x
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -4389,7 +4386,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
               }   // mode
             }     // th
           }       // x
-          srcY += srcStrideY << 1;
+          srcY += srcStrideY << chromaScaleY;
           srcU += srcStrideU;
           srcV += srcStrideV;
           org += orgStride;
@@ -4466,8 +4463,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
         }       // edge_type
       }         // x
       srcY += srcStrideY;
-      srcU += srcStrideU * (y & 0x1);
-      srcV += srcStrideV * (y & 0x1);
+      srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+      srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
       org += orgStride;
       dst += dstStride;
     }   // y
@@ -4532,7 +4529,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStatsEdgeNew(
           }
         }
       }
-      srcY += srcStrideY << 1;
+      srcY += srcStrideY << chromaScaleY;
       srcU += srcStrideU;
       srcV += srcStrideV;
       org += orgStride;
@@ -4558,16 +4555,20 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
                                              , bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                                              , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-                                             , const int chromaScaleX, const int chromaScaleY 
 #endif
                                              )
 {
   const int candPosYX = g_ccSaoCandPosX[COMPONENT_Y][candPosY];
   const int candPosYY = g_ccSaoCandPosY[COMPONENT_Y][candPosY];
 
+  const int chromaScaleX = getChannelTypeScaleX( CHANNEL_TYPE_CHROMA, chromaFormat );
+  const int chromaScaleY = getChannelTypeScaleY( CHANNEL_TYPE_CHROMA, chromaFormat );
+  const int chromaScaleYM1 = 1 - chromaScaleY;
+
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
   int x, y, startX, startY, endX, endY;
   int firstLineStartX, firstLineEndX;
+
   switch (compID)
   {
   case COMPONENT_Y:
@@ -4581,6 +4582,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
       {
         startX = isLeftAvail ? 0 : 1;
         endX   = width;
+
         // 1st line
         firstLineStartX = isAboveLeftAvail ? 0 : 1;
         firstLineEndX   = isAboveAvail ? endX : 1;
@@ -4604,8 +4606,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         org += orgStride;
         dst += dstStride;
 
@@ -4632,8 +4634,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
             blkStats[setIdx][ctuRsAddr].count[classIdx]++;
           }
           srcY += srcStrideY;
-          srcU += srcStrideU * (y & 0x1);
-          srcV += srcStrideV * (y & 0x1);
+          srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+          srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
           org += orgStride;
           dst += dstStride;
         }
@@ -4646,8 +4648,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
       if (!isAboveAvail)
       {
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         org += orgStride;
         dst += dstStride;
       }
@@ -4673,8 +4675,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         org += orgStride;
         dst += dstStride;
       }
@@ -4708,8 +4710,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
       }
 
       srcY += srcStrideY;
-      srcU += srcStrideU * (0 & 0x1);
-      srcV += srcStrideV * (0 & 0x1);
+      srcU += srcStrideU * chromaScaleYM1;
+      srcV += srcStrideV * chromaScaleYM1;
       org += orgStride;
       dst += dstStride;
 
@@ -4736,8 +4738,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         org += orgStride;
         dst += dstStride;
       }
@@ -4770,8 +4772,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         org += orgStride;
         dst += dstStride;
       }
@@ -4798,8 +4800,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         org += orgStride;
         dst += dstStride;
       }
@@ -4832,8 +4834,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         org += orgStride;
         dst += dstStride;
       }
@@ -4866,8 +4868,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         org += orgStride;
         dst += dstStride;
       }
@@ -4900,8 +4902,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         org += orgStride;
         dst += dstStride;
       }
@@ -4934,8 +4936,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
         srcY += srcStrideY;
-        srcU += srcStrideU * (y & 0x1);
-        srcV += srcStrideV * (y & 0x1);
+        srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+        srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
         org += orgStride;
         dst += dstStride;
       }
@@ -4979,7 +4981,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].diff[classIdx] += org[x] - dst[x];
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -5007,7 +5009,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
             blkStats[setIdx][ctuRsAddr].diff[classIdx] += org[x] - dst[x];
             blkStats[setIdx][ctuRsAddr].count[classIdx]++;
           }
-          srcY += srcStrideY << 1;
+          srcY += srcStrideY << chromaScaleY;
           srcU += srcStrideU;
           srcV += srcStrideV;
           org += orgStride;
@@ -5022,8 +5024,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
       if (!isAboveAvail)
       {
         srcY += srcStrideY;
-        srcU += srcStrideU * (0 & 0x1);
-        srcV += srcStrideV * (0 & 0x1);
+        srcU += srcStrideU * chromaScaleYM1;
+        srcV += srcStrideV * chromaScaleYM1;
         org += orgStride;
         dst += dstStride;
       }
@@ -5048,7 +5050,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].diff[classIdx] += org[x] - dst[x];
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -5083,7 +5085,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
         blkStats[setIdx][ctuRsAddr].count[classIdx]++;
       }
 
-      srcY += srcStrideY << 1;
+      srcY += srcStrideY << chromaScaleY;
       srcU += srcStrideU;
       srcV += srcStrideV;
       org += orgStride;
@@ -5111,7 +5113,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].diff[classIdx] += org[x] - dst[x];
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -5145,7 +5147,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].diff[classIdx] += org[x] - dst[x];
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -5173,7 +5175,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].diff[classIdx] += org[x] - dst[x];
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -5207,7 +5209,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].diff[classIdx] += org[x] - dst[x];
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -5241,7 +5243,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].diff[classIdx] += org[x] - dst[x];
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -5275,7 +5277,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].diff[classIdx] += org[x] - dst[x];
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -5309,7 +5311,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
           blkStats[setIdx][ctuRsAddr].diff[classIdx] += org[x] - dst[x];
           blkStats[setIdx][ctuRsAddr].count[classIdx]++;
         }
-        srcY += srcStrideY << 1;
+        srcY += srcStrideY << chromaScaleY;
         srcU += srcStrideU;
         srcV += srcStrideV;
         org += orgStride;
@@ -5349,8 +5351,8 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
       }
 
       srcY += srcStrideY;
-      srcU += srcStrideU * (y & 0x1);
-      srcV += srcStrideV * (y & 0x1);
+      srcU += srcStrideU * ((y & 0x1) | chromaScaleYM1);
+      srcV += srcStrideV * ((y & 0x1) | chromaScaleYM1);
       org += orgStride;
       dst += dstStride;
     }
@@ -5377,7 +5379,7 @@ void EncSampleAdaptiveOffset::getCcSaoBlkStats(const ComponentID compID, const C
         blkStats[setIdx][ctuRsAddr].count[classIdx]++;
       }
 
-      srcY += srcStrideY << 1;
+      srcY += srcStrideY << chromaScaleY;
       srcU += srcStrideU;
       srcV += srcStrideV;
       org += orgStride;
diff --git a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.h b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.h
index fe5295be17d6c89b2c019334d9d3d388bc555f2d..c18cfcf098d6a1326dd22e05262b8bcd0d03b148 100644
--- a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.h
+++ b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.h
@@ -244,20 +244,6 @@ private: //methods
                               CcSaoStatData *blkStats[MAX_CCSAO_SET_NUM],
                               CcSaoStatData *blkStatsEdgePre[MAX_CCSAO_SET_NUM - 1], const CcSaoEncParam &ccSaoParam);
 
-  void getCcSaoBlkStatsEdge(const ComponentID compID, const ChromaFormat chromaFormat, const int bitDepth,
-                            const int setIdx, CcSaoStatData *blkStats[MAX_CCSAO_SET_NUM], const int ctuRsAddr,
-                            const uint16_t candPosY, const uint16_t bandNumY, const uint16_t bandNumU,
-                            const uint16_t bandNumV, const Pel *srcY, const Pel *srcU, const Pel *srcV, const Pel *org,
-                            const Pel *dst, const int srcStrideY, const int srcStrideU, const int srcStrideV,
-                            const int orgStride, const int dstStride, const int width, const int height,
-                            bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail,
-                            bool isAboveLeftAvail, bool isAboveRightAvail
-#if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
-                          , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-                          , const int chromaScaleX, const int chromaScaleY 
-#endif
-  );
-
   void getCcSaoBlkStatsEdgeNew(const ComponentID compID, const ChromaFormat chromaFormat, const int bitDepth,
                                const int setIdx, CcSaoStatData *blkStats[N_C - 1], const int ctuRsAddr,
                                const uint16_t candPosY, const uint16_t bandNumY, const uint16_t bandNumU,
@@ -268,7 +254,6 @@ private: //methods
                                bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                              , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-                             , const int chromaScaleX, const int chromaScaleY 
 #endif
     );
 #endif
@@ -281,7 +266,6 @@ private: //methods
                       , bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail
 #if JVET_Z0105_LOOP_FILTER_VIRTUAL_BOUNDARY
                       , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry
-                      , const int chromaScaleX, const int chromaScaleY 
 #endif
   );
   void getCcSaoFrameStats(const ComponentID compID, const int setIdx, const uint8_t* ccSaoControl