[x265] [PATCH] noise reduction, ported from x264
Steve Borho
steve at borho.org
Wed May 7 21:53:18 CEST 2014
On Wed, May 7, 2014 at 8:24 AM, <praveen at multicorewareinc.com> wrote:
> # HG changeset patch
> # User Praveen Tiwari
> # Date 1399469049 -19800
> # Node ID a81311047a4d3176d16c07a0ca01be931141ab24
> # Parent 7773ee321539810625636bb0a163004225040707
> noise reduction, ported from x264
>
> diff -r 7773ee321539 -r a81311047a4d doc/reST/cli.rst
> --- a/doc/reST/cli.rst Wed May 07 10:49:02 2014 +0530
> +++ b/doc/reST/cli.rst Wed May 07 18:54:09 2014 +0530
> @@ -182,6 +182,14 @@
> picture. Only applicable when the input bit depth is larger than
> 8bits and internal bit depth is 8bits. Default disabled
>
> +.. option:: --nr
> +
> + It's just an adaptive deadzone applied after DCT (subtracting from DCT coefficients),
> + before quantization, on inter blocks. It does no pixel-level filtering, doesn't cross
> + DCT block boundaries, has no overlap, doesn't affect intra blocks.
> +
> + **Values:** any value in range of 100 to 1000. Default disabled.
> +
> **CLI ONLY**
this option isn't CLI only but the option above was (you've stolen
this line from its description)
>
> .. option:: --input-res <wxh>
> diff -r 7773ee321539 -r a81311047a4d source/Lib/TLibCommon/TComRom.cpp
> --- a/source/Lib/TLibCommon/TComRom.cpp Wed May 07 10:49:02 2014 +0530
> +++ b/source/Lib/TLibCommon/TComRom.cpp Wed May 07 18:54:09 2014 +0530
> @@ -590,5 +590,38 @@
> 106, 110, 114, 118, 122, 126, 130, 135, 139, 143, 147, 152, 156, 161, 165, 170,
> 175, 179, 184, 189, 194, 198, 203, 208, 214, 219, 224, 229, 234, 240, 245, 250
> };
> +
> +/* inverse squared */
> +#define W(i) (i == 0 ? FIX8(3.125) : \
> + i == 1 ? FIX8(1.25) : \
> + i == 2 ? FIX8(0.5) : 0)
> +
> +const uint32_t g_dctDenoiseWeight4x4[16] = {
> + W(0), W(1), W(0), W(1),
> + W(1), W(2), W(1), W(2),
> + W(0), W(1), W(0), W(1),
> + W(1), W(2), W(1), W(2)
> +};
> +#undef W
> +
> +#define W(i) (i == 0 ? FIX8(1.00000) : \
> + i == 1 ? FIX8(0.78487) : \
> + i == 2 ? FIX8(2.56132) : \
> + i == 3 ? FIX8(0.88637) : \
> + i == 4 ? FIX8(1.60040) : \
> + i == 5 ? FIX8(1.41850) : 0)
> +
> +const uint32_t g_dctDenoiseWeight8x8[64] = {
> + W(0), W(3), W(4), W(3), W(0), W(3), W(4), W(3),
> + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1),
> + W(4), W(5), W(2), W(5), W(4), W(5), W(2), W(5),
> + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1),
> +
> + W(0), W(3), W(4), W(3), W(0), W(3), W(4), W(3),
> + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1),
> + W(4), W(5), W(2), W(5), W(4), W(5), W(2), W(5),
> + W(3), W(1), W(5), W(1), W(3), W(1), W(5), W(1)
> +};
> +#undef W
> }
> //! \}
> diff -r 7773ee321539 -r a81311047a4d source/Lib/TLibCommon/TComRom.h
> --- a/source/Lib/TLibCommon/TComRom.h Wed May 07 10:49:02 2014 +0530
> +++ b/source/Lib/TLibCommon/TComRom.h Wed May 07 18:54:09 2014 +0530
> @@ -200,6 +200,9 @@
> #define MAX_MATRIX_COEF_NUM 64 ///< max coefficient number for quantization matrix
> #define MAX_MATRIX_SIZE_NUM 8 ///< max size number for quantization matrix
> #define SCALING_LIST_DC 16 ///< default DC value
> +
> +#define FIX8(f) ((int)(f * (1 << 8) + .5))
> +
> enum ScalingListSize
> {
> SCALING_LIST_4x4 = 0,
> @@ -278,6 +281,10 @@
> // CABAC tables
> extern const uint8_t g_lpsTable[64][4];
> extern const uint8_t x265_exp2_lut[64];
> +
> +// DCT denoise tables
> +extern const uint32_t g_dctDenoiseWeight4x4[16];
> +extern const uint32_t g_dctDenoiseWeight8x8[64];
> }
>
> #endif //ifndef X265_TCOMROM_H
> diff -r 7773ee321539 -r a81311047a4d source/Lib/TLibCommon/TComTrQuant.cpp
> --- a/source/Lib/TLibCommon/TComTrQuant.cpp Wed May 07 10:49:02 2014 +0530
> +++ b/source/Lib/TLibCommon/TComTrQuant.cpp Wed May 07 18:54:09 2014 +0530
> @@ -95,6 +95,19 @@
> destroyScalingList();
> }
>
> +static void denoiseDct(coeff_t* dctCoef, uint32_t* resSum, uint16_t* offset, int size)
> +{
> + for (int i = 0; i < size; i++)
> + {
> + int level = dctCoef[i];
> + int sign = level >> 31;
> + level = (level + sign) ^ sign;
> + resSum[i] += level;
> + level -= offset[i];
> + dctCoef[i] = level < 0 ? 0 : (level ^ sign) - sign;
> + }
> +}
> +
> /** Set qP for Quantization.
> * \param qpy QPy
> * \param bLowpass
> @@ -300,16 +313,17 @@
> m_useTransformSkipFast = useTransformSkipFast;
> }
>
> -uint32_t TComTrQuant::transformNxN(TComDataCU* cu,
> - int16_t* residual,
> - uint32_t stride,
> - coeff_t* coeff,
> - uint32_t trSize,
> - TextType ttype,
> - uint32_t absPartIdx,
> - int32_t* lastPos,
> - bool useTransformSkip,
> - bool curUseRDOQ)
> +uint32_t TComTrQuant::transformNxN(TComDataCU* cu,
> + int16_t* residual,
> + uint32_t stride,
> + coeff_t* coeff,
> + uint32_t trSize,
> + TextType ttype,
> + uint32_t absPartIdx,
> + int32_t* lastPos,
> + NoiseReduction* nr,
> + bool useTransformSkip,
> + bool curUseRDOQ)
> {
> if (cu->getCUTransquantBypass(absPartIdx))
> {
> @@ -346,6 +360,30 @@
> // TODO: this may need larger data types for X265_DEPTH > 8
> const uint32_t log2BlockSize = g_convertToBit[trSize];
> primitives.dct[DCT_4x4 + log2BlockSize - ((trSize == 4) && (mode != REG_DCT))](residual, m_tmpCoeff, stride);
> + if (nr->bNoiseReduction)
> + {
> + int index = (DCT_4x4 + log2BlockSize - ((trSize == 4) && (mode != REG_DCT)));
> + if (index == 1 || index == 4)
> + {
> + for (int count = 0; count < (index * index * index); count++)
> + {
> + denoiseDct(m_tmpCoeff + (count * 16), nr->residualSum[0], nr->offset[0], 16);
> + }
> + }
> + else if (index == 2)
> + {
> + nr->count[1] += 1 * 8;
> + denoiseDct(m_tmpCoeff, nr->residualSum[1], nr->offset[1], 64);
> + }
> + else if (index == 3)
> + {
> + for (int count = 0; count < (X265_CSP_I444 ? 8 : 16); count++)
> + {
> + nr->count[0] += 1 * 4;
> + denoiseDct(m_tmpCoeff + (count * 16), nr->residualSum[0], nr->offset[0], 16);
> + }
> + }
> + }
> }
> return xQuant(cu, m_tmpCoeff, coeff, trSize, ttype, absPartIdx, lastPos, curUseRDOQ);
> }
> diff -r 7773ee321539 -r a81311047a4d source/Lib/TLibCommon/TComTrQuant.h
> --- a/source/Lib/TLibCommon/TComTrQuant.h Wed May 07 10:49:02 2014 +0530
> +++ b/source/Lib/TLibCommon/TComTrQuant.h Wed May 07 18:54:09 2014 +0530
> @@ -128,7 +128,7 @@
>
> // transform & inverse transform functions
> uint32_t transformNxN(TComDataCU* cu, int16_t* residual, uint32_t stride, coeff_t* coeff, uint32_t trSize,
> - TextType ttype, uint32_t absPartIdx, int32_t* lastPos, bool useTransformSkip = false, bool curUseRDOQ = true);
> + TextType ttype, uint32_t absPartIdx, int32_t* lastPos, NoiseReduction* nr, bool useTransformSkip = false, bool curUseRDOQ = true);
>
> void invtransformNxN(bool transQuantBypass, uint32_t mode, int16_t* residual, uint32_t stride, coeff_t* coeff, uint32_t trSize, int scalingListType, bool useTransformSkip = false, int lastPos = MAX_INT);
>
> diff -r 7773ee321539 -r a81311047a4d source/Lib/TLibEncoder/TEncSearch.cpp
> --- a/source/Lib/TLibEncoder/TEncSearch.cpp Wed May 07 10:49:02 2014 +0530
> +++ b/source/Lib/TLibEncoder/TEncSearch.cpp Wed May 07 18:54:09 2014 +0530
clang triggers a really ugly looking warning for this file:
/Users/steve/repos/x265/source/Lib/TLibEncoder/TEncSearch.cpp:1495:118:
warning: initialization of pointer of type 'NoiseReduction *' to null
from a constant boolean expression [-Wbool-conversion]
...= m_trQuant->transformNxN(cu, residual, stride, coeff, width,
ttype, absTUPartIdxC, &lastPos, useTransformSkipChroma);
Please look into this. It certainly smells like a bug
> @@ -456,7 +456,7 @@
> m_trQuant->setQPforQuant(cu->getQP(0), TEXT_LUMA, QP_BD_OFFSET, 0, chFmt);
> m_trQuant->selectLambda(TEXT_LUMA);
>
> - absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, width, TEXT_LUMA, absPartIdx, &lastPos, useTransformSkip);
> + absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, width, TEXT_LUMA, absPartIdx, &lastPos, &(m_cfg->m_nr), useTransformSkip);
>
> //--- set coded block flag ---
> cu->setCbfSubParts((absSum ? 1 : 0) << trDepth, TEXT_LUMA, absPartIdx, fullDepth);
> @@ -581,7 +581,7 @@
>
> m_trQuant->selectLambda(TEXT_CHROMA);
>
> - absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, width, ttype, absPartIdx, &lastPos, useTransformSkipChroma);
> + absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, width, ttype, absPartIdx, &lastPos, &(m_cfg->m_nr), useTransformSkipChroma);
>
> //--- set coded block flag ---
> cu->setCbfPartRange((((absSum > 0) ? 1 : 0) << origTrDepth), ttype, absPartIdx, absPartIdxStep);
> @@ -896,7 +896,7 @@
>
> m_trQuant->setQPforQuant(cu->getQP(0), TEXT_LUMA, QP_BD_OFFSET, 0, chFmt);
> m_trQuant->selectLambda(TEXT_LUMA);
> - absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, width, TEXT_LUMA, absPartIdx, &lastPos, useTransformSkip);
> + absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, width, TEXT_LUMA, absPartIdx, &lastPos, &(m_cfg->m_nr), useTransformSkip);
>
> //--- set coded block flag ---
> cu->setCbfSubParts((absSum ? 1 : 0) << trDepth, TEXT_LUMA, absPartIdx, fullDepth);
> @@ -2890,7 +2890,7 @@
> m_trQuant->selectLambda(TEXT_LUMA);
>
> absSumY = m_trQuant->transformNxN(cu, resiYuv->getLumaAddr(absTUPartIdx), resiYuv->m_width, coeffCurY,
> - trWidth, TEXT_LUMA, absPartIdx, &lastPosY, false, curuseRDOQ);
> + trWidth, TEXT_LUMA, absPartIdx, &lastPosY, &(m_cfg->m_nr), false, curuseRDOQ);
>
> cu->setCbfSubParts(absSumY ? setCbf : 0, TEXT_LUMA, absPartIdx, depth);
>
> @@ -2934,12 +2934,12 @@
> m_trQuant->selectLambda(TEXT_CHROMA);
>
> absSumU = m_trQuant->transformNxN(cu, resiYuv->getCbAddr(absTUPartIdxC), resiYuv->m_cwidth, coeffCurU + subTUBufferOffset,
> - trWidthC, TEXT_CHROMA_U, absTUPartIdxC, &lastPosU, false, curuseRDOQ);
> + trWidthC, TEXT_CHROMA_U, absTUPartIdxC, &lastPosU, &(m_cfg->m_nr), false, curuseRDOQ);
>
> curChromaQpOffset = cu->getSlice()->getPPS()->getChromaCrQpOffset() + cu->getSlice()->getSliceQpDeltaCr();
> m_trQuant->setQPforQuant(cu->getQP(0), TEXT_CHROMA, cu->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset, chFmt);
> absSumV = m_trQuant->transformNxN(cu, resiYuv->getCrAddr(absTUPartIdxC), resiYuv->m_cwidth, coeffCurV + subTUBufferOffset,
> - trWidthC, TEXT_CHROMA_V, absTUPartIdxC, &lastPosV, false, curuseRDOQ);
> + trWidthC, TEXT_CHROMA_V, absTUPartIdxC, &lastPosV, &(m_cfg->m_nr), false, curuseRDOQ);
>
> cu->setCbfPartRange(absSumU ? setCbf : 0, TEXT_CHROMA_U, absTUPartIdxC, tuIterator.m_absPartIdxStep);
> cu->setCbfPartRange(absSumV ? setCbf : 0, TEXT_CHROMA_V, absTUPartIdxC, tuIterator.m_absPartIdxStep);
> @@ -3107,7 +3107,7 @@
> m_trQuant->selectLambda(TEXT_LUMA);
>
> absSum[TEXT_LUMA][0] = m_trQuant->transformNxN(cu, resiYuv->getLumaAddr(absTUPartIdx), resiYuv->m_width, coeffCurY,
> - trWidth, TEXT_LUMA, absPartIdx, &lastPos[TEXT_LUMA][0], false, curuseRDOQ);
> + trWidth, TEXT_LUMA, absPartIdx, &lastPos[TEXT_LUMA][0], &(m_cfg->m_nr), false, curuseRDOQ);
>
> cu->setCbfSubParts(absSum[TEXT_LUMA][0] ? setCbf : 0, TEXT_LUMA, absPartIdx, depth);
>
> @@ -3144,12 +3144,12 @@
> m_trQuant->selectLambda(TEXT_CHROMA);
>
> absSum[TEXT_CHROMA_U][tuIterator.m_section] = m_trQuant->transformNxN(cu, resiYuv->getCbAddr(tuIterator.m_absPartIdxTURelCU), resiYuv->m_cwidth, coeffCurU + subTUBufferOffset,
> - widthC, TEXT_CHROMA_U, tuIterator.m_absPartIdxTURelCU, &lastPos[TEXT_CHROMA_U][tuIterator.m_section], false, curuseRDOQ);
> + widthC, TEXT_CHROMA_U, tuIterator.m_absPartIdxTURelCU, &lastPos[TEXT_CHROMA_U][tuIterator.m_section], &(m_cfg->m_nr), false, curuseRDOQ);
> //Cr transform
> curChromaQpOffset = cu->getSlice()->getPPS()->getChromaCrQpOffset() + cu->getSlice()->getSliceQpDeltaCr();
> m_trQuant->setQPforQuant(cu->getQP(0), TEXT_CHROMA, cu->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset, chFmt);
> absSum[TEXT_CHROMA_V][tuIterator.m_section] = m_trQuant->transformNxN(cu, resiYuv->getCrAddr(tuIterator.m_absPartIdxTURelCU), resiYuv->m_cwidth, coeffCurV + subTUBufferOffset,
> - widthC, TEXT_CHROMA_V, tuIterator.m_absPartIdxTURelCU, &lastPos[TEXT_CHROMA_V][tuIterator.m_section], false, curuseRDOQ);
> + widthC, TEXT_CHROMA_V, tuIterator.m_absPartIdxTURelCU, &lastPos[TEXT_CHROMA_V][tuIterator.m_section], &(m_cfg->m_nr), false, curuseRDOQ);
>
> cu->setCbfPartRange(absSum[TEXT_CHROMA_U][tuIterator.m_section] ? setCbf : 0, TEXT_CHROMA_U, tuIterator.m_absPartIdxTURelCU, tuIterator.m_absPartIdxStep);
> cu->setCbfPartRange(absSum[TEXT_CHROMA_V][tuIterator.m_section] ? setCbf : 0, TEXT_CHROMA_V, tuIterator.m_absPartIdxTURelCU, tuIterator.m_absPartIdxStep);
> @@ -3440,7 +3440,7 @@
>
> m_trQuant->selectLambda(TEXT_LUMA);
> absSumTransformSkipY = m_trQuant->transformNxN(cu, resiYuv->getLumaAddr(absTUPartIdx), resiYuv->m_width, coeffCurY,
> - trWidth, TEXT_LUMA, absPartIdx, &lastPosTransformSkip[TEXT_LUMA][0], true, curuseRDOQ);
> + trWidth, TEXT_LUMA, absPartIdx, &lastPosTransformSkip[TEXT_LUMA][0], &(m_cfg->m_nr), true, curuseRDOQ);
> cu->setCbfSubParts(absSumTransformSkipY ? setCbf : 0, TEXT_LUMA, absPartIdx, depth);
>
> if (absSumTransformSkipY != 0)
> @@ -3533,11 +3533,11 @@
> m_trQuant->selectLambda(TEXT_CHROMA);
>
> absSumTransformSkipU = m_trQuant->transformNxN(cu, resiYuv->getCbAddr(tuIterator.m_absPartIdxTURelCU), resiYuv->m_cwidth, coeffCurU + subTUBufferOffset,
> - widthC, TEXT_CHROMA_U, tuIterator.m_absPartIdxTURelCU, &lastPosTransformSkip[TEXT_CHROMA_U][tuIterator.m_section], true, curuseRDOQ);
> + widthC, TEXT_CHROMA_U, tuIterator.m_absPartIdxTURelCU, &lastPosTransformSkip[TEXT_CHROMA_U][tuIterator.m_section], &(m_cfg->m_nr), true, curuseRDOQ);
> curChromaQpOffset = cu->getSlice()->getPPS()->getChromaCrQpOffset() + cu->getSlice()->getSliceQpDeltaCr();
> m_trQuant->setQPforQuant(cu->getQP(0), TEXT_CHROMA, cu->getSlice()->getSPS()->getQpBDOffsetC(), curChromaQpOffset, chFmt);
> absSumTransformSkipV = m_trQuant->transformNxN(cu, resiYuv->getCrAddr(tuIterator.m_absPartIdxTURelCU), resiYuv->m_cwidth, coeffCurV + subTUBufferOffset,
> - widthC, TEXT_CHROMA_V, tuIterator.m_absPartIdxTURelCU, &lastPosTransformSkip[TEXT_CHROMA_V][tuIterator.m_section], true, curuseRDOQ);
> + widthC, TEXT_CHROMA_V, tuIterator.m_absPartIdxTURelCU, &lastPosTransformSkip[TEXT_CHROMA_V][tuIterator.m_section], &(m_cfg->m_nr), true, curuseRDOQ);
>
> cu->setCbfPartRange(absSumTransformSkipU ? setCbf : 0, TEXT_CHROMA_U, tuIterator.m_absPartIdxTURelCU, tuIterator.m_absPartIdxStep);
> cu->setCbfPartRange(absSumTransformSkipV ? setCbf : 0, TEXT_CHROMA_V, tuIterator.m_absPartIdxTURelCU, tuIterator.m_absPartIdxStep);
> diff -r 7773ee321539 -r a81311047a4d source/common/common.h
> --- a/source/common/common.h Wed May 07 10:49:02 2014 +0530
> +++ b/source/common/common.h Wed May 07 18:54:09 2014 +0530
> @@ -166,6 +166,20 @@
> #define X265_LOG2(x) log2(x)
> #endif
>
> +struct NoiseReduction
> +{
> + bool bNoiseReduction;
> +
> + /* 0 = luma 4x4, 1 = luma 8x8, 2 = chroma 4x4, 3 = chroma 8x8 */
> + uint16_t (*offset)[64];
> + uint32_t (*residualSum)[64];
> + uint32_t *count;
> +
> + uint16_t offsetDenoise[4][64];
> + uint32_t residualSumBuf[2][4][64];
> + uint32_t countBuf[2][4];
> +};
> +
> /* defined in common.cpp */
> int64_t x265_mdate(void);
> void x265_log(const x265_param *param, int level, const char *fmt, ...);
> diff -r 7773ee321539 -r a81311047a4d source/common/param.cpp
> --- a/source/common/param.cpp Wed May 07 10:49:02 2014 +0530
> +++ b/source/common/param.cpp Wed May 07 18:54:09 2014 +0530
> @@ -688,6 +688,7 @@
> &p->vui.defDispWinRightOffset,
> &p->vui.defDispWinBottomOffset) != 4;
> }
> + OPT("nr") p->noiseReduction = atoi(value);
> else
> return X265_PARAM_BAD_NAME;
> #undef OPT
> @@ -980,6 +981,8 @@
> CHECK(param->rc.bitrate < 0,
> "Target bitrate can not be less than zero");
> CHECK(param->bFrameBias < 0, "Bias towards B frame decisions must be 0 or greater");
> + if (param->noiseReduction)
> + CHECK(100 > param->noiseReduction || param->noiseReduction > 1000, "Valid noise reduction range 100 - 1000");
> return check_failed;
> }
>
> diff -r 7773ee321539 -r a81311047a4d source/encoder/encoder.cpp
> --- a/source/encoder/encoder.cpp Wed May 07 10:49:02 2014 +0530
> +++ b/source/encoder/encoder.cpp Wed May 07 18:54:09 2014 +0530
> @@ -72,6 +72,14 @@
> m_csvfpt = NULL;
> param = NULL;
>
> + memset(m_nr.offsetDenoise, 0, sizeof(m_nr.offsetDenoise[0][0]) * 4 * 64);
> + memset(m_nr.residualSumBuf, 0, sizeof(m_nr.residualSumBuf[0][0][0]) * 2 * 4 * 64);
> + memset(m_nr.countBuf, 0, sizeof(m_nr.countBuf[0][0]) * 2 * 4);
> +
> + m_nr.offset = m_nr.offsetDenoise;
> + m_nr.residualSum = m_nr.residualSumBuf[0];
> + m_nr.count = m_nr.countBuf[0];
> +
> #if ENC_DEC_TRACE
> g_hTrace = fopen("TraceEnc.txt", "wb");
> g_bJustDoIt = g_bEncDecTraceDisable;
> @@ -194,6 +202,7 @@
> }
> m_lookahead->init();
> m_encodeStartTime = x265_mdate();
> + m_nr.bNoiseReduction = !!param->noiseReduction;
> }
>
> int Encoder::getStreamHeaders(NALUnitEBSP **nalunits)
> @@ -226,6 +235,42 @@
> }
> }
>
> +/****************************************************************************
> + * DCT-domain noise reduction / adaptive deadzone
> + * from libavcodec
> + ****************************************************************************/
> +
> +void Encoder::noiseReductionUpdate(NoiseReduction* h)
> +{
> + h->offset = h->offsetDenoise;
> + h->residualSum = h->residualSumBuf[0];
> + h->count = h->countBuf[0];
> +
> + int isCspI444 = (param->internalCsp == X265_CSP_I444) ? 1 : 0;
> + for (int cat = 0; cat < 3 + isCspI444; cat++)
> + {
> + int dct8x8 = cat&1;
> + int size = dct8x8 ? 64 : 16;
> + const uint32_t* weight = dct8x8 ? g_dctDenoiseWeight4x4 : g_dctDenoiseWeight8x8;
> +
> + if (h->count[cat] > (dct8x8 ? (1 << 16) : (1 << 18)))
> + {
> + for (int i = 0; i < size; i++)
> + h->residualSum[cat][i] >>= 1;
> + h->count[cat] >>= 1;
> + }
> +
> + for (int i = 0; i < size; i++)
> + h->offset[cat][i] =
> + ((uint64_t)param->noiseReduction * h->count[cat]
> + + h->residualSum[cat][i] / 2)
> + / ((uint64_t)h->residualSum[cat][i] * weight[i] / 256 + 1);
> +
> + // Don't denoise DC coefficients
> + h->offset[cat][0] = 0;
> + }
> +}
> +
> #define VERBOSE_RATE 0
> #if VERBOSE_RATE
> static const char* nalUnitTypeToString(NalUnitType type)
> @@ -442,6 +487,9 @@
> m_rateControl->rateControlEnd(out, bits, &curEncoder->m_rce);
> finishFrameStats(out, curEncoder, bits);
>
> + if (m_nr.bNoiseReduction)
> + noiseReductionUpdate(&m_nr);
> +
> // Allow this frame to be recycled if no frame encoders are using it for reference
> ATOMIC_DEC(&out->m_countRefEncoders);
> m_dpb->recycleUnreferenced(m_freeList);
> diff -r 7773ee321539 -r a81311047a4d source/encoder/encoder.h
> --- a/source/encoder/encoder.h Wed May 07 10:49:02 2014 +0530
> +++ b/source/encoder/encoder.h Wed May 07 18:54:09 2014 +0530
> @@ -195,6 +195,8 @@
> x265_nal* m_nals;
> char* m_packetData;
>
> + NoiseReduction m_nr;
> +
> Encoder();
>
> virtual ~Encoder();
> @@ -228,6 +230,8 @@
>
> void updateVbvPlan(RateControl* rc);
>
> + void noiseReductionUpdate(NoiseReduction* nr);
> +
> protected:
>
> void finishFrameStats(TComPic* pic, FrameEncoder *curEncoder, uint64_t bits);
> diff -r 7773ee321539 -r a81311047a4d source/x265.cpp
> --- a/source/x265.cpp Wed May 07 10:49:02 2014 +0530
> +++ b/source/x265.cpp Wed May 07 18:54:09 2014 +0530
> @@ -170,6 +170,7 @@
> { "aud", no_argument, NULL, 0 },
> { "no-aud", no_argument, NULL, 0 },
> { "qpfile", required_argument, NULL, 0 },
> + { "nr", required_argument, NULL, 0 },
> { 0, 0, 0, 0 }
> };
>
> @@ -404,6 +405,8 @@
> H0(" Format of each line: framenumber frametype QP\n");
> H0(" QP is optional (none lets x265 choose). Frametypes: I,i,P,B,b.\n");
> H0(" QPs are restricted by qpmin/qpmax.\n");
> + H0("\nNoiseReduction option:\n");
> + H0(" --nr <integer> An integer value in range of 100 to 1000, which denotes strength of noise reduction. Default disabled\n");
> #undef OPT
> #undef H0
> printf("\n\nFull documentation may be found at http://x265.readthedocs.org/en/default/cli.html\n");
> diff -r 7773ee321539 -r a81311047a4d source/x265.h
> --- a/source/x265.h Wed May 07 10:49:02 2014 +0530
> +++ b/source/x265.h Wed May 07 18:54:09 2014 +0530
> @@ -635,6 +635,10 @@
> * Default is 0, which is recommended */
> int crQpOffset;
>
> + /* An integer value in range of 100 to 1000, which denotes strength of noise
> + * reduction */
> + int noiseReduction;
> +
> /*== Rate Control ==*/
>
> struct
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
--
Steve Borho
More information about the x265-devel
mailing list