[x265] [PATCH 2/14] Modify CmakeLists.txt to add temporalfilter.cpp and temporalfilter.h file
Snehaa Giridharan
snehaa at multicorewareinc.com
Wed Oct 19 07:27:39 UTC 2022
>From c2b49f57dce86763f2d03e7444d3cda5260d9703 Mon Sep 17 00:00:00 2001
From: ashok2022 <ashok at multicorewareinc.com>
Date: Wed, 21 Sep 2022 17:19:14 +0530
Subject: [PATCH] Modify CmakeLists.txt to add temporalfilter.cpp and
temporalfilter.h file
---
source/common/CMakeLists.txt | 3 +-
source/common/temporalfilter.cpp | 960 +++++++++++++++++++++++++++++++
source/common/temporalfilter.h | 181 ++++++
3 files changed, 1143 insertions(+), 1 deletion(-)
create mode 100644 source/common/temporalfilter.cpp
create mode 100644 source/common/temporalfilter.h
diff --git a/source/common/CMakeLists.txt b/source/common/CMakeLists.txt
index 0db9d297f..7dce52015 100644
--- a/source/common/CMakeLists.txt
+++ b/source/common/CMakeLists.txt
@@ -173,4 +173,5 @@ add_library(common OBJECT
quant.cpp quant.h contexts.h
deblock.cpp deblock.h
scaler.cpp scaler.h
- ringmem.cpp ringmem.h)
+ ringmem.cpp ringmem.h
+ temporalfilter.cpp temporalfilter.h)
diff --git a/source/common/temporalfilter.cpp
b/source/common/temporalfilter.cpp
new file mode 100644
index 000000000..b286fc235
--- /dev/null
+++ b/source/common/temporalfilter.cpp
@@ -0,0 +1,960 @@
+/*****************************************************************************
+* Copyright (C) 2013-2021 MulticoreWare, Inc
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111,
USA.
+*
+* This program is also available under a commercial proprietary license.
+* For more information, contact us at license @ x265.com.
+*****************************************************************************/
+
+#include "temporalfilter.h"
+
+#include "frame.h"
+#include "slice.h"
+#include "framedata.h"
+#include "analysis.h"
+
+using namespace X265_NS;
+
+void OrigPicBuffer::addPicture(Frame* inFrame)
+{
+ m_mcstfPicList.pushFrontMCSTF(*inFrame);
+}
+
+void OrigPicBuffer::addEncPicture(Frame* inFrame)
+{
+ m_mcstfOrigPicFreeList.pushFrontMCSTF(*inFrame);
+}
+
+void OrigPicBuffer::addEncPictureToPicList(Frame* inFrame)
+{
+ m_mcstfOrigPicList.pushFrontMCSTF(*inFrame);
+}
+
+OrigPicBuffer::~OrigPicBuffer()
+{
+ while (!m_mcstfOrigPicList.empty())
+ {
+ Frame* curFrame = m_mcstfOrigPicList.popBackMCSTF();
+ curFrame->destroy();
+ delete curFrame;
+ }
+
+ while (!m_mcstfOrigPicFreeList.empty())
+ {
+ Frame* curFrame = m_mcstfOrigPicFreeList.popBackMCSTF();
+ curFrame->destroy();
+ delete curFrame;
+ }
+}
+
+void OrigPicBuffer::setOrigPicList(Frame* inFrame, int frameCnt)
+{
+ Slice* slice = inFrame->m_encData->m_slice;
+ uint8_t j = 0;
+ for (int iterPOC = (inFrame->m_poc - inFrame->m_mcstf->s_range);
+ iterPOC <= (inFrame->m_poc + inFrame->m_mcstf->s_range); iterPOC++)
+ {
+ if (iterPOC != inFrame->m_poc)
+ {
+ if (iterPOC < 0)
+ continue;
+ if (iterPOC >= frameCnt)
+ break;
+
+ Frame *iterFrame = m_mcstfPicList.getPOCMCSTF(iterPOC);
+ X265_CHECK(iterFrame, "Reference frame not found in OPB");
+ if (iterFrame != NULL)
+ {
+ slice->m_mcstfRefFrameList[1][j] = iterFrame;
+ iterFrame->m_refPicCnt[1]--;
+ }
+
+ iterFrame = m_mcstfOrigPicList.getPOCMCSTF(iterPOC);
+ if (iterFrame != NULL)
+ {
+
+ slice->m_mcstfRefFrameList[1][j] = iterFrame;
+
+ iterFrame->m_refPicCnt[1]--;
+ Frame *cFrame =
m_mcstfOrigPicList.getPOCMCSTF(inFrame->m_poc);
+ X265_CHECK(cFrame, "Reference frame not found in encoded
OPB");
+ cFrame->m_refPicCnt[1]--;
+ }
+ j++;
+ }
+ }
+}
+
+void OrigPicBuffer::recycleOrigPicList()
+{
+ Frame *iterFrame = m_mcstfPicList.first();
+
+ while (iterFrame)
+ {
+ Frame *curFrame = iterFrame;
+ iterFrame = iterFrame->m_nextMCSTF;
+ if (!curFrame->m_refPicCnt[1])
+ {
+ m_mcstfPicList.removeMCSTF(*curFrame);
+ iterFrame = m_mcstfPicList.first();
+ }
+ }
+
+ iterFrame = m_mcstfOrigPicList.first();
+
+ while (iterFrame)
+ {
+ Frame *curFrame = iterFrame;
+ iterFrame = iterFrame->m_nextMCSTF;
+ if (!curFrame->m_refPicCnt[1])
+ {
+ m_mcstfOrigPicList.removeMCSTF(*curFrame);
+ *curFrame->m_isSubSampled = false;
+ m_mcstfOrigPicFreeList.pushFrontMCSTF(*curFrame);
+ iterFrame = m_mcstfOrigPicList.first();
+ }
+ }
+}
+
+void OrigPicBuffer::addPictureToFreelist(Frame* inFrame)
+{
+ m_mcstfOrigPicFreeList.pushBack(*inFrame);
+}
+
+TemporalFilter::TemporalFilter() {
+ m_FrameSkip = 0;
+ m_sourceWidth = 0;
+ m_sourceHeight = 0,
+ m_QP = 0;
+ m_GOPSize = 0;
+ m_framesToBeEncoded = 0;
+ m_sliceTypeConfig = 3;
+ m_numRef = 0;
+
+ s_range = 2;
+ s_chromaFactor = 0.55;
+ s_sigmaMultiplier = 9.0;
+ s_sigmaZeroPoint = 10.0;
+ s_motionVectorFactor = 16;
+ s_padding = 128;
+}
+
+void TemporalFilter::init(const x265_param* param)
+{
+ m_param = param;
+ m_bitDepth = param->internalBitDepth;
+ m_sourceWidth = param->sourceWidth;
+ m_sourceHeight = param->sourceHeight;
+ m_internalCsp = param->internalCsp;
+ m_numComponents = (m_internalCsp != X265_CSP_I400) ? MAX_NUM_COMPONENT
: 1;
+}
+
+int TemporalFilter::createRefPicInfo(MCTFReferencePicInfo* refFrame,
x265_param* param)
+{
+ CHECKED_MALLOC_ZERO(refFrame->mvs, MV, sizeof(MV)* ((m_sourceWidth ) /
4) * ((m_sourceHeight ) / 4));
+ refFrame->mvsStride = m_sourceWidth / 4;
+ CHECKED_MALLOC_ZERO(refFrame->mvs0, MV, sizeof(MV)* ((m_sourceWidth )
/ 16) * ((m_sourceHeight ) / 16));
+ refFrame->mvsStride0 = m_sourceWidth / 16;
+ CHECKED_MALLOC_ZERO(refFrame->mvs1, MV, sizeof(MV)* ((m_sourceWidth )
/ 16) * ((m_sourceHeight ) / 16));
+ refFrame->mvsStride1 = m_sourceWidth / 16;
+ CHECKED_MALLOC_ZERO(refFrame->mvs2, MV, sizeof(MV)* ((m_sourceWidth )
/ 16)*((m_sourceHeight ) / 16));
+ refFrame->mvsStride2 = m_sourceWidth / 16;
+
+ CHECKED_MALLOC_ZERO(refFrame->noise, int, sizeof(int) *
((m_sourceWidth) / 4) * ((m_sourceHeight) / 4));
+ CHECKED_MALLOC_ZERO(refFrame->error, int, sizeof(int) *
((m_sourceWidth) / 4) * ((m_sourceHeight) / 4));
+
+ refFrame->slicetype = X265_TYPE_AUTO;
+
+ refFrame->compensatedPic = new PicYuv;
+ refFrame->compensatedPic->create(param, true);
+
+ return 1;
+fail:
+ return 0;
+}
+
+int TemporalFilter::motionErrorLuma(
+ PicYuv *orig,
+ PicYuv *buffer,
+ int x,
+ int y,
+ int dx,
+ int dy,
+ int bs,
+ int besterror)
+{
+
+ pixel* origOrigin = orig->m_picOrg[0];
+ intptr_t origStride = orig->m_stride;
+ pixel *buffOrigin = buffer->m_picOrg[0];
+ intptr_t buffStride = buffer->m_stride;
+ int error = 0;// dx * 10 + dy * 10;
+ if (((dx | dy) & 0xF) == 0)
+ {
+ dx /= s_motionVectorFactor;
+ dy /= s_motionVectorFactor;
+ for (int y1 = 0; y1 < bs; y1++)
+ {
+ const pixel* origRowStart = origOrigin + (y + y1)*origStride +
x;
+ const pixel* bufferRowStart = buffOrigin + (y + y1 +
dy)*buffStride + (x + dx);
+ for (int x1 = 0; x1 < bs; x1 += 2)
+ {
+ int diff = origRowStart[x1] - bufferRowStart[x1];
+ error += diff * diff;
+ diff = origRowStart[x1 + 1] - bufferRowStart[x1 + 1];
+ error += diff * diff;
+ }
+ if (error > besterror)
+ {
+ return error;
+ }
+ }
+ }
+ else
+ {
+ const int *xFilter = s_interpolationFilter[dx & 0xF];
+ const int *yFilter = s_interpolationFilter[dy & 0xF];
+ int tempArray[64 + 8][64];
+
+ int iSum, iBase;
+ for (int y1 = 1; y1 < bs + 7; y1++)
+ {
+ const int yOffset = y + y1 + (dy >> 4) - 3;
+ const pixel *sourceRow = buffOrigin + (yOffset)*buffStride + 0;
+ for (int x1 = 0; x1 < bs; x1++)
+ {
+ iSum = 0;
+ iBase = x + x1 + (dx >> 4) - 3;
+ const pixel *rowStart = sourceRow + iBase;
+
+ iSum += xFilter[1] * rowStart[1];
+ iSum += xFilter[2] * rowStart[2];
+ iSum += xFilter[3] * rowStart[3];
+ iSum += xFilter[4] * rowStart[4];
+ iSum += xFilter[5] * rowStart[5];
+ iSum += xFilter[6] * rowStart[6];
+
+ tempArray[y1][x1] = iSum;
+ }
+ }
+
+ const pixel maxSampleValue = (1 << m_bitDepth) - 1;
+ for (int y1 = 0; y1 < bs; y1++)
+ {
+ const pixel *origRow = origOrigin + (y + y1)*origStride + 0;
+ for (int x1 = 0; x1 < bs; x1++)
+ {
+ iSum = 0;
+ iSum += yFilter[1] * tempArray[y1 + 1][x1];
+ iSum += yFilter[2] * tempArray[y1 + 2][x1];
+ iSum += yFilter[3] * tempArray[y1 + 3][x1];
+ iSum += yFilter[4] * tempArray[y1 + 4][x1];
+ iSum += yFilter[5] * tempArray[y1 + 5][x1];
+ iSum += yFilter[6] * tempArray[y1 + 6][x1];
+
+ iSum = (iSum + (1 << 11)) >> 12;
+ iSum = iSum < 0 ? 0 : (iSum > maxSampleValue ?
maxSampleValue : iSum);
+
+ error += (iSum - origRow[x + x1]) * (iSum - origRow[x +
x1]);
+ }
+ if (error > besterror)
+ {
+ return error;
+ }
+ }
+ }
+ return error;
+}
+
+void TemporalFilter::applyMotion(MV *mvs, uint32_t mvsStride, PicYuv
*input, PicYuv *output)
+{
+ static const int lumaBlockSize = 8;
+ int srcStride = 0;
+ int dstStride = 0;
+ int csx = 0, csy = 0;
+ for (int c = 0; c < m_numComponents; c++)
+ {
+ const pixel maxValue = (1 << X265_DEPTH) - 1;
+
+ const pixel *pSrcImage = input->m_picOrg[c];
+ pixel *pDstImage = output->m_picOrg[c];
+
+ if (c == 0)
+ {
+ srcStride = (int)input->m_stride;
+ dstStride = (int)output->m_stride;
+ }
+ else
+ {
+ srcStride = (int)input->m_strideC;
+ dstStride = (int)output->m_strideC;
+ csx = CHROMA_H_SHIFT(m_internalCsp);
+ csy = CHROMA_V_SHIFT(m_internalCsp);
+ }
+ const int blockSizeX = lumaBlockSize >> csx;
+ const int blockSizeY = lumaBlockSize >> csy;
+ const int height = input->m_picHeight >> csy;
+ const int width = input->m_picWidth >> csx;
+
+ for (int y = 0, blockNumY = 0; y + blockSizeY <= height; y +=
blockSizeY, blockNumY++)
+ {
+ for (int x = 0, blockNumX = 0; x + blockSizeX <= width; x +=
blockSizeX, blockNumX++)
+ {
+ int mvIdx = blockNumY * mvsStride + blockNumX;
+ const MV &mv = mvs[mvIdx];
+ const int dx = mv.x >> csx;
+ const int dy = mv.y >> csy;
+ const int xInt = mv.x >> (4 + csx);
+ const int yInt = mv.y >> (4 + csy);
+
+ const int *xFilter = s_interpolationFilter[dx & 0xf];
+ const int *yFilter = s_interpolationFilter[dy & 0xf]; //
will add 6 bit.
+ const int numFilterTaps = 7;
+ const int centreTapOffset = 3;
+
+ int tempArray[lumaBlockSize +
numFilterTaps][lumaBlockSize];
+
+ for (int by = 1; by < blockSizeY + numFilterTaps; by++)
+ {
+ const int yOffset = y + by + yInt - centreTapOffset;
+ const pixel *sourceRow = pSrcImage + yOffset *
srcStride;
+ for (int bx = 0; bx < blockSizeX; bx++)
+ {
+ int iBase = x + bx + xInt - centreTapOffset;
+ const pixel *rowStart = sourceRow + iBase;
+
+ int iSum = 0;
+ iSum += xFilter[1] * rowStart[1];
+ iSum += xFilter[2] * rowStart[2];
+ iSum += xFilter[3] * rowStart[3];
+ iSum += xFilter[4] * rowStart[4];
+ iSum += xFilter[5] * rowStart[5];
+ iSum += xFilter[6] * rowStart[6];
+
+ tempArray[by][bx] = iSum;
+ }
+ }
+
+ pixel *pDstRow = pDstImage + y * dstStride;
+ for (int by = 0; by < blockSizeY; by++, pDstRow +=
dstStride)
+ {
+ pixel *pDstPel = pDstRow + x;
+ for (int bx = 0; bx < blockSizeX; bx++, pDstPel++)
+ {
+ int iSum = 0;
+
+ iSum += yFilter[1] * tempArray[by + 1][bx];
+ iSum += yFilter[2] * tempArray[by + 2][bx];
+ iSum += yFilter[3] * tempArray[by + 3][bx];
+ iSum += yFilter[4] * tempArray[by + 4][bx];
+ iSum += yFilter[5] * tempArray[by + 5][bx];
+ iSum += yFilter[6] * tempArray[by + 6][bx];
+
+ iSum = (iSum + (1 << 11)) >> 12;
+ iSum = iSum < 0 ? 0 : (iSum > maxValue ? maxValue
: iSum);
+ *pDstPel = (pixel)iSum;
+ }
+ }
+ }
+ }
+ }
+}
+
+#if 0
+/*
+* Old Version: bilateralFilter
+*/
+void TemporalFilter::bilateralFilter(Frame* frame,
+ MCTFReferencePicInfo* m_mctfRefList,
+ double overallStrength)
+{
+
+ const int numRefs = frame->m_mcstf->m_numRef;
+
+ for (int i = 0; i < numRefs; i++)
+ {
+ MCTFReferencePicInfo *ref = &m_mctfRefList[i];
+ applyMotion(m_mctfRefList[i].mvs, m_mctfRefList[i].mvsStride,
m_mctfRefList[i].picBuffer, ref->compensatedPic);
+ }
+
+ int refStrengthRow = 2;
+ if (numRefs == s_range * 2)
+ {
+ refStrengthRow = 0;
+ }
+ else if (numRefs == s_range)
+ {
+ refStrengthRow = 1;
+ }
+
+ const double lumaSigmaSq = (m_QP - s_sigmaZeroPoint) * (m_QP -
s_sigmaZeroPoint) * s_sigmaMultiplier;
+ const double chromaSigmaSq = 30 * 30;
+
+ PicYuv* orgPic = frame->m_fencPic;
+
+ for (int c = 0; c < m_numComponents; c++)
+ {
+ int height, width;
+ pixel *srcPelRow = NULL;
+ intptr_t srcStride, correctedPicsStride = 0;
+
+ if (c == 0)
+ {
+ height = orgPic->m_picHeight;
+ width = orgPic->m_picWidth;
+ srcPelRow = orgPic->m_picOrg[c];
+ srcStride = orgPic->m_stride;
+ }
+ else
+ {
+ int csx = CHROMA_H_SHIFT(m_internalCsp);
+ int csy = CHROMA_V_SHIFT(m_internalCsp);
+
+ height = orgPic->m_picHeight >> csy;
+ width = orgPic->m_picWidth >> csx;
+ srcPelRow = orgPic->m_picOrg[c];
+ srcStride = (int)orgPic->m_strideC;
+ }
+
+ const double sigmaSq = (!c) ? lumaSigmaSq : chromaSigmaSq;
+ const double weightScaling = overallStrength * ((!c) ? 0.4 :
s_chromaFactor);
+
+ const pixel maxSampleValue = (1 << m_bitDepth) - 1;
+ const double bitDepthDiffWeighting = 1024.0 / (maxSampleValue + 1);
+
+ for (int y = 0; y < height; y++, srcPelRow += srcStride/*,
dstPelRow += dstStride*/)
+ {
+ pixel *srcPel = srcPelRow;
+
+ for (int x = 0; x < width; x++, srcPel++)
+ {
+ const int orgVal = (int)*srcPel;
+ double temporalWeightSum = 1.0;
+ double newVal = (double)orgVal;
+
+ for (int i = 0; i < numRefs; i++)
+ {
+ MCTFReferencePicInfo *refPicInfo = &m_mctfRefList[i];
+
+ if (c == 0)
+ correctedPicsStride =
refPicInfo->compensatedPic->m_stride;
+ else
+ correctedPicsStride =
refPicInfo->compensatedPic->m_strideC;
+
+ const pixel *pCorrectedPelPtr =
refPicInfo->compensatedPic->m_picOrg[c] + (y * correctedPicsStride + x);
+ const int refVal = (int)*pCorrectedPelPtr;
+ double diff = (double)(refVal - orgVal);
+ diff *= bitDepthDiffWeighting;
+ double diffSq = diff * diff;
+
+ const int index = X265_MIN(1,
std::abs(refPicInfo->origOffset) - 1);
+ const double weight = weightScaling *
s_refStrengths[refStrengthRow][index] * exp(-diffSq / (2 * sigmaSq));
+
+ newVal += weight * refVal;
+ temporalWeightSum += weight;
+ }
+ newVal /= temporalWeightSum;
+ pixel sampleVal = (pixel)round(newVal);
+ sampleVal = (sampleVal < 0 ? 0 : (sampleVal >
maxSampleValue ? maxSampleValue : sampleVal));
+ //*dstPel = sampleVal;
+ *srcPel = sampleVal;
+ }
+ }
+ }
+}
+
+#else
+
+/*
+* New Version: bilateralFilter
+*/
+void TemporalFilter::bilateralFilter(Frame* frame,
+ MCTFReferencePicInfo* m_mctfRefList,
+ double overallStrength)
+{
+
+ const int numRefs = frame->m_mcstf->m_numRef;
+
+ for (int i = 0; i < numRefs; i++)
+ {
+ MCTFReferencePicInfo *ref = &m_mctfRefList[i];
+ applyMotion(m_mctfRefList[i].mvs, m_mctfRefList[i].mvsStride,
m_mctfRefList[i].picBuffer, ref->compensatedPic);
+ }
+
+ int refStrengthRow = 2;
+ if (numRefs == s_range * 2)
+ {
+ refStrengthRow = 0;
+ }
+ else if (numRefs == s_range)
+ {
+ refStrengthRow = 1;
+ }
+
+ const double lumaSigmaSq = (m_QP - s_sigmaZeroPoint) * (m_QP -
s_sigmaZeroPoint) * s_sigmaMultiplier;
+ const double chromaSigmaSq = 30 * 30;
+
+ PicYuv* orgPic = frame->m_fencPic;
+
+ for (int c = 0; c < m_numComponents; c++)
+ {
+ int height, width;
+ pixel *srcPelRow = NULL;
+ intptr_t srcStride, correctedPicsStride = 0;
+
+ if (c == 0)
+ {
+ height = orgPic->m_picHeight;
+ width = orgPic->m_picWidth;
+ srcPelRow = orgPic->m_picOrg[c];
+ srcStride = orgPic->m_stride;
+ }
+ else
+ {
+ int csx = CHROMA_H_SHIFT(m_internalCsp);
+ int csy = CHROMA_V_SHIFT(m_internalCsp);
+
+ height = orgPic->m_picHeight >> csy;
+ width = orgPic->m_picWidth >> csx;
+ srcPelRow = orgPic->m_picOrg[c];
+ srcStride = (int)orgPic->m_strideC;
+ }
+
+ const double sigmaSq = (!c) ? lumaSigmaSq : chromaSigmaSq;
+ const double weightScaling = overallStrength * ( (!c) ? 0.4 :
s_chromaFactor);
+
+ const pixel maxSampleValue = (1 << m_bitDepth) - 1;
+ const double bitDepthDiffWeighting = 1024.0 / (maxSampleValue + 1);
+
+ const int blkSize = (!c) ? 8 : 4;
+
+ for (int y = 0; y < height; y++, srcPelRow += srcStride)
+ {
+ pixel *srcPel = srcPelRow;
+
+ for (int x = 0; x < width; x++, srcPel++)
+ {
+ const int orgVal = (int)*srcPel;
+ double temporalWeightSum = 1.0;
+ double newVal = (double)orgVal;
+
+ if ((y % blkSize == 0) && (x % blkSize == 0))
+ {
+ for (int i = 0; i < numRefs; i++)
+ {
+ MCTFReferencePicInfo *refPicInfo =
&m_mctfRefList[i];
+
+ if (!c)
+ correctedPicsStride =
refPicInfo->compensatedPic->m_stride;
+ else
+ correctedPicsStride =
refPicInfo->compensatedPic->m_strideC;
+
+ double variance = 0, diffsum = 0;
+ for (int y1 = 0; y1 < blkSize - 1; y1++)
+ {
+ for (int x1 = 0; x1 < blkSize - 1; x1++)
+ {
+ int pix = *(srcPel + x1);
+ int pixR = *(srcPel + x1 + 1);
+ int pixD = *(srcPel + x1 + srcStride);
+
+ int ref =
*(refPicInfo->compensatedPic->m_picOrg[c] + ((y + y1) * correctedPicsStride
+ x + x1));
+ int refR =
*(refPicInfo->compensatedPic->m_picOrg[c] + ((y + y1) * correctedPicsStride
+ x + x1 + 1));
+ int refD =
*(refPicInfo->compensatedPic->m_picOrg[c] + ((y + y1 + 1) *
correctedPicsStride + x + x1));
+
+ int diff = pix - ref;
+ int diffR = pixR - refR;
+ int diffD = pixD - refD;
+
+ variance += diff * diff;
+ diffsum += (diffR - diff) * (diffR - diff);
+ diffsum += (diffD - diff) * (diffD - diff);
+ }
+ }
+
+ refPicInfo->noise[(y / blkSize) *
refPicInfo->mvsStride + (x / blkSize)] = (int)round((300 * variance + 50) /
(10 * diffsum + 50));
+ }
+ }
+
+ double minError = 9999999;
+ for (int i = 0; i < numRefs; i++)
+ {
+ MCTFReferencePicInfo *refPicInfo = &m_mctfRefList[i];
+ minError = X265_MIN(minError,
(double)refPicInfo->error[(y / blkSize) * refPicInfo->mvsStride + (x /
blkSize)]);
+ }
+
+ for (int i = 0; i < numRefs; i++)
+ {
+ MCTFReferencePicInfo *refPicInfo = &m_mctfRefList[i];
+
+ const int error = refPicInfo->error[(y / blkSize) *
refPicInfo->mvsStride + (x / blkSize)];
+ const int noise = refPicInfo->noise[(y / blkSize) *
refPicInfo->mvsStride + (x / blkSize)];
+
+ const pixel *pCorrectedPelPtr =
refPicInfo->compensatedPic->m_picOrg[c] + (y * correctedPicsStride + x);
+ const int refVal = (int)*pCorrectedPelPtr;
+ double diff = (double)(refVal - orgVal);
+ diff *= bitDepthDiffWeighting;
+ double diffSq = diff * diff;
+
+ const int index = X265_MIN(3,
std::abs(refPicInfo->origOffset) - 1);
+ double ww = 1, sw = 1;
+ ww *= (noise < 25) ? 1 : 1.2;
+ sw *= (noise < 25) ? 1.3 : 0.8;
+ ww *= (error < 50) ? 1.2 : ((error > 100) ? 0.8 : 1);
+ sw *= (error < 50) ? 1.3 : 1;
+ ww *= ((minError + 1) / (error + 1));
+ const double weight = weightScaling *
s_refStrengths[refStrengthRow][index] * ww * exp(-diffSq / (2 * sw *
sigmaSq));
+
+ newVal += weight * refVal;
+ temporalWeightSum += weight;
+ }
+ newVal /= temporalWeightSum;
+ pixel sampleVal = (pixel)round(newVal);
+ sampleVal = (sampleVal < 0 ? 0 : (sampleVal >
maxSampleValue ? maxSampleValue : sampleVal));
+ //*dstPel = sampleVal;
+ *srcPel = sampleVal;
+ }
+ }
+ }
+}
+#endif
+
+#if 0
+/*Old Version: motionEstimationLuma*/
+
+void TemporalFilter::motionEstimationLuma(MV *mvs, uint32_t mvStride,
PicYuv *orig, PicYuv *buffer, int blockSize,
+ MV *previous, uint32_t prevMvStride, int factor, bool doubleRes, int*
minError)
+{
+
+ int range = 5;
+
+
+ const int stepSize = blockSize;
+
+ const int origWidth = orig->m_picWidth;
+ const int origHeight = orig->m_picHeight;
+
+
+ for (int blockY = 0; blockY + blockSize < origHeight; blockY +=
stepSize)
+ {
+ for (int blockX = 0; blockX + blockSize < origWidth; blockX +=
stepSize)
+ {
+ MV best(0, 0);
+ int leastError = INT_MAX;
+
+ if (previous == NULL)
+ {
+ range = 8;
+ }
+ else
+ {
+
+ for (int py = -2; py <= 2; py++)
+ {
+ int testy = blockY / (2 * blockSize) + py;
+
+ for (int px = -2; px <= 2; px++)
+ {
+
+ int testx = blockX / (2 * blockSize) + px;
+ if ((testx >= 0) && (testx < origWidth / (2 *
blockSize)) && (testy >= 0) && (testy < origHeight / (2 * blockSize)))
+ {
+ int mvIdx = testy * prevMvStride + testx;
+ MV old = previous[mvIdx];
+
+ int error = motionErrorLuma(orig, buffer,
blockX, blockY, old.x * factor, old.y * factor, blockSize, leastError);
+ if (error < leastError)
+ {
+ best.set(old.x * factor, old.y * factor);
+ leastError = error;
+ }
+ }
+ }
+ }
+
+ }
+
+ MV prevBest = best;
+ for (int y2 = prevBest.y / s_motionVectorFactor - range; y2 <=
prevBest.y / s_motionVectorFactor + range; y2++)
+ {
+ for (int x2 = prevBest.x / s_motionVectorFactor - range;
x2 <= prevBest.x / s_motionVectorFactor + range; x2++)
+ {
+ int error = motionErrorLuma(orig, buffer, blockX,
blockY, x2 * s_motionVectorFactor, y2 * s_motionVectorFactor, blockSize,
leastError/*best.error*/);
+ if (error < leastError)
+ {
+ best.set(x2 * s_motionVectorFactor, y2 *
s_motionVectorFactor);
+ leastError = error;
+ }
+ }
+ }
+
+ if (doubleRes)
+ { // merge into one loop, probably with precision array (here
[12, 3] or maybe [4, 1]) with setable number of iterations
+ prevBest = best;
+ int doubleRange = 3 * 4;
+ for (int y2 = prevBest.y - doubleRange; y2 <= prevBest.y +
doubleRange; y2 += 4)
+ {
+ for (int x2 = prevBest.x - doubleRange; x2 <=
prevBest.x + doubleRange; x2 += 4)
+ {
+ int error = motionErrorLuma(orig, buffer, blockX,
blockY, x2, y2, blockSize, leastError);
+ if (error < leastError)
+ {
+ best.set(x2, y2);
+ leastError = error;
+ }
+ }
+ }
+
+ prevBest = best;
+ doubleRange = 3;
+ for (int y2 = prevBest.y - doubleRange; y2 <= prevBest.y +
doubleRange; y2++)
+ {
+ for (int x2 = prevBest.x - doubleRange; x2 <=
prevBest.x + doubleRange; x2++)
+ {
+ int error = motionErrorLuma(orig, buffer, blockX,
blockY, x2, y2, blockSize, leastError);
+ if (error < leastError)
+ {
+ best.set(x2, y2);
+ leastError = error;
+ }
+ }
+ }
+ }
+
+ int mvIdx = (blockY / stepSize) * mvStride + (blockX /
stepSize);
+ mvs[mvIdx] = best;
+ if (doubleRes)
+ minError[mvIdx] = leastError;
+ }
+ }
+}
+
+#else
+
+/*New Version: motionEstimationLuma*/
+void TemporalFilter::motionEstimationLuma(MV *mvs, uint32_t mvStride,
PicYuv *orig, PicYuv *buffer, int blockSize,
+ MV *previous, uint32_t prevMvStride, int factor, bool doubleRes, int*
minError)
+{
+
+ int range = doubleRes ? 0 : 5;
+
+
+ const int stepSize = blockSize;
+
+ const int origWidth = orig->m_picWidth;
+ const int origHeight = orig->m_picHeight;
+
+
+ for (int blockY = 0; blockY + blockSize <= origHeight; blockY +=
stepSize)
+ {
+ for (int blockX = 0; blockX + blockSize <= origWidth; blockX +=
stepSize)
+ {
+ MV best(0, 0);
+ int leastError = INT_MAX;
+
+ if (previous == NULL)
+ {
+ range = 8;
+ }
+ else
+ {
+
+ for (int py = -1; py <= 1; py++)
+ {
+ int testy = blockY / (2 * blockSize) + py;
+
+ for (int px = -1; px <= 1; px++)
+ {
+
+ int testx = blockX / (2 * blockSize) + px;
+ if ((testx >= 0) && (testx < origWidth / (2 *
blockSize)) && (testy >= 0) && (testy < origHeight / (2 * blockSize)))
+ {
+ int mvIdx = testy * prevMvStride + testx;
+ MV old = previous[mvIdx];
+ int error = motionErrorLuma(orig, buffer,
blockX, blockY, old.x * factor, old.y * factor, blockSize, leastError);
+ if (error < leastError)
+ {
+ best.set(old.x * factor, old.y * factor);
+ leastError = error;
+ }
+ }
+ }
+ }
+
+ int error = motionErrorLuma(orig, buffer, blockX, blockY,
0, 0, blockSize, leastError);
+ if (error < leastError)
+ {
+ best.set(0, 0);
+ leastError = error;
+ }
+
+ }
+
+ MV prevBest = best;
+ for (int y2 = prevBest.y / s_motionVectorFactor - range; y2 <=
prevBest.y / s_motionVectorFactor + range; y2++)
+ {
+ for (int x2 = prevBest.x / s_motionVectorFactor - range;
x2 <= prevBest.x / s_motionVectorFactor + range; x2++)
+ {
+ int error = motionErrorLuma(orig, buffer, blockX,
blockY, x2 * s_motionVectorFactor, y2 * s_motionVectorFactor, blockSize,
leastError);
+ if (error < leastError)
+ {
+ best.set(x2 * s_motionVectorFactor, y2 *
s_motionVectorFactor);
+ leastError = error;
+ }
+ }
+ }
+
+ if (doubleRes)
+ { // merge into one loop, probably with precision array (here
[12, 3] or maybe [4, 1]) with setable number of iterations
+ prevBest = best;
+ int doubleRange = 3 * 4;
+ for (int y2 = prevBest.y - doubleRange; y2 <= prevBest.y +
doubleRange; y2 += 4)
+ {
+ for (int x2 = prevBest.x - doubleRange; x2 <=
prevBest.x + doubleRange; x2 += 4)
+ {
+ int error = motionErrorLuma(orig, buffer, blockX,
blockY, x2, y2, blockSize, leastError);
+ if (error < leastError)
+ {
+ best.set(x2, y2);
+ leastError = error;
+ }
+ }
+ }
+
+ prevBest = best;
+ doubleRange = 3;
+ for (int y2 = prevBest.y - doubleRange; y2 <= prevBest.y +
doubleRange; y2++)
+ {
+ for (int x2 = prevBest.x - doubleRange; x2 <=
prevBest.x + doubleRange; x2++)
+ {
+ int error = motionErrorLuma(orig, buffer, blockX,
blockY, x2, y2, blockSize, leastError);
+ if (error < leastError)
+ {
+ best.set(x2, y2);
+ leastError = error;
+ }
+ }
+ }
+ }
+
+ if (blockY > 0)
+ {
+ MV aboveMV = mvs[(blockX / stepSize, (blockY - stepSize) /
stepSize)];
+ int error = motionErrorLuma(orig, buffer, blockX, blockY,
aboveMV.x, aboveMV.y, blockSize, leastError);
+ if (error < leastError)
+ {
+ best.set(aboveMV.x, aboveMV.y);
+ leastError = error;
+ }
+ }
+ if (blockX > 0)
+ {
+ MV leftMV = mvs[((blockX - stepSize) / stepSize, blockY /
stepSize)];
+ int error = motionErrorLuma(orig, buffer, blockX, blockY,
leftMV.x, leftMV.y, blockSize, leastError);
+ if (error < leastError)
+ {
+ best.set(leftMV.x, leftMV.y);
+ leastError = error;
+ }
+ }
+
+ // calculate average
+ double avg = 0.0;
+ for (int x1 = 0; x1 < blockSize; x1++)
+ {
+ for (int y1 = 0; y1 < blockSize; y1++)
+ {
+ avg = avg + *(orig->m_picOrg[0] + (blockX + x1 +
orig->m_stride * (blockY + y1)));
+ }
+ }
+ avg = avg / (blockSize * blockSize);
+
+ // calculate variance
+ double variance = 0;
+ for (int x1 = 0; x1 < blockSize; x1++)
+ {
+ for (int y1 = 0; y1 < blockSize; y1++)
+ {
+ int pix = *(orig->m_picOrg[0] + (blockX + x1 +
orig->m_stride * (blockY + y1)));
+ variance = variance + (pix - avg) * (pix - avg);
+ }
+ }
+
+ leastError = (int)(20 * ((leastError + 5.0) / (variance +
5.0)) + (leastError / (blockSize * blockSize)) / 50);
+
+ int mvIdx = (blockY / stepSize) * mvStride + (blockX /
stepSize);
+ mvs[mvIdx] = best;
+ if (doubleRes)
+ minError[mvIdx] = leastError;
+ }
+ }
+}
+#endif
+
+void TemporalFilter::subsampleLuma(PicYuv *input, PicYuv *output, int
factor)
+{
+
+ int newWidth = output->m_picWidth;
+ int newHeight = output->m_picHeight;
+
+ pixel* srcRow = input->m_picOrg[0];
+ intptr_t srcStride = input->m_stride;
+
+ pixel *dstRow = output->m_picOrg[0];
+ intptr_t dstStride = output->m_stride;
+
+ for (int y = 0; y < newHeight; y++, srcRow += factor * srcStride,
dstRow += dstStride)
+ {
+ pixel *inRow = srcRow;
+ pixel *inRowBelow = srcRow + srcStride;
+ pixel *target = dstRow;
+
+ for (int x = 0; x < newWidth; x++)
+ {
+ target[x] = (inRow[0] + inRowBelow[0] + inRow[1] +
inRowBelow[1] + 2) >> 2;
+ inRow += 2;
+ inRowBelow += 2;
+ }
+ }
+
+ // output.extendPicBorder();
+ extendPicBorder(output->m_picOrg[0], output->m_stride,
output->m_picWidth, output->m_picHeight, output->m_lumaMarginX,
output->m_lumaMarginY);
+}
+
+void TemporalFilter::destroyRefPicInfo(MCTFReferencePicInfo* curFrame)
+{
+ if (curFrame)
+ {
+ if (curFrame->compensatedPic)
+ {
+ curFrame->compensatedPic->destroy();
+ delete curFrame->compensatedPic;
+ }
+
+ if (curFrame->mvs)
+ X265_FREE(curFrame->mvs);
+ if (curFrame->mvs0)
+ X265_FREE(curFrame->mvs0);
+ if (curFrame->mvs1)
+ X265_FREE(curFrame->mvs1);
+ if (curFrame->mvs2)
+ X265_FREE(curFrame->mvs2);
+ if (curFrame->noise)
+ X265_FREE(curFrame->noise);
+ if (curFrame->error)
+ X265_FREE(curFrame->error);
+ }
+}
diff --git a/source/common/temporalfilter.h b/source/common/temporalfilter.h
new file mode 100644
index 000000000..14d59c396
--- /dev/null
+++ b/source/common/temporalfilter.h
@@ -0,0 +1,181 @@
+/*****************************************************************************
+* Copyright (C) 2013-2021 MulticoreWare, Inc
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111,
USA.
+*
+* This program is also available under a commercial proprietary license.
+* For more information, contact us at license @ x265.com.
+*****************************************************************************/
+
+#ifndef X265_TEMPORAL_FILTER
+#define X265_TEMPORAL_FILTER
+
+#include "x265.h"
+#include "picyuv.h"
+#include "mv.h"
+#include <vector>
+#include <deque>
+#include "piclist.h"
+#include "yuv.h"
+
+using namespace X265_NS;
+
+#define BILTERAL_FILTER_NEW_VERSION 1
+
+const int s_interpolationFilter[16][8] =
+{
+ { 0, 0, 0, 64, 0, 0, 0, 0 }, //0
+ { 0, 1, -3, 64, 4, -2, 0, 0 }, //1 -->-->
+ { 0, 1, -6, 62, 9, -3, 1, 0 }, //2 -->
+ { 0, 2, -8, 60, 14, -5, 1, 0 }, //3 -->-->
+ { 0, 2, -9, 57, 19, -7, 2, 0 }, //4
+ { 0, 3, -10, 53, 24, -8, 2, 0 }, //5 -->-->
+ { 0, 3, -11, 50, 29, -9, 2, 0 }, //6 -->
+ { 0, 3, -11, 44, 35, -10, 3, 0 }, //7 -->-->
+ { 0, 1, -7, 38, 38, -7, 1, 0 }, //8
+ { 0, 3, -10, 35, 44, -11, 3, 0 }, //9 -->-->
+ { 0, 2, -9, 29, 50, -11, 3, 0 }, //10-->
+ { 0, 2, -8, 24, 53, -10, 3, 0 }, //11-->-->
+ { 0, 2, -7, 19, 57, -9, 2, 0 }, //12
+ { 0, 1, -5, 14, 60, -8, 2, 0 }, //13-->-->
+ { 0, 1, -3, 9, 62, -6, 1, 0 }, //14-->
+ { 0, 0, -2, 4, 64, -3, 1, 0 } //15-->-->
+};
+
+#if BILTERAL_FILTER_NEW_VERSION
+const double s_refStrengths[3][4] =
+{ // abs(POC offset)
+ // 1, 2 3 4
+ {0.85, 0.57, 0.41, 0.33}, // m_range * 2
+ {1.13, 0.97, 0.81, 0.57}, // m_range
+ {0.30, 0.30, 0.30, 0.30} // otherwise
+};
+#else
+const double s_refStrengths[2][2] =
+{ // abs(POC offset)
+ // 1, 2
+ {0.85, 0.60}, // w future refs
+ {1.20, 1.00}, // w/o future refs
+};
+#endif
+
+class OrigPicBuffer
+{
+public:
+ PicList m_mcstfPicList;
+ PicList m_mcstfOrigPicFreeList;
+ PicList m_mcstfOrigPicList;
+
+ ~OrigPicBuffer();
+ void addPicture(Frame*);
+ void addEncPicture(Frame*);
+ void setOrigPicList(Frame*, int);
+ void recycleOrigPicList();
+ void addPictureToFreelist(Frame*);
+ void addEncPictureToPicList(Frame*);
+};
+
+struct TemporalFilterRefPicInfo
+{
+ PicYuv* picBuffer;
+ MV* mvs;
+ int origOffset;
+};
+
+struct MCTFReferencePicInfo
+{
+ PicYuv* picBuffer;
+ PicYuv* picBufferSubSampled2;
+ PicYuv* picBufferSubSampled4;
+ MV* mvs;
+ MV* mvs0;
+ MV* mvs1;
+ MV* mvs2;
+ uint32_t mvsStride;
+ uint32_t mvsStride0;
+ uint32_t mvsStride1;
+ uint32_t mvsStride2;
+ int* error;
+ int* noise;
+
+ int16_t origOffset;
+ bool isFilteredFrame;
+ PicYuv* compensatedPic;
+
+ int* isSubsampled;
+
+ int slicetype;
+};
+
+class TemporalFilter
+{
+public:
+ TemporalFilter();
+ ~TemporalFilter() {}
+
+ void init(const x265_param* param);
+
+//private:
+ // Private static member variables
+ const x265_param *m_param;
+ int32_t m_bitDepth;
+ int s_range;
+ uint8_t m_numRef;
+ double s_chromaFactor;
+ double s_sigmaMultiplier;
+ double s_sigmaZeroPoint;
+ int s_motionVectorFactor;
+ int s_padding;
+
+ // Private member variables
+ int m_FrameSkip;
+ int m_sourceWidth;
+ int m_sourceHeight;
+ int m_QP;
+ int m_GOPSize;
+
+ int m_aiPad[2];
+ int m_framesToBeEncoded;
+ bool m_bClipInputVideoToRec709Range;
+ bool m_gopBasedTemporalFilterFutureReference;
+ int m_internalCsp;
+ int m_numComponents;
+ uint8_t m_sliceTypeConfig;
+
+ void subsampleLuma(PicYuv *input, PicYuv *output, int factor = 2);
+
+ int createRefPicInfo(MCTFReferencePicInfo* refFrame, x265_param*
param);
+
+ void bilateralFilter(Frame* frame, MCTFReferencePicInfo* mctfRefList,
double overallStrength);
+
+ void motionEstimationLuma(MV *mvs, uint32_t mvStride, PicYuv *orig,
PicYuv *buffer, int bs,
+ MV *previous = 0, uint32_t prevmvStride = 0, int factor = 1, bool
doubleRes = false, int *minError = 0);
+
+ int motionErrorLuma(PicYuv *orig,
+ PicYuv *buffer,
+ int x,
+ int y,
+ int dx,
+ int dy,
+ int bs,
+ int besterror = 8 * 8 * 1024 * 1024);
+
+ void destroyRefPicInfo(MCTFReferencePicInfo* curFrame);
+
+ void applyMotion(MV *mvs, uint32_t mvsStride, PicYuv *input, PicYuv
*output);
+
+};
+
+#endif
--
2.37.2.windows.2
*Thanks and Regards,*
*Snehaa.GVideo Codec Engineer,Media & AI analytics
<https://multicorewareinc.com/>*
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20221019/e9126c6c/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mcstf_patch_02.diff
Type: application/octet-stream
Size: 42143 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20221019/e9126c6c/attachment-0001.obj>
More information about the x265-devel
mailing list