00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <inttypes.h>
00025 #include <assert.h>
00026
00027 #include "config.h"
00028 #include "mp_msg.h"
00029
00030 #if HAVE_MALLOC_H
00031 #include <malloc.h>
00032 #endif
00033
00034 #include "libavutil/avutil.h"
00035 #include "img_format.h"
00036 #include "mp_image.h"
00037 #include "vf.h"
00038 #include "libswscale/swscale.h"
00039 #include "vf_scale.h"
00040
00041
00042
00043
00044 typedef struct FilterParam{
00045 float radius;
00046 float preFilterRadius;
00047 float strength;
00048 float quality;
00049 struct SwsContext *preFilterContext;
00050 uint8_t *preFilterBuf;
00051 int preFilterStride;
00052 int distWidth;
00053 int distStride;
00054 int *distCoeff;
00055 int colorDiffCoeff[512];
00056 }FilterParam;
00057
00058 struct vf_priv_s {
00059 FilterParam luma;
00060 FilterParam chroma;
00061 };
00062
00063
00064
00065
00066
00067 static void getSubSampleFactors(int *h, int *v, int format){
00068 switch(format){
00069 case IMGFMT_YV12:
00070 case IMGFMT_I420:
00071 *h=1;
00072 *v=1;
00073 break;
00074 case IMGFMT_YVU9:
00075 *h=2;
00076 *v=2;
00077 break;
00078 case IMGFMT_444P:
00079 *h=0;
00080 *v=0;
00081 break;
00082 case IMGFMT_422P:
00083 *h=1;
00084 *v=0;
00085 break;
00086 case IMGFMT_411P:
00087 *h=2;
00088 *v=0;
00089 break;
00090 }
00091 }
00092
00093 static int allocStuff(FilterParam *f, int width, int height){
00094 int stride= (width+7)&~7;
00095 SwsVector *vec;
00096 SwsFilter swsF;
00097 int i,x,y;
00098 f->preFilterBuf= av_malloc(stride*height);
00099 f->preFilterStride= stride;
00100
00101 vec = sws_getGaussianVec(f->preFilterRadius, f->quality);
00102 swsF.lumH= swsF.lumV= vec;
00103 swsF.chrH= swsF.chrV= NULL;
00104 f->preFilterContext= sws_getContext(
00105 width, height, PIX_FMT_GRAY8, width, height, PIX_FMT_GRAY8, SWS_POINT, &swsF, NULL, NULL);
00106
00107 sws_freeVec(vec);
00108 vec = sws_getGaussianVec(f->strength, 5.0);
00109 for(i=0; i<512; i++){
00110 double d;
00111 int index= i-256 + vec->length/2;
00112
00113 if(index<0 || index>=vec->length) d= 0.0;
00114 else d= vec->coeff[index];
00115
00116 f->colorDiffCoeff[i]= (int)(d/vec->coeff[vec->length/2]*(1<<12) + 0.5);
00117 }
00118 sws_freeVec(vec);
00119 vec = sws_getGaussianVec(f->radius, f->quality);
00120 f->distWidth= vec->length;
00121 f->distStride= (vec->length+7)&~7;
00122 f->distCoeff= av_malloc(f->distWidth*f->distStride*sizeof(int32_t));
00123
00124 for(y=0; y<vec->length; y++){
00125 for(x=0; x<vec->length; x++){
00126 double d= vec->coeff[x] * vec->coeff[y];
00127
00128 f->distCoeff[x + y*f->distStride]= (int)(d*(1<<10) + 0.5);
00129
00130
00131 }
00132 }
00133 sws_freeVec(vec);
00134
00135 return 0;
00136 }
00137
00138 static int config(struct vf_instance *vf,
00139 int width, int height, int d_width, int d_height,
00140 unsigned int flags, unsigned int outfmt){
00141
00142 int sw, sh;
00143
00144 allocStuff(&vf->priv->luma, width, height);
00145
00146 getSubSampleFactors(&sw, &sh, outfmt);
00147 allocStuff(&vf->priv->chroma, width>>sw, height>>sh);
00148
00149 return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
00150 }
00151
00152 static void freeBuffers(FilterParam *f){
00153 if(f->preFilterContext) sws_freeContext(f->preFilterContext);
00154 f->preFilterContext=NULL;
00155
00156 av_free(f->preFilterBuf);
00157 f->preFilterBuf=NULL;
00158
00159 av_free(f->distCoeff);
00160 f->distCoeff=NULL;
00161 }
00162
00163 static void uninit(struct vf_instance *vf){
00164 if(!vf->priv) return;
00165
00166 freeBuffers(&vf->priv->luma);
00167 freeBuffers(&vf->priv->chroma);
00168
00169 free(vf->priv);
00170 vf->priv=NULL;
00171 }
00172
00173 static inline void blur(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride, FilterParam *fp){
00174 int x, y;
00175 FilterParam f= *fp;
00176 const int radius= f.distWidth/2;
00177 const uint8_t* const srcArray[MP_MAX_PLANES] = {src};
00178 uint8_t *dstArray[MP_MAX_PLANES]= {f.preFilterBuf};
00179 int srcStrideArray[MP_MAX_PLANES]= {srcStride};
00180 int dstStrideArray[MP_MAX_PLANES]= {f.preFilterStride};
00181
00182
00183 sws_scale(f.preFilterContext, srcArray, srcStrideArray, 0, h, dstArray, dstStrideArray);
00184
00185 for(y=0; y<h; y++){
00186 for(x=0; x<w; x++){
00187 int sum=0;
00188 int div=0;
00189 int dy;
00190 const int preVal= f.preFilterBuf[x + y*f.preFilterStride];
00191 #if 0
00192 const int srcVal= src[x + y*srcStride];
00193 if((x/32)&1){
00194 dst[x + y*dstStride]= srcVal;
00195 if(y%32==0) dst[x + y*dstStride]= 0;
00196 continue;
00197 }
00198 #endif
00199 if(x >= radius && x < w - radius){
00200 for(dy=0; dy<radius*2+1; dy++){
00201 int dx;
00202 int iy= y+dy - radius;
00203 if (iy<0) iy= -iy;
00204 else if(iy>=h) iy= h+h-iy-1;
00205
00206 for(dx=0; dx<radius*2+1; dx++){
00207 const int ix= x+dx - radius;
00208 int factor;
00209
00210 factor= f.colorDiffCoeff[256+preVal - f.preFilterBuf[ix + iy*f.preFilterStride] ]
00211 *f.distCoeff[dx + dy*f.distStride];
00212 sum+= src[ix + iy*srcStride] *factor;
00213 div+= factor;
00214 }
00215 }
00216 }else{
00217 for(dy=0; dy<radius*2+1; dy++){
00218 int dx;
00219 int iy= y+dy - radius;
00220 if (iy<0) iy= -iy;
00221 else if(iy>=h) iy= h+h-iy-1;
00222
00223 for(dx=0; dx<radius*2+1; dx++){
00224 int ix= x+dx - radius;
00225 int factor;
00226 if (ix<0) ix= -ix;
00227 else if(ix>=w) ix= w+w-ix-1;
00228
00229 factor= f.colorDiffCoeff[256+preVal - f.preFilterBuf[ix + iy*f.preFilterStride] ]
00230 *f.distCoeff[dx + dy*f.distStride];
00231 sum+= src[ix + iy*srcStride] *factor;
00232 div+= factor;
00233 }
00234 }
00235 }
00236 dst[x + y*dstStride]= (sum + div/2)/div;
00237 }
00238 }
00239 }
00240
00241 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
00242 int cw= mpi->w >> mpi->chroma_x_shift;
00243 int ch= mpi->h >> mpi->chroma_y_shift;
00244
00245 mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt,
00246 MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
00247 mpi->w,mpi->h);
00248
00249 assert(mpi->flags&MP_IMGFLAG_PLANAR);
00250
00251 blur(dmpi->planes[0], mpi->planes[0], mpi->w,mpi->h, dmpi->stride[0], mpi->stride[0], &vf->priv->luma);
00252 blur(dmpi->planes[1], mpi->planes[1], cw , ch , dmpi->stride[1], mpi->stride[1], &vf->priv->chroma);
00253 blur(dmpi->planes[2], mpi->planes[2], cw , ch , dmpi->stride[2], mpi->stride[2], &vf->priv->chroma);
00254
00255 return vf_next_put_image(vf,dmpi, pts);
00256 }
00257
00258
00259
00260 static int query_format(struct vf_instance *vf, unsigned int fmt){
00261 switch(fmt)
00262 {
00263 case IMGFMT_YV12:
00264 case IMGFMT_I420:
00265 case IMGFMT_IYUV:
00266 case IMGFMT_YVU9:
00267 case IMGFMT_444P:
00268 case IMGFMT_422P:
00269 case IMGFMT_411P:
00270 return vf_next_query_format(vf, fmt);
00271 }
00272 return 0;
00273 }
00274
00275 static int vf_open(vf_instance_t *vf, char *args){
00276 int e;
00277
00278 vf->config=config;
00279 vf->put_image=put_image;
00280
00281 vf->query_format=query_format;
00282 vf->uninit=uninit;
00283 vf->priv=malloc(sizeof(struct vf_priv_s));
00284 memset(vf->priv, 0, sizeof(struct vf_priv_s));
00285
00286 if(args==NULL) return 0;
00287
00288 e=sscanf(args, "%f:%f:%f:%f:%f:%f",
00289 &vf->priv->luma.radius,
00290 &vf->priv->luma.preFilterRadius,
00291 &vf->priv->luma.strength,
00292 &vf->priv->chroma.radius,
00293 &vf->priv->chroma.preFilterRadius,
00294 &vf->priv->chroma.strength
00295 );
00296
00297 vf->priv->luma.quality = vf->priv->chroma.quality= 3.0;
00298
00299 if(e==3){
00300 vf->priv->chroma.radius= vf->priv->luma.radius;
00301 vf->priv->chroma.preFilterRadius = vf->priv->luma.preFilterRadius;
00302 vf->priv->chroma.strength= vf->priv->luma.strength;
00303 }else if(e!=6)
00304 return 0;
00305
00306
00307
00308
00309 return 1;
00310 }
00311
00312 const vf_info_t vf_info_sab = {
00313 "shape adaptive blur",
00314 "sab",
00315 "Michael Niedermayer",
00316 "",
00317 vf_open,
00318 NULL
00319 };
00320
00321