<div dir="ltr">Results after converting from float to int.<div><br><div><div><b>Before(crowd_run, medium)</b></div><div>encoded 500 frames in 76.15s (6.57 fps), 9685.07 kb/s, Avg QP:37.80, Global PSNR : 31.045, SSIM Mean Y: 0.8417967 ( 8.008 dB)</div><div><b>After float to fixed</b></div><div>encoded 500 frames in 75.17s (6.65 fps), 9689.38 kb/s, Avg QP:37.79, Global PSNR : 31.045, SSIM Mean Y: 0.8418636 ( 8.010 dB)</div><div><br></div><div><b>Before(crowd_run, veryslow)</b></div><div>encoded 500 frames in 904.58s (0.55 fps), 9500.28 kb/s, Avg QP:37.78, Global PSNR: 31.504, SSIM Mean Y: 0.8496374 ( 8.229 dB)</div><div><b>After float to fixed</b></div><div>encoded 500 frames in 946.15s (0.53 fps), 9504.15 kb/s, Avg QP:37.79, Global PSNR: 31.503, SSIM Mean Y: 0.8496565 ( 8.229 dB)</div><div><br></div><div><b>Before(crowd_run, veryslow, --bitrate 7000)</b></div><div>encoded 500 frames in 784.06s (0.64 fps), 6944.36 kb/s, Avg QP:39.73, Global PSNR: 30.432, SSIM Mean Y: 0.8161498 ( 7.355 dB)</div><div><b>After float to fixed</b></div><div>encoded 500 frames in 765.03s (0.65 fps), 6944.96 kb/s, Avg QP:39.73, Global PSNR: 30.432, SSIM Mean Y: 0.8164274 ( 7.362 dB)</div><div><br></div><div><b>Before(crowd_run, medium, --bitrate 7000)</b></div><div>encoded 500 frames in 69.49s (7.20 fps), 6947.67 kb/s, Avg QP:39.77, Global PSNR : 29.970, SSIM Mean Y: 0.8073355 ( 7.152 dB)</div><div><b>After float to fixed</b></div><div>encoded 500 frames in 70.02s (7.14 fps), 6948.83 kb/s, Avg QP:39.76, Global PSNR : 29.972, SSIM Mean Y: 0.8075512 ( 7.157 dB)</div><div><br></div><div><b>Before(crowd_run, medium, 2160p, --bitrate 7000)</b></div><div>encoded 500 frames in 258.98s (1.93 fps), 6963.32 kb/s, Avg QP:45.10, Global PSNR: 30.257, SSIM Mean Y: 0.7517402 ( 6.051 dB)</div><div><b>After float to fixed</b></div><div>encoded 500 frames in 264.31s (1.89 fps), 6962.31 kb/s, Avg QP:45.10, Global PSNR: 30.257, SSIM Mean Y: 0.7517543 ( 6.051 dB)</div><div><br></div><div><br></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Apr 6, 2016 at 1:13 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 1459928537 -19800<br>
#      Wed Apr 06 13:12:17 2016 +0530<br>
# Node ID 511241d3ee7d6d53a999d46881e7921a601fa0e9<br>
# Parent  33ff2e5f6eb7c8cf4f3edaa265762f32aa9b6f0f<br>
[OUTPUT CHANGED]SAO: convert sao rdo cost calculation from float to int<br>
<br>
diff -r 33ff2e5f6eb7 -r 511241d3ee7d source/encoder/sao.cpp<br>
--- a/source/encoder/sao.cpp    Tue Mar 29 13:10:49 2016 +0530<br>
+++ b/source/encoder/sao.cpp    Wed Apr 06 13:12:17 2016 +0530<br>
@@ -53,7 +53,7 @@<br>
     return r;<br>
 }<br>
<br>
-inline int64_t estSaoDist(int32_t count, int offset, int32_t offsetOrg)<br>
+inline int64_t estSaoDist(int32_t count, int32_t offset, int32_t offsetOrg)<br>
 {<br>
     return (count * offset - offsetOrg * 2) * offset;<br>
 }<br>
