📄 timgfiltersharpen.cpp
字号:
/*
* Copyright (c) 2002-2006 Milan Cutka
* algorithms based on VirtualDub and AviSynth filters by Donald A. Graft
* asharp by Marc Fauconneau
*
* 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 "TimgFilterSharpen.h"
#include "TsharpenSettings.h"
#include "IffdshowBase.h"
#include "T3x3blur.h"
#include "Tconfig.h"
#include "Tlibmplayer.h"
#include "postproc/swscale.h"
#include "simd.h"
//==================================== TimgFilterAsharp ====================================
TimgFilterAsharp::TimgFilterAsharp(IffdshowBase *Ideci,Tfilters *Iparent):TimgFilter(Ideci,Iparent)
{
asharp_run=getAsharp();
aline=NULL;
oldAsharpT=INT_MAX;
}
void TimgFilterAsharp::done(void)
{
if (aline) aligned_free(aline);aline=NULL;
}
bool TimgFilterAsharp::is(const TffPictBase &pict,const TfilterSettingsVideo *cfg0)
{
const TsharpenSettings *cfg=(const TsharpenSettings*)cfg0;
return super::is(pict,cfg) && cfg->asharpT;
}
HRESULT TimgFilterAsharp::process(TfilterQueue::iterator it,TffPict &pict,const TfilterSettingsVideo *cfg0)
{
if (is(pict,cfg0))
{
const TsharpenSettings *cfg=(const TsharpenSettings*)cfg0;
if (oldAsharpT!=cfg->asharpT || oldAsharpD!=cfg->asharpD || oldAsharpB!=cfg->asharpB || oldAsharpHQBF!=cfg->asharpHQBF)
{
oldAsharpT=cfg->asharpT;oldAsharpD=cfg->asharpD;oldAsharpB=cfg->asharpB;oldAsharpHQBF=cfg->asharpHQBF;
//TODO: remove comparisons - it shouldn't be possible to enter too small/large parameter
double t=oldAsharpT/100.0;
asharpCfgT=(int)(t*(4<<7));
asharpCfgT=limit(asharpCfgT,int(-(4<<7)),int(32*(4<<7))); // yes, negatives values are accepted
double d=oldAsharpD/100.0;
asharpCfgD=(int)(d*(4<<7));
asharpCfgD=limit(asharpCfgD,0,int(16*(4<<7)));
if (oldAsharpB==0)
asharpCfgB=asharpCfgB2=256;
else
{
double b=oldAsharpB/100.0;
asharpCfgB=(int)(256-b*64);
asharpCfgB=limit(asharpCfgB,0,256);
asharpCfgB2=(int)(256-b*48);
asharpCfgB2=limit(asharpCfgB2,0,256);
}
}
init(pict,cfg->full,cfg->half);
if (!aline) aline=(unsigned char*)aligned_malloc(pictRect.dx*2);
unsigned char *dst;
getCurNext(FF_CSPS_MASK_YUV_PLANAR,pict,cfg->full,COPYMODE_DEF,&dst,NULL,NULL,NULL);
unsigned char *lastX2,*lastX1;
if (oldAsharpHQBF)
{
lastX2=(unsigned char*)_alloca(dy1[0]);lastX1=(unsigned char*)_alloca(dy1[0]);
for (unsigned int y=0;y<dy1[0];y++)
{
lastX2[y]=dst[y*stride2[0]+dx1[0]-2];
lastX1[y]=dst[y*stride2[0]+dx1[0]-1];
}
}
else
lastX2=lastX1=NULL;
asharp_run(dst,(int)stride2[0],dy1[0],dx1[0],asharpCfgT,asharpCfgD,asharpCfgB,asharpCfgB2,oldAsharpHQBF,aline);
_mm_empty();
if (oldAsharpHQBF)
for (unsigned int y=0;y<dy1[0];y++)
{
dst[y*stride2[0]+dx1[0]-2]=lastX2[y];
dst[y*stride2[0]+dx1[0]-1]=lastX1[y];
}
}
return parent->deliverSample(++it,pict);
}
//==================================== TimgFilterMplayerSharp ====================================
TimgFilterMplayerSharp::TimgFilterMplayerSharp(IffdshowBase *Ideci,Tfilters *Iparent):TimgFilter(Ideci,Iparent)
{
libmplayer=NULL;swsc=NULL;swsf=NULL;oldmplayersharpenluma=oldmplayersharpenchroma=-1;
}
TimgFilterMplayerSharp::~TimgFilterMplayerSharp()
{
if (libmplayer) libmplayer->Release();
}
void TimgFilterMplayerSharp::done(void)
{
if (swsf) libmplayer->sws_freeFilter(swsf);swsf=NULL;
if (swsc) libmplayer->sws_freeContext(swsc);swsc=NULL;
}
bool TimgFilterMplayerSharp::is(const TffPictBase &pict,const TfilterSettingsVideo *cfg0)
{
const TsharpenSettings *cfg=(const TsharpenSettings*)cfg0;
return super::is(pict,cfg) && (cfg->mplayerLuma || cfg->mplayerChroma);
}
HRESULT TimgFilterMplayerSharp::process(TfilterQueue::iterator it,TffPict &pict,const TfilterSettingsVideo *cfg0)
{
if (is(pict,cfg0))
{
const TsharpenSettings *cfg=(const TsharpenSettings*)cfg0;
init(pict,cfg->full,cfg->half);
bool cspChanged=false;
const unsigned char *src[4];
cspChanged|=getCur(SWS_IN_CSPS,pict,cfg->full,src);
unsigned char *dst[4];
cspChanged|=getNext(SWS_OUT_CSPS,pict,cfg->full,dst);
if (cspChanged) done();
if (!swsc || oldmplayersharpenluma!=cfg->mplayerLuma || oldmplayersharpenchroma!=cfg->mplayerChroma)
{
oldmplayersharpenluma=cfg->mplayerLuma;oldmplayersharpenchroma=cfg->mplayerChroma;
if (!libmplayer) deci->getPostproc(&libmplayer);
done();
swsf=libmplayer->sws_getDefaultFilter(0,0,oldmplayersharpenluma/100.0f,oldmplayersharpenchroma/100.0f,0,0,0);
SwsParams params;Tlibmplayer::swsInitParams(¶ms,0);
swsc=libmplayer->sws_getContext(dx1[0],dy1[0],csp_ffdshow2mplayer(csp1),dx1[0],dy1[0],csp_ffdshow2mplayer(csp2),¶ms,swsf,NULL);
}
if (swsc)
libmplayer->sws_scale_ordered(swsc,src,stride1,0,dy1[0],dst,stride2);
}
return parent->deliverSample(++it,pict);
}
//==================================== TimgFilterUnsharp ====================================
TimgFilterUnsharp::TimgFilterUnsharp(IffdshowBase *Ideci,Tfilters *Iparent):TimgFilter(Ideci,Iparent)
{
Ysum=NULL;
#ifdef __SSE2__
if (Tconfig::cpu_flags&FF_CPU_SSE2)
unsharpFc=&TimgFilterUnsharp::unsharp<Tsse2>;
else
#endif
unsharpFc=&TimgFilterUnsharp::unsharp<Tmmx>;
}
void TimgFilterUnsharp::done(void)
{
if (Ysum) aligned_free(Ysum);Ysum=NULL;
}
bool TimgFilterUnsharp::is(const TffPictBase &pict,const TfilterSettingsVideo *cfg0)
{
const TsharpenSettings *cfg=(const TsharpenSettings*)cfg0;
return super::is(pict,cfg) && cfg->unsharpStrength;
}
template<class _mm> void TimgFilterUnsharp::unsharp(const TsharpenSettings *cfg,const unsigned char *src,unsigned char *dst,unsigned short *sum)
{
static const int C_SCALE=32;
typename _mm::__m div9_64=_mm::set1_pi16(7281),m0=_mm::setzero_si64();
//typename _mm::__m T64=_mm::set1_pi16((short)cfg->unsharpThreshold);
typename _mm::__m C64=_mm::set1_pi16(short(cfg->unsharpStrength+C_SCALE)); //strength=0..250
src+=stride1[0];dst+=stride2[0];sum+=minStride;
for (const unsigned char *srcEnd=src+(dy1[0]-2)*stride1[0];src!=srcEnd;src+=stride1[0],sum+=minStride,dst+=stride2[0])
{
for (unsigned int x=0;x<dx1[0]-1;x+=_mm::size/2)
{
typename _mm::__m mm0=_mm::unpacklo_pi8(_mm::load2(src+stride1[0]+x ),m0);
typename _mm::__m mm1=_mm::unpacklo_pi8(_mm::load2(src+stride1[0]+x+1),m0);
typename _mm::__m mm2=_mm::unpacklo_pi8(_mm::load2(src+stride1[0]+x+2),m0);
_mm::storeU(sum+minStride+1+x,_mm::add_pi16(mm0,_mm::add_pi16(mm1,mm2)));
}
for (unsigned int x=0;x<dx1[0]-1;x+=_mm::size/2)
{
typename _mm::__m y_sum=_mm::mulhi_pi16(_mm::add_pi16(_mm::add_pi16(*(typename _mm::__m*)(sum+x),*(typename _mm::__m*)(sum+minStride+x)),*(typename _mm::__m*)(sum-minStride+x)),div9_64);
typename _mm::__m diff=_mm::sub_pi16(_mm::unpacklo_pi8(_mm::load2(src+x),m0),y_sum);
diff=_mm::adds_pi16(_mm::srai_pi16(_mm::mullo_pi16(diff,C64),5),y_sum);
_mm::store2(dst+x,_mm::packs_pu16(diff,m0));
}
}
_mm::empty();
}
HRESULT TimgFilterUnsharp::process(TfilterQueue::iterator it,TffPict &pict,const TfilterSettingsVideo *cfg0)
{
if (is(pict,cfg0))
{
const TsharpenSettings *cfg=(const TsharpenSettings*)cfg0;
init(pict,cfg->full,cfg->half);
if (!Ysum)
{
minStride=(pictRect.dx/16+2)*16;
Ysum=(unsigned short*)aligned_malloc(minStride*pictRect.dy*2);
}
const unsigned char *src_;
unsigned char *dst_;
getCur(FF_CSPS_MASK_YUV_PLANAR,pict,cfg->full,&src_,NULL,NULL,NULL);
getNext(csp1,pict,cfg->full,&dst_,NULL,NULL,NULL);
const unsigned char *src=src_;
unsigned char *dst=dst_;
unsigned short *sum=Ysum;
for (unsigned int x=1;x<dx1[0]-1;x++)
{
sum[x ]=(unsigned short)(src[x-1 ]+src[x ]+src[x+1 ]);
sum[x+minStride]=(unsigned short)(src[x-1+stride1[0]]+src[x+stride1[0]]+src[x+1+stride1[0]]);
}
(this->*unsharpFc)(cfg,src,dst,sum);
const unsigned char *srcL=src_+stride1[0],*srcR=srcL+dx1[0]-1;unsigned char *dstL=dst_+stride2[0],*dstR=dstL+dx1[0]-1;
for (unsigned int y=1;y<dy1[0]-1;srcL+=stride1[0],srcR+=stride1[0],dstL+=stride2[0],dstR+=stride2[0],y++)
{
*dstL=*srcL;
*dstR=*srcR;
}
memcpy(dst_,src_,dx1[0]);
memcpy(dst_+stride2[0]*(dy1[0]-2),src_+stride1[0]*(dy1[0]-2),dx1[0]);
memcpy(dst_+stride2[0]*(dy1[0]-1),src_+stride1[0]*(dy1[0]-1),dx1[0]);
}
return parent->deliverSample(++it,pict);
}
//==================================== TimgFilterXsharp =====================================
TimgFilterXsharp::TimgFilterXsharp(IffdshowBase *Ideci,Tfilters *Iparent):TimgFilter(Ideci,Iparent)
{
Ymin=Ymax=NULL;
#ifdef __SSE2__
if (Tconfig::cpu_flags&FF_CPU_SSE2)
xsharpenFc=&TimgFilterXsharp::xsharpen<Tsse2>;
else
#endif
if (Tconfig::cpu_flags&FF_CPU_MMXEXT)
xsharpenFc=&TimgFilterXsharp::xsharpen<Tmmxext>;
else
xsharpenFc=&TimgFilterXsharp::xsharpen<Tmmx>;
}
void TimgFilterXsharp::done(void)
{
if (Ymin) aligned_free(Ymin);Ymin=NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -