FFmpeg
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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  vf->dmpi = ff_vf_get_image( vf->next, mpi->imgfmt, mpi->type, mpi->flags, mpi->w, mpi->h );
169  mpi->planes[0] = vf->dmpi->planes[0];
170  mpi->stride[0] = vf->dmpi->stride[0];
171  mpi->width = vf->dmpi->width;
172  if( mpi->flags & MP_IMGFLAG_PLANAR ) {
173  mpi->planes[1] = vf->dmpi->planes[1];
174  mpi->planes[2] = vf->dmpi->planes[2];
175  mpi->stride[1] = vf->dmpi->stride[1];
176  mpi->stride[2] = vf->dmpi->stride[2];
177  }
178  mpi->flags |= MP_IMGFLAG_DIRECT;
179 }
180 
181 static int put_image( struct vf_instance *vf, mp_image_t *mpi, double pts) {
182  mp_image_t *dmpi;
183 
184  if( !(mpi->flags & MP_IMGFLAG_DIRECT) )
185  // no DR, so get a new image! hope we'll get DR buffer:
186  vf->dmpi = ff_vf_get_image( vf->next,vf->priv->outfmt, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, mpi->w, mpi->h);
187  dmpi= vf->dmpi;
188 
189  unsharp( dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, &vf->priv->lumaParam );
190  unsharp( dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, &vf->priv->chromaParam );
191  unsharp( dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, &vf->priv->chromaParam );
192 
193  ff_vf_clone_mpi_attributes(dmpi, mpi);
194 
195 #if HAVE_MMX
196  if(ff_gCpuCaps.hasMMX)
197  __asm__ volatile ("emms\n\t");
198 #endif
199 #if HAVE_MMX2
200  if(ff_gCpuCaps.hasMMX2)
201  __asm__ volatile ("sfence\n\t");
202 #endif
203 
204  return ff_vf_next_put_image( vf, dmpi, pts);
205 }
206 
207 static void uninit( struct vf_instance *vf ) {
208  unsigned int z;
209  FilterParam *fp;
210 
211  if( !vf->priv ) return;
212 
213  fp = &vf->priv->lumaParam;
214  for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
215  av_free( fp->SC[z] );
216  fp->SC[z] = NULL;
217  }
218  fp = &vf->priv->chromaParam;
219  for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
220  av_free( fp->SC[z] );
221  fp->SC[z] = NULL;
222  }
223 
224  free( vf->priv );
225  vf->priv = NULL;
226 }
227 
228 //===========================================================================//
229 
230 static int query_format( struct vf_instance *vf, unsigned int fmt ) {
231  switch(fmt) {
232  case IMGFMT_YV12:
233  case IMGFMT_I420:
234  case IMGFMT_IYUV:
235  return ff_vf_next_query_format( vf, vf->priv->outfmt );
236  }
237  return 0;
238 }
239 
240 //===========================================================================//
241 
242 static void parse( FilterParam *fp, char* args ) {
243 
244  // l7x5:0.8:c3x3:-0.2
245 
246  char *z;
247  char *pos = args;
248  char *max = args + strlen(args);
249 
250  // parse matrix sizes
251  fp->msizeX = ( pos && pos+1<max ) ? atoi( pos+1 ) : 0;
252  z = strchr( pos+1, 'x' );
253  fp->msizeY = ( z && z+1<max ) ? atoi( pos=z+1 ) : fp->msizeX;
254 
255  // min/max & odd
256  fp->msizeX = 1 | av_clip(fp->msizeX, MIN_MATRIX_SIZE, MAX_MATRIX_SIZE);
257  fp->msizeY = 1 | av_clip(fp->msizeY, MIN_MATRIX_SIZE, MAX_MATRIX_SIZE);
258 
259  // parse amount
260  pos = strchr( pos+1, ':' );
261  fp->amount = ( pos && pos+1<max ) ? atof( pos+1 ) : 0;
262 }
263 
264 //===========================================================================//
265 
266 static const unsigned int fmt_list[] = {
267  IMGFMT_YV12,
268  IMGFMT_I420,
269  IMGFMT_IYUV,
270  0
271 };
272 
273 static int vf_open( vf_instance_t *vf, char *args ) {
274  vf->config = config;
275  vf->put_image = put_image;
276  vf->get_image = get_image;
278  vf->uninit = uninit;
279  vf->priv = malloc( sizeof(struct vf_priv_s) );
280  memset( vf->priv, 0, sizeof(struct vf_priv_s) );
281 
282  if( args ) {
283  char *args2 = strchr( args, 'l' );
284  if( args2 )
285  parse( &vf->priv->lumaParam, args2 );
286  else {
287  vf->priv->lumaParam.amount =
288  vf->priv->lumaParam.msizeX =
289  vf->priv->lumaParam.msizeY = 0;
290  }
291 
292  args2 = strchr( args, 'c' );
293  if( args2 )
294  parse( &vf->priv->chromaParam, args2 );
295  else {
296  vf->priv->chromaParam.amount =
297  vf->priv->chromaParam.msizeX =
298  vf->priv->chromaParam.msizeY = 0;
299  }
300 
301  if( !vf->priv->lumaParam.msizeX && !vf->priv->chromaParam.msizeX )
302  return 0; // nothing to do
303  }
304 
305  // check csp:
307  if( !vf->priv->outfmt ) {
308  uninit( vf );
309  return 0; // no csp match :(
310  }
311 
312  return 1;
313 }
314 
316  "unsharp mask & gaussian blur",
317  "unsharp",
318  "Remi Guyomarch",
319  "",
320  vf_open,
321  NULL
322 };
323 
324 //===========================================================================//