<div dir="ltr">Kindly ignore this patch. Let me explain the reason for binary mismatch in linux.<div>Even there is binary mismatch in release and debug mode in linux. It is all because of double type comparison</div><div>to find the best band offset position among 32 sao bands. There is no error or reading uninitialized memory. Only </div><div>sometimes the band offset is changing based on the comparison of band costs. Very few pixels are changing keeping</div><div>SSIM and PSNR values remain same.  </div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Apr 18, 2016 at 4:34 PM,  <span dir="ltr"><<a href="mailto:ashok@multicorewareinc.com" target="_blank">ashok@multicorewareinc.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"># HG changeset patch<br>
# User Ashok Kumar Mishra<<a href="mailto:ashok@multicorewareinc.com">ashok@multicorewareinc.com</a>><br>
# Date 1460973467 -19800<br>
#      Mon Apr 18 15:27:47 2016 +0530<br>
# Node ID e038716af1b84f81e0123e75e1d016af31a0c505<br>
# Parent  02d79be487d7f825c961d15535a8681a201da3b1<br>
SAO: fix for output mismatch in linux<br>
<br>
diff -r 02d79be487d7 -r e038716af1b8 source/encoder/sao.cpp<br>
--- a/source/encoder/sao.cpp    Sun Apr 17 21:07:28 2016 +0000<br>
+++ b/source/encoder/sao.cpp    Mon Apr 18 15:27:47 2016 +0530<br>
@@ -1249,13 +1249,12 @@<br>
         m_entropyCoder.codeSaoMerge(0);<br>
     m_entropyCoder.store(m_rdContexts.temp);<br>
<br>
-    double mergeDist[NUM_MERGE_MODE] = { 0.0 };<br>
+    // Estimate distortion and cost of new SAO params<br>
     double bestCost = 0.0;<br>
-<br>
-    // Estimate distortion and cost of new SAO params<br>
-    saoLumaComponentParamDist(saoParam, addr, mergeDist, lambda, bestCost);<br>
-    if (chroma && saoParam->bSaoFlag[1])<br>
-        saoChromaComponentParamDist(saoParam, addr, mergeDist, lambda, bestCost);<br>
+    double rateDist = 0.0;<br>
+    saoLumaComponentParamDist(saoParam, addr, rateDist, lambda, bestCost);<br>
+    if (chroma)<br>
+        saoChromaComponentParamDist(saoParam, addr, rateDist, lambda, bestCost);<br>
<br>
     if (saoParam->bSaoFlag[0] || saoParam->bSaoFlag[1])<br>
     {<br>
@@ -1265,6 +1264,7 @@<br>
             if (!allowMerge[mergeIdx])<br>
                 continue;<br>
<br>
+            double mergeDist = 0;<br>
             for (int plane = 0; plane < 3; plane++)<br>
             {<br>
                 int64_t estDist = 0;<br>
@@ -1280,7 +1280,7 @@<br>
                     }<br>
                 }<br>
<br>
-                mergeDist[mergeIdx + 1] += ((double)estDist / lambda[!!plane]);<br>
+                mergeDist += ((double)estDist / lambda[!!plane]);<br>
             }<br>
<br>
             m_entropyCoder.load(m_rdContexts.cur);<br>
@@ -1290,8 +1290,8 @@<br>
             if (allowMerge[1] && (mergeIdx == 1))<br>
                 m_entropyCoder.codeSaoMerge(1);<br>
<br>
-            int32_t rate = m_entropyCoder.getNumberOfWrittenBits();<br>
-            double mergeCost = mergeDist[mergeIdx + 1] + (double)rate;<br>
+            uint32_t estRate = m_entropyCoder.getNumberOfWrittenBits();<br>
+            double mergeCost = mergeDist + (double)estRate;<br>
             if (mergeCost < bestCost)<br>
             {<br>
                 SaoMergeMode mergeMode = mergeIdx ? SAO_MERGE_UP : SAO_MERGE_LEFT;<br>
@@ -1374,7 +1374,7 @@<br>
     }<br>
 }<br>
<br>
-void SAO::estIterOffset(int typeIdx, double lambda, int32_t count, int32_t offsetOrg, int& offset, int& distClasses, double& costClasses)<br>
+inline void SAO::estIterOffset(int typeIdx, double lambda, int& offset, int32_t count, int32_t offsetOrg, int& distClasses, double& costClasses)<br>
 {<br>
     int bestOffset = 0;<br>
     distClasses    = 0;<br>
@@ -1405,15 +1405,13 @@<br>
     offset = bestOffset;<br>
 }<br>
<br>
-void SAO::saoLumaComponentParamDist(SAOParam* saoParam, int addr, double* mergeDist, double* lambda, double &bestCost)<br>
+void SAO::saoLumaComponentParamDist(SAOParam* saoParam, int addr, double& rateDist, double* lambda, double &bestCost)<br>
 {<br>
     int64_t bestDist = 0;<br>
     int bestTypeIdx = -1;<br>
<br>
     SaoCtuParam* lclCtuParam = &saoParam->ctuParam[0][addr];<br>
<br>
-    int    distClasses[MAX_NUM_SAO_CLASS];<br>
-    double costClasses[MAX_NUM_SAO_CLASS];<br>
<br>
     // RDO SAO_NA<br>
     m_entropyCoder.load(m_rdContexts.temp);<br>
@@ -1423,6 +1421,8 @@<br>
     double dCostPartBest = m_entropyCoder.getNumberOfWrittenBits() * lambda[0];<br>
<br>
     //EO distortion calculation<br>
+    int    distEOClasses;<br>
+    double costEOClasses;<br>
     for (int typeIdx = 0; typeIdx < MAX_NUM_SAO_TYPE - 1; typeIdx++)<br>
     {<br>
         int64_t estDist = 0;<br>
@@ -1431,11 +1431,11 @@<br>
             int32_t  count     = m_count[0][typeIdx][classIdx];<br>
             int32_t& offsetOrg = m_offsetOrg[0][typeIdx][classIdx];<br>
             int32_t& offsetOut = m_offset[0][typeIdx][classIdx];<br>
+            if (count)<br>
+                estIterOffset(typeIdx, lambda[0], offsetOut, count, offsetOrg, distEOClasses, costEOClasses);<br>
<br>
-            estIterOffset(typeIdx, lambda[0], count, offsetOrg, offsetOut, distClasses[classIdx], costClasses[classIdx]);<br>
-<br>
-            //Calculate distortion<br>
-            estDist += distClasses[classIdx];<br>
+            estDist += estSaoDist(count, (int)offsetOut << SAO_BIT_INC, offsetOrg);<br>
+<br>
         }<br>
<br>
         m_entropyCoder.load(m_rdContexts.temp);<br>
@@ -1463,6 +1463,8 @@<br>
     }<br>
<br>
     //BO RDO<br>
+    int    distBOClasses[MAX_NUM_SAO_CLASS];<br>
+    double costBOClasses[MAX_NUM_SAO_CLASS];<br>
     int64_t estDist = 0;<br>
     for (int classIdx = 0; classIdx < MAX_NUM_SAO_CLASS; classIdx++)<br>
     {<br>
@@ -1470,7 +1472,7 @@<br>
         int32_t& offsetOrg = m_offsetOrg[0][SAO_BO][classIdx];<br>
         int32_t& offsetOut = m_offset[0][SAO_BO][classIdx];<br>
<br>
-        estIterOffset(SAO_BO, lambda[0], count, offsetOrg, offsetOut, distClasses[classIdx], costClasses[classIdx]);<br>
+        estIterOffset(SAO_BO, lambda[0], offsetOut, count, offsetOrg, distBOClasses[classIdx], costBOClasses[classIdx]);<br>
     }<br>
<br>
     // Estimate Best Position<br>
@@ -1481,7 +1483,7 @@<br>
     {<br>
         double currentRDCost = 0.0;<br>
         for (int j = i; j < i + SAO_NUM_OFFSET; j++)<br>
-            currentRDCost += costClasses[j];<br>
+            currentRDCost += costBOClasses[j];<br>
<br>
         if (currentRDCost < bestRDCostBO)<br>
         {<br>
@@ -1492,7 +1494,7 @@<br>
<br>
     estDist = 0;<br>
     for (int classIdx = bestClassBO; classIdx < bestClassBO + SAO_NUM_OFFSET; classIdx++)<br>
-        estDist += distClasses[classIdx];<br>
+        estDist += distBOClasses[classIdx];<br>
<br>
     m_entropyCoder.load(m_rdContexts.temp);<br>
     m_entropyCoder.resetBits();<br>
@@ -1513,33 +1515,35 @@<br>
             lclCtuParam->offset[classIdx] = (int)m_offset[0][SAO_BO][classIdx + bestClassBO];<br>
     }<br>
<br>
-    mergeDist[0] = ((double)bestDist / lambda[0]);<br>
+    rateDist = ((double)bestDist / lambda[0]);<br>
     m_entropyCoder.load(m_rdContexts.temp);<br>
     m_entropyCoder.codeSaoOffset(*lclCtuParam, 0);<br>
     m_entropyCoder.store(m_rdContexts.temp);<br>
<br>
-    uint32_t rate = m_entropyCoder.getNumberOfWrittenBits();<br>
-    bestCost = mergeDist[0] + (double)rate;<br>
+    if (m_param->internalCsp == X265_CSP_I400)<br>
+    {<br>
+        uint32_t rate = m_entropyCoder.getNumberOfWrittenBits();<br>
+        bestCost = rateDist + (double)rate;<br>
+    }<br>
 }<br>
