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.
29 #include "cpudetect.h"
35 #include "img_format.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
{
49 uint32_t *SC
[MAX_MATRIX_SIZE
-1];
53 FilterParam lumaParam
;
54 FilterParam chromaParam
;
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
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);
88 if( dstStride
== srcStride
)
89 fast_memcpy( dst
, src
, srcStride
*height
);
91 for( y
=0; y
<height
; y
++, dst
+=dstStride
, src
+=srcStride
)
92 fast_memcpy( dst
, src
, width
);
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
;
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
;
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
) {
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
);
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
);
197 __asm__
volatile ("emms\n\t");
201 __asm__
volatile ("sfence\n\t");
204 return vf_next_put_image( vf
, dmpi
, pts
);
207 static void uninit( struct vf_instance_s
* vf
) {
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
] );
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
] );
228 //===========================================================================//
230 static int query_format( struct vf_instance_s
* vf
, unsigned int fmt
) {
235 return vf_next_query_format( vf
, vf
->priv
->outfmt
);
240 //===========================================================================//
242 static void parse( FilterParam
*fp
, char* args
) {
244 // l7x5:0.8:c3x3:-0.2
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
;
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
);
260 pos
= strchr( pos
+1, ':' );
261 fp
->amount
= ( pos
&& pos
+1<max
) ? atof( pos
+1 ) : 0;
264 //===========================================================================//
266 static unsigned int fmt_list
[] = {
273 static int open( vf_instance_t
*vf
, char* args
) {
275 vf
->put_image
= put_image
;
276 vf
->get_image
= get_image
;
277 vf
->query_format
= query_format
;
279 vf
->priv
= malloc( sizeof(struct vf_priv_s
) );
280 memset( vf
->priv
, 0, sizeof(struct vf_priv_s
) );
283 char *args2
= strchr( args
, 'l' );
285 parse( &vf
->priv
->lumaParam
, args2
);
287 vf
->priv
->lumaParam
.amount
=
288 vf
->priv
->lumaParam
.msizeX
=
289 vf
->priv
->lumaParam
.msizeY
= 0;
292 args2
= strchr( args
, 'c' );
294 parse( &vf
->priv
->chromaParam
, args2
);
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
306 vf
->priv
->outfmt
= vf_match_csp( &vf
->next
, fmt_list
, IMGFMT_YV12
);
307 if( !vf
->priv
->outfmt
) {
309 return 0; // no csp match :(
315 const vf_info_t vf_info_unsharp
= {
316 "unsharp mask & gaussian blur",
324 //===========================================================================//