2 Copyright (C) 2002 Remi 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "cpudetect.h"
34 #include "img_format.h"
37 #include "libvo/fastmemcpy.h"
38 #include "libavutil/common.h"
40 //===========================================================================//
42 #define MIN_MATRIX_SIZE 3
43 #define MAX_MATRIX_SIZE 63
45 typedef struct FilterParam
{
48 uint32_t *SC
[MAX_MATRIX_SIZE
-1];
52 FilterParam lumaParam
;
53 FilterParam chromaParam
;
58 //===========================================================================//
60 /* This code is based on :
62 An Efficient algorithm for Gaussian blur using finite-state machines
63 Frederick M. Waltz and John W. V. Miller
65 SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII
66 Originally published Boston, Nov 98
70 static void unsharp( uint8_t *dst
, uint8_t *src
, int dstStride
, int srcStride
, int width
, int height
, FilterParam
*fp
) {
72 uint32_t **SC
= fp
->SC
;
73 uint32_t SR
[MAX_MATRIX_SIZE
-1], Tmp1
, Tmp2
;
74 uint8_t* src2
= src
; // avoid gcc warning
78 int amount
= fp
->amount
* 65536.0;
79 int stepsX
= fp
->msizeX
/2;
80 int stepsY
= fp
->msizeY
/2;
81 int scalebits
= (stepsX
+stepsY
)*2;
82 int32_t halfscale
= 1 << ((stepsX
+stepsY
)*2-1);
87 if( dstStride
== srcStride
)
88 fast_memcpy( dst
, src
, srcStride
*height
);
90 for( y
=0; y
<height
; y
++, dst
+=dstStride
, src
+=srcStride
)
91 fast_memcpy( dst
, src
, width
);
95 for( y
=0; y
<2*stepsY
; y
++ )
96 memset( SC
[y
], 0, sizeof(SC
[y
][0]) * (width
+2*stepsX
) );
98 for( y
=-stepsY
; y
<height
+stepsY
; y
++ ) {
99 if( y
< height
) src2
= src
;
100 memset( SR
, 0, sizeof(SR
[0]) * (2*stepsX
-1) );
101 for( x
=-stepsX
; x
<width
+stepsX
; x
++ ) {
102 Tmp1
= x
<=0 ? src2
[0] : x
>=width
? src2
[width
-1] : src2
[x
];
103 for( z
=0; z
<stepsX
*2; z
+=2 ) {
104 Tmp2
= SR
[z
+0] + Tmp1
; SR
[z
+0] = Tmp1
;
105 Tmp1
= SR
[z
+1] + Tmp2
; SR
[z
+1] = Tmp2
;
107 for( z
=0; z
<stepsY
*2; z
+=2 ) {
108 Tmp2
= SC
[z
+0][x
+stepsX
] + Tmp1
; SC
[z
+0][x
+stepsX
] = Tmp1
;
109 Tmp1
= SC
[z
+1][x
+stepsX
] + Tmp2
; SC
[z
+1][x
+stepsX
] = Tmp2
;
111 if( x
>=stepsX
&& y
>=stepsY
) {
112 uint8_t* srx
= src
- stepsY
*srcStride
+ x
- stepsX
;
113 uint8_t* dsx
= dst
- stepsY
*dstStride
+ x
- stepsX
;
115 res
= (int32_t)*srx
+ ( ( ( (int32_t)*srx
- (int32_t)((Tmp1
+halfscale
) >> scalebits
) ) * amount
) >> 16 );
116 *dsx
= res
>255 ? 255 : res
<0 ? 0 : (uint8_t)res
;
126 //===========================================================================//
128 static int config( struct vf_instance_s
* vf
,
129 int width
, int height
, int d_width
, int d_height
,
130 unsigned int flags
, unsigned int outfmt
) {
132 int z
, stepsX
, stepsY
;
138 fp
= &vf
->priv
->lumaParam
;
139 effect
= fp
->amount
== 0 ? "don't touch" : fp
->amount
< 0 ? "blur" : "sharpen";
140 mp_msg( MSGT_VFILTER
, MSGL_INFO
, "unsharp: %dx%d:%0.2f (%s luma) \n", fp
->msizeX
, fp
->msizeY
, fp
->amount
, effect
);
141 memset( fp
->SC
, 0, sizeof( fp
->SC
) );
142 stepsX
= fp
->msizeX
/2;
143 stepsY
= fp
->msizeY
/2;
144 for( z
=0; z
<2*stepsY
; z
++ )
145 fp
->SC
[z
] = memalign( 16, sizeof(*(fp
->SC
[z
])) * (width
+2*stepsX
) );
147 fp
= &vf
->priv
->chromaParam
;
148 effect
= fp
->amount
== 0 ? "don't touch" : fp
->amount
< 0 ? "blur" : "sharpen";
149 mp_msg( MSGT_VFILTER
, MSGL_INFO
, "unsharp: %dx%d:%0.2f (%s chroma)\n", fp
->msizeX
, fp
->msizeY
, fp
->amount
, effect
);
150 memset( fp
->SC
, 0, sizeof( fp
->SC
) );
151 stepsX
= fp
->msizeX
/2;
152 stepsY
= fp
->msizeY
/2;
153 for( z
=0; z
<2*stepsY
; z
++ )
154 fp
->SC
[z
] = memalign( 16, sizeof(*(fp
->SC
[z
])) * (width
+2*stepsX
) );
156 return vf_next_config( vf
, width
, height
, d_width
, d_height
, flags
, outfmt
);
159 //===========================================================================//
161 static void get_image( struct vf_instance_s
* vf
, mp_image_t
*mpi
) {
162 if( mpi
->flags
& MP_IMGFLAG_PRESERVE
)
163 return; // don't change
164 if( mpi
->imgfmt
!=vf
->priv
->outfmt
)
165 return; // colorspace differ
167 vf
->dmpi
= vf_get_image( vf
->next
, mpi
->imgfmt
, mpi
->type
, mpi
->flags
, mpi
->w
, mpi
->h
);
168 mpi
->planes
[0] = vf
->dmpi
->planes
[0];
169 mpi
->stride
[0] = vf
->dmpi
->stride
[0];
170 mpi
->width
= vf
->dmpi
->width
;
171 if( mpi
->flags
& MP_IMGFLAG_PLANAR
) {
172 mpi
->planes
[1] = vf
->dmpi
->planes
[1];
173 mpi
->planes
[2] = vf
->dmpi
->planes
[2];
174 mpi
->stride
[1] = vf
->dmpi
->stride
[1];
175 mpi
->stride
[2] = vf
->dmpi
->stride
[2];
177 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
180 static int put_image( struct vf_instance_s
* vf
, mp_image_t
*mpi
, double pts
) {
183 if( !(mpi
->flags
& MP_IMGFLAG_DIRECT
) )
184 // no DR, so get a new image! hope we'll get DR buffer:
185 vf
->dmpi
= vf_get_image( vf
->next
,vf
->priv
->outfmt
, MP_IMGTYPE_TEMP
, MP_IMGFLAG_ACCEPT_STRIDE
, mpi
->w
, mpi
->h
);
188 unsharp( dmpi
->planes
[0], mpi
->planes
[0], dmpi
->stride
[0], mpi
->stride
[0], mpi
->w
, mpi
->h
, &vf
->priv
->lumaParam
);
189 unsharp( dmpi
->planes
[1], mpi
->planes
[1], dmpi
->stride
[1], mpi
->stride
[1], mpi
->w
/2, mpi
->h
/2, &vf
->priv
->chromaParam
);
190 unsharp( dmpi
->planes
[2], mpi
->planes
[2], dmpi
->stride
[2], mpi
->stride
[2], mpi
->w
/2, mpi
->h
/2, &vf
->priv
->chromaParam
);
192 vf_clone_mpi_attributes(dmpi
, mpi
);
196 asm volatile ("emms\n\t");
200 asm volatile ("sfence\n\t");
203 return vf_next_put_image( vf
, dmpi
, pts
);
206 static void uninit( struct vf_instance_s
* vf
) {
210 if( !vf
->priv
) return;
212 fp
= &vf
->priv
->lumaParam
;
213 for( z
=0; z
<sizeof(fp
->SC
)/sizeof(fp
->SC
[0]); z
++ ) {
214 if( fp
->SC
[z
] ) free( fp
->SC
[z
] );
217 fp
= &vf
->priv
->chromaParam
;
218 for( z
=0; z
<sizeof(fp
->SC
)/sizeof(fp
->SC
[0]); z
++ ) {
219 if( fp
->SC
[z
] ) free( fp
->SC
[z
] );
227 //===========================================================================//
229 static int query_format( struct vf_instance_s
* vf
, unsigned int fmt
) {
234 return vf_next_query_format( vf
, vf
->priv
->outfmt
);
239 //===========================================================================//
241 static void parse( FilterParam
*fp
, char* args
) {
243 // l7x5:0.8:c3x3:-0.2
247 char *max
= args
+ strlen(args
);
249 // parse matrix sizes
250 fp
->msizeX
= ( pos
&& pos
+1<max
) ? atoi( pos
+1 ) : 0;
251 z
= strchr( pos
+1, 'x' );
252 fp
->msizeY
= ( z
&& z
+1<max
) ? atoi( pos
=z
+1 ) : fp
->msizeX
;
255 fp
->msizeX
= 1 | av_clip(fp
->msizeX
, MIN_MATRIX_SIZE
, MAX_MATRIX_SIZE
);
256 fp
->msizeY
= 1 | av_clip(fp
->msizeY
, MIN_MATRIX_SIZE
, MAX_MATRIX_SIZE
);
259 pos
= strchr( pos
+1, ':' );
260 fp
->amount
= ( pos
&& pos
+1<max
) ? atof( pos
+1 ) : 0;
263 //===========================================================================//
265 static unsigned int fmt_list
[] = {
272 static int open( vf_instance_t
*vf
, char* args
) {
274 vf
->put_image
= put_image
;
275 vf
->get_image
= get_image
;
276 vf
->query_format
= query_format
;
278 vf
->priv
= malloc( sizeof(struct vf_priv_s
) );
279 memset( vf
->priv
, 0, sizeof(struct vf_priv_s
) );
282 char *args2
= strchr( args
, 'l' );
284 parse( &vf
->priv
->lumaParam
, args2
);
286 vf
->priv
->lumaParam
.amount
=
287 vf
->priv
->lumaParam
.msizeX
=
288 vf
->priv
->lumaParam
.msizeY
= 0;
291 args2
= strchr( args
, 'c' );
293 parse( &vf
->priv
->chromaParam
, args2
);
295 vf
->priv
->chromaParam
.amount
=
296 vf
->priv
->chromaParam
.msizeX
=
297 vf
->priv
->chromaParam
.msizeY
= 0;
300 if( !vf
->priv
->lumaParam
.msizeX
&& !vf
->priv
->chromaParam
.msizeX
)
301 return 0; // nothing to do
305 vf
->priv
->outfmt
= vf_match_csp( &vf
->next
, fmt_list
, IMGFMT_YV12
);
306 if( !vf
->priv
->outfmt
) {
308 return 0; // no csp match :(
314 const vf_info_t vf_info_unsharp
= {
315 "unsharp mask & gaussian blur",
323 //===========================================================================//