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 + -
显示快捷键?