sd_ass: initialize structs for external tracks properly
[mplayer.git] / libmpcodecs / vf_unsharp.c
blob864c99862a5c53c158992c0753afd6e0c6d4e3d3
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 #include "img_format.h"
32 #include "mp_image.h"
33 #include "vf.h"
34 #include "libvo/fastmemcpy.h"
35 #include "libavutil/common.h"
37 //===========================================================================//
39 #define MIN_MATRIX_SIZE 3
40 #define MAX_MATRIX_SIZE 63
42 typedef struct FilterParam {
43 int msizeX, msizeY;
44 double amount;
45 uint32_t *SC[MAX_MATRIX_SIZE-1];
46 } FilterParam;
48 struct vf_priv_s {
49 FilterParam lumaParam;
50 FilterParam chromaParam;
51 unsigned int outfmt;
55 //===========================================================================//
57 /* This code is based on :
59 An Efficient algorithm for Gaussian blur using finite-state machines
60 Frederick M. Waltz and John W. V. Miller
62 SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII
63 Originally published Boston, Nov 98
67 static void unsharp( uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp ) {
69 uint32_t **SC = fp->SC;
70 uint32_t SR[MAX_MATRIX_SIZE-1], Tmp1, Tmp2;
71 uint8_t* src2 = src; // avoid gcc warning
73 int32_t res;
74 int x, y, z;
75 int amount = fp->amount * 65536.0;
76 int stepsX = fp->msizeX/2;
77 int stepsY = fp->msizeY/2;
78 int scalebits = (stepsX+stepsY)*2;
79 int32_t halfscale = 1 << ((stepsX+stepsY)*2-1);
81 if( !fp->amount ) {
82 if( src == dst )
83 return;
84 if( dstStride == srcStride )
85 fast_memcpy( dst, src, srcStride*height );
86 else
87 for( y=0; y<height; y++, dst+=dstStride, src+=srcStride )
88 fast_memcpy( dst, src, width );
89 return;
92 for( y=0; y<2*stepsY; y++ )
93 memset( SC[y], 0, sizeof(SC[y][0]) * (width+2*stepsX) );
95 for( y=-stepsY; y<height+stepsY; y++ ) {
96 if( y < height ) src2 = src;
97 memset( SR, 0, sizeof(SR[0]) * (2*stepsX-1) );
98 for( x=-stepsX; x<width+stepsX; x++ ) {
99 Tmp1 = x<=0 ? src2[0] : x>=width ? src2[width-1] : src2[x];
100 for( z=0; z<stepsX*2; z+=2 ) {
101 Tmp2 = SR[z+0] + Tmp1; SR[z+0] = Tmp1;
102 Tmp1 = SR[z+1] + Tmp2; SR[z+1] = Tmp2;
104 for( z=0; z<stepsY*2; z+=2 ) {
105 Tmp2 = SC[z+0][x+stepsX] + Tmp1; SC[z+0][x+stepsX] = Tmp1;
106 Tmp1 = SC[z+1][x+stepsX] + Tmp2; SC[z+1][x+stepsX] = Tmp2;
108 if( x>=stepsX && y>=stepsY ) {
109 uint8_t* srx = src - stepsY*srcStride + x - stepsX;
110 uint8_t* dsx = dst - stepsY*dstStride + x - stepsX;
112 res = (int32_t)*srx + ( ( ( (int32_t)*srx - (int32_t)((Tmp1+halfscale) >> scalebits) ) * amount ) >> 16 );
113 *dsx = res>255 ? 255 : res<0 ? 0 : (uint8_t)res;
116 if( y >= 0 ) {
117 dst += dstStride;
118 src += srcStride;
123 //===========================================================================//
125 static int config( struct vf_instance *vf,
126 int width, int height, int d_width, int d_height,
127 unsigned int flags, unsigned int outfmt ) {
129 int z, stepsX, stepsY;
130 FilterParam *fp;
131 char *effect;
133 // allocate buffers
135 fp = &vf->priv->lumaParam;
136 effect = fp->amount == 0 ? "don't touch" : fp->amount < 0 ? "blur" : "sharpen";
137 mp_msg( MSGT_VFILTER, MSGL_INFO, "unsharp: %dx%d:%0.2f (%s luma) \n", fp->msizeX, fp->msizeY, fp->amount, effect );
138 memset( fp->SC, 0, sizeof( fp->SC ) );
139 stepsX = fp->msizeX/2;
140 stepsY = fp->msizeY/2;
141 for( z=0; z<2*stepsY; z++ )
142 fp->SC[z] = av_malloc(sizeof(*(fp->SC[z])) * (width+2*stepsX));
144 fp = &vf->priv->chromaParam;
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 chroma)\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] = av_malloc(sizeof(*(fp->SC[z])) * (width+2*stepsX));
153 return vf_next_config( vf, width, height, d_width, d_height, flags, outfmt );
156 //===========================================================================//
158 static void get_image( struct vf_instance *vf, mp_image_t *mpi ) {
159 if( mpi->flags & MP_IMGFLAG_PRESERVE )
160 return; // don't change
161 if( mpi->imgfmt!=vf->priv->outfmt )
162 return; // colorspace differ
164 vf->dmpi = vf_get_image( vf->next, mpi->imgfmt, mpi->type, mpi->flags, mpi->w, mpi->h );
165 mpi->planes[0] = vf->dmpi->planes[0];
166 mpi->stride[0] = vf->dmpi->stride[0];
167 mpi->width = vf->dmpi->width;
168 if( mpi->flags & MP_IMGFLAG_PLANAR ) {
169 mpi->planes[1] = vf->dmpi->planes[1];
170 mpi->planes[2] = vf->dmpi->planes[2];
171 mpi->stride[1] = vf->dmpi->stride[1];
172 mpi->stride[2] = vf->dmpi->stride[2];
174 mpi->flags |= MP_IMGFLAG_DIRECT;
177 static int put_image( struct vf_instance *vf, mp_image_t *mpi, double pts) {
178 mp_image_t *dmpi;
180 if( !(mpi->flags & MP_IMGFLAG_DIRECT) )
181 // no DR, so get a new image! hope we'll get DR buffer:
182 vf->dmpi = vf_get_image( vf->next,vf->priv->outfmt, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, mpi->w, mpi->h);
183 dmpi= vf->dmpi;
185 unsharp( dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, &vf->priv->lumaParam );
186 unsharp( dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, &vf->priv->chromaParam );
187 unsharp( dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, &vf->priv->chromaParam );
189 vf_clone_mpi_attributes(dmpi, mpi);
191 #if HAVE_MMX
192 if(gCpuCaps.hasMMX)
193 __asm__ volatile ("emms\n\t");
194 #endif
195 #if HAVE_MMX2
196 if(gCpuCaps.hasMMX2)
197 __asm__ volatile ("sfence\n\t");
198 #endif
200 return vf_next_put_image( vf, dmpi, pts);
203 static void uninit( struct vf_instance *vf ) {
204 unsigned int z;
205 FilterParam *fp;
207 if( !vf->priv ) return;
209 fp = &vf->priv->lumaParam;
210 for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
211 av_free( fp->SC[z] );
212 fp->SC[z] = NULL;
214 fp = &vf->priv->chromaParam;
215 for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
216 av_free( fp->SC[z] );
217 fp->SC[z] = NULL;
220 free( vf->priv );
221 vf->priv = NULL;
224 //===========================================================================//
226 static int query_format( struct vf_instance *vf, unsigned int fmt ) {
227 switch(fmt) {
228 case IMGFMT_YV12:
229 case IMGFMT_I420:
230 case IMGFMT_IYUV:
231 return vf_next_query_format( vf, vf->priv->outfmt );
233 return 0;
236 //===========================================================================//
238 static void parse( FilterParam *fp, char* args ) {
240 // l7x5:0.8:c3x3:-0.2
242 char *z;
243 char *pos = args;
244 char *max = args + strlen(args);
246 // parse matrix sizes
247 fp->msizeX = ( pos && pos+1<max ) ? atoi( pos+1 ) : 0;
248 z = strchr( pos+1, 'x' );
249 fp->msizeY = ( z && z+1<max ) ? atoi( pos=z+1 ) : fp->msizeX;
251 // min/max & odd
252 fp->msizeX = 1 | av_clip(fp->msizeX, MIN_MATRIX_SIZE, MAX_MATRIX_SIZE);
253 fp->msizeY = 1 | av_clip(fp->msizeY, MIN_MATRIX_SIZE, MAX_MATRIX_SIZE);
255 // parse amount
256 pos = strchr( pos+1, ':' );
257 fp->amount = ( pos && pos+1<max ) ? atof( pos+1 ) : 0;
260 //===========================================================================//
262 static const unsigned int fmt_list[] = {
263 IMGFMT_YV12,
264 IMGFMT_I420,
265 IMGFMT_IYUV,
269 static int vf_open( vf_instance_t *vf, char *args ) {
270 vf->config = config;
271 vf->put_image = put_image;
272 vf->get_image = get_image;
273 vf->query_format = query_format;
274 vf->uninit = uninit;
275 vf->priv = malloc( sizeof(struct vf_priv_s) );
276 memset( vf->priv, 0, sizeof(struct vf_priv_s) );
278 if( args ) {
279 char *args2 = strchr( args, 'l' );
280 if( args2 )
281 parse( &vf->priv->lumaParam, args2 );
282 else {
283 vf->priv->lumaParam.amount =
284 vf->priv->lumaParam.msizeX =
285 vf->priv->lumaParam.msizeY = 0;
288 args2 = strchr( args, 'c' );
289 if( args2 )
290 parse( &vf->priv->chromaParam, args2 );
291 else {
292 vf->priv->chromaParam.amount =
293 vf->priv->chromaParam.msizeX =
294 vf->priv->chromaParam.msizeY = 0;
297 if( !vf->priv->lumaParam.msizeX && !vf->priv->chromaParam.msizeX )
298 return 0; // nothing to do
301 // check csp:
302 vf->priv->outfmt = vf_match_csp( &vf->next, fmt_list, IMGFMT_YV12 );
303 if( !vf->priv->outfmt ) {
304 uninit( vf );
305 return 0; // no csp match :(
308 return 1;
311 const vf_info_t vf_info_unsharp = {
312 "unsharp mask & gaussian blur",
313 "unsharp",
314 "Remi Guyomarch",
316 vf_open,
317 NULL
320 //===========================================================================//