<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Oct 4, 2013 at 6:21 AM, Aarthi Thirumalai <span dir="ltr"><<a href="mailto:aarthi@multicorewareinc.com" target="_blank">aarthi@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 Aarthi Thirumalai<br>
# Date 1380885604 -19800<br>
#      Fri Oct 04 16:50:04 2013 +0530<br>
# Node ID ed4f57163274364e419dabfa4f864aa5a48cab6b<br>
# Parent  92641f3d3195b8da2275cfc44b1921d8f81a54bc<br>
calculate SSIM for each Row after deblock, sao.<br>
<br>
diff -r 92641f3d3195 -r ed4f57163274 source/Lib/TLibEncoder/TEncTop.cpp<br>
--- a/source/Lib/TLibEncoder/TEncTop.cpp        Fri Oct 04 16:46:15 2013 +0530<br>
+++ b/source/Lib/TLibEncoder/TEncTop.cpp        Fri Oct 04 16:50:04 2013 +0530<br>
@@ -513,7 +513,7 @@<br>
     int width  = recon->getWidth() - getPad(0);<br>
     int height = recon->getHeight() - getPad(1);<br>
     int size = width * height;<br>
-<br>
+    double ssim = 0;<br>
     UInt64 ssdY = computeSSD(orig->getLumaAddr(), recon->getLumaAddr(), stride, width, height);<br>
<br>
     height >>= 1;<br>
@@ -604,7 +604,11 @@<br>
     {<br>
         m_analyzeB.addResult(psnrY, psnrU, psnrV, (double)bits);<br>
     }<br>
-<br>
+    if (param.bEnableSsim)<br>
+    {<br>
+        ssim += pic->getSlice()->m_ssim / pic->getSlice()->m_ssimCnt;<br></blockquote><div><br></div><div>is m_ssimCnt always non-zero?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+        m_globalSsim += ssim;<br>
+    }<br>
     if (param.logLevel >= X265_LOG_DEBUG)<br>
     {<br>
         char c = (slice->isIntra() ? 'I' : slice->isInterP() ? 'P' : 'B');<br>
diff -r 92641f3d3195 -r ed4f57163274 source/encoder/frameencoder.cpp<br>
--- a/source/encoder/frameencoder.cpp   Fri Oct 04 16:46:15 2013 +0530<br>
+++ b/source/encoder/frameencoder.cpp   Fri Oct 04 16:50:04 2013 +0530<br>
@@ -111,6 +111,9 @@<br>
         m_rows[i].create(top);<br>
     }<br>
<br>
+    if (m_cfg->param.bEnableSsim)<br>
+        CHECKED_MALLOC(tempBuf, int, m_cfg->param.bEnableSsim * 8 * (m_cfg->param.sourceWidth / 4 + 3));<br>
+<br>
     // NOTE: 2 times of numRows because both Encoder and Filter in same queue<br>
     if (!WaveFront::init(m_numRows * 2))<br>
     {<br>
@@ -168,6 +171,10 @@<br>
         assert(0);<br>
     }<br>
     start();<br>
+    return;<br>
+fail:<br>
+    X265_FREE(tempBuf);<br>
+    tempBuf = 0;<br></blockquote><div><br></div><div>this looks quite backwards, you only free tempBuf on malloc failure?  the buffer doesn't appear to be used?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

 }<br>
<br>
 int FrameEncoder::getStreamHeaders(NALUnitEBSP **nalunits)<br>
@@ -540,6 +547,32 @@<br>
         slice->setSaoEnabledFlag((saoParam->bSaoFlag[0] == 1) ? true : false);<br>
     }<br>
<br>
+    /*Compute SSIM if enabled*/<br>
+    if (m_cfg->param.bEnableSsim)<br>
+    {<br>
+        pixel *rec = (pixel*)m_pic->getPicYuvRec()->getLumaAddr();<br>
+        pixel *org = (pixel*)m_pic->getPicYuvOrg()->getLumaAddr();<br>
+        int stride1 = m_pic->getPicYuvOrg()->getStride();<br>
+        int stride2 = m_pic->getPicYuvRec()->getStride();<br>
+        for (int row = 0; row < m_numRows; row++)<br>
+        {<br>
+            int bEnd = ((row + 1) == (this->m_numRows - 1));<br>
+            int bStart = (row == 0);<br>
+            int minPixY = row * 64 - 4 * !bStart;<br>
+            int maxPixY = (row + 1) * 64 - 4 * !bEnd;<br>
+            int ssim_cnt;<br>
+            x265_emms();<br>
+<br>
+            /* SSIM is done for each row in blocks of 4x4 . The First blocks are offset by 2 pixels to the right<br>
+            * to avoid alignment of ssim blocks with DCT blocks. */<br>
+            minPixY += bStart ? 2 : -6;<br>
+            slice->m_ssim +=<br>
+                calculateSSIM(rec + 2 + minPixY * stride1, stride1, org + 2 + minPixY * stride2, stride2,<br>
+                              m_cfg->param.sourceWidth - 2, maxPixY - minPixY, tempBuf, &ssim_cnt);<br>
+            slice->m_ssimCnt += ssim_cnt;<br>
+        }<br>
+    }<br>
+<br>
     entropyCoder->setBitstream(NULL);<br>
<br>
     // Reconstruction slice<br>
@@ -687,6 +720,39 @@<br>
     delete bitstreamRedirect;<br>
 }<br>
<br>
+/* Function to calculate SSIM for each row */<br>
+float FrameEncoder::calculateSSIM(pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int width, int height, void *buf, int *cnt)<br>
+{<br>
+    int z = 0;<br>
+    float ssim = 0.0;<br>
+<br>
+    int(*sum0)[4] = (int(*)[4])buf;<br>
+    int(*sum1)[4] = sum0 + (width >> 2) + 3;<br>
+    width >>= 2;<br>
+    height >>= 2;<br>
+    for (int y = 1; y < height; y++)<br>
+    {<br>
+        for (; z <= y; z++)<br>
+        {<br>
+            void* swap = sum0;<br>
+            sum0 = sum1;<br>
+            sum1 = (int(*)[4])swap;<br>
+            for (int x = 0; x < width; x += 2)<br>
+            {<br>
+                primitives.ssim_4x4x2_core_int(&pix1[4 * (x + (z * stride1))], stride1, &pix2[4 * (x + (z * stride2))], stride2, &sum0[x]);<br>
+            }<br>
+        }<br>
+<br>
+        for (int x = 0; x < width - 1; x += 4)<br>
+        {<br>
+            ssim += primitives.ssim_end4_int(sum0 + x, sum1 + x, X265_MIN(4, width - x - 1));<br>
+        }<br>
+    }<br>
+<br>
+    *cnt = (height - 1) * (width - 1);<br>
+    return ssim;<br>
+}<br>
+<br>
 void FrameEncoder::encodeSlice(TComOutputBitstream* substreams)<br>
 {<br>
     // choose entropy coder<br>
diff -r 92641f3d3195 -r ed4f57163274 source/encoder/frameencoder.h<br>
--- a/source/encoder/frameencoder.h     Fri Oct 04 16:46:15 2013 +0530<br>
+++ b/source/encoder/frameencoder.h     Fri Oct 04 16:50:04 2013 +0530<br>
@@ -145,6 +145,9 @@<br>
     /* called by compressFrame to perform wave-front compression analysis */<br>
     void compressCTURows();<br>
<br>
+    /* called by compressFrame to calculate SSIM for each row . */<br>
+    float calculateSSIM(pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int width, int height, void *buf, int *cnt);<br>
+<br>
     void encodeSlice(TComOutputBitstream* substreams);<br>
<br>
     /* blocks until worker thread is done, returns encoded picture and bitstream */<br>
@@ -185,6 +188,9 @@<br>
     int                      m_filterRowDelay;<br>
     CTURow*                  m_rows;<br>
     Event                    m_completionEvent;<br>
+<br>
+    /* Temp Storage that doesnt need repeated malloc */<br>
+    void *                   tempBuf;<br>
 };<br>
 }<br>
<br>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br>Steve Borho
</div></div>