[x265] [PATCH] calculate SSIM for each Row after deblock, sao
Aarthi Thirumalai
aarthi at multicorewareinc.com
Sun Oct 6 22:42:15 CEST 2013
# HG changeset patch
# User Aarthi Thirumalai
# Date 1381092064 -19800
# Mon Oct 07 02:11:04 2013 +0530
# Node ID e116b5414806b6c981998f60877b3e0314d14c48
# Parent e58bbff11696e0f6f4f5b2975d1b449174e9e839
calculate SSIM for each Row after deblock, sao
diff -r e58bbff11696 -r e116b5414806 source/Lib/TLibEncoder/TEncTop.cpp
--- a/source/Lib/TLibEncoder/TEncTop.cpp Mon Oct 07 02:09:36 2013 +0530
+++ b/source/Lib/TLibEncoder/TEncTop.cpp Mon Oct 07 02:11:04 2013 +0530
@@ -513,7 +513,7 @@
int width = recon->getWidth() - getPad(0);
int height = recon->getHeight() - getPad(1);
int size = width * height;
-
+ double ssim = 0;
UInt64 ssdY = computeSSD(orig->getLumaAddr(), recon->getLumaAddr(), stride, width, height);
height >>= 1;
@@ -604,7 +604,14 @@
{
m_analyzeB.addResult(psnrY, psnrU, psnrV, (double)bits);
}
-
+ if (param.bEnableSsim)
+ {
+ if(pic->getSlice()->m_ssimCnt > 0)
+ {
+ ssim += pic->getSlice()->m_ssim / pic->getSlice()->m_ssimCnt;
+ m_globalSsim += ssim;
+ }
+ }
if (param.logLevel >= X265_LOG_DEBUG)
{
char c = (slice->isIntra() ? 'I' : slice->isInterP() ? 'P' : 'B');
diff -r e58bbff11696 -r e116b5414806 source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp Mon Oct 07 02:09:36 2013 +0530
+++ b/source/encoder/frameencoder.cpp Mon Oct 07 02:11:04 2013 +0530
@@ -92,7 +92,7 @@
}
m_frameFilter.destroy();
-
+ X265_FREE(ssimBuf);
// wait for worker thread to exit
stop();
}
@@ -111,6 +111,15 @@
m_rows[i].create(top);
}
+ if (m_cfg->param.bEnableSsim)
+ {
+#if !HIGH_BIT_DEPTH
+ CHECKED_MALLOC(ssimBuf, int32_t, m_cfg->param.bEnableSsim * 8 * (m_cfg->param.sourceWidth / 4 + 3));
+#else
+ CHECKED_MALLOC(ssimBuf, int64_t, m_cfg->param.bEnableSsim * 8 * (m_cfg->param.sourceWidth / 4 + 3));
+#endif
+ }
+
// NOTE: 2 times of numRows because both Encoder and Filter in same queue
if (!WaveFront::init(m_numRows * 2))
{
@@ -168,6 +177,10 @@
assert(0);
}
start();
+ return;
+fail:
+ X265_FREE(ssimBuf);
+ ssimBuf = 0;
}
int FrameEncoder::getStreamHeaders(NALUnitEBSP **nalunits)
@@ -540,6 +553,36 @@
slice->setSaoEnabledFlag((saoParam->bSaoFlag[0] == 1) ? true : false);
}
+ /*Compute SSIM if enabled*/
+ if (m_cfg->param.bEnableSsim && ssimBuf)
+ {
+ pixel *rec = (pixel*)m_pic->getPicYuvRec()->getLumaAddr();
+ pixel *org = (pixel*)m_pic->getPicYuvOrg()->getLumaAddr();
+ int stride1 = m_pic->getPicYuvOrg()->getStride();
+ int stride2 = m_pic->getPicYuvRec()->getStride();
+ for (int row = 0; row < m_numRows; row++)
+ {
+ int bEnd = ((row + 1) == (this->m_numRows - 1));
+ int bStart = (row == 0);
+ int minPixY = row * 64 - 4 * !bStart;
+ int maxPixY = (row + 1) * 64 - 4 * !bEnd;
+ int ssim_cnt;
+ x265_emms();
+
+ /* SSIM is done for each row in blocks of 4x4 . The First blocks are offset by 2 pixels to the right
+ * to avoid alignment of ssim blocks with DCT blocks. */
+ minPixY += bStart ? 2 : -6;
+#if HIGH_BIT_DEPTH
+ slice->m_ssim += calculateSSIM_int64(rec + 2 + minPixY * stride1, stride1, org + 2 + minPixY * stride2, stride2,
+ m_cfg->param.sourceWidth - 2, maxPixY - minPixY, ssimBuf, &ssim_cnt);
+#else
+ slice->m_ssim += calculateSSIM_int32(rec + 2 + minPixY * stride1, stride1, org + 2 + minPixY * stride2, stride2,
+ m_cfg->param.sourceWidth - 2, maxPixY - minPixY, ssimBuf, &ssim_cnt);
+#endif
+ slice->m_ssimCnt += ssim_cnt;
+ }
+ }
+
entropyCoder->setBitstream(NULL);
// Reconstruction slice
@@ -687,6 +730,73 @@
delete bitstreamRedirect;
}
+/* Function to calculate SSIM for each row */
+float FrameEncoder::calculateSSIM_int32(pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int width, int height, void *buf, int *cnt)
+{
+ int z = 0;
+ float ssim = 0.0;
+
+ int32_t(*sum0)[4] = (int32_t(*)[4])buf;
+ int32_t(*sum1)[4] = sum0 + (width >> 2) + 3;
+ width >>= 2;
+ height >>= 2;
+
+ for (int y = 1; y < height; y++)
+ {
+ for (; z <= y; z++)
+ {
+ void* swap = sum0;
+ sum0 = sum1;
+ sum1 = (int32_t(*)[4])swap;
+ for (int x = 0; x < width; x += 2)
+ {
+ primitives.ssim_4x4x2_core_int32(&pix1[4 * (x + (z * stride1))], stride1, &pix2[4 * (x + (z * stride2))], stride2, &sum0[x]);
+ }
+ }
+
+ for (int x = 0; x < width - 1; x += 4)
+ {
+ ssim += primitives.ssim_end4_int32(sum0 + x, sum1 + x, X265_MIN(4, width - x - 1));
+ }
+ }
+
+ *cnt = (height - 1) * (width - 1);
+ return ssim;
+}
+
+float FrameEncoder::calculateSSIM_int64(pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int width, int height, void *buf, int *cnt)
+{
+ int z = 0;
+ float ssim = 0.0;
+
+ int64_t(*sum0)[4] = (int64_t(*)[4])buf;
+ int64_t(*sum1)[4] = sum0 + (width >> 2) + 3;
+ width >>= 2;
+ height >>= 2;
+
+ for (int y = 1; y < height; y++)
+ {
+ for (; z <= y; z++)
+ {
+ void* swap = sum0;
+ sum0 = sum1;
+ sum1 = (int64_t(*)[4])swap;
+ for (int x = 0; x < width; x += 2)
+ {
+ primitives.ssim_4x4x2_core_int64(&pix1[4 * (x + (z * stride1))], stride1, &pix2[4 * (x + (z * stride2))], stride2, &sum0[x]);
+ }
+ }
+
+ for (int x = 0; x < width - 1; x += 4)
+ {
+ ssim += primitives.ssim_end4_int64(sum0 + x, sum1 + x, X265_MIN(4, width - x - 1));
+ }
+ }
+
+ *cnt = (height - 1) * (width - 1);
+ return ssim;
+}
+
void FrameEncoder::encodeSlice(TComOutputBitstream* substreams)
{
// choose entropy coder
diff -r e58bbff11696 -r e116b5414806 source/encoder/frameencoder.h
--- a/source/encoder/frameencoder.h Mon Oct 07 02:09:36 2013 +0530
+++ b/source/encoder/frameencoder.h Mon Oct 07 02:11:04 2013 +0530
@@ -145,6 +145,10 @@
/* called by compressFrame to perform wave-front compression analysis */
void compressCTURows();
+ /* called by compressFrame to calculate SSIM for each row . */
+ float calculateSSIM_int32(pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int width, int height, void *buf, int *cnt);
+ float calculateSSIM_int64(pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int width, int height, void *buf, int *cnt);
+
void encodeSlice(TComOutputBitstream* substreams);
/* blocks until worker thread is done, returns encoded picture and bitstream */
@@ -185,6 +189,9 @@
int m_filterRowDelay;
CTURow* m_rows;
Event m_completionEvent;
+
+ /* Temp Storage for ssim computation that doesnt need repeated malloc */
+ void * ssimBuf;
};
}
More information about the x265-devel
mailing list