<div dir="ltr">From 679defdc97e93ed7597623045e8306fcdc29d916 Mon Sep 17 00:00:00 2001<br>From: AnusuyaKumarasamy <<a href="mailto:anusuya.kumarasamy@multicorewareinc.com">anusuya.kumarasamy@multicorewareinc.com</a>><br>Date: Thu, 24 Oct 2024 15:41:44 +0530<br>Subject: [PATCH 04/10] shifted mcstf from encoder to lookahead<br><br>---<br> source/common/frame.cpp         |   3 +<br> source/common/frame.h           |   1 +<br> source/common/picyuv.cpp        |   4 +<br> source/common/temporalfilter.h  |   2 +<br> source/encoder/encoder.cpp      |  55 ++++++++------<br> source/encoder/frameencoder.cpp |   2 +-<br> source/encoder/slicetype.cpp    | 125 ++++++++++++++++++++++++++++++++<br> source/encoder/slicetype.h      |   7 ++<br> 8 files changed, 175 insertions(+), 24 deletions(-)<br><br>diff --git a/source/common/frame.cpp b/source/common/frame.cpp<br>index 4c800e94e..80f341edf 100644<br>--- a/source/common/frame.cpp<br>+++ b/source/common/frame.cpp<br>@@ -94,6 +94,9 @@ bool Frame::create(x265_param *param, float* quantOffsets)<br>         m_mcstf->m_range = param->mcstfFrameRange;<br>         m_mcstf->init(param);<br> <br>+        for (int i = 0; i < (m_mcstf->m_range << 1); i++)<br>+            m_mcstf->createRefPicInfo(&m_mcstfRefList[i], m_param);<br>+<br>         m_fencPicSubsampled2 = new PicYuv;<br>         m_fencPicSubsampled4 = new PicYuv;<br> <br>diff --git a/source/common/frame.h b/source/common/frame.h<br>index 8d330026e..e85727deb 100644<br>--- a/source/common/frame.h<br>+++ b/source/common/frame.h<br>@@ -147,6 +147,7 @@ public:<br>     Frame*                 m_nextMCSTF;           // PicList doubly linked list pointers<br>     Frame*                 m_prevMCSTF;<br>     int*                   m_isSubSampled;<br>+    TemporalFilterRefPicInfo m_mcstfRefList[MAX_MCSTF_TEMPORAL_WINDOW_LENGTH];<br> <br>     /*Vbv-End-Flag*/<br>     int vbvEndFlag;<br>diff --git a/source/common/picyuv.cpp b/source/common/picyuv.cpp<br>index a0190acc3..df8d666ea 100644<br>--- a/source/common/picyuv.cpp<br>+++ b/source/common/picyuv.cpp<br>@@ -154,6 +154,10 @@ bool PicYuv::createScaledPicYUV(x265_param* param, uint8_t scaleFactor)<br>     m_param = param;<br>     m_picWidth = m_param->sourceWidth / scaleFactor;<br>     m_picHeight = m_param->sourceHeight / scaleFactor;<br>+    int maxBlocksInRow = (m_picWidth + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;<br>+    int maxBlocksInCol = (m_picHeight + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;<br>+    m_picWidth = maxBlocksInRow * X265_LOWRES_CU_SIZE;<br>+    m_picHeight = maxBlocksInCol * X265_LOWRES_CU_SIZE;<br> <br>     m_picCsp = m_param->internalCsp;<br>     m_hChromaShift = CHROMA_H_SHIFT(m_picCsp);<br>diff --git a/source/common/temporalfilter.h b/source/common/temporalfilter.h<br>index 9fe51da8c..1cd8028c7 100644<br>--- a/source/common/temporalfilter.h<br>+++ b/source/common/temporalfilter.h<br>@@ -105,6 +105,8 @@ namespace X265_NS {<br>         int*       error;<br>         int*       noise;<br>         int        poc;<br>+        pixel*     lowres;<br>+        pixel*     lowerRes;<br> <br>         int16_t    origOffset;<br>         bool       isFilteredFrame;<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 0a0c09307..d75dcafd8 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -1415,6 +1415,15 @@ inline int enqueueRefFrame(FrameEncoder* curframeEncoder, Frame* iterFrame, Fram<br>     dest->isFilteredFrame = isPreFiltered;<br>     dest->isSubsampled = iterFrame->m_isSubSampled;<br>     dest->origOffset = i;<br>+<br>+    TemporalFilterRefPicInfo* temp = &curFrame->m_mcstfRefList[curFrame->m_mcstf->m_numRef];<br>+    temp->poc = iterFrame->m_poc;<br>+    temp->picBuffer = iterFrame->m_fencPic;<br>+    temp->lowres = iterFrame->m_lowres.lowresPlane[0];<br>+    temp->lowerRes = iterFrame->m_lowres.lowerResPlane[0];<br>+    temp->isFilteredFrame = isPreFiltered;<br>+    temp->origOffset = i;<br>+<br>     curFrame->m_mcstf->m_numRef++;<br> <br>     return 1;<br>@@ -1443,12 +1452,12 @@ bool Encoder::generateMcstfRef(Frame* frameEnc, FrameEncoder* currEncoder)<br>                         TemporalFilter* mcstf = frameEnc->m_mcstf;<br>                         while (mcstf->m_numRef)<br>                         {<br>-                            memset(currEncoder->m_mcstfRefList[mcstf->m_numRef].mvs0,  0, sizeof(MV) * ((mcstf->m_sourceWidth / 16) * (mcstf->m_sourceHeight / 16)));<br>-                            memset(currEncoder->m_mcstfRefList[mcstf->m_numRef].mvs1,  0, sizeof(MV) * ((mcstf->m_sourceWidth / 16) * (mcstf->m_sourceHeight / 16)));<br>-                            memset(currEncoder->m_mcstfRefList[mcstf->m_numRef].mvs2,  0, sizeof(MV) * ((mcstf->m_sourceWidth / 16) * (mcstf->m_sourceHeight / 16)));<br>-                            memset(currEncoder->m_mcstfRefList[mcstf->m_numRef].mvs,   0, sizeof(MV) * ((mcstf->m_sourceWidth /  4) * (mcstf->m_sourceHeight /  4)));<br>-                            memset(currEncoder->m_mcstfRefList[mcstf->m_numRef].noise, 0, sizeof(int) * ((mcstf->m_sourceWidth / 4) * (mcstf->m_sourceHeight / 4)));<br>-                            memset(currEncoder->m_mcstfRefList[mcstf->m_numRef].error, 0, sizeof(int) * ((mcstf->m_sourceWidth / 4) * (mcstf->m_sourceHeight / 4)));<br>+                            memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].mvs0, 0, sizeof(MV) * ((mcstf->m_sourceWidth / 16) * (mcstf->m_sourceHeight / 16)));<br>+                            memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].mvs1, 0, sizeof(MV) * ((mcstf->m_sourceWidth / 16) * (mcstf->m_sourceHeight / 16)));<br>+                            memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].mvs2, 0, sizeof(MV) * ((mcstf->m_sourceWidth / 16) * (mcstf->m_sourceHeight / 16)));<br>+                            memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].mvs, 0, sizeof(MV) * ((mcstf->m_sourceWidth / 4) * (mcstf->m_sourceHeight / 4)));<br>+                            memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].noise, 0, sizeof(int) * ((mcstf->m_sourceWidth / 4) * (mcstf->m_sourceHeight / 4)));<br>+                            memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].error, 0, sizeof(int) * ((mcstf->m_sourceWidth / 4) * (mcstf->m_sourceHeight / 4)));<br> <br>                             mcstf->m_numRef--;<br>                         }<br>@@ -1513,7 +1522,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>         m_dpb->recycleUnreferenced();<br> <br>         if (m_param->bEnableTemporalFilter)<br>-            m_origPicBuffer->recycleOrigPicList();<br>+            m_lookahead->m_origPicBuf->recycleOrigPicList();<br>     }<br> <br>     if ((pic_in && (!m_param->chunkEnd || (m_encodedFrameNum < m_param->chunkEnd))) || (m_param->bEnableFrameDuplication && !pic_in && (read < written)))<br>@@ -1917,7 +1926,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>                                 dupFrame->m_fencPic->m_cuOffsetC = m_sps.cuOffsetC;<br>                                 dupFrame->m_fencPic->m_buOffsetC = m_sps.buOffsetC;<br>                             }<br>-                            m_origPicBuffer->addEncPicture(dupFrame);<br>+                            m_lookahead->m_origPicBuf->addEncPicture(dupFrame);<br>                         }<br>                     }<br>                 }<br>@@ -1936,7 +1945,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>             extendPicBorder(orig->m_picOrg[2], orig->m_strideC, orig->m_picWidth >> orig->m_hChromaShift, orig->m_picHeight >> orig->m_vChromaShift, orig->m_chromaMarginX, orig->m_chromaMarginY);<br> <br>             //TODO: Add subsampling here if required<br>-            m_origPicBuffer->addPicture(inFrame[0]);<br>+            m_lookahead->m_origPicBuf->addPicture(inFrame[0]);;<br>         }<br> <br>         m_lookahead->addPicture(*inFrame[0], sliceType);<br>@@ -2188,11 +2197,11 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br> <br>                 if (m_param->bEnableTemporalFilter)<br>                 {<br>-                    Frame* curFrame = m_origPicBuffer->m_mcstfPicList.getPOCMCSTF(outFrame->m_poc);<br>+                    Frame* curFrame = m_lookahead->m_origPicBuf->m_mcstfPicList.getPOCMCSTF(outFrame->m_poc);<br>                     X265_CHECK(curFrame, "Outframe not found in DPB's mcstfPicList");<br>                     curFrame->m_refPicCnt[0]--;<br>                     curFrame->m_refPicCnt[1]--;<br>-                    curFrame = m_origPicBuffer->m_mcstfOrigPicList.getPOCMCSTF(outFrame->m_poc);<br>+                    curFrame = m_lookahead->m_origPicBuf->m_mcstfOrigPicList.getPOCMCSTF(outFrame->m_poc);<br>                     X265_CHECK(curFrame, "Outframe not found in OPB's mcstfOrigPicList");<br>                     curFrame->m_refPicCnt[1]--;<br>                 }<br>@@ -2203,7 +2212,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>                     ATOMIC_DEC(&outFrame->m_countRefEncoders);<br>                     m_dpb->recycleUnreferenced();<br>                     if (m_param->bEnableTemporalFilter)<br>-                        m_origPicBuffer->recycleOrigPicList();<br>+                        m_lookahead->m_origPicBuf->recycleOrigPicList();<br>                 }<br>                 else<br>                     m_exportedPic[sLayer] = outFrame;<br>@@ -2448,9 +2457,9 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br> <br>             if (m_param->bEnableTemporalFilter)<br>             {<br>-                X265_CHECK(!m_origPicBuffer->m_mcstfOrigPicFreeList.empty(), "Frames not available in Encoded OPB");<br>+                X265_CHECK(!m_lookahead->m_origPicBuf->m_mcstfOrigPicFreeList.empty(), "Frames not available in Encoded OPB");<br> <br>-                Frame *dupFrame = m_origPicBuffer->m_mcstfOrigPicFreeList.popBackMCSTF();<br>+                Frame* dupFrame = m_lookahead->m_origPicBuf->m_mcstfOrigPicFreeList.popBackMCSTF();<br>                 dupFrame->m_fencPic->copyFromFrame(frameEnc[0]->m_fencPic);<br>                 dupFrame->m_poc = frameEnc[0]->m_poc;<br>                 dupFrame->m_encodeOrder = frameEnc[0]->m_encodeOrder;<br>@@ -2461,8 +2470,8 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>                 if (m_param->totalFrames && (dupFrame->m_poc >= (m_param->totalFrames - dupFrame->m_mcstf->m_range)))<br>                     dupFrame->m_refPicCnt[1] -= (uint8_t)(dupFrame->m_poc + dupFrame->m_mcstf->m_range - m_param->totalFrames + 1);<br> <br>-                m_origPicBuffer->addEncPictureToPicList(dupFrame);<br>-                m_origPicBuffer->setOrigPicList(frameEnc[0], m_pocLast);<br>+                m_lookahead->m_origPicBuf->addEncPictureToPicList(dupFrame);<br>+                m_lookahead->m_origPicBuf->setOrigPicList(frameEnc[0], m_pocLast);<br>             }<br> <br>             for (int layer = 0; layer < m_param->numLayers; layer++)<br>@@ -2510,18 +2519,18 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br> <br>                 for (uint8_t i = 1; i <= frameEnc[0]->m_mcstf->m_numRef; i++)<br>                 {<br>-                    TemporalFilterRefPicInfo *ref = &curEncoder->m_mcstfRefList[i - 1];<br>-                    Frame* curFrame = m_origPicBuffer->m_mcstfPicList.getPOCMCSTF(ref->poc);<br>+                    TemporalFilterRefPicInfo* ref = &frameEnc[0]->m_mcstfRefList[i - 1];<br>+                    Frame* curFrame = m_lookahead->m_origPicBuf->m_mcstfPicList.getPOCMCSTF(ref->poc);<br> <br>-                    curEncoder->m_frameEncTF->motionEstimationLuma(ref->mvs0, ref->mvsStride0, frameEnc[0]->m_lowres.lowerResPlane[0], (frameEnc[0]->m_lowres.lumaStride / 2), frameEnc[0]->m_fencPicSubsampled4->m_picHeight, frameEnc[0]->m_fencPicSubsampled4->m_picWidth, curFrame->m_lowres.lowerResPlane[0], 16);<br>-                    curEncoder->m_frameEncTF->motionEstimationLuma(ref->mvs1, ref->mvsStride1, frameEnc[0]->m_lowres.lowresPlane[0], frameEnc[0]->m_lowres.lumaStride, frameEnc[0]->m_fencPicSubsampled2->m_picHeight, frameEnc[0]->m_fencPicSubsampled2->m_picWidth, curFrame->m_lowres.lowresPlane[0], 16, ref->mvs0, ref->mvsStride0, 2);<br>-                    curEncoder->m_frameEncTF->motionEstimationLuma(ref->mvs2, ref->mvsStride2, frameEnc[0]->m_fencPic->m_picOrg[0], frameEnc[0]->m_fencPic->m_stride, frameEnc[0]->m_fencPic->m_picHeight, frameEnc[0]->m_fencPic->m_picWidth, ref->picBuffer->m_picOrg[0], 16, ref->mvs1, ref->mvsStride1, 2);<br>-                    curEncoder->m_frameEncTF->motionEstimationLumaDoubleRes(ref->mvs, ref->mvsStride, frameEnc[0]->m_fencPic, ref->picBuffer, 8, ref->mvs2, ref->mvsStride2, 1, ref->error);<br>+                    //curFrame->m_mcstf->motionEstimationLuma(ref->mvs0, ref->mvsStride0, frameEnc[0]->m_lowres.lowerResPlane[0], (curFrame->m_lowres.lumaStride / 2), (curFrame->m_lowres.lines / 2), (curFrame->m_lowres.width / 2), ref->lowerRes, 16);<br>+                    //curFrame->m_mcstf->motionEstimationLuma(ref->mvs1, ref->mvsStride1, frameEnc[0]->m_lowres.lowresPlane[0], (curFrame->m_lowres.lumaStride), (curFrame->m_lowres.lines), (curFrame->m_lowres.width), ref->lowres, 16, ref->mvs0, ref->mvsStride0, 2);<br>+                    curFrame->m_mcstf->motionEstimationLuma(ref->mvs2, ref->mvsStride2, frameEnc[0]->m_fencPic->m_picOrg[0], curFrame->m_fencPic->m_stride, curFrame->m_fencPic->m_picHeight, curFrame->m_fencPic->m_picWidth, ref->picBuffer->m_picOrg[0], 16, ref->mvs1, ref->mvsStride1, 2);<br>+                    curFrame->m_mcstf->motionEstimationLumaDoubleRes(ref->mvs, ref->mvsStride, frameEnc[0]->m_fencPic, ref->picBuffer, 8, ref->mvs2, ref->mvsStride2, 1, ref->error);<br>                 }<br> <br>                 for (int i = 0; i < frameEnc[0]->m_mcstf->m_numRef; i++)<br>                 {<br>-                    TemporalFilterRefPicInfo *ref = &curEncoder->m_mcstfRefList[i];<br>+                    TemporalFilterRefPicInfo* ref = &frameEnc[0]->m_mcstfRefList[i];<br>                     ref->slicetype = m_lookahead->findSliceType(frameEnc[0]->m_poc + ref->origOffset);<br>                     Frame* dpbframePtr = m_dpb->m_picList.getPOC(frameEnc[0]->m_poc + ref->origOffset, 0);<br>                     if (dpbframePtr != NULL)<br>diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp<br>index b6f2d6ed1..772810f3d 100644<br>--- a/source/encoder/frameencoder.cpp<br>+++ b/source/encoder/frameencoder.cpp<br>@@ -677,7 +677,7 @@ void FrameEncoder::compressFrame(int layer)<br>     if (m_param->bEnableTemporalFilter)<br>     {<br>         m_frameEncTF->m_QP = qp;<br>-        m_frameEncTF->bilateralFilter(m_frame[layer], m_mcstfRefList, m_param->temporalFilterStrength);<br>+        m_frameEncTF->bilateralFilter(m_frame[layer], m_frame[layer]->m_mcstfRefList, m_param->temporalFilterStrength);<br>     }<br> <br>     if (m_nr)<br>diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp<br>index 8bbac8244..19f6d8f53 100644<br>--- a/source/encoder/slicetype.cpp<br>+++ b/source/encoder/slicetype.cpp<br>@@ -991,6 +991,7 @@ Lookahead::Lookahead(x265_param *param, ThreadPool* pool)<br>     m_isFadeIn = false;<br>     m_fadeCount = 0;<br>     m_fadeStart = -1;<br>+    m_origPicBuf = 0;<br> <br>     /* Allow the strength to be adjusted via qcompress, since the two concepts<br>      * are very similar. */<br>@@ -1126,6 +1127,9 @@ bool Lookahead::create()<br>         m_tld[i].init(m_8x8Width, m_8x8Height, m_8x8Blocks);<br>     m_scratch = X265_MALLOC(int, m_tld[0].widthInCU);<br> <br>+    if (m_param->bEnableTemporalFilter)<br>+        m_origPicBuf = new OrigPicBuffer();<br>+<br>     return m_tld && m_scratch;<br> }<br> <br>@@ -1165,6 +1169,9 @@ void Lookahead::destroy()<br>         delete curFrame;<br>     }<br> <br>+    if (m_param->bEnableTemporalFilter)<br>+        delete m_origPicBuf;<br>+<br>     X265_FREE(m_scratch);<br>     delete [] m_tld;<br>     if (m_param->lookaheadThreads > 0)<br>@@ -1787,6 +1794,108 @@ void Lookahead::compCostBref(Lowres **frames, int start, int end, int num)<br>     }<br> }<br> <br>+void Lookahead::estimatelowresmotion(Frame* curframe)<br>+{<br>+<br>+    for (int i = 1; i <= curframe->m_mcstf->m_numRef; i++)<br>+    {<br>+        TemporalFilterRefPicInfo * ref = &curframe->m_mcstfRefList[i - 1];<br>+<br>+        curframe->m_mcstf->motionEstimationLuma(ref->mvs0, ref->mvsStride0, curframe->m_lowres.lowerResPlane[0], (curframe->m_lowres.lumaStride / 2), (curframe->m_lowres.lines / 2), (curframe->m_lowres.width / 2), ref->lowerRes, 16);<br>+        curframe->m_mcstf->motionEstimationLuma(ref->mvs1, ref->mvsStride1, curframe->m_lowres.lowresPlane[0], (curframe->m_lowres.lumaStride), (curframe->m_lowres.lines), (curframe->m_lowres.width), ref->lowres, 16, ref->mvs0, ref->mvsStride0, 2);<br>+        //curframe->m_mcstf->motionEstimationLuma(ref->mvs2, ref->mvsStride2, curframe->m_fencPic->m_picOrg[0], curframe->m_fencPic->m_stride, curframe->m_fencPic->m_picHeight, curframe->m_fencPic->m_picWidth, ref->picBuffer->m_picOrg[0], 16, ref->mvs1, ref->mvsStride1, 2);<br>+        //curframe->m_mcstf->motionEstimationLumaDoubleRes(ref->mvs, ref->mvsStride, curframe->m_fencPic, ref->picBuffer, 8, ref->mvs2, ref->mvsStride2, 1, ref->error);<br>+    }<br>+<br>+}<br>+<br>+inline int enqueueRefFrame(Frame* iterFrame, Frame* curFrame, bool isPreFiltered, int16_t i)<br>+{<br>+    TemporalFilterRefPicInfo * temp = &curFrame->m_mcstfRefList[curFrame->m_mcstf->m_numRef];<br>+    temp->poc = iterFrame->m_poc;<br>+    temp->picBuffer = iterFrame->m_fencPic;<br>+    temp->lowres = iterFrame->m_lowres.lowresPlane[0];<br>+    temp->lowerRes = iterFrame->m_lowres.lowerResPlane[0];<br>+    temp->isFilteredFrame = isPreFiltered;<br>+    temp->isSubsampled = iterFrame->m_isSubSampled;<br>+    temp->origOffset = i;<br>+    curFrame->m_mcstf->m_numRef++;<br>+<br>+     return 1;<br>+}<br>+<br>+bool Lookahead::isFilterThisframe(uint8_t sliceTypeConfig, int curSliceType)<br>+{<br>+    uint8_t newSliceType = 0;<br>+    switch (curSliceType)<br>+    {<br>+        case 1: newSliceType |= 1 << 0;<br>+               break;<br>+        case 2: newSliceType |= 1 << 0;<br>+               break;<br>+        case 3: newSliceType |= 1 << 1;<br>+               break;<br>+        case 4: newSliceType |= 1 << 2;<br>+               break;<br>+        case 5: newSliceType |= 1 << 3;<br>+               break;<br>+        default: return 0;<br>+    }<br>+     return ((sliceTypeConfig & newSliceType) != 0);<br>+}<br>+<br>+bool Lookahead::generatemcstf(Frame * frameEnc, PicList refPic, int poclast)<br>+ {<br>+     frameEnc->m_mcstf->m_numRef = 0;<br>+<br>+    for (int iterPOC = (frameEnc->m_poc - frameEnc->m_mcstf->m_range);<br>+            iterPOC <= (frameEnc->m_poc + frameEnc->m_mcstf->m_range); iterPOC++)<br>+    {<br>+         bool isFound = false;<br>+        if (iterPOC != frameEnc->m_poc)<br>+        {<br>+                //search for the reference frame in the Original Picture Buffer<br>+            if (!isFound)<br>+                {<br>+                for (int j = 0; j < (2 * frameEnc->m_mcstf->m_range); j++)<br>+                {<br>+                    if (iterPOC < 0)<br>+                         continue;<br>+                    if (iterPOC >= poclast)<br>+                         {<br>+<br>+                    TemporalFilter * mcstf = frameEnc->m_mcstf;<br>+                    while (mcstf->m_numRef)<br>+                    {<br>+                        memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].mvs0, 0, sizeof(MV) * ((mcstf->m_sourceWidth / 16) * (mcstf->m_sourceHeight / 16)));<br>+                        memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].mvs1, 0, sizeof(MV) * ((mcstf->m_sourceWidth / 16) * (mcstf->m_sourceHeight / 16)));<br>+                        memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].mvs2, 0, sizeof(MV) * ((mcstf->m_sourceWidth / 16) * (mcstf->m_sourceHeight / 16)));<br>+                        memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].mvs, 0, sizeof(MV) * ((mcstf->m_sourceWidth / 4) * (mcstf->m_sourceHeight / 4)));<br>+                        memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].noise, 0, sizeof(int) * ((mcstf->m_sourceWidth / 4) * (mcstf->m_sourceHeight / 4)));<br>+                        memset(frameEnc->m_mcstfRefList[mcstf->m_numRef].error, 0, sizeof(int) * ((mcstf->m_sourceWidth / 4) * (mcstf->m_sourceHeight / 4)));<br>+<br>+                        mcstf->m_numRef--;<br>+                    }<br>+<br>+                    break;<br>+                    }<br>+                    Frame * iterFrame = refPic.getPOCMCSTF(iterPOC);<br>+                    if (iterFrame->m_poc == iterPOC)<br>+                    {<br>+                        if (!enqueueRefFrame(iterFrame, frameEnc, false, (int16_t)(iterPOC - frameEnc->m_poc)))<br>+                        {<br>+                            return false;<br>+                        };<br>+                        break;<br>+                    }<br>+                }<br>+            }<br>+        }<br>+    }<br>+<br>+    return true;<br>+}<br>+<br> /* called by API thread or worker thread with inputQueueLock acquired */<br> void Lookahead::slicetypeDecide()<br> {<br>@@ -2047,6 +2156,22 @@ void Lookahead::slicetypeDecide()<br>         }<br>     }<br> <br>+    Frame* frameEnc = m_inputQueue.first();<br>+    for (int i = 0; i < m_inputQueue.size(); i++)<br>+    {<br>+        if (m_param->bEnableTemporalFilter && isFilterThisframe(frameEnc->m_mcstf->m_sliceTypeConfig, frameEnc->m_lowres.sliceType))<br>+        {<br>+            if (!generatemcstf(frameEnc, m_origPicBuf->m_mcstfPicList, m_inputQueue.last()->m_poc))<br>+            {<br>+                x265_log(m_param, X265_LOG_ERROR, "Failed to initialize MCSTFReferencePicInfo at POC %d\n", frameEnc->m_poc);<br>+                fflush(stderr);<br>+            }<br>+<br>+            estimatelowresmotion(frameEnc);<br>+        }<br>+         frameEnc = frameEnc->m_next;<br>+    }<br>+<br>     if (m_param->bEnableTemporalSubLayers > 2)<br>     {<br>         //Split the partial mini GOP into sub mini GOPs when temporal sub layers are enabled<br>diff --git a/source/encoder/slicetype.h b/source/encoder/slicetype.h<br>index f4184e4e2..214e295b7 100644<br>--- a/source/encoder/slicetype.h<br>+++ b/source/encoder/slicetype.h<br>@@ -30,6 +30,7 @@<br> #include "motion.h"<br> #include "piclist.h"<br> #include "threadpool.h"<br>+#include "temporalfilter.h"<br> <br> namespace X265_NS {<br> // private namespace<br>@@ -202,6 +203,8 @@ public:<br> <br>     int8_t                  m_gopId;<br> <br>+    OrigPicBuffer*          m_origPicBuf;<br>+<br>     Lookahead(x265_param *param, ThreadPool *pool);<br> #if DETAILED_CU_STATS<br>     int64_t       m_slicetypeDecideElapsedTime;<br>@@ -224,6 +227,10 @@ public:<br>     void    getEstimatedPictureCost(Frame *pic);<br>     void    setLookaheadQueue();<br>     int     findSliceType(int poc);<br>+    void    estimatelowresmotion(Frame* frame);<br>+    bool    generatemcstf(Frame * frame, PicList refPic, int poclast);<br>+    bool    isFilterThisframe(uint8_t sliceTypeConfig, int curSliceType);<br>+<br> <br> protected:<br> <br>-- <br>2.36.0.windows.1<br><br></div>