timgfilternoise.cpp

来自「从FFMPEG转换而来的H264解码程序,VC下编译..」· C++ 代码 · 共 797 行 · 第 1/2 页

CPP
797
字号
/*
 * Copyright (c) 2002-2006 Milan Cutka
 * noise algorithm 1 by avih
 * noise algorithm 2 by Michael Niedermayer and ...
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "stdafx.h"
#include "TimgFilterNoise.h"
#include "Tconfig.h"
#include "TimgFilterLuma.h"
#include "TimgFilterOffset.h"

#pragma warning(push)
#pragma warning(disable:4799)

//================================= TimgFilterNoiseMplayer::Tprocess ===============================
TimgFilterNoiseMplayer::Tprocess::Tprocess(void)
{
 noise=NULL;
 nonTempRandShift[0]=-1;
 lineNoise=lineNoise_C;
 lineNoiseAvg=lineNoiseAvg_C;
 if (Tconfig::cpu_flags&FF_CPU_MMX)
  {
   lineNoise=lineNoise_simd<Tmmx>;
   lineNoiseAvg=lineNoiseAvg_simd<Tmmx>;
  }
 if (Tconfig::cpu_flags&FF_CPU_MMXEXT)
  lineNoise=lineNoise_simd<Tmmxext>;
#ifdef __SSE2__
 if (Tconfig::cpu_flags&FF_CPU_SSE2)
  {
   lineNoise=lineNoise_simd<Tsse2>;
   lineNoiseAvg=lineNoiseAvg_simd<Tsse2>;
  }
#endif
}

void TimgFilterNoiseMplayer::Tprocess::done(void)
{
 if (noise) aligned_free(noise);noise=NULL;
 nonTempRandShift[0]=-1;
}

void TimgFilterNoiseMplayer::Tprocess::init(int strength,const TnoiseSettings *Icfg)
{
 cfg=*Icfg;
 noise=(int8_t*)aligned_malloc(MAX_NOISE*sizeof(int8_t));
 int i,j;
 for (i=0,j=0;i<MAX_NOISE;i++,j++)
  {
   if(cfg.uniform)
    if (cfg.averaged)
     if (cfg.pattern)
      noise[i]=int8_t((RAND_N(strength)-strength/2)/6+TimgFilterNoise::patt[j%4]*strength*0.25/3);
     else
      noise[i]=int8_t((RAND_N(strength)-strength/2)/3);
    else
     if (cfg.pattern)
      noise[i]=int8_t((RAND_N(strength)-strength/2)/2+TimgFilterNoise::patt[j%4]*strength*0.25);
     else
      noise[i]=int8_t(RAND_N(strength)-strength/2);
   else
    {
     double x1, x2, w, y1;
     do
      {
       x1=2.0*rand()/(float)RAND_MAX-1.0;
       x2=2.0*rand()/(float)RAND_MAX-1.0;
       w=x1*x1+x2*x2;
      } while (w>=1.0);

     w=sqrt((-2.0*log(w))/w);
     y1=x1*w;
     y1*=strength/sqrt(3.0);
     if (cfg.pattern)
      {
       y1/=2;
       y1+=TimgFilterNoise::patt[j%4]*strength*0.35;
      }
     if      (y1<-128) y1=-128;
     else if (y1> 127) y1= 127;
     if (cfg.averaged) y1/=3.0;
     noise[i]=(int8_t)y1;
    }
   if (RAND_N(6)==0) j--;
  }

 for (i=0;i<MAX_RES;i++)
  for (j=0;j<3;j++)
   prev_shift[i][j]=noise+(rand()&(MAX_SHIFT-1));

 if (nonTempRandShift[0]==-1)
  for (i=0;i<MAX_RES;i++)
   nonTempRandShift[i]=rand()&(MAX_SHIFT-1);

 shiftptr=0;
}

void TimgFilterNoiseMplayer::Tprocess::process(const uint8_t *src,uint8_t *dst,stride_t dstStride,stride_t srcStride,unsigned int width,unsigned int height)
{
 int shift=0;
 for (unsigned int y=0;y<height;y++)
  {
   if (cfg.mplayerTemporal)
    shift=rand()&(MAX_SHIFT-1);
   else
    shift=nonTempRandShift[y];

   if (cfg.mplayerQuality==0)
    shift&=~7;

   if (cfg.averaged)
    {
     lineNoiseAvg(dst,src,width,prev_shift[y]);
     prev_shift[y][shiftptr]=noise+shift;
    }
   else
    lineNoise(dst,src,noise,width,shift);
   dst+=dstStride;
   src+=srcStride;
  }
 shiftptr++;
 if (shiftptr==3) shiftptr=0;
}

void TimgFilterNoiseMplayer::Tprocess::lineNoise_C(uint8_t *dst,const uint8_t *src, int8_t *noise, int len, int shift)
{
 noise+=shift;
 for (int i=0;i<len;i++)
  {
   int v=src[i]+noise[i];
   if (v>255)   dst[i]=255;
   else if(v<0) dst[i]=0;
   else         dst[i]=uint8_t(v);
  }
}

void TimgFilterNoiseMplayer::Tprocess::lineNoiseAvg_C(uint8_t *dst,const uint8_t *src, int len, int8_t **shift)
{
 const int8_t *src2=(const int8_t*)src;
 for (int i=0;i<len;i++)
  {
   int n=shift[0][i]+shift[1][i]+shift[2][i];
   dst[i]=uint8_t(src2[i]+((n*src2[i])>>7));
  }
}

template<class _mm> void TimgFilterNoiseMplayer::Tprocess::lineNoise_simd(uint8_t *dst,const uint8_t *src, int8_t *noise, int len, int shift)
{
 if (_mm::align && (intptr_t(src)&15 || intptr_t(dst)&15))
  {
   lineNoise_simd<typename _mm::T64>(dst,src,noise,len,shift);
   return;
  }
 int mmx_len=len&(~(_mm::size-1));
 noise+=shift;

 typename _mm::__m mm7;
 pcmpeqb(mm7,mm7);
 psllw(mm7,15);
 packsswb(mm7,mm7);
 for (int x=-mmx_len;x<0;x+=_mm::size)
  {
   //".balign 16			\n\t"
   typename _mm::__m mm0,mm1;
   movq   (mm0,src+mmx_len+x);
   movdqu (mm1,noise+mmx_len+x); //SSE3
   pxor   (mm0,mm7);
   paddsb (mm0,mm1);
   pxor   (mm0,mm7);
   _mm::movntq(dst+mmx_len+x,mm0);
  }

 if (mmx_len!=len)
  lineNoise_C(dst+mmx_len,src+mmx_len,noise+mmx_len,len-mmx_len,0);
}
template<class _mm> void TimgFilterNoiseMplayer::Tprocess::lineNoiseAvg_simd(uint8_t *dst,const uint8_t *src, int len, int8_t **shift_)
{
 if (_mm::align && (intptr_t(src)&15 || intptr_t(dst)&15))
  {
   lineNoiseAvg_simd<typename _mm::T64>(dst,src,len,shift_);
   return;
  }
 const int mmx_len=len&(~(_mm::size-1));

 int8_t *shift2[3]={shift_[0]+mmx_len, shift_[1]+mmx_len, shift_[2]+mmx_len};
 for (int x=-mmx_len;x<0;x+=_mm::size)
  {
   //".balign 16                   \n\t"
   typename _mm::__m mm0,mm1,mm2,mm3;
   movdqu (mm1,shift2[0]+mmx_len+x);
   movq (mm0,src+mmx_len+x);
   typename _mm::__m shift1_8=_mm::loadU(shift2[1]+mmx_len+x);
   paddb (mm1,shift1_8);
   typename _mm::__m shift2_8=_mm::loadU(shift2[2]+mmx_len+x);
   paddb (mm1,shift2_8);
   movq (mm2,mm0);
   movq (mm3,mm1);
   punpcklbw (mm0,mm0);
   punpckhbw (mm2,mm2);
   punpcklbw (mm1,mm1);
   punpckhbw (mm3,mm3);
   pmulhw (mm1,mm0);
   pmulhw (mm3,mm2);
   paddw (mm1,mm1);
   paddw (mm3,mm3);
   paddw (mm1,mm0);
   paddw (mm3,mm2);
   psrlw (mm1,8);
   psrlw (mm3,8);
   packuswb (mm1,mm3);
   movq (dst+mmx_len+x,mm1);
  }

 if (mmx_len!=len)
  lineNoiseAvg_C(dst+mmx_len, src+mmx_len, len-mmx_len, shift2);
}

TimgFilterNoiseMplayer::TimgFilterNoiseMplayer(IffdshowBase *Ideci,Tfilters *Iparent):TimgFilter(Ideci,Iparent)
{
 oldnoise.strength=-1;oldcsp=FF_CSP_NULL;
}
void TimgFilterNoiseMplayer::done(void)
{
 y.done();
 doneChroma();
}
void TimgFilterNoiseMplayer::doneChroma(void)
{
 uv.done();
}
bool TimgFilterNoiseMplayer::is(const TffPictBase &pict,const TfilterSettingsVideo *cfg0)
{
 const TnoiseSettings *cfg=(const TnoiseSettings*)cfg0;
 return super::is(pict,cfg0) && (cfg->strength || cfg->strengthChroma);
}
HRESULT TimgFilterNoiseMplayer::process(TfilterQueue::iterator it,TffPict &pict,const TfilterSettingsVideo *cfg0)
{
 if (is(pict,cfg0))
  {
   const TnoiseSettings *cfg=(const TnoiseSettings*)cfg0;
   init(pict,cfg->full,cfg->half);
   if (!cfg->equal(oldnoise))
    {
     oldnoise=*cfg;
     y.done();uv.done();
    }
   int csp=0;
   if (cfg->strength)
    {
     const unsigned char *srcY;
     getCur(FF_CSPS_MASK_YUV_PLANAR,pict,cfg->full,&srcY,NULL,NULL,NULL);
     unsigned char *dstY;
     getCurNext(csp=csp1,pict,cfg->full,COPYMODE_NO,&dstY,NULL,NULL,NULL);
     if (!y)
      y.init(cfg->strength/(cfg->averaged?1:3),cfg);
     y.process(srcY,dstY,stride2[0],stride1[0],dx1[0],dy1[0]);
     _mm_empty();
    }
   if (cfg->strengthChroma)
    {
     const unsigned char *srcU,*srcV;
     getCur(csp?csp:FF_CSPS_MASK_YUV_PLANAR,pict,cfg->full,NULL,&srcU,&srcV,NULL);
     unsigned char *dstU,*dstV;
     getCurNext(csp1,pict,cfg->full,COPYMODE_NO,NULL,&dstU,&dstV,NULL);
     if (oldcsp!=csp1)
      {
       oldcsp=csp1;
       doneChroma();
      }
     if (!uv)
      uv.init(cfg->strengthChroma/(cfg->averaged?1:2),cfg);
     uv.process(srcU,dstU,stride2[1],stride1[1],dx1[1],dy1[1]);
     uv.process(srcV,dstV,stride2[2],stride1[2],dx1[2],dy1[2]);
     _mm_empty();
    }
  }
 return parent->deliverSample(++it,pict);
}

//========================================= TimgFilterNoise =========================================
__m64 TimgFilterNoise::noiseConst64,TimgFilterNoise::noisenext64;
template<> __m64& TimgFilterNoise::Tnoise<Tmmx>::noiseConst() {return noiseConst64;}
template<> __m64& TimgFilterNoise::Tnoise<Tmmx>::noisenext() {return noisenext64;}
template<> void TimgFilterNoise::Tnoise<Tmmx>::init(void)
{
 noiseConst64=Tmmx::set1_pi64(6364136223846793005LL);
}
template<> void TimgFilterNoise::Tnoise<Tmmx>::reset(void)
{
 noisenext64=Tmmx::set1_pi64(time(NULL));
}

#ifdef __SSE2__
__m128i TimgFilterNoise::noiseConst128,TimgFilterNoise::noisenext128;
template<> __m128i& TimgFilterNoise::Tnoise<Tsse2>::noiseConst() {return noiseConst128;}
template<> __m128i& TimgFilterNoise::Tnoise<Tsse2>::noisenext() {return noisenext128;}
template<> void TimgFilterNoise::Tnoise<Tsse2>::init(void)
{
 noiseConst128=_mm_set_epi32(0xaa294349,0x6f4805c,0x987ec766,0xcf68ec93);
}
template<> void TimgFilterNoise::Tnoise<Tsse2>::reset(void)
{
 __align16(int64_t,t[])={0,time(NULL)};
 noisenext128=*(__m128i*)t;
}
#endif

const int TimgFilterNoise::patt[4]={-2,0,2,0};

TimgFilterNoise::TimgFilterNoise(IffdshowBase *Ideci,Tfilters *Iparent):TimgFilter(Ideci,Iparent)
{
 noiseMask[0]=noiseMask[1]=noiseMask[2]=NULL;
 oldnoise.strength=-1;oldcsp=FF_CSP_NULL;
#ifdef __SSE2__
 if (Tconfig::cpu_flags&FF_CPU_SSE2)
  {
   Tnoise<Tsse2>::init();
   processLumaFc=&TimgFilterNoise::processLuma<Tsse2>;
   processChromaFc=&TimgFilterNoise::processChroma<Tsse2>;
  }
 else
#endif
  {
   processLumaFc=&TimgFilterNoise::processLuma<Tmmx>;
   processChromaFc=&TimgFilterNoise::processChroma<Tmmx>;
  }
 Tnoise<Tmmx>::init();
 _mm_empty();
}
void TimgFilterNoise::done(void)
{
 if (noiseMask[0]) aligned_free(noiseMask[0]);noiseMask[0]=NULL;
 doneChroma();
}
void TimgFilterNoise::doneChroma(void)
{
 for (int i=1;i<3;i++)
  if (noiseMask[i])
   {
    aligned_free(noiseMask[i]);
    noiseMask[i]=NULL;
   }
}
void TimgFilterNoise::onSizeChange(void)
{
 done();
 noiseCount[0]=noiseCount[1]=noiseCount[2]=-1;
 noiseAvihStrength=0;oldPattern=-1;
#ifdef __SSE2__
 if (Tconfig::cpu_flags&FF_CPU_SSE2)
  Tnoise<Tsse2>::reset();
#endif
 Tnoise<Tmmx>::reset();
 _mm_empty();
}

template<class _mm,bool chroma,bool avih,bool uniform> void TimgFilterNoise::addNoise(const unsigned char *src,stride_t srcStride,unsigned char *dst,stride_t dstStride,unsigned int dx,unsigned int dy,short *noiseMask,stride_t noiseMaskStride,int noiseStrength)
{
 typename _mm::__m noisenext64;
 if (!avih)
  noisenext64=Tnoise<_mm>::noisenext();
 typename _mm::__m noiseStrength64=_mm::set1_pi16((short)noiseStrength);
 typename _mm::__m m0=_mm::setzero_si64(),m255=_mm::set1_pi16(255),m128=_mm::set1_pi16(128);
 for (const unsigned char *srcEnd=src+srcStride*dy;src!=srcEnd;src+=srcStride,dst+=dstStride,noiseMask+=noiseMaskStride)
  {
   int x=0;
   for (;x<int(dx-_mm::size/2+1);x+=_mm::size/2)
    {
     typename _mm::__m noise;
     if (!avih)
      {
       noise=noisenext64=_mm::add_pi16(_mm::madd_pi16(noisenext64,Tnoise<_mm>::noiseConst()),Tnoise<_mm>::noiseConst());
       noise=_mm::subs_pi16(_mm::and_si64(noise,m255),m128);
      }
     else
      noise=_mm::loadU(noiseMask+x); //SSE3
     typename _mm::__m noiseMul,src8=_mm::unpacklo_pi8(_mm::load2(src+x),m0);
     if (uniform)
      noiseMul=noise;
     else
      {
       noiseMul=src8;
       if (chroma)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?