comparison libmpcodecs/vf_unsharp.c @ 7966:a03235a5f395

new video filter: unsharp - does image (l/c/l+c) sharping/bluring by R«±mi Guyomarch <rguyom@pobox.com>
author arpi
date Tue, 29 Oct 2002 22:37:11 +0000
parents
children 403f7a58ccf2
comparison
equal deleted inserted replaced
7965:af50b41f0af8 7966:a03235a5f395
1 /*
2 Copyright (C) 2002 Rémi Guyomarch <rguyom@pobox.com>
3
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.
8
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.
13
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
17
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <inttypes.h>
24 #include <math.h>
25
26 #include "../config.h"
27 #include "../mp_msg.h"
28 #include "../cpudetect.h"
29
30 #ifdef HAVE_MALLOC_H
31 #include <malloc.h>
32 #endif
33
34 #include "img_format.h"
35 #include "mp_image.h"
36 #include "vf.h"
37 #include "../libvo/fastmemcpy.h"
38
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
45
46 //===========================================================================//
47
48 #define MIN_MATRIX_SIZE 3
49 #define MAX_MATRIX_SIZE 63
50
51 typedef struct FilterParam {
52 int msizeX, msizeY;
53 double amount;
54 uint32_t *SC[MAX_MATRIX_SIZE-1];
55 } FilterParam;
56
57 struct vf_priv_s {
58 FilterParam lumaParam;
59 FilterParam chromaParam;
60 mp_image_t *dmpi;
61 unsigned int outfmt;
62 };
63
64
65 //===========================================================================//
66
67 /* This code is based on :
68
69 An Efficient algorithm for Gaussian blur using finite-state machines
70 Frederick M. Waltz and John W. V. Miller
71
72 SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII
73 Originally published Boston, Nov 98
74
75 */
76
77 static void unsharp( uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp ) {
78
79 uint32_t **SC = fp->SC;
80 uint32_t SR[MAX_MATRIX_SIZE-1], Tmp1, Tmp2;
81 uint8_t* src2 = src; // avoid gcc warning
82
83 int32_t res;
84 int x, y, z;
85 int amount = fp->amount * 65536.0;
86 int stepsX = fp->msizeX/2;
87 int stepsY = fp->msizeY/2;
88 int scalebits = (stepsX+stepsY)*2;
89 int32_t halfscale = 1 << (stepsX+stepsY);
90
91 if( !fp->amount ) {
92 if( src == dst )
93 return;
94 if( dstStride == srcStride )
95 memcpy( dst, src, srcStride*height );
96 else
97 for( y=0; y<height; y++, dst+=dstStride, src+=srcStride )
98 memcpy( dst, src, width );
99 return;
100 }
101
102 for( y=0; y<2*stepsY; y++ )
103 memset( SC[y], 0, sizeof(SC[y][0]) * (width+2*stepsX) );
104
105 for( y=-stepsY; y<height+stepsY; y++ ) {
106 if( y < height ) src2 = src;
107 memset( SR, 0, sizeof(SR[0]) * (2*stepsX-1) );
108 for( x=-stepsX; x<width+stepsX; x++ ) {
109 Tmp1 = x<=0 ? src2[0] : x>=width ? src2[width-1] : src2[x];
110 for( z=0; z<stepsX*2; z+=2 ) {
111 Tmp2 = SR[z+0] + Tmp1; SR[z+0] = Tmp1;
112 Tmp1 = SR[z+1] + Tmp2; SR[z+1] = Tmp2;
113 }
114 for( z=0; z<stepsY*2; z+=2 ) {
115 Tmp2 = SC[z+0][x+stepsX] + Tmp1; SC[z+0][x+stepsX] = Tmp1;
116 Tmp1 = SC[z+1][x+stepsX] + Tmp2; SC[z+1][x+stepsX] = Tmp2;
117 }
118 if( x>=stepsX && y>=stepsY ) {
119 uint8_t* srx = src - stepsY*srcStride + x - stepsX;
120 uint8_t* dsx = dst - stepsY*dstStride + x - stepsX;
121
122 res = (int32_t)*srx + ( ( ( (int32_t)*srx - (int32_t)((Tmp1+halfscale) >> scalebits) ) * amount ) >> 16 );
123 *dsx = res>255 ? 255 : res<0 ? 0 : (uint8_t)res;
124 }
125 }
126 if( y >= 0 ) {
127 dst += dstStride;
128 src += srcStride;
129 }
130 }
131 }
132
133 //===========================================================================//
134
135 static int config( struct vf_instance_s* vf,
136 int width, int height, int d_width, int d_height,
137 unsigned int flags, unsigned int outfmt ) {
138
139 int z, stepsX, stepsY;
140 FilterParam *fp;
141
142 // allocate buffers
143
144 fp = &vf->priv->lumaParam;
145 mp_msg( MSGT_VFILTER, MSGL_INFO, "unsharp: %dx%d:%0.2f (luma) \n", fp->msizeX, fp->msizeY, fp->amount );
146 memset( fp->SC, 0, sizeof( fp->SC ) );
147 stepsX = fp->msizeX/2;
148 stepsY = fp->msizeY/2;
149 for( z=0; z<2*stepsY; z++ )
150 fp->SC[z] = memalign( 16, sizeof(*(fp->SC[z])) * (width+2*stepsX) );
151
152 fp = &vf->priv->chromaParam;
153 mp_msg( MSGT_VFILTER, MSGL_INFO, "unsharp: %dx%d:%0.2f (chroma)\n", fp->msizeX, fp->msizeY, fp->amount );
154 memset( fp->SC, 0, sizeof( fp->SC ) );
155 stepsX = fp->msizeX/2;
156 stepsY = fp->msizeY/2;
157 for( z=0; z<2*stepsY; z++ )
158 fp->SC[z] = memalign( 16, sizeof(*(fp->SC[z])) * (width+2*stepsX) );
159
160 return vf_next_config( vf, width, height, d_width, d_height, flags, outfmt );
161 }
162
163 //===========================================================================//
164
165 static void get_image( struct vf_instance_s* vf, mp_image_t *mpi ) {
166 if( mpi->flags & MP_IMGFLAG_PRESERVE )
167 return; // don't change
168 if( mpi->imgfmt!=vf->priv->outfmt )
169 return; // colorspace differ
170
171 vf->priv->dmpi = vf_get_image( vf->next, mpi->imgfmt, mpi->type, mpi->flags, mpi->w, mpi->h );
172 mpi->planes[0] = vf->priv->dmpi->planes[0];
173 mpi->stride[0] = vf->priv->dmpi->stride[0];
174 mpi->width = vf->priv->dmpi->width;
175 if( mpi->flags & MP_IMGFLAG_PLANAR ) {
176 mpi->planes[1] = vf->priv->dmpi->planes[1];
177 mpi->planes[2] = vf->priv->dmpi->planes[2];
178 mpi->stride[1] = vf->priv->dmpi->stride[1];
179 mpi->stride[2] = vf->priv->dmpi->stride[2];
180 }
181 mpi->flags |= MP_IMGFLAG_DIRECT;
182 }
183
184 static int put_image( struct vf_instance_s* vf, mp_image_t *mpi ) {
185 mp_image_t *dmpi;
186
187 if( !(mpi->flags & MP_IMGFLAG_DIRECT) )
188 // no DR, so get a new image! hope we'll get DR buffer:
189 vf->priv->dmpi = vf_get_image( vf->next,vf->priv->outfmt, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, mpi->w, mpi->h);
190 dmpi= vf->priv->dmpi;
191
192 unsharp( dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, &vf->priv->lumaParam );
193 unsharp( dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, &vf->priv->chromaParam );
194 unsharp( dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, &vf->priv->chromaParam );
195
196 dmpi->qscale = mpi->qscale;
197 dmpi->qstride = mpi->qstride;
198
199 #ifdef HAVE_MMX
200 if(gCpuCaps.hasMMX)
201 asm volatile ("emms\n\t");
202 #endif
203 #ifdef HAVE_MMX2
204 if(gCpuCaps.hasMMX2)
205 asm volatile ("sfence\n\t");
206 #endif
207
208 return vf_next_put_image( vf, dmpi );
209 }
210
211 static void uninit( struct vf_instance_s* vf ) {
212 unsigned int z;
213 FilterParam *fp;
214
215 if( !vf->priv ) return;
216
217 fp = &vf->priv->lumaParam;
218 for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
219 if( fp->SC[z] ) free( fp->SC[z] );
220 fp->SC[z] = NULL;
221 }
222 fp = &vf->priv->chromaParam;
223 for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
224 if( fp->SC[z] ) free( fp->SC[z] );
225 fp->SC[z] = NULL;
226 }
227
228 free( vf->priv );
229 vf->priv = NULL;
230 }
231
232 //===========================================================================//
233
234 static int query_format( struct vf_instance_s* vf, unsigned int fmt ) {
235 switch(fmt) {
236 case IMGFMT_YV12:
237 case IMGFMT_I420:
238 case IMGFMT_IYUV:
239 return vf_next_query_format( vf, vf->priv->outfmt );
240 }
241 return 0;
242 }
243
244 //===========================================================================//
245
246 static void parse( FilterParam *fp, char* args ) {
247
248 // l7x5:0.8:c3x3:-0.2
249
250 char *z;
251 char *pos = args;
252 char *max = args + strlen(args);
253
254 // parse matrix sizes
255 fp->msizeX = ( pos && pos+1<max ) ? atoi( pos+1 ) : 0;
256 z = strchr( pos+1, 'x' );
257 fp->msizeY = ( z && z+1<max ) ? atoi( pos=z+1 ) : fp->msizeX;
258
259 // min/max & odd
260 fp->msizeX = 1 | MIN( MAX( fp->msizeX, MIN_MATRIX_SIZE ), MAX_MATRIX_SIZE );
261 fp->msizeY = 1 | MIN( MAX( fp->msizeY, MIN_MATRIX_SIZE ), MAX_MATRIX_SIZE );
262
263 // parse amount
264 pos = strchr( pos+1, ':' );
265 fp->amount = ( pos && pos+1<max ) ? atof( pos+1 ) : 0;
266 }
267
268 //===========================================================================//
269
270 static unsigned int fmt_list[] = {
271 IMGFMT_YV12,
272 IMGFMT_I420,
273 IMGFMT_IYUV,
274 0
275 };
276
277 static int open( vf_instance_t *vf, char* args ) {
278 vf->config = config;
279 vf->put_image = put_image;
280 vf->get_image = get_image;
281 vf->query_format = query_format;
282 vf->uninit = uninit;
283 vf->priv = malloc( sizeof(struct vf_priv_s) );
284 memset( vf->priv, 0, sizeof(struct vf_priv_s) );
285
286 if( args ) {
287 char *args2 = strchr( args, 'l' );
288 if( args2 )
289 parse( &vf->priv->lumaParam, args2 );
290 else {
291 vf->priv->lumaParam.amount =
292 vf->priv->lumaParam.msizeX =
293 vf->priv->lumaParam.msizeY = 0;
294 }
295
296 args2 = strchr( args, 'c' );
297 if( args2 )
298 parse( &vf->priv->chromaParam, args2 );
299 else {
300 vf->priv->chromaParam.amount =
301 vf->priv->chromaParam.msizeX =
302 vf->priv->chromaParam.msizeY = 0;
303 }
304
305 if( !vf->priv->lumaParam.msizeX && !vf->priv->chromaParam.msizeX )
306 return 0; // nothing to do
307 }
308
309 // check csp:
310 vf->priv->outfmt = vf_match_csp( &vf->next, fmt_list, IMGFMT_YV12 );
311 if( !vf->priv->outfmt ) {
312 uninit( vf );
313 return 0; // no csp match :(
314 }
315
316 return 1;
317 }
318
319 vf_info_t vf_info_unsharp = {
320 "unsharp mask",
321 "unsharp",
322 "Rémi Guyomarch",
323 "",
324 open
325 };
326
327 //===========================================================================//