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
28 #include "cpudetect.h"
34 #include "img_format.h"
37 #include "libvo/fastmemcpy.h"
40 #define MIN(a,b) (((a)<(b))?(a):(b))
43 #define MAX(a,b) (((a)>(b))?(a):(b))
46 //===========================================================================//
48 #define MIN_MATRIX_SIZE 3
49 #define MAX_MATRIX_SIZE 63
51 typedef struct FilterParam
{
54 uint32_t *SC
[MAX_MATRIX_SIZE
-1];
58 FilterParam lumaParam
;
59 FilterParam chromaParam
;
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
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);
93 if( dstStride
== srcStride
)
94 memcpy( dst
, src
, srcStride
*height
);
96 for( y
=0; y
<height
; y
++, dst
+=dstStride
, src
+=srcStride
)
97 memcpy( dst
, src
, width
);
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
;
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
;
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
) {
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
);
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
);
202 asm volatile ("emms\n\t");
206 asm volatile ("sfence\n\t");
209 return vf_next_put_image( vf
, dmpi
);
212 static void uninit( struct vf_instance_s
* vf
) {
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
] );
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
] );
233 //===========================================================================//
235 static int query_format( struct vf_instance_s
* vf
, unsigned int fmt
) {
240 return vf_next_query_format( vf
, vf
->priv
->outfmt
);
245 //===========================================================================//
247 static void parse( FilterParam
*fp
, char* args
) {
249 // l7x5:0.8:c3x3:-0.2
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
;
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
);
265 pos
= strchr( pos
+1, ':' );
266 fp
->amount
= ( pos
&& pos
+1<max
) ? atof( pos
+1 ) : 0;
269 //===========================================================================//
271 static unsigned int fmt_list
[] = {
278 static int open( vf_instance_t
*vf
, char* args
) {
280 vf
->put_image
= put_image
;
281 vf
->get_image
= get_image
;
282 vf
->query_format
= query_format
;
284 vf
->priv
= malloc( sizeof(struct vf_priv_s
) );
285 memset( vf
->priv
, 0, sizeof(struct vf_priv_s
) );
288 char *args2
= strchr( args
, 'l' );
290 parse( &vf
->priv
->lumaParam
, args2
);
292 vf
->priv
->lumaParam
.amount
=
293 vf
->priv
->lumaParam
.msizeX
=
294 vf
->priv
->lumaParam
.msizeY
= 0;
297 args2
= strchr( args
, 'c' );
299 parse( &vf
->priv
->chromaParam
, args2
);
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
311 vf
->priv
->outfmt
= vf_match_csp( &vf
->next
, fmt_list
, IMGFMT_YV12
);
312 if( !vf
->priv
->outfmt
) {
314 return 0; // no csp match :(
320 vf_info_t vf_info_unsharp
= {
321 "unsharp mask & gaussian blur",
329 //===========================================================================//