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

Steve Borho steve at borho.org
Tue May 20 16:10:42 CEST 2014


On Tue, May 20, 2014 at 2:20 AM,  <praveen at multicorewareinc.com> wrote:
> # HG changeset patch
> # User Praveen Tiwari
> # Date 1400570170 -19800
> # Node ID 5dd459c0b7a0c4d7a4c194323d00fdc044f2ba13
> # Parent  b35a5d8f012b5d2d45865bf2a1419df2cd8087d6
> noise reduction feature, ported from x264

I was going to queue this today, but I discovered too many problems
still remaining.

>
> diff -r b35a5d8f012b -r 5dd459c0b7a0 doc/reST/cli.rst
> --- a/doc/reST/cli.rst  Sun May 18 15:02:27 2014 +0900
> +++ b/doc/reST/cli.rst  Tue May 20 12:46:10 2014 +0530
> @@ -184,6 +184,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**

CLI ONLY is for the dither option above, it doesn't apply to --nr.
Also, you need to specify the argument type and in general I had
improved the description locally to look like this:

.. option:: --nr <integer>

 Noise reduction - 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, and doesn't affect intra blocks. The
 higher the strength value parameter, the more aggressively it will
 reduce noise.

    **Values:** any value in range of 100 to 1000. Default disabled.


>
>  .. option:: --input-res <wxh>
> diff -r b35a5d8f012b -r 5dd459c0b7a0 source/Lib/TLibCommon/TComRom.h
> --- a/source/Lib/TLibCommon/TComRom.h   Sun May 18 15:02:27 2014 +0900
> +++ b/source/Lib/TLibCommon/TComRom.h   Tue May 20 12:46:10 2014 +0530
> @@ -278,6 +278,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 b35a5d8f012b -r 5dd459c0b7a0 source/Lib/TLibCommon/TComTrQuant.cpp
> --- a/source/Lib/TLibCommon/TComTrQuant.cpp     Sun May 18 15:02:27 2014 +0900
> +++ b/source/Lib/TLibCommon/TComTrQuant.cpp     Tue May 20 12:46:10 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,15 @@
>          // 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 > 0 && index < 5)
> +            {
> +                denoiseDct(m_tmpCoeff, nr->residualSum[index - 1], nr->offset[index - 1], (16 << (index - 1) * 2 ));
> +                nr->count[index - 1]++;
> +            }
> +        }
>      }
>      return xQuant(cu, m_tmpCoeff, coeff, trSize, ttype, absPartIdx, lastPos, curUseRDOQ);
>  }
> diff -r b35a5d8f012b -r 5dd459c0b7a0 source/Lib/TLibCommon/TComTrQuant.h
> --- a/source/Lib/TLibCommon/TComTrQuant.h       Sun May 18 15:02:27 2014 +0900
> +++ b/source/Lib/TLibCommon/TComTrQuant.h       Tue May 20 12:46:10 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 b35a5d8f012b -r 5dd459c0b7a0 source/Lib/TLibEncoder/TEncSearch.cpp
> --- a/source/Lib/TLibEncoder/TEncSearch.cpp     Sun May 18 15:02:27 2014 +0900
> +++ b/source/Lib/TLibEncoder/TEncSearch.cpp     Tue May 20 12:46:10 2014 +0530
> @@ -465,7 +465,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, tuSize, TEXT_LUMA, absPartIdx, &lastPos, useTransformSkip);
> +    absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, tuSize, TEXT_LUMA, absPartIdx, &lastPos, &(m_cfg->m_nr), useTransformSkip);
>
>      //--- set coded block flag ---
>      cu->setCbfSubParts((absSum ? 1 : 0) << trDepth, TEXT_LUMA, absPartIdx, fullDepth);
> @@ -589,7 +589,7 @@
>
>          m_trQuant->selectLambda(TEXT_CHROMA);
>
> -        absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, tuSize, ttype, absPartIdx, &lastPos, useTransformSkipChroma);
> +        absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, tuSize, ttype, absPartIdx, &lastPos, &(m_cfg->m_nr), useTransformSkipChroma);
>
>          //--- set coded block flag ---
>          cu->setCbfPartRange((((absSum > 0) ? 1 : 0) << origTrDepth), ttype, absPartIdx, absPartIdxStep);
> @@ -902,7 +902,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, tuSize, TEXT_LUMA, absPartIdx, &lastPos, useTransformSkip);
> +        absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, tuSize, TEXT_LUMA, absPartIdx, &lastPos, &(m_cfg->m_nr), useTransformSkip);
>
>          //--- set coded block flag ---
>          cu->setCbfSubParts((absSum ? 1 : 0) << trDepth, TEXT_LUMA, absPartIdx, fullDepth);
> @@ -1497,7 +1497,7 @@
>
>                  m_trQuant->selectLambda(TEXT_CHROMA);
>
> -                absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, tuSize, ttype, absTUPartIdxC, &lastPos, useTransformSkipChroma);
> +                absSum = m_trQuant->transformNxN(cu, residual, stride, coeff, tuSize, ttype, absTUPartIdxC, &lastPos, &(m_cfg->m_nr), useTransformSkipChroma);
>
>                  //--- set coded block flag ---
>                  cu->setCbfPartRange((((absSum > 0) ? 1 : 0) << origTrDepth), ttype, absTUPartIdxC, tuIterator.m_absPartIdxStep);
> @@ -2901,7 +2901,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);
>
> @@ -2945,12 +2945,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);
> @@ -3118,7 +3118,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);
>
> @@ -3156,12 +3156,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);