<br>
-void SAO::saoChromaComponentParamDist(SAOParam* saoParam, int addr, double* mergeDist, double* lambda, double &bestCost)<br>
+void SAO::saoChromaComponentParamDist(SAOParam* saoParam, int addr, double& rateDist, double* lambda, double &bestCost)<br>
 {<br>
     int64_t bestDist = 0;<br>
     int bestTypeIdx = -1;<br>
<br>
     SaoCtuParam* lclCtuParam[2] = { &saoParam->ctuParam[1][addr], &saoParam->ctuParam[2][addr] };<br>
<br>
-    double costClasses[MAX_NUM_SAO_CLASS];<br>
-    int    distClasses[MAX_NUM_SAO_CLASS];<br>
-    int    bestClassBO[2] = { 0, 0 };<br>
<br>
     m_entropyCoder.load(m_rdContexts.temp);<br>
     m_entropyCoder.resetBits();<br>
     m_entropyCoder.codeSaoType(0);<br>
<br>
-    double dCostPartBest = m_entropyCoder.getNumberOfWrittenBits() * lambda[1];<br>
+    double costPartBest = m_entropyCoder.getNumberOfWrittenBits() * lambda[1];<br>
<br>
     //EO RDO<br>
+    double costEOClasses;<br>
+    int    distEOClasses;<br>
     for (int typeIdx = 0; typeIdx < MAX_NUM_SAO_TYPE - 1; typeIdx++)<br>
     {<br>
         int64_t estDist[2] = {0, 0};<br>
@@ -1551,9 +1555,10 @@<br>
                 int32_t& offsetOrg = m_offsetOrg[compIdx][typeIdx][classIdx];<br>
                 int32_t& offsetOut = m_offset[compIdx][typeIdx][classIdx];<br>
<br>
-                estIterOffset(typeIdx, lambda[1], count, offsetOrg, offsetOut, distClasses[classIdx], costClasses[classIdx]);<br>
+                if (count)<br>
+                    estIterOffset(typeIdx, lambda[1], offsetOut, count, offsetOrg, distEOClasses, costEOClasses);<br>
<br>
-                estDist[compIdx - 1] += distClasses[classIdx];<br>
+                estDist[compIdx - 1] += estSaoDist(count, (int)offsetOut << SAO_BIT_INC, offsetOrg);<br>
             }<br>
         }<br>
<br>
@@ -1566,9 +1571,9 @@<br>
         uint32_t estRate = m_entropyCoder.getNumberOfWrittenBits();<br>
         double cost = (double)(estDist[0] + estDist[1]) + lambda[1] * (double)estRate;<br>
<br>
-        if (cost < dCostPartBest)<br>
+        if (cost < costPartBest)<br>
         {<br>
-            dCostPartBest = cost;<br>
+            costPartBest = cost;<br>
             bestDist = (estDist[0] + estDist[1]);<br>
             bestTypeIdx = typeIdx;<br>
         }<br>
@@ -1587,6 +1592,9 @@<br>
     }<br>
<br>
     // BO RDO<br>
+    double  costBOClasses[MAX_NUM_SAO_CLASS];<br>
+    int     distBOClasses[MAX_NUM_SAO_CLASS];<br>
+    int     bestClassBO[2] = { 0, 0 };<br>
     int64_t estDist[2];<br>
<br>
     // Estimate Best Position<br>
@@ -1600,14 +1608,14 @@<br>
             int32_t& offsetOrg = m_offsetOrg[compIdx][SAO_BO][classIdx];<br>
             int32_t& offsetOut = m_offset[compIdx][SAO_BO][classIdx];<br>
<br>
-            estIterOffset(SAO_BO, lambda[1], count, offsetOrg, offsetOut, distClasses[classIdx], costClasses[classIdx]);<br>
+            estIterOffset(SAO_BO, lambda[1], offsetOut, count, offsetOrg, distBOClasses[classIdx], costBOClasses[classIdx]);<br>
         }<br>