@@ -1193,17 +1193,15 @@<br>
     const CUData* cu = m_frame->m_encData->getPicCTU(addr);<br>
     int qp = cu->m_qp[0];<br>
<br>
-    double lambda[2] = {0.0};<br>
-<br>
+    int64_t lambda[2] = { 0 };<br>
     int qpCb = qp;<br>
     if (m_param->internalCsp == X265_CSP_I420)<br>
         qpCb = x265_clip3(QP_MIN, QP_MAX_MAX, (int)g_chromaScale[qp + slice->m_pps->chromaQpOffset[0]]);<br>
     else<br>
         qpCb = X265_MIN(qp + slice->m_pps->chromaQpOffset[0], QP_MAX_SPEC);<br>
<br>
-    lambda[0] = x265_lambda2_tab[qp];<br>
-    lambda[1] = x265_lambda2_tab[qpCb]; // Use Cb QP for SAO chroma<br>
-<br>
+    lambda[0] = (int64_t)floor(256.0 * x265_lambda2_tab[qp]);<br>
+    lambda[1] = (int64_t)floor(256.0 * x265_lambda2_tab[qpCb]); // Use Cb QP for SAO chroma<br>
     const bool allowMerge[2] = {(idxX != 0), (rowBaseAddr != 0)}; // left, up<br>
<br>
     const int addrMerge[2] = {(idxX ? addr - 1 : -1), (rowBaseAddr ? addr - m_numCuInWidth : -1)};// left, up<br>
@@ -1249,8 +1247,8 @@<br>
         m_entropyCoder.codeSaoMerge(0);<br>
     m_entropyCoder.store(m_rdContexts.temp);<br>
<br>
-    double mergeDist[NUM_MERGE_MODE] = { 0.0 };<br>
-    double bestCost = 0.0;<br>
+    int64_t mergeDist[NUM_MERGE_MODE] = { 0 };<br>
+    int64_t bestCost = 0;<br>
<br>
     // Estimate distortion and cost of new SAO params<br>
     saoLumaComponentParamDist(saoParam, addr, mergeDist, lambda, bestCost);<br>
@@ -1279,8 +1277,7 @@<br>
                         estDist += estSaoDist(m_count[plane][typeIdx][classIdx + bandPos], mergeOffset, m_offsetOrg[plane][typeIdx][classIdx + bandPos]);<br>
                     }<br>
                 }<br>
-<br>
-                mergeDist[mergeIdx + 1] += ((double)estDist / lambda[!!plane]);<br>
+                mergeDist[mergeIdx + 1] += (estDist / (lambda[!!plane] >> 8));<br>
             }<br>
<br>
             m_entropyCoder.load(m_rdContexts.cur);<br>
