FFmpeg
vf_unsharp.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2002 Remi Guyomarch <rguyom@pobox.com>
3  *
4  * This file is part of MPlayer.
5  *
6  * MPlayer is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * MPlayer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <inttypes.h>
25 #include <math.h>
26 
27 #include "config.h"
28 #include "mp_msg.h"
29 #include "cpudetect.h"
30 
31 #if HAVE_MALLOC_H
32 #include <malloc.h>
33 #endif
34 
35 #include "img_format.h"
36 #include "mp_image.h"
37 #include "vf.h"
38 #include "libvo/fastmemcpy.h"
39 #include "libavutil/common.h"
40 
41 //===========================================================================//
42 
43 #define MIN_MATRIX_SIZE 3
44 #define MAX_MATRIX_SIZE 63
45 
46 typedef struct FilterParam {
47  int msizeX, msizeY;
48  double amount;
49  uint32_t *SC[MAX_MATRIX_SIZE-1];
50 } FilterParam;
51 
52 struct vf_priv_s {
55  unsigned int outfmt;
56 };
57 
58 
59 //===========================================================================//
60 
61 /* This code is based on :
62 
63 An Efficient algorithm for Gaussian blur using finite-state machines
64 Frederick M. Waltz and John W. V. Miller
65 
66 SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII
67 Originally published Boston, Nov 98
68 
69 */
70 
71 static void unsharp( uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp ) {
72 
73  uint32_t **SC = fp->SC;
74  uint32_t SR[MAX_MATRIX_SIZE-1], Tmp1, Tmp2;
75  uint8_t* src2 = src; // avoid gcc warning
76 
77  int32_t res;
78  int x, y, z;
79  int amount = fp->amount * 65536.0;
80  int stepsX = fp->msizeX/2;
81  int stepsY = fp->msizeY/2;
82  int scalebits = (stepsX+stepsY)*2;
83  int32_t halfscale = 1 << ((stepsX+stepsY)*2-1);
84 
85  if( !fp->amount ) {
86  if( src == dst )
87  return;
88  if( dstStride == srcStride )
89  fast_memcpy( dst, src, srcStride*height );
90  else
91  for( y=0; y<height; y++, dst+=dstStride, src+=srcStride )
92  fast_memcpy( dst, src, width );
93  return;
94  }
95 
96  for( y=0; y<2*stepsY; y++ )
97  memset( SC[y], 0, sizeof(SC[y][0]) * (width+2*stepsX) );
98 
99  for( y=-stepsY; y<height+stepsY; y++ ) {
100  if( y < height ) src2 = src;
101  memset( SR, 0, sizeof(SR[0]) * (2*stepsX-1) );
102  for( x=-stepsX; x<width+stepsX; x++ ) {
103  Tmp1 = x<=0 ? src2[0] : x>=width ? src2[width-1] : src2[x];
104  for( z=0; z<stepsX*2; z+=2 ) {
105  Tmp2 = SR[z+0] + Tmp1; SR[z+0] = Tmp1;
106  Tmp1 = SR[z+1] + Tmp2; SR[z+1] = Tmp2;
107  }
108  for( z=0; z<stepsY*2; z+=2 ) {
109  Tmp2 = SC[z+0][x+stepsX] + Tmp1; SC[z+0][x+stepsX] = Tmp1;
110  Tmp1 = SC[z+1][x+stepsX] + Tmp2; SC[z+1][x+stepsX] = Tmp2;
111  }
112  if( x>=stepsX && y>=stepsY ) {
113  uint8_t* srx = src - stepsY*srcStride + x - stepsX;
114  uint8_t* dsx = dst - stepsY*dstStride + x - stepsX;
115 
116  res = (int32_t)*srx + ( ( ( (int32_t)*srx - (int32_t)((Tmp1+halfscale) >> scalebits) ) * amount ) >> 16 );
117  *dsx = res>255 ? 255 : res<0 ? 0 : (uint8_t)res;
118  }
119  }
120  if( y >= 0 ) {
121  dst += dstStride;
122  src += srcStride;
123  }
124  }
125 }
126 
127 //===========================================================================//
128 
129 static int config( struct vf_instance *vf,
130  int width, int height, int d_width, int d_height,
131  unsigned int flags, unsigned int outfmt ) {
132 
133  int z, stepsX, stepsY;
134  FilterParam *fp;
135  const char *effect;
136 
137  // allocate buffers
138 
139  fp = &vf->priv->lumaParam;
140  effect = fp->amount == 0 ? "don't touch" : fp->amount < 0 ? "blur" : "sharpen";
141  ff_mp_msg( MSGT_VFILTER, MSGL_INFO, "unsharp: %dx%d:%0.2f (%s luma) \n", fp->msizeX, fp->msizeY, fp->amount, effect );
142  memset( fp->SC, 0, sizeof( fp->SC ) );
143  stepsX = fp->msizeX/2;
144  stepsY = fp->msizeY/2;
145  for( z=0; z<2*stepsY; z++ )
146  fp->SC[z] = av_malloc(sizeof(*(fp->SC[z])) * (width+2*stepsX));
147 
148  fp = &vf->priv->chromaParam;
149  effect = fp->amount == 0 ? "don't touch" : fp->amount < 0 ? "blur" : "sharpen";
150  ff_mp_msg( MSGT_VFILTER, MSGL_INFO, "unsharp: %dx%d:%0.2f (%s chroma)\n", fp->msizeX, fp->msizeY, fp->amount, effect );
151  memset( fp->SC, 0, sizeof( fp->SC ) );
152  stepsX = fp->msizeX/2;
153  stepsY = fp->msizeY/2;
154  for( z=0; z<2*stepsY; z++ )
155  fp->SC[z] = av_malloc(sizeof(*(fp->SC[z])) * (width+2*stepsX));
156 
157  return ff_vf_next_config( vf, width, height, d_width, d_height, flags, outfmt );
158 }
159 
160 //===========================================================================//
161 
162 static void get_image( struct vf_instance *vf, mp_image_t *mpi ) {
163  if( mpi->flags & MP_IMGFLAG_PRESERVE )
164  return; // don't change
165  if( mpi->imgfmt!=vf->priv->outfmt )
166  return; // colorspace differ
167 
168  mpi->priv =
169  vf->dmpi = ff_vf_get_image( vf->next, mpi->imgfmt, mpi->type, mpi->flags, mpi->width, mpi->height );
170  mpi->planes[0] = vf->dmpi->planes[0];
171  mpi->stride[0] = vf->dmpi->stride[0];
172  mpi->width = vf->dmpi->width;
173  if( mpi->flags & MP_IMGFLAG_PLANAR ) {
174  mpi->planes[1] = vf->dmpi->planes[1];
175  mpi->planes[2] = vf->dmpi->planes[2];
176  mpi->stride[1] = vf->dmpi->stride[1];
177  mpi->stride[2] = vf->dmpi->stride[2];
178  }
179  mpi->flags |= MP_IMGFLAG_DIRECT;
180 }
181 
182 static int put_image( struct vf_instance *vf, mp_image_t *mpi, double pts) {
183  mp_image_t *dmpi = mpi->priv;
184  mpi->priv = NULL;
185 
186  if( !(mpi->flags & MP_IMGFLAG_DIRECT) )
187  // no DR, so get a new image! hope we'll get DR buffer:
189 
190  unsharp( dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, &vf->priv->lumaParam );
191  unsharp( dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, &vf->priv->chromaParam );
192  unsharp( dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, &vf->priv->chromaParam );
193 
194  ff_vf_clone_mpi_attributes(dmpi, mpi);
195 
196 #if HAVE_MMX
197  if(ff_gCpuCaps.hasMMX)
198  __asm__ volatile ("emms\n\t");
199 #endif
200 #if HAVE_MMX2
201  if(ff_gCpuCaps.hasMMX2)
202  __asm__ volatile ("sfence\n\t");
203 #endif
204 
205  return ff_vf_next_put_image( vf, dmpi, pts);
206 }
207 
208 static void uninit( struct vf_instance *vf ) {
209  unsigned int z;
210  FilterParam *fp;
211 
212  if( !vf->priv ) return;
213 
214  fp = &vf->priv->lumaParam;
215  for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
216  av_free( fp->SC[z] );
217  fp->SC[z] = NULL;
218  }
219  fp = &vf->priv->chromaParam;
220  for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
221  av_free( fp->SC[z] );
222  fp->SC[z] = NULL;
223  }
224 
225  free( vf->priv );
226  vf->priv = NULL;
227 }
228 
229 //===========================================================================//
230 
231 static int query_format( struct vf_instance *vf, unsigned int fmt ) {
232  switch(fmt) {
233  case IMGFMT_YV12:
234  case IMGFMT_I420:
235  case IMGFMT_IYUV:
236  return ff_vf_next_query_format( vf, vf->priv->outfmt );
237  }
238  return 0;
239 }
240 
241 //===========================================================================//
242 
243 static void parse( FilterParam *fp, char* args ) {
244 
245  // l7x5:0.8:c3x3:-0.2
246 
247  char *z;
248  char *pos = args;
249  char *max = args + strlen(args);
250 
251  // parse matrix sizes
252  fp->msizeX = ( pos && pos+1<max ) ? atoi( pos+1 ) : 0;
253  z = strchr( pos+1, 'x' );
254  fp->msizeY = ( z && z+1<max ) ? atoi( pos=z+1 ) : fp->msizeX;
255 
256  // min/max & odd
257  fp->msizeX = 1 | av_clip(fp->msizeX, MIN_MATRIX_SIZE, MAX_MATRIX_SIZE);
258  fp->msizeY = 1 | av_clip(fp->msizeY, MIN_MATRIX_SIZE, MAX_MATRIX_SIZE);
259 
260  // parse amount
261  pos = strchr( pos+1, ':' );
262  fp->amount = ( pos && pos+1<max ) ? atof( pos+1 ) : 0;
263 }
264 
265 //===========================================================================//
266 
267 static const unsigned int fmt_list[] = {
268  IMGFMT_YV12,
269  IMGFMT_I420,
270  IMGFMT_IYUV,
271  0
272 };
273 
274 static int vf_open( vf_instance_t *vf, char *args ) {
275  vf->config = config;
276  vf->put_image = put_image;
277  vf->get_image = get_image;
279  vf->uninit = uninit;
280  vf->priv = malloc( sizeof(struct vf_priv_s) );
281  memset( vf->priv, 0, sizeof(struct vf_priv_s) );
282 
283  if( args ) {
284  char *args2 = strchr( args, 'l' );
285  if( args2 )
286  parse( &vf->priv->lumaParam, args2 );
287  else {
288  vf->priv->lumaParam.amount =
289  vf->priv->lumaParam.msizeX =
290  vf->priv->lumaParam.msizeY = 0;
291  }
292 
293  args2 = strchr( args, 'c' );
294  if( args2 )
295  parse( &vf->priv->chromaParam, args2 );
296  else {
297  vf->priv->chromaParam.amount =
298  vf->priv->chromaParam.msizeX =
299  vf->priv->chromaParam.msizeY = 0;
300  }
301 
302  if( !vf->priv->lumaParam.msizeX && !vf->priv->chromaParam.msizeX )
303  return 0; // nothing to do
304  }
305 
306  // check csp:
308  if( !vf->priv->outfmt ) {
309  uninit( vf );
310  return 0; // no csp match :(
311  }
312 
313  return 1;
314 }
315 
317  "unsharp mask & gaussian blur",
318  "unsharp",
319  "Remi Guyomarch",
320  "",
321  vf_open,
322  NULL
323 };
324 
325 //===========================================================================//