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