<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, Oct 6, 2013 at 3:42 PM, 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:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"># HG changeset patch<br>
# User Aarthi Thirumalai<br>
# Date 1381092064 -19800<br>
# Mon Oct 07 02:11:04 2013 +0530<br>
# Node ID e116b5414806b6c981998f60877b3e0314d14c48<br>
# Parent e58bbff11696e0f6f4f5b2975d1b449174e9e839<br>
calculate SSIM for each Row after deblock, sao<br>
<br>
diff -r e58bbff11696 -r e116b5414806 source/Lib/TLibEncoder/TEncTop.cpp<br>
--- a/source/Lib/TLibEncoder/TEncTop.cpp Mon Oct 07 02:09:36 2013 +0530<br>
+++ b/source/Lib/TLibEncoder/TEncTop.cpp Mon Oct 07 02:11: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,14 @@<br>
{<br>
m_analyzeB.addResult(psnrY, psnrU, psnrV, (double)bits);<br>
}<br>
-<br>
+ if (param.bEnableSsim)<br>
+ {<br>
+ if(pic->getSlice()->m_ssimCnt > 0)<br></blockquote><div><br></div><div>white-space</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+ {<br>
+ ssim += pic->getSlice()->m_ssim / pic->getSlice()->m_ssimCnt;<br>
+ m_globalSsim += ssim;<br>
+ }<br>
+ }<br>
if (param.logLevel >= X265_LOG_DEBUG)<br>
{<br>
char c = (slice->isIntra() ? 'I' : slice->isInterP() ? 'P' : 'B');<br>
diff -r e58bbff11696 -r e116b5414806 source/encoder/frameencoder.cpp<br>
--- a/source/encoder/frameencoder.cpp Mon Oct 07 02:09:36 2013 +0530<br>
+++ b/source/encoder/frameencoder.cpp Mon Oct 07 02:11:04 2013 +0530<br>
@@ -92,7 +92,7 @@<br>
}<br>
<br>
m_frameFilter.destroy();<br>
-<br>
+ X265_FREE(ssimBuf);<br>
// wait for worker thread to exit<br>
stop();<br>
}<br>
@@ -111,6 +111,15 @@<br>
m_rows[i].create(top);<br>
}<br>
<br>
+ if (m_cfg->param.bEnableSsim)<br>
+ {<br>
+#if !HIGH_BIT_DEPTH<br>
+ CHECKED_MALLOC(ssimBuf, int32_t, m_cfg->param.bEnableSsim * 8 * (m_cfg->param.sourceWidth / 4 + 3));<br>
+#else<br>
+ CHECKED_MALLOC(ssimBuf, int64_t, m_cfg->param.bEnableSsim * 8 * (m_cfg->param.sourceWidth / 4 + 3));<br></blockquote><div><br></div><div>There is no point in including m_cfg->param.bEnableSsim in the calculation.</div>
<div><br></div><div>Also, it would be a lot cleaner to place code like this in your header:</div><div><br></div><div>#if HIGH_BIT_DEPTH</div><div>typedef uint64_t ssim_t;</div><div>#else</div><div>typedef uint32_t ssim_t;</div>
<div>#endif</div><div><br></div><div>Then you can just use ssim_t for the pointer type and malloc calls.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+#endif<br>
+ }<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 +177,10 @@<br>
assert(0);<br>
}<br>
start();<br>
+ return;<br>
+fail:<br>
+ X265_FREE(ssimBuf);<br>
+ ssimBuf = 0;<br></blockquote><div><br></div><div>if the malloc failed, X265_FREE is a NOP and so is ssimBuf</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
}<br>
<br>
int FrameEncoder::getStreamHeaders(NALUnitEBSP **nalunits)<br>
@@ -540,6 +553,36 @@<br>
slice->setSaoEnabledFlag((saoParam->bSaoFlag[0] == 1) ? true : false);<br>
}<br>
<br>
+ /*Compute SSIM if enabled*/<br>
+ if (m_cfg->param.bEnableSsim && ssimBuf)<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>
+#if HIGH_BIT_DEPTH<br>
+ slice->m_ssim += calculateSSIM_int64(rec + 2 + minPixY * stride1, stride1, org + 2 + minPixY * stride2, stride2,<br>
+ m_cfg->param.sourceWidth - 2, maxPixY - minPixY, ssimBuf, &ssim_cnt);<br>
+#else<br>
+ slice->m_ssim += calculateSSIM_int32(rec + 2 + minPixY * stride1, stride1, org + 2 + minPixY * stride2, stride2,<br>
+ m_cfg->param.sourceWidth - 2, maxPixY - minPixY, ssimBuf, &ssim_cnt);<br>
+#endif<br>
+ slice->m_ssimCnt += ssim_cnt;<br>
+ }<br>
+ }<br>
+<br>
entropyCoder->setBitstream(NULL);<br>
<br>
// Reconstruction slice<br>
@@ -687,6 +730,73 @@<br>
delete bitstreamRedirect;<br>
}<br>
<br>
+/* Function to calculate SSIM for each row */<br>
+float FrameEncoder::calculateSSIM_int32(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>
+ int32_t(*sum0)[4] = (int32_t(*)[4])buf;<br>
+ int32_t(*sum1)[4] = sum0 + (width >> 2) + 3;<br>
+ width >>= 2;<br>
+ height >>= 2;<br>
+<br>
+ for (int y = 1; y < height; y++)<br>
+ {<br>
+ for (; z <= y; z++)<br>
+ {<br>
+ void* swap = sum0;<br>
+ sum0 = sum1;<br>
+ sum1 = (int32_t(*)[4])swap;<br>
+ for (int x = 0; x < width; x += 2)<br>
+ {<br>
+ primitives.ssim_4x4x2_core_int32(&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_int32(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>
+float FrameEncoder::calculateSSIM_int64(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>
+ int64_t(*sum0)[4] = (int64_t(*)[4])buf;<br>
+ int64_t(*sum1)[4] = sum0 + (width >> 2) + 3;<br>
+ width >>= 2;<br>
+ height >>= 2;<br>
+<br>
+ for (int y = 1; y < height; y++)<br>
+ {<br>
+ for (; z <= y; z++)<br>
+ {<br>
+ void* swap = sum0;<br>
+ sum0 = sum1;<br>
+ sum1 = (int64_t(*)[4])swap;<br>
+ for (int x = 0; x < width; x += 2)<br>
+ {<br>
+ primitives.ssim_4x4x2_core_int64(&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_int64(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 e58bbff11696 -r e116b5414806 source/encoder/frameencoder.h<br>
--- a/source/encoder/frameencoder.h Mon Oct 07 02:09:36 2013 +0530<br>
+++ b/source/encoder/frameencoder.h Mon Oct 07 02:11:04 2013 +0530<br>
@@ -145,6 +145,10 @@<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_int32(pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int width, int height, void *buf, int *cnt);<br>
+ float calculateSSIM_int64(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 +189,9 @@<br>
int m_filterRowDelay;<br>
CTURow* m_rows;<br>
Event m_completionEvent;<br>
+<br>
+ /* Temp Storage for ssim computation that doesnt need repeated malloc */<br>
+ void * ssimBuf;<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>