We don't use parens around &(m_cfg->m_nr). Order of precedence in C
make &m_cfg->m_nr work just fine.

>
>                  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);
> @@ -3451,7 +3451,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)
> @@ -3544,11 +3544,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 b35a5d8f012b -r 5dd459c0b7a0 source/common/common.h
> --- a/source/common/common.h    Sun May 18 15:02:27 2014 +0900
> +++ b/source/common/common.h    Tue May 20 12:46:10 2014 +0530
> @@ -177,6 +177,21 @@
>  #define X265_LOG2(x)  log2(x)
>  #endif
>
> +struct NoiseReduction
> +{
> +    bool bNoiseReduction;
> +
> +    /* 0 = luma 4x4, 1 = luma 8x8, 2 = luma 16x16, 3 = luma 32x32
> +     * 4 = chroma 4x4, 5 = chroma 8x8, 6 = chroma 16x16, 7 = chroma 32x32 */
> +    uint16_t (*offset)[1024];
> +    uint32_t (*residualSum)[1024];
> +    uint32_t *count;
> +
> +    uint16_t offsetDenoise[8][1024];
> +    uint32_t residualSumBuf[4][8][1024];
> +    uint32_t countBuf[4][8];
> +};
> +
>  /* defined in common.cpp */
>  int64_t x265_mdate(void);
>  void x265_log(const x265_param *param, int level, const char *fmt, ...);
> diff -r b35a5d8f012b -r 5dd459c0b7a0 source/common/param.cpp
> --- a/source/common/param.cpp   Sun May 18 15:02:27 2014 +0900
> +++ b/source/common/param.cpp   Tue May 20 12:46:10 2014 +0530
> @@ -694,6 +694,7 @@
>                           &p->vui.defDispWinRightOffset,
>                           &p->vui.defDispWinBottomOffset) != 4;
>      }
> +    OPT("nr") p->noiseReduction = atoi(value);
>      else
>          return X265_PARAM_BAD_NAME;
>  #undef OPT
> @@ -986,6 +987,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 b35a5d8f012b -r 5dd459c0b7a0 source/encoder/encoder.cpp
> --- a/source/encoder/encoder.cpp        Sun May 18 15:02:27 2014 +0900
> +++ b/source/encoder/encoder.cpp        Tue May 20 12:46:10 2014 +0530
> @@ -64,6 +64,14 @@
>      m_csvfpt = NULL;
>      param = NULL;
>
> +    memset(m_nr.offsetDenoise, 0, sizeof(m_nr.offsetDenoise[0][0]) * 8 * 1024);
> +    memset(m_nr.residualSumBuf, 0, sizeof(m_nr.residualSumBuf[0][0][0]) * 4 * 8 * 1024);
> +    memset(m_nr.countBuf, 0, sizeof(m_nr.countBuf[0][0]) * 4 * 8);
> +
> +    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;
> @@ -186,6 +194,7 @@
>      }
>      m_lookahead->init();
>      m_encodeStartTime = x265_mdate();
> +    m_nr.bNoiseReduction = !!param->noiseReduction;
>  }
>
>  int Encoder::getStreamHeaders(NALUnitEBSP **nalunits)
> @@ -218,6 +227,44 @@
>      }
>  }
>
> +/****************************************************************************
> + * DCT-domain noise reduction / adaptive deadzone
> + * from libavcodec
> + ****************************************************************************/
> +
> +void Encoder::noiseReductionUpdate(NoiseReduction* h)

