Allocate a larger backbuffer to allow resizing without reinit.
[mplayer/glamo.git] / libmpcodecs / vf_unsharp.c
blobd5deebfafbaa35de60086d4e4c6df76989715c26
1 /*
2 * Copyright (C) 2002 Remi Guyomarch <rguyom@pobox.com>
4 * This file is part of MPlayer.
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.
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.
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.
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <inttypes.h>
25 #include <math.h>
27 #include "config.h"
28 #include "mp_msg.h"
29 #include "cpudetect.h"
31 #ifdef HAVE_MALLOC_H
32 #include <malloc.h>
33 #endif
35 #include "img_format.h"
36 #include "mp_image.h"
37 #include "vf.h"
38 #include "libvo/fastmemcpy.h"
39 #include "libavutil/common.h"
41 //===========================================================================//
43 #define MIN_MATRIX_SIZE 3
44 #define MAX_MATRIX_SIZE 63
46 typedef struct FilterParam {
47 int msizeX, msizeY;
48 double amount;
49 uint32_t *SC[MAX_MATRIX_SIZE-1];
50 } FilterParam;
52 struct vf_priv_s {
53 FilterParam lumaParam;
54 FilterParam chromaParam;
55 unsigned int outfmt;
59 //===========================================================================//
61 /* This code is based on :
63 An Efficient algorithm for Gaussian blur using finite-state machines
64 Frederick M. Waltz and John W. V. Miller
66 SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII
67 Originally published Boston, Nov 98
71 static void unsharp( uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp ) {
73 uint32_t **SC = fp->SC;
74 uint32_t SR[MAX_MATRIX_SIZE-1], Tmp1, Tmp2;
75 uint8_t* src2 = src; // avoid gcc warning
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);
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;
96 for( y=0; y<2*stepsY; y++ )
97 memset( SC[y], 0, sizeof(SC[y][0]) * (width+2*stepsX) );
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;
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;
112 if( x>=stepsX && y>=stepsY ) {
113 uint8_t* srx = src - stepsY*srcStride + x - stepsX;
114 uint8_t* dsx = dst - stepsY*dstStride + x - stepsX;
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;
120 if( y >= 0 ) {
121 dst += dstStride;
122 src += srcStride;
127 //===========================================================================//
129 static int config( struct vf_instance_s* vf,
130 int width, int height, int d_width, int d_height,
131 unsigned int flags, unsigned int outfmt ) {
133 int z, stepsX, stepsY;
134 FilterParam *fp;
135 char *effect;
137 // allocate buffers
139 fp = &vf->priv->lumaParam;
140 effect = fp->amount == 0 ? "don't touch" : fp->amount < 0 ? "blur" : "sharpen";
141 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] = memalign( 16, sizeof(*(fp->SC[z])) * (width+2*stepsX) );
148 fp = &vf->priv->chromaParam;
149 effect = fp->amount == 0 ? "don't touch" : fp->amount < 0 ? "blur" : "sharpen";
150 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] = memalign( 16, sizeof(*(fp->SC[z])) * (width+2*stepsX) );
157 return vf_next_config( vf, width, height, d_width, d_height, flags, outfmt );
160 //===========================================================================//
162 static void get_image( struct vf_instance_s* 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
168 vf->dmpi = 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];
178 mpi->flags |= MP_IMGFLAG_DIRECT;
181 static int put_image( struct vf_instance_s* vf, mp_image_t *mpi, double pts) {
182 mp_image_t *dmpi;
184 if( !(mpi->flags & MP_IMGFLAG_DIRECT) )
185 // no DR, so get a new image! hope we'll get DR buffer:
186 vf->dmpi = vf_get_image( vf->next,vf->priv->outfmt, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, mpi->w, mpi->h);
187 dmpi= vf->dmpi;
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 );
193 vf_clone_mpi_attributes(dmpi, mpi);
195 #if HAVE_MMX
196 if(gCpuCaps.hasMMX)
197 __asm__ volatile ("emms\n\t");
198 #endif
199 #if HAVE_MMX2
200 if(gCpuCaps.hasMMX2)
201 __asm__ volatile ("sfence\n\t");
202 #endif
204 return vf_next_put_image( vf, dmpi, pts);
207 static void uninit( struct vf_instance_s* vf ) {
208 unsigned int z;
209 FilterParam *fp;
211 if( !vf->priv ) return;
213 fp = &vf->priv->lumaParam;
214 for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
215 if( fp->SC[z] ) free( fp->SC[z] );
216 fp->SC[z] = NULL;
218 fp = &vf->priv->chromaParam;
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;
224 free( vf->priv );
225 vf->priv = NULL;
228 //===========================================================================//
230 static int query_format( struct vf_instance_s* vf, unsigned int fmt ) {
231 switch(fmt) {
232 case IMGFMT_YV12:
233 case IMGFMT_I420:
234 case IMGFMT_IYUV:
235 return vf_next_query_format( vf, vf->priv->outfmt );
237 return 0;
240 //===========================================================================//
242 static void parse( FilterParam *fp, char* args ) {
244 // l7x5:0.8:c3x3:-0.2
246 char *z;
247 char *pos = args;
248 char *max = args + strlen(args);
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;
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);
259 // parse amount
260 pos = strchr( pos+1, ':' );
261 fp->amount = ( pos && pos+1<max ) ? atof( pos+1 ) : 0;
264 //===========================================================================//
266 static unsigned int fmt_list[] = {
267 IMGFMT_YV12,
268 IMGFMT_I420,
269 IMGFMT_IYUV,
273 static int open( vf_instance_t *vf, char* args ) {
274 vf->config = config;
275 vf->put_image = put_image;
276 vf->get_image = get_image;
277 vf->query_format = query_format;
278 vf->uninit = uninit;
279 vf->priv = malloc( sizeof(struct vf_priv_s) );
280 memset( vf->priv, 0, sizeof(struct vf_priv_s) );
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;
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;
301 if( !vf->priv->lumaParam.msizeX && !vf->priv->chromaParam.msizeX )
302 return 0; // nothing to do
305 // check csp:
306 vf->priv->outfmt = vf_match_csp( &vf->next, fmt_list, IMGFMT_YV12 );
307 if( !vf->priv->outfmt ) {
308 uninit( vf );
309 return 0; // no csp match :(
312 return 1;
315 const vf_info_t vf_info_unsharp = {
316 "unsharp mask & gaussian blur",
317 "unsharp",
318 "Remi Guyomarch",
320 open,
321 NULL
324 //===========================================================================//