[x265] [PATCH] noise reduction feature, ported from x264

praveen at multicorewareinc.com praveen at multicorewareinc.com
Thu May 8 13:11:35 CEST 2014


# HG changeset patch
# User Praveen Tiwari
# Date 1399547477 -19800
# Node ID 9ee52ef9f0dd4981fd866a8774527bd1e965096e
# Parent  8e64aa56d6352a1a8cfb6fb57cb547607bcec9b1
noise reduction feature, ported from x264

diff -r 8e64aa56d635 -r 9ee52ef9f0dd doc/reST/cli.rst
--- a/doc/reST/cli.rst	Thu May 08 11:01:04 2014 +0530
+++ b/doc/reST/cli.rst	Thu May 08 16:41:17 2014 +0530
@@ -184,6 +184,14 @@
 
 	**CLI ONLY**
 
+.. 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.
+
 .. option:: --input-res <wxh>
 
 	YUV only: Source picture size [w x h]
diff -r 8e64aa56d635 -r 9ee52ef9f0dd source/Lib/TLibCommon/TComRom.cpp
--- a/source/Lib/TLibCommon/TComRom.cpp	Thu May 08 11:01:04 2014 +0530
+++ b/source/Lib/TLibCommon/TComRom.cpp	Thu May 08 16:41:17 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 8e64aa56d635 -r 9ee52ef9f0dd source/Lib/TLibCommon/TComRom.h
--- a/source/Lib/TLibCommon/TComRom.h	Thu May 08 11:01:04 2014 +0530
+++ b/source/Lib/TLibCommon/TComRom.h	Thu May 08 16:41:17 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 8e64aa56d635 -r 9ee52ef9f0dd source/Lib/TLibCommon/TComTrQuant.cpp
--- a/source/Lib/TLibCommon/TComTrQuant.cpp	Thu May 08 11:01:04 2014 +0530
+++ b/source/Lib/TLibCommon/TComTrQuant.cpp	Thu May 08 16:41:17 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 8e64aa56d635 -r 9ee52ef9f0dd source/Lib/TLibCommon/TComTrQuant.h
--- a/source/Lib/TLibCommon/TComTrQuant.h	Thu May 08 11:01:04 2014 +0530
+++ b/source/Lib/TLibCommon/TComTrQuant.h	Thu May 08 16:41:17 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 8e64aa56d635 -r 9ee52ef9f0dd source/Lib/TLibEncoder/TEncSearch.cpp
--- a/source/Lib/TLibEncoder/TEncSearch.cpp	Thu May 08 11:01:04 2014 +0530
+++ b/source/Lib/TLibEncoder/TEncSearch.cpp	Thu May 08 16:41:17 2014 +0530
@@ -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);
@@ -1492,7 +1492,7 @@
 
                 m_trQuant->selectLambda(TEXT_CHROMA);
 
-                absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, width, ttype, absTUPartIdxC, &lastPos, useTransformSkipChroma);
+                absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, width, ttype, absTUPartIdxC, &lastPos, &(m_cfg->m_nr), useTransformSkipChroma);
 
                 //--- set coded block flag ---
                 cu->setCbfPartRange((((absSum > 0) ? 1 : 0) << origTrDepth), ttype, absTUPartIdxC, tuIterator.m_absPartIdxStep);
@@ -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 8e64aa56d635 -r 9ee52ef9f0dd source/common/common.h
--- a/source/common/common.h	Thu May 08 11:01:04 2014 +0530
+++ b/source/common/common.h	Thu May 08 16:41:17 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 8e64aa56d635 -r 9ee52ef9f0dd source/common/param.cpp
--- a/source/common/param.cpp	Thu May 08 11:01:04 2014 +0530
+++ b/source/common/param.cpp	Thu May 08 16:41:17 2014 +0530
@@ -689,6 +689,7 @@
                          &p->vui.defDispWinRightOffset,
                          &p->vui.defDispWinBottomOffset) != 4;
     }
+    OPT("nr") p->noiseReduction = atoi(value);
     else
         return X265_PARAM_BAD_NAME;
 #undef OPT
@@ -981,6 +982,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 8e64aa56d635 -r 9ee52ef9f0dd source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Thu May 08 11:01:04 2014 +0530
+++ b/source/encoder/encoder.cpp	Thu May 08 16:41:17 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 8e64aa56d635 -r 9ee52ef9f0dd source/encoder/encoder.h
--- a/source/encoder/encoder.h	Thu May 08 11:01:04 2014 +0530
+++ b/source/encoder/encoder.h	Thu May 08 16:41:17 2014 +0530
@@ -194,6 +194,8 @@
     x265_nal*          m_nals;
     char*              m_packetData;
 
+    NoiseReduction     m_nr;
+
     Encoder();
 
     virtual ~Encoder();
@@ -227,6 +229,8 @@
 
     void updateVbvPlan(RateControl* rc);
 
+    void noiseReductionUpdate(NoiseReduction* nr);
+
 protected:
 
     void finishFrameStats(TComPic* pic, FrameEncoder *curEncoder, uint64_t bits);
diff -r 8e64aa56d635 -r 9ee52ef9f0dd source/x265.cpp
--- a/source/x265.cpp	Thu May 08 11:01:04 2014 +0530
+++ b/source/x265.cpp	Thu May 08 16:41:17 2014 +0530
@@ -171,6 +171,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 }
 };
 
@@ -407,6 +408,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 8e64aa56d635 -r 9ee52ef9f0dd source/x265.h
--- a/source/x265.h	Thu May 08 11:01:04 2014 +0530
+++ b/source/x265.h	Thu May 08 16:41:17 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


More information about the x265-devel mailing list