naming this pointer `h` is probably an x264'ism we don't need to bring
along from their code.  `nr` would be better.

> +{
> +    h->offset = h->offsetDenoise;
> +    h->residualSum = h->residualSumBuf[0];
> +    h->count = h->countBuf[0];
> +
> +    int transformSize[4] = {16, 64, 256, 1024};
> +    uint32_t blockCount[4] = { 1 << 18, 1 << 16, 1 << 14, 1 << 12 };
> +
> +    int isCspI444 = (param->internalCsp == X265_CSP_I444) ? 1 : 0;
> +    for (int cat = 0; cat < 7 + isCspI444; cat++)
> +    {
> +        int index = cat % 4;
> +        int size = transformSize[index];
> +
> +        if (h->count[cat] > blockCount[index])
> +        {
> +            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] =
> +                (uint16_t)(((uint64_t)param->noiseReduction * h->count[cat]
> +                 + h->residualSum[cat][i] / 2)
> +              / ((uint64_t)h->residualSum[cat][i] + 1));
> +
> +        // Don't denoise DC coefficients
> +        h->offset[cat][0] = 0;
> +    }

Now we get to the more serious problem; this function is not thread
safe and it makes the encoder non-deterministic.

In order to make the encoder deterministic, noiseReductionUpdate()
cannot be run at the same time a worker thread might be reading the
noise reduction structure.  So m_nr needs to be moved from the top
level Encoder to the FrameEncoder class (based on the name of the
parameter to the function, x264 did roughly the same thing).
noiseReductionUpdate() would need to be called at the end of
compressFrame().

Note that even after moving the m_nr structure to the FrameEncoder,
--nr will be the only option which will make the outputs diverge
between -FN and -FM (where N != M and N != 1 && M != 1), and this
needs to be clearly documented in the --nr section of cli.txt and in
the discussion of frame parallelism in threading.txt.

> +}
> +
>  #define VERBOSE_RATE 0
>  #if VERBOSE_RATE
>  static const char* nalUnitTypeToString(NalUnitType type)
> @@ -434,6 +481,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 b35a5d8f012b -r 5dd459c0b7a0 source/encoder/encoder.h
> --- a/source/encoder/encoder.h  Sun May 18 15:02:27 2014 +0900
> +++ b/source/encoder/encoder.h  Tue May 20 12:46:10 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 b35a5d8f012b -r 5dd459c0b7a0 source/x265.cpp
> --- a/source/x265.cpp   Sun May 18 15:02:27 2014 +0900
> +++ b/source/x265.cpp   Tue May 20 12:46:10 2014 +0530
> @@ -176,6 +176,7 @@
>      { "qpfile",         required_argument, NULL, 0 },
>      { "b-intra",              no_argument, NULL, 0 },
>      { "no-b-intra",           no_argument, NULL, 0 },
> +    { "nr",             required_argument, NULL, 0 },
>      { 0, 0, 0, 0 }
>  };
>
> @@ -414,6 +415,8 @@
>      H0("\nReconstructed video options (debugging):\n");
>      H0("-r/--recon <filename>            Reconstructed raw image YUV or Y4M output file name\n");
>      H0("   --recon-depth <integer>       Bit-depth of reconstructed raw image file. Defaults to input bit depth, or 8 if Y4M\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 b35a5d8f012b -r 5dd459c0b7a0 source/x265.h
> --- a/source/x265.h     Sun May 18 15:02:27 2014 +0900
> +++ b/source/x265.h     Tue May 20 12:46:10 2014 +0530
> @@ -646,6 +646,10 @@
>       * regardless of this setting. */
>      int       bIntraInBFrames;
>
> +    /* An integer value in range of 100 to 1000, which denotes strength of noise
> +     * reduction */
> +    int       noiseReduction;
> +
>      /*== Rate Control ==*/
>
>      struct

Lastly, the patch needs to increase X265_BUILD

-- 
Steve Borho


More information about the x265-devel mailing list