fix
[mplayer/glamo.git] / libmpcodecs / vf_unsharp.c
blobf04647e796074f01ed3169ec364696905a963d49
1 /*
2 Copyright (C) 2002 Rémi Guyomarch <rguyom@pobox.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <inttypes.h>
24 #include <math.h>
26 #include "config.h"
27 #include "mp_msg.h"
28 #include "cpudetect.h"
30 #ifdef HAVE_MALLOC_H
31 #include <malloc.h>
32 #endif
34 #include "img_format.h"
35 #include "mp_image.h"
36 #include "vf.h"
37 #include "libvo/fastmemcpy.h"
39 #ifndef MIN
40 #define MIN(a,b) (((a)<(b))?(a):(b))
41 #endif
42 #ifndef MAX
43 #define MAX(a,b) (((a)>(b))?(a):(b))
44 #endif
46 //===========================================================================//
48 #define MIN_MATRIX_SIZE 3
49 #define MAX_MATRIX_SIZE 63
51 typedef struct FilterParam {
52 int msizeX, msizeY;
53 double amount;
54 uint32_t *SC[MAX_MATRIX_SIZE-1];
55 } FilterParam;
57 struct vf_priv_s {
58 FilterParam lumaParam;
59 FilterParam chromaParam;
60 unsigned int outfmt;
64 //===========================================================================//
66 /* This code is based on :
68 An Efficient algorithm for Gaussian blur using finite-state machines
69 Frederick M. Waltz and John W. V. Miller
71 SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII
72 Originally published Boston, Nov 98
76 static void unsharp( uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp ) {
78 uint32_t **SC = fp->SC;
79 uint32_t SR[MAX_MATRIX_SIZE-1], Tmp1, Tmp2;
80 uint8_t* src2 = src; // avoid gcc warning
82 int32_t res;
83 int x, y, z;
84 int amount = fp->amount * 65536.0;
85 int stepsX = fp->msizeX/2;
86 int stepsY = fp->msizeY/2;
87 int scalebits = (stepsX+stepsY)*2;
88 int32_t halfscale = 1 << ((stepsX+stepsY)*2-1);
90 if( !fp->amount ) {
91 if( src == dst )
92 return;
93 if( dstStride == srcStride )
94 memcpy( dst, src, srcStride*height );
95 else
96 for( y=0; y<height; y++, dst+=dstStride, src+=srcStride )
97 memcpy( dst, src, width );
98 return;
101 for( y=0; y<2*stepsY; y++ )
102 memset( SC[y], 0, sizeof(SC[y][0]) * (width+2*stepsX) );
104 for( y=-stepsY; y<height+stepsY; y++ ) {
105 if( y < height ) src2 = src;
106 memset( SR, 0, sizeof(SR[0]) * (2*stepsX-1) );
107 for( x=-stepsX; x<width+stepsX; x++ ) {
108 Tmp1 = x<=0 ? src2[0] : x>=width ? src2[width-1] : src2[x];
109 for( z=0; z<stepsX*2; z+=2 ) {
110 Tmp2 = SR[z+0] + Tmp1; SR[z+0] = Tmp1;
111 Tmp1 = SR[z+1] + Tmp2; SR[z+1] = Tmp2;
113 for( z=0; z<stepsY*2; z+=2 ) {
114 Tmp2 = SC[z+0][x+stepsX] + Tmp1; SC[z+0][x+stepsX] = Tmp1;
115 Tmp1 = SC[z+1][x+stepsX] + Tmp2; SC[z+1][x+stepsX] = Tmp2;
117 if( x>=stepsX && y>=stepsY ) {
118 uint8_t* srx = src - stepsY*srcStride + x - stepsX;
119 uint8_t* dsx = dst - stepsY*dstStride + x - stepsX;
121 res = (int32_t)*srx + ( ( ( (int32_t)*srx - (int32_t)((Tmp1+halfscale) >> scalebits) ) * amount ) >> 16 );
122 *dsx = res>255 ? 255 : res<0 ? 0 : (uint8_t)res;
125 if( y >= 0 ) {
126 dst += dstStride;
127 src += srcStride;
132 //===========================================================================//
134 static int config( struct vf_instance_s* vf,
135 int width, int height, int d_width, int d_height,
136 unsigned int flags, unsigned int outfmt ) {
138 int z, stepsX, stepsY;
139 FilterParam *fp;
140 char *effect;
142 // allocate buffers
144 fp = &vf->priv->lumaParam;
145 effect = fp->amount == 0 ? "don't touch" : fp->amount < 0 ? "blur" : "sharpen";
146 mp_msg( MSGT_VFILTER, MSGL_INFO, "unsharp: %dx%d:%0.2f (%s luma) \n", fp->msizeX, fp->msizeY, fp->amount, effect );
147 memset( fp->SC, 0, sizeof( fp->SC ) );
148 stepsX = fp->msizeX/2;
149 stepsY = fp->msizeY/2;
150 for( z=0; z<2*stepsY; z++ )
151 fp->SC[z] = memalign( 16, sizeof(*(fp->SC[z])) * (width+2*stepsX) );
153 fp = &vf->priv->chromaParam;
154 effect = fp->amount == 0 ? "don't touch" : fp->amount < 0 ? "blur" : "sharpen";
155 mp_msg( MSGT_VFILTER, MSGL_INFO, "unsharp: %dx%d:%0.2f (%s chroma)\n", fp->msizeX, fp->msizeY, fp->amount, effect );
156 memset( fp->SC, 0, sizeof( fp->SC ) );
157 stepsX = fp->msizeX/2;
158 stepsY = fp->msizeY/2;
159 for( z=0; z<2*stepsY; z++ )
160 fp->SC[z] = memalign( 16, sizeof(*(fp->SC[z])) * (width+2*stepsX) );
162 return vf_next_config( vf, width, height, d_width, d_height, flags, outfmt );
165 //===========================================================================//
167 static void get_image( struct vf_instance_s* vf, mp_image_t *mpi ) {
168 if( mpi->flags & MP_IMGFLAG_PRESERVE )
169 return; // don't change
170 if( mpi->imgfmt!=vf->priv->outfmt )
171 return; // colorspace differ
173 vf->dmpi = vf_get_image( vf->next, mpi->imgfmt, mpi->type, mpi->flags, mpi->w, mpi->h );
174 mpi->planes[0] = vf->dmpi->planes[0];
175 mpi->stride[0] = vf->dmpi->stride[0];
176 mpi->width = vf->dmpi->width;
177 if( mpi->flags & MP_IMGFLAG_PLANAR ) {
178 mpi->planes[1] = vf->dmpi->planes[1];
179 mpi->planes[2] = vf->dmpi->planes[2];
180 mpi->stride[1] = vf->dmpi->stride[1];
181 mpi->stride[2] = vf->dmpi->stride[2];
183 mpi->flags |= MP_IMGFLAG_DIRECT;
186 static int put_image( struct vf_instance_s* vf, mp_image_t *mpi ) {
187 mp_image_t *dmpi;
189 if( !(mpi->flags & MP_IMGFLAG_DIRECT) )
190 // no DR, so get a new image! hope we'll get DR buffer:
191 vf->dmpi = vf_get_image( vf->next,vf->priv->outfmt, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, mpi->w, mpi->h);
192 dmpi= vf->dmpi;
194 unsharp( dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, &vf->priv->lumaParam );
195 unsharp( dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, &vf->priv->chromaParam );
196 unsharp( dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, &vf->priv->chromaParam );
198 vf_clone_mpi_attributes(dmpi, mpi);
200 #ifdef HAVE_MMX
201 if(gCpuCaps.hasMMX)
202 asm volatile ("emms\n\t");
203 #endif
204 #ifdef HAVE_MMX2
205 if(gCpuCaps.hasMMX2)
206 asm volatile ("sfence\n\t");
207 #endif
209 return vf_next_put_image( vf, dmpi );
212 static void uninit( struct vf_instance_s* vf ) {
213 unsigned int z;
214 FilterParam *fp;
216 if( !vf->priv ) return;
218 fp = &vf->priv->lumaParam;
219 for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
220 if( fp->SC[z] ) free( fp->SC[z] );
221 fp->SC[z] = NULL;
223 fp = &vf->priv->chromaParam;
224 for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
225 if( fp->SC[z] ) free( fp->SC[z] );
226 fp->SC[z] = NULL;
229 free( vf->priv );
230 vf->priv = NULL;
233 //===========================================================================//
235 static int query_format( struct vf_instance_s* vf, unsigned int fmt ) {
236 switch(fmt) {
237 case IMGFMT_YV12:
238 case IMGFMT_I420:
239 case IMGFMT_IYUV:
240 return vf_next_query_format( vf, vf->priv->outfmt );
242 return 0;
245 //===========================================================================//
247 static void parse( FilterParam *fp, char* args ) {
249 // l7x5:0.8:c3x3:-0.2
251 char *z;
252 char *pos = args;
253 char *max = args + strlen(args);
255 // parse matrix sizes
256 fp->msizeX = ( pos && pos+1<max ) ? atoi( pos+1 ) : 0;
257 z = strchr( pos+1, 'x' );
258 fp->msizeY = ( z && z+1<max ) ? atoi( pos=z+1 ) : fp->msizeX;
260 // min/max & odd
261 fp->msizeX = 1 | MIN( MAX( fp->msizeX, MIN_MATRIX_SIZE ), MAX_MATRIX_SIZE );
262 fp->msizeY = 1 | MIN( MAX( fp->msizeY, MIN_MATRIX_SIZE ), MAX_MATRIX_SIZE );
264 // parse amount
265 pos = strchr( pos+1, ':' );
266 fp->amount = ( pos && pos+1<max ) ? atof( pos+1 ) : 0;
269 //===========================================================================//
271 static unsigned int fmt_list[] = {
272 IMGFMT_YV12,
273 IMGFMT_I420,
274 IMGFMT_IYUV,
278 static int open( vf_instance_t *vf, char* args ) {
279 vf->config = config;
280 vf->put_image = put_image;
281 vf->get_image = get_image;
282 vf->query_format = query_format;
283 vf->uninit = uninit;
284 vf->priv = malloc( sizeof(struct vf_priv_s) );
285 memset( vf->priv, 0, sizeof(struct vf_priv_s) );
287 if( args ) {
288 char *args2 = strchr( args, 'l' );
289 if( args2 )
290 parse( &vf->priv->lumaParam, args2 );
291 else {
292 vf->priv->lumaParam.amount =
293 vf->priv->lumaParam.msizeX =
294 vf->priv->lumaParam.msizeY = 0;
297 args2 = strchr( args, 'c' );
298 if( args2 )
299 parse( &vf->priv->chromaParam, args2 );
300 else {
301 vf->priv->chromaParam.amount =
302 vf->priv->chromaParam.msizeX =
303 vf->priv->chromaParam.msizeY = 0;
306 if( !vf->priv->lumaParam.msizeX && !vf->priv->chromaParam.msizeX )
307 return 0; // nothing to do
310 // check csp:
311 vf->priv->outfmt = vf_match_csp( &vf->next, fmt_list, IMGFMT_YV12 );
312 if( !vf->priv->outfmt ) {
313 uninit( vf );
314 return 0; // no csp match :(
317 return 1;
320 vf_info_t vf_info_unsharp = {
321 "unsharp mask & gaussian blur",
322 "unsharp",
323 "Rémi Guyomarch",
325 open,
326 NULL
329 //===========================================================================//