<div dir="ltr"><div dir="ltr"><div>From 0d1748cbf58e83b6357e4ff3c9696687e3c30ddd Mon Sep 17 00:00:00 2001</div><div>From: ashok2022 <<a href="mailto:ashok@multicorewareinc.com">ashok@multicorewareinc.com</a>></div><div>Date: Thu, 13 Oct 2022 20:22:07 +0530</div><div>Subject: [PATCH] Implement ASM for SSD used for motion estimation</div><div><br></div><div>---</div><div> source/common/temporalfilter.cpp | 47 +++++++++++++++++++++++++-------</div><div> source/common/temporalfilter.h   | 31 ++++++++++++++++-----</div><div> source/encoder/frameencoder.cpp  |  2 ++</div><div> source/encoder/motion.cpp        | 25 +++++++++++++++++</div><div> source/encoder/motion.h          |  2 +-</div><div> 5 files changed, 89 insertions(+), 18 deletions(-)</div><div><br></div><div>diff --git a/source/common/temporalfilter.cpp b/source/common/temporalfilter.cpp</div><div>index 1d5a7d076..a937e2a67 100644</div><div>--- a/source/common/temporalfilter.cpp</div><div>+++ b/source/common/temporalfilter.cpp</div><div>@@ -1,6 +1,8 @@</div><div> /*****************************************************************************</div><div> * Copyright (C) 2013-2021 MulticoreWare, Inc</div><div> *</div><div>+ * Authors: Ashok Kumar Mishra <<a href="mailto:ashok@multicorewareinc.com">ashok@multicorewareinc.com</a>></div><div>+ *</div><div> * This program is free software; you can redistribute it and/or modify</div><div> * it under the terms of the GNU General Public License as published by</div><div> * the Free Software Foundation; either version 2 of the License, or</div><div>@@ -18,8 +20,9 @@</div><div> * This program is also available under a commercial proprietary license.</div><div> * For more information, contact us at license @ <a href="http://x265.com">x265.com</a>.</div><div> *****************************************************************************/</div><div>-</div><div>+#include "common.h"</div><div> #include "temporalfilter.h"</div><div>+#include "primitives.h"</div><div> </div><div> #include "frame.h"</div><div> #include "slice.h"</div><div>@@ -160,6 +163,10 @@ void TemporalFilter::init(const x265_param* param)</div><div>     m_sourceHeight = param->sourceHeight;</div><div>     m_internalCsp = param->internalCsp;</div><div>     m_numComponents = (m_internalCsp != X265_CSP_I400) ? MAX_NUM_COMPONENT : 1;</div><div>+</div><div>+    m_metld = new MotionEstimatorTLD;</div><div>+</div><div>+    predPUYuv.create(FENC_STRIDE, X265_CSP_I400);</div><div> }</div><div> </div><div> int TemporalFilter::createRefPicInfo(MCTFReferencePicInfo* refFrame, x265_param* param)</div><div>@@ -206,21 +213,33 @@ int TemporalFilter::motionErrorLuma(</div><div>     {</div><div>         dx /= s_motionVectorFactor;</div><div>         dy /= s_motionVectorFactor;</div><div>+</div><div>+        const pixel* bufferRowStart = buffOrigin + (y + dy) * buffStride + (x + dx);</div><div>+#if 0</div><div>+        const pixel* origRowStart = origOrigin + y *origStride + x;</div><div>+</div><div>         for (int y1 = 0; y1 < bs; y1++)</div><div>         {</div><div>-            const pixel* origRowStart = origOrigin + (y + y1)*origStride + x;</div><div>-            const pixel* bufferRowStart = buffOrigin + (y + y1 + dy)*buffStride + (x + dx);</div><div>-            for (int x1 = 0; x1 < bs; x1 += 2)</div><div>+            for (int x1 = 0; x1 < bs; x1++)</div><div>             {</div><div>                 int diff = origRowStart[x1] - bufferRowStart[x1];</div><div>                 error += diff * diff;</div><div>-                diff = origRowStart[x1 + 1] - bufferRowStart[x1 + 1];</div><div>-                error += diff * diff;</div><div>-            }</div><div>-            if (error > besterror)</div><div>-            {</div><div>-                return error;</div><div>             }</div><div>+</div><div>+            origRowStart += origStride;</div><div>+            bufferRowStart += buffStride;</div><div>+        }</div><div>+#else</div><div>+        int partEnum = partitionFromSizes(bs, bs);</div><div>+        /* copy PU block into cache */</div><div>+        primitives.pu[partEnum].copy_pp(predPUYuv.m_buf[0], FENC_STRIDE, bufferRowStart, buffStride);</div><div>+</div><div>+        error = <a href="http://primitives.cu">primitives.cu</a>[partEnum].sse_pp(m_metld->me.fencPUYuv.m_buf[0], FENC_STRIDE, predPUYuv.m_buf[0], FENC_STRIDE);</div><div>+</div><div>+#endif</div><div>+        if (error > besterror)</div><div>+        {</div><div>+            return error;</div><div>         }</div><div>     }</div><div>     else</div><div>@@ -761,6 +780,10 @@ void TemporalFilter::motionEstimationLuma(MV *mvs, uint32_t mvStride, PicYuv *or</div><div>     {</div><div>         for (int blockX = 0; blockX + blockSize <= origWidth; blockX += stepSize)</div><div>         {</div><div>+            const intptr_t pelOffset = blockY * orig->m_stride + blockX;</div><div>+            m_metld->me.setSourcePU(orig->m_picOrg[0], orig->m_stride, pelOffset, blockSize, blockSize, X265_HEX_SEARCH, 1);</div><div>+</div><div>+</div><div>             MV best(0, 0);</div><div>             int leastError = INT_MAX;</div><div> </div><div>@@ -889,6 +912,10 @@ void TemporalFilter::motionEstimationLumaDoubleRes(MV *mvs, uint32_t mvStride, P</div><div>     {</div><div>         for (int blockX = 0; blockX + blockSize <= origWidth; blockX += stepSize)</div><div>         {</div><div>+</div><div>+            const intptr_t pelOffset = blockY * orig->m_stride + blockX;</div><div>+            m_metld->me.setSourcePU(orig->m_picOrg[0], orig->m_stride, pelOffset, blockSize, blockSize, X265_HEX_SEARCH, 1);</div><div>+</div><div>             MV best(0, 0);</div><div>             int leastError = INT_MAX;</div><div> </div><div>diff --git a/source/common/temporalfilter.h b/source/common/temporalfilter.h</div><div>index 003630994..801359914 100644</div><div>--- a/source/common/temporalfilter.h</div><div>+++ b/source/common/temporalfilter.h</div><div>@@ -29,6 +29,7 @@</div><div> #include <deque></div><div> #include "piclist.h"</div><div> #include "yuv.h"</div><div>+#include "motion.h"</div><div> </div><div> using namespace X265_NS;</div><div> </div><div>@@ -94,6 +95,19 @@ struct TemporalFilterRefPicInfo</div><div>     int        origOffset;</div><div> };</div><div> </div><div>+struct MotionEstimatorTLD</div><div>+{</div><div>+    MotionEstimate  me;</div><div>+</div><div>+    MotionEstimatorTLD()</div><div>+    {</div><div>+        me.init(X265_CSP_I400);</div><div>+        me.setQP(X265_LOOKAHEAD_QP);</div><div>+    }</div><div>+</div><div>+    ~MotionEstimatorTLD() {}</div><div>+};</div><div>+</div><div> struct MCTFReferencePicInfo</div><div> {</div><div>     PicYuv*    picBuffer;</div><div>@@ -103,16 +117,16 @@ struct MCTFReferencePicInfo</div><div>     MV*        mvs0;</div><div>     MV*        mvs1;</div><div>     MV*        mvs2;</div><div>-    uint32_t mvsStride;</div><div>-    uint32_t mvsStride0;</div><div>-    uint32_t mvsStride1;</div><div>-    uint32_t mvsStride2;</div><div>-    int*     error;</div><div>-    int*     noise;</div><div>+    uint32_t   mvsStride;</div><div>+    uint32_t   mvsStride0;</div><div>+    uint32_t   mvsStride1;</div><div>+    uint32_t   mvsStride2;</div><div>+    int*       error;</div><div>+    int*       noise;</div><div> </div><div>     int16_t    origOffset;</div><div>     bool       isFilteredFrame;</div><div>-    PicYuv*       compensatedPic;</div><div>+    PicYuv*    compensatedPic;</div><div> </div><div>     int*       isSubsampled;</div><div> </div><div>@@ -154,6 +168,9 @@ public:</div><div>     int m_numComponents;</div><div>     uint8_t m_sliceTypeConfig;</div><div> </div><div>+    MotionEstimatorTLD* m_metld;</div><div>+    Yuv        predPUYuv;</div><div>+</div><div>     void subsampleLuma(PicYuv *input, PicYuv *output, int factor = 2);</div><div> </div><div>     int createRefPicInfo(MCTFReferencePicInfo* refFrame, x265_param* param);</div><div>diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp</div><div>index 0a44eb22f..ec78fc9f2 100644</div><div>--- a/source/encoder/frameencoder.cpp</div><div>+++ b/source/encoder/frameencoder.cpp</div><div>@@ -105,6 +105,8 @@ void FrameEncoder::destroy()</div><div> </div><div>     if (m_param->bEnableGopBasedTemporalFilter)</div><div>     {</div><div>+        delete m_frameEncTF->m_metld;</div><div>+</div><div>         for (int i = 0; i < (m_frameEncTF->s_range << 1); i++)</div><div>             m_frameEncTF->destroyRefPicInfo(&m_mcstfRefList[i]);</div><div> </div><div>diff --git a/source/encoder/motion.cpp b/source/encoder/motion.cpp</div><div>index f10db884e..2bb613ec0 100644</div><div>--- a/source/encoder/motion.cpp</div><div>+++ b/source/encoder/motion.cpp</div><div>@@ -190,6 +190,31 @@ void MotionEstimate::setSourcePU(pixel *fencY, intptr_t stride, intptr_t offset,</div><div>     X265_CHECK(!bChromaSATD, "chroma distortion measurements impossible in this code path\n");</div><div> }</div><div> </div><div>+/* Called by lookahead, luma only, no use of PicYuv */</div><div>+void MotionEstimate::setSourcePU(pixel *fencY, intptr_t stride, intptr_t offset, int pwidth, int pheight, const int method, const int refine)</div><div>+{</div><div>+    partEnum = partitionFromSizes(pwidth, pheight);</div><div>+    X265_CHECK(LUMA_4x4 != partEnum, "4x4 inter partition detected!\n");</div><div>+    sad = primitives.pu[partEnum].sad;</div><div>+    ads = primitives.pu[partEnum].ads;</div><div>+    satd = primitives.pu[partEnum].satd;</div><div>+    sad_x3 = primitives.pu[partEnum].sad_x3;</div><div>+    sad_x4 = primitives.pu[partEnum].sad_x4;</div><div>+</div><div>+</div><div>+    blockwidth = pwidth;</div><div>+    blockOffset = offset;</div><div>+    absPartIdx = ctuAddr = -1;</div><div>+</div><div>+    /* Search params */</div><div>+    searchMethod = method;</div><div>+    subpelRefine = refine;</div><div>+</div><div>+    /* copy PU block into cache */</div><div>+    primitives.pu[partEnum].copy_pp(fencPUYuv.m_buf[0], FENC_STRIDE, fencY + offset, stride);</div><div>+    X265_CHECK(!bChromaSATD, "chroma distortion measurements impossible in this code path\n");</div><div>+}</div><div>+</div><div> /* Called by Search::predInterSearch() or --pme equivalent, chroma residual might be considered */</div><div> void MotionEstimate::setSourcePU(const Yuv& srcFencYuv, int _ctuAddr, int cuPartIdx, int puPartIdx, int pwidth, int pheight, const int method, const int refine, bool bChroma)</div><div> {</div><div>diff --git a/source/encoder/motion.h b/source/encoder/motion.h</div><div>index d306230b4..790bc5fb4 100644</div><div>--- a/source/encoder/motion.h</div><div>+++ b/source/encoder/motion.h</div><div>@@ -77,7 +77,7 @@ public:</div><div>     void init(int csp);</div><div> </div><div>     /* Methods called at slice setup */</div><div>-</div><div>+    void setSourcePU(pixel *fencY, intptr_t stride, intptr_t offset, int pwidth, int pheight, const int searchMethod, const int subpelRefine);</div><div>     void setSourcePU(pixel *fencY, intptr_t stride, intptr_t offset, int pwidth, int pheight, const int searchMethod, const int searchL0, const int searchL1, const int subpelRefine);</div><div>     void setSourcePU(const Yuv& srcFencYuv, int ctuAddr, int cuPartIdx, int puPartIdx, int pwidth, int pheight, const int searchMethod, const int subpelRefine, bool bChroma);</div><div> </div><div>-- </div><div>2.34.1.windows.1</div><div><br></div><div><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><i><font face="georgia, serif">Thanks and Regards,</font></i></div><div><i><font face="georgia, serif"><b>Snehaa.G</b><br>Video Codec Engineer,<br>Media & AI analytics<br><a href="https://multicorewareinc.com/" target="_blank"><img src="https://ci3.googleusercontent.com/mail-sig/AIorK4yEumXeQ2mgcFAR2us9INa7z3rCbl8ordut3fbdeIbuPv0n3EA75Or1rHs0neGaI0WM8mFPz1g"></a><br><span></span><span></span><br></font></i></div></div></div></div></div></div>