<br>
         for (int i = 0; i < MAX_NUM_SAO_CLASS - SAO_NUM_OFFSET + 1; i++)<br>
         {<br>
             double currentRDCost = 0.0;<br>
             for (int j = i; j < i + SAO_NUM_OFFSET; j++)<br>
-                currentRDCost += costClasses[j];<br>
+                currentRDCost += costBOClasses[j];<br>
<br>
             if (currentRDCost < bestRDCostBO)<br>
             {<br>
@@ -1618,7 +1626,7 @@<br>
<br>
         estDist[compIdx - 1] = 0;<br>
         for (int classIdx = bestClassBO[compIdx - 1]; classIdx < bestClassBO[compIdx - 1] + SAO_NUM_OFFSET; classIdx++)<br>
-            estDist[compIdx - 1] += distClasses[classIdx];<br>
+            estDist[compIdx - 1] += distBOClasses[classIdx];<br>
     }<br>
<br>
     m_entropyCoder.load(m_rdContexts.temp);<br>
@@ -1630,9 +1638,9 @@<br>
     uint32_t estRate = m_entropyCoder.getNumberOfWrittenBits();<br>
     double cost = (double)(estDist[0] + estDist[1]) + lambda[1] * (double)estRate;<br>
<br>
-    if (cost < dCostPartBest)<br>
+    if (cost < costPartBest)<br>
     {<br>
-        dCostPartBest = cost;<br>
+        costPartBest = cost;<br>
         bestDist = (estDist[0] + estDist[1]);<br>
<br>
         for (int compIdx = 0; compIdx < 2; compIdx++)<br>
@@ -1645,15 +1653,20 @@<br>
         }<br>
     }<br>
<br>
-    mergeDist[0] += ((double)bestDist / lambda[1]);<br>
+    rateDist += ((double)bestDist / lambda[1]);<br>
     m_entropyCoder.load(m_rdContexts.temp);<br>
+    uint32_t rate = m_entropyCoder.getNumberOfWrittenBits();<br>
+    if (saoParam->bSaoFlag[1])<br>
+    {<br>
+        m_entropyCoder.codeSaoOffset(*lclCtuParam[0], 1);<br>
+        m_entropyCoder.codeSaoOffset(*lclCtuParam[1], 2);<br>
+        m_entropyCoder.store(m_rdContexts.temp);<br>
<br>
-    m_entropyCoder.codeSaoOffset(*lclCtuParam[0], 1);<br>
-    m_entropyCoder.codeSaoOffset(*lclCtuParam[1], 2);<br>
-    m_entropyCoder.store(m_rdContexts.temp);<br>
-<br>
-    uint32_t rate = m_entropyCoder.getNumberOfWrittenBits();<br>
-    bestCost = mergeDist[0] + (double)rate;<br>
+        rate = m_entropyCoder.getNumberOfWrittenBits();<br>
+        bestCost = rateDist + (double)rate;<br>
+    }<br>
+    else<br>
+        bestCost = rateDist + (double)rate;<br>
 }<br>
<br>
 // NOTE: must put in namespace X265_NS since we need class SAO<br>
diff -r 02d79be487d7 -r e038716af1b8 source/encoder/sao.h<br>
--- a/source/encoder/sao.h      Sun Apr 17 21:07:28 2016 +0000<br>
+++ b/source/encoder/sao.h      Mon Apr 18 15:27:47 2016 +0530<br>
@@ -46,7 +46,6 @@<br>
 class SAO<br>
 {<br>
 public:<br>
-<br>
     enum { SAO_MAX_DEPTH = 4 };<br>
     enum { SAO_BO_BITS  = 5 };<br>
     enum { MAX_NUM_SAO_CLASS = 32 };<br>
@@ -54,7 +53,6 @@<br>
     enum { OFFSET_THRESH = 1 << X265_MIN(X265_DEPTH - 5, 5) };<br>
     enum { NUM_EDGETYPE = 5 };<br>
     enum { NUM_PLANE = 3 };<br>
-    enum { NUM_MERGE_MODE = 3 };<br>
     enum { SAO_DEPTHRATE_SIZE = 4 };<br>
<br>
     static const uint32_t s_eoTable[NUM_EDGETYPE];<br>
@@ -127,10 +125,11 @@<br>
     void calcSaoStatsCu(int addr, int plane);<br>
     void calcSaoStatsCu_BeforeDblk(Frame* pic, int idxX, int idxY);<br>
<br>
-    void saoLumaComponentParamDist(SAOParam* saoParam, int addr, double* mergeDist, double* lambda, double &bestCost);<br>
-    void saoChromaComponentParamDist(SAOParam* saoParam, int addr, double* mergeDist, double* lambda, double &bestCost);<br>
+    void saoLumaComponentParamDist(SAOParam* saoParam, int addr, double& rateDist, double* lambda, double &bestCost);<br>
+    void saoChromaComponentParamDist(SAOParam* saoParam, int addr, double& rateDist, double* lambda, double &bestCost);<br>
<br>
-    void estIterOffset(int typeIdx, double lambda, int32_t count, int32_t offsetOrg, int& offset, int& distClasses, double& costClasses);<br>
+    void estIterOffset(int typeIdx, double lambda, int& offset, int32_t count, int32_t offsetOrg,<br>
+                             int& distClasses, double& costClasses);<br>
     void rdoSaoUnitRowEnd(const SAOParam* saoParam, int numctus);<br>
     void rdoSaoUnitCu(SAOParam* saoParam, int rowBaseAddr, int idxX, int addr);<br>
<br>
</blockquote></div><br></div>