@@ -1290,8 +1287,9 @@<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 rate = m_entropyCoder.getNumberOfWrittenBits();<br>
+            int64_t mergeCost = mergeDist[mergeIdx + 1] + rate;<br>
+            // Compare merge cost with best offset cost<br>
             if (mergeCost < bestCost)<br>
             {<br>
                 SaoMergeMode mergeMode = mergeIdx ? SAO_MERGE_UP : SAO_MERGE_LEFT;<br>
@@ -1338,7 +1336,7 @@<br>
         {<br>
             for (int classIdx = 1; classIdx < SAO_NUM_OFFSET + 1; classIdx++)<br>
             {<br>
-                int32_t  count     = m_count[plane][typeIdx][classIdx];<br>
+                int32_t& count     = m_count[plane][typeIdx][classIdx];<br>
                 int32_t& offsetOrg = m_offsetOrg[plane][typeIdx][classIdx];<br>
                 int32_t& offsetOut = m_offset[plane][typeIdx][classIdx];<br>
<br>
@@ -1361,7 +1359,7 @@<br>
     {<br>
         for (int classIdx = 0; classIdx < MAX_NUM_SAO_CLASS; classIdx++)<br>
         {<br>
-            int32_t  count     = m_count[plane][SAO_BO][classIdx];<br>
+            int32_t& count     = m_count[plane][SAO_BO][classIdx];<br>
             int32_t& offsetOrg = m_offsetOrg[plane][SAO_BO][classIdx];<br>
             int32_t& offsetOut = m_offset[plane][SAO_BO][classIdx];<br>
<br>
@@ -1374,14 +1372,28 @@<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 int64_t SAO::calcSaoRdoCost(int64_t distortion, uint32_t bits, int64_t lambda)<br>
+{<br>
+#if X265_DEPTH < 10<br>
+        X265_CHECK(bits <= (INT64_MAX - 128) / lambda,<br>
+                   "calcRdCost wrap detected dist: %u, bits %u, lambda: " X265_LL "\n",<br>
+                   distortion, bits, lambda);<br>
+#else<br>
+        X265_CHECK(bits <= (INT64_MAX - 128) / lambda2,<br>
+                   "calcRdCost wrap detected dist: " X265_LL ", bits %u, lambda: " X265_LL "\n",<br>
+                   distortion, bits, lambda);<br>
+#endif<br>
+        return distortion + ((bits * lambda + 128) >> 8);<br>
+}<br>
+<br>
+void SAO::estIterOffset(int typeIdx, int64_t lambda, int32_t count, int32_t offsetOrg, int32_t& offset, int32_t& distClasses, int64_t& costClasses)<br>
 {<br>
     int bestOffset = 0;<br>
     distClasses    = 0;<br>
<br>
     // Assuming sending quantized value 0 results in zero offset and sending the value zero needs 1 bit.<br>
     // entropy coder can be used to measure the exact rate here.<br>
-    double bestCost = lambda;<br>
+    int64_t bestCost = calcSaoRdoCost(0, 1, lambda);<br>
     while (offset != 0)<br>
     {<br>
         // Calculate the bits required for signalling the offset<br>
@@ -1391,7 +1403,7 @@<br>
<br>
         // Do the dequntization before distorion calculation<br>
         int64_t dist = estSaoDist(count, offset << SAO_BIT_INC, offsetOrg);<br>
-        double cost  = ((double)dist + lambda * (double)rate);<br>
+        int64_t cost = calcSaoRdoCost(dist, rate, lambda);<br>
         if (cost < bestCost)<br>
         {<br>
             bestCost = cost;<br>
@@ -1405,30 +1417,30 @@<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, int32_t addr, int64_t* mergeDist, int64_t* lambda, int64_t &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>
+    int32_t  distClasses[MAX_NUM_SAO_CLASS];<br>
+    int64_t  costClasses[MAX_NUM_SAO_CLASS];<br>
<br>
     // RDO SAO_NA<br>
     m_entropyCoder.load(m_rdContexts.temp);<br>
     m_entropyCoder.resetBits();<br>
     m_entropyCoder.codeSaoType(0);<br>
+    uint32_t rate = m_entropyCoder.getNumberOfWrittenBits();<br>
+    int64_t costPartBest = calcSaoRdoCost(0, rate, lambda[0]);<br>
<br>
-    double dCostPartBest = m_entropyCoder.getNumberOfWrittenBits() * lambda[0];<br>
-<br>
-    //EO distortion calculation<br>
+    // RDO SAO_EO<br>
     for (int typeIdx = 0; typeIdx < MAX_NUM_SAO_TYPE - 1; typeIdx++)<br>
     {<br>
         int64_t estDist = 0;<br>
         for (int classIdx = 1; classIdx < SAO_NUM_OFFSET + 1; classIdx++)<br>
         {<br>
-            int32_t  count     = m_count[0][typeIdx][classIdx];<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>
<br>
@@ -1441,13 +1453,12 @@<br>
         m_entropyCoder.load(m_rdContexts.temp);<br>
         m_entropyCoder.resetBits();<br>
         m_entropyCoder.codeSaoOffsetEO(m_offset[0][typeIdx] + 1, typeIdx, 0);<br>
+        uint32_t rate = m_entropyCoder.getNumberOfWrittenBits();<br>
+        int64_t cost = calcSaoRdoCost(estDist, rate, lambda[0]);<br>
<br>
-        uint32_t estRate = m_entropyCoder.getNumberOfWrittenBits();<br>
-        double cost = (double)estDist + lambda[0] * (double)estRate;<br>
-<br>
-        if (cost < dCostPartBest)<br>
+        if (cost < costPartBest)<br>
         {<br>
-            dCostPartBest = cost;<br>
+            costPartBest = cost;<br>
             bestDist = estDist;<br>
             bestTypeIdx = typeIdx;<br>
         }<br>
@@ -1459,14 +1470,14 @@<br>
         lclCtuParam->typeIdx = bestTypeIdx;<br>
         lclCtuParam->bandPos = 0;<br>
         for (int classIdx = 0; classIdx < SAO_NUM_OFFSET; classIdx++)<br>
-            lclCtuParam->offset[classIdx] = (int)m_offset[0][bestTypeIdx][classIdx + 1];<br>
+            lclCtuParam->offset[classIdx] = m_offset[0][bestTypeIdx][classIdx + 1];<br>
     }<br>
<br>
-    //BO RDO<br>
+    // RDO SAO_BO<br>
     int64_t estDist = 0;<br>
     for (int classIdx = 0; classIdx < MAX_NUM_SAO_CLASS; classIdx++)<br>
     {<br>
-        int32_t  count     = m_count[0][SAO_BO][classIdx];<br>
+        int32_t&  count    = m_count[0][SAO_BO][classIdx];<br>
         int32_t& offsetOrg = m_offsetOrg[0][SAO_BO][classIdx];<br>
         int32_t& offsetOut = m_offset[0][SAO_BO][classIdx];<br>
<br>
@@ -1474,12 +1485,12 @@<br>
     }<br>
<br>
     // Estimate Best Position<br>
-    double bestRDCostBO = MAX_DOUBLE;<br>
-    int    bestClassBO  = 0;<br>
+    int64_t bestRDCostBO = MAX_INT64;<br>
+    int32_t bestClassBO  = 0;<br>
<br>
     for (int i = 0; i < MAX_NUM_SAO_CLASS - SAO_NUM_OFFSET + 1; i++)<br>
     {<br>
-        double currentRDCost = 0.0;<br>
+        int64_t currentRDCost = 0;<br>
         for (int j = i; j < i + SAO_NUM_OFFSET; j++)<br>
             currentRDCost += costClasses[j];<br>
<br>
@@ -1494,52 +1505,54 @@<br>
     for (int classIdx = bestClassBO; classIdx < bestClassBO + SAO_NUM_OFFSET; classIdx++)<br>
         estDist += distClasses[classIdx];<br>
<br>
+    // Estimate best BO cost<br>
     m_entropyCoder.load(m_rdContexts.temp);<br>
     m_entropyCoder.resetBits();<br>
     m_entropyCoder.codeSaoOffsetBO(m_offset[0][SAO_BO] + bestClassBO, bestClassBO, 0);<br>
+    uint32_t estRate = m_entropyCoder.getNumberOfWrittenBits();<br>
+    int64_t cost = calcSaoRdoCost(estDist, estRate, lambda[0]);<br>
<br>
-    uint32_t estRate = m_entropyCoder.getNumberOfWrittenBits();<br>
-    double cost = (double)estDist + lambda[0] * (double)estRate;<br>
-<br>
-    if (cost < dCostPartBest)<br>
+    if (cost < costPartBest)<br>
     {<br>
-        dCostPartBest = cost;<br>
+        costPartBest = cost;<br>
         bestDist = estDist;<br>
<br>
         lclCtuParam->mergeMode = SAO_MERGE_NONE;<br>
         lclCtuParam->typeIdx = SAO_BO;<br>
         lclCtuParam->bandPos = bestClassBO;<br>
         for (int classIdx = 0; classIdx < SAO_NUM_OFFSET; classIdx++)<br>
-            lclCtuParam->offset[classIdx] = (int)m_offset[0][SAO_BO][classIdx + bestClassBO];<br>
+            lclCtuParam->offset[classIdx] = m_offset[0][SAO_BO][classIdx + bestClassBO];<br>
     }<br>
<br>
-    mergeDist[0] = ((double)bestDist / lambda[0]);<br>
+    mergeDist[0] = bestDist / (lambda[0] >> 8);<br>
+<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>
+    uint32_t bits = m_entropyCoder.getNumberOfWrittenBits();<br>
+    bestCost = mergeDist[0] + bits;<br>
 }<br>
<br>
-void SAO::saoChromaComponentParamDist(SAOParam* saoParam, int addr, double* mergeDist, double* lambda, double &bestCost)<br>
+void SAO::saoChromaComponentParamDist(SAOParam* saoParam, int32_t addr, int64_t* mergeDist, int64_t* lambda, int64_t &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>
+    int64_t costClasses[MAX_NUM_SAO_CLASS];<br>
+    int32_t distClasses[MAX_NUM_SAO_CLASS];<br>
+    int32_t bestClassBO[2] = { 0, 0 };<br>
<br>
+    // RDO SAO_NA<br>
     m_entropyCoder.load(m_rdContexts.temp);<br>
     m_entropyCoder.resetBits();<br>
     m_entropyCoder.codeSaoType(0);<br>
+    uint32_t bits = m_entropyCoder.getNumberOfWrittenBits();<br>
+    int64_t costPartBest = calcSaoRdoCost(0, bits, lambda[1]);<br>
<br>
-    double dCostPartBest = m_entropyCoder.getNumberOfWrittenBits() * lambda[1];<br>
-<br>
-    //EO RDO<br>
+    // RDO SAO_EO<br>
     for (int typeIdx = 0; typeIdx < MAX_NUM_SAO_TYPE - 1; typeIdx++)<br>
     {<br>
         int64_t estDist[2] = {0, 0};<br>
@@ -1547,7 +1560,7 @@<br>
         {<br>
             for (int classIdx = 1; classIdx < SAO_NUM_OFFSET + 1; classIdx++)<br>
             {<br>
-                int32_t  count = m_count[compIdx][typeIdx][classIdx];<br>
+                int32_t& count     = m_count[compIdx][typeIdx][classIdx];<br>
                 int32_t& offsetOrg = m_offsetOrg[compIdx][typeIdx][classIdx];<br>
                 int32_t& offsetOut = m_offset[compIdx][typeIdx][classIdx];<br>
<br>
@@ -1564,11 +1577,11 @@<br>
             m_entropyCoder.codeSaoOffsetEO(m_offset[compIdx + 1][typeIdx] + 1, typeIdx, compIdx + 1);<br>
<br>
         uint32_t estRate = m_entropyCoder.getNumberOfWrittenBits();<br>
-        double cost = (double)(estDist[0] + estDist[1]) + lambda[1] * (double)estRate;<br>
+        int64_t cost = calcSaoRdoCost((estDist[0] + estDist[1]), estRate, lambda[1]);<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>
@@ -1582,21 +1595,21 @@<br>
             lclCtuParam[compIdx]->typeIdx = bestTypeIdx;<br>
             lclCtuParam[compIdx]->bandPos = 0;<br>
             for (int classIdx = 0; classIdx < SAO_NUM_OFFSET; classIdx++)<br>
-                lclCtuParam[compIdx]->offset[classIdx] = (int)m_offset[compIdx + 1][bestTypeIdx][classIdx + 1];<br>
+                lclCtuParam[compIdx]->offset[classIdx] = m_offset[compIdx + 1][bestTypeIdx][classIdx + 1];<br>
         }<br>
     }<br>
<br>
-    // BO RDO<br>
+    // RDO SAO_BO<br>
     int64_t estDist[2];<br>
<br>
     // Estimate Best Position<br>
     for (int compIdx = 1; compIdx < 3; compIdx++)<br>
     {<br>
-        double bestRDCostBO = MAX_DOUBLE;<br>
+        int64_t bestRDCostBO = MAX_INT64;<br>
<br>
         for (int classIdx = 0; classIdx < MAX_NUM_SAO_CLASS; classIdx++)<br>
         {<br>
-            int32_t  count = m_count[compIdx][SAO_BO][classIdx];<br>
+            int32_t& count     = m_count[compIdx][SAO_BO][classIdx];<br>
             int32_t& offsetOrg = m_offsetOrg[compIdx][SAO_BO][classIdx];<br>
             int32_t& offsetOut = m_offset[compIdx][SAO_BO][classIdx];<br>
<br>
@@ -1605,7 +1618,7 @@<br>
<br>
         for (int i = 0; i < MAX_NUM_SAO_CLASS - SAO_NUM_OFFSET + 1; i++)<br>
         {<br>
-            double currentRDCost = 0.0;<br>
+            int64_t currentRDCost = 0;<br>
             for (int j = i; j < i + SAO_NUM_OFFSET; j++)<br>
                 currentRDCost += costClasses[j];<br>
<br>
@@ -1628,11 +1641,11 @@<br>
         m_entropyCoder.codeSaoOffsetBO(m_offset[compIdx + 1][SAO_BO] + bestClassBO[compIdx], bestClassBO[compIdx], compIdx + 1);<br>
<br>
     uint32_t estRate = m_entropyCoder.getNumberOfWrittenBits();<br>
-    double cost = (double)(estDist[0] + estDist[1]) + lambda[1] * (double)estRate;<br>
+    int64_t cost = calcSaoRdoCost((estDist[0] + estDist[1]), estRate, lambda[1]);<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>
@@ -1641,11 +1654,11 @@<br>
             lclCtuParam[compIdx]->typeIdx = SAO_BO;<br>
             lclCtuParam[compIdx]->bandPos = bestClassBO[compIdx];<br>
             for (int classIdx = 0; classIdx < SAO_NUM_OFFSET; classIdx++)<br>
-                lclCtuParam[compIdx]->offset[classIdx] = (int)m_offset[compIdx + 1][SAO_BO][classIdx + bestClassBO[compIdx]];<br>
+                lclCtuParam[compIdx]->offset[classIdx] = m_offset[compIdx + 1][SAO_BO][classIdx + bestClassBO[compIdx]];<br>
         }<br>
     }<br>
<br>
-    mergeDist[0] += ((double)bestDist / lambda[1]);<br>
+    mergeDist[0] += (bestDist / (lambda[1] >> 8));<br>
     m_entropyCoder.load(m_rdContexts.temp);<br>
<br>
     m_entropyCoder.codeSaoOffset(*lclCtuParam[0], 1);<br>
@@ -1653,7 +1666,7 @@<br>
     m_entropyCoder.store(m_rdContexts.temp);<br>
<br>
     uint32_t rate = m_entropyCoder.getNumberOfWrittenBits();<br>
-    bestCost = mergeDist[0] + (double)rate;<br>
+    bestCost = mergeDist[0] + rate;<br>
 }<br>
<br>
 // NOTE: must put in namespace X265_NS since we need class SAO<br>
diff -r 33ff2e5f6eb7 -r 511241d3ee7d source/encoder/sao.h<br>
--- a/source/encoder/sao.h      Tue Mar 29 13:10:49 2016 +0530<br>
+++ b/source/encoder/sao.h      Wed Apr 06 13:12:17 2016 +0530<br>
@@ -127,12 +127,14 @@<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, int64_t* mergeDist, int64_t* lambda, int64_t &bestCost);<br>
+    void saoChromaComponentParamDist(SAOParam* saoParam, int addr, int64_t* mergeDist, int64_t* lambda, int64_t &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, int64_t lambda, int32_t count, int32_t offsetOrg, int32_t& offset,<br>
+                          int32_t& distClasses, int64_t& costClasses);<br>
     void rdoSaoUnitRowEnd(const SAOParam* saoParam, int numctus);<br>
     void rdoSaoUnitCu(SAOParam* saoParam, int rowBaseAddr, int idxX, int addr);<br>
+    int64_t calcSaoRdoCost(int64_t distortion, uint32_t bits, int64_t lambda);<br>
<br>
     void saoStatsInitialOffset(bool chroma);<br>
<br>
</blockquote></div><br></div>