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"
31 #include "img_format.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
{
45 uint32_t *SC
[MAX_MATRIX_SIZE
-1];
49 FilterParam lumaParam
;
50 FilterParam chromaParam
;
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
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);
84 if( dstStride
== srcStride
)
85 fast_memcpy( dst
, src
, srcStride
*height
);
87 for( y
=0; y
<height
; y
++, dst
+=dstStride
, src
+=srcStride
)
88 fast_memcpy( dst
, src
, width
);
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
;
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
;
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
) {
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
);
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
);
193 __asm__
volatile ("emms\n\t");
197 __asm__
volatile ("sfence\n\t");
200 return vf_next_put_image( vf
, dmpi
, pts
);
203 static void uninit( struct vf_instance
*vf
) {
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
] );
214 fp
= &vf
->priv
->chromaParam
;
215 for( z
=0; z
<sizeof(fp
->SC
)/sizeof(fp
->SC
[0]); z
++ ) {
216 av_free( fp
->SC
[z
] );
224 //===========================================================================//
226 static int query_format( struct vf_instance
*vf
, unsigned int fmt
) {
231 return vf_next_query_format( vf
, vf
->priv
->outfmt
);
236 //===========================================================================//
238 static void parse( FilterParam
*fp
, char* args
) {
240 // l7x5:0.8:c3x3:-0.2
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
;
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
);
256 pos
= strchr( pos
+1, ':' );
257 fp
->amount
= ( pos
&& pos
+1<max
) ? atof( pos
+1 ) : 0;
260 //===========================================================================//
262 static const unsigned int fmt_list
[] = {
269 static int vf_open( vf_instance_t
*vf
, char *args
) {
271 vf
->put_image
= put_image
;
272 vf
->get_image
= get_image
;
273 vf
->query_format
= query_format
;
275 vf
->priv
= malloc( sizeof(struct vf_priv_s
) );
276 memset( vf
->priv
, 0, sizeof(struct vf_priv_s
) );
279 char *args2
= strchr( args
, 'l' );
281 parse( &vf
->priv
->lumaParam
, args2
);
283 vf
->priv
->lumaParam
.amount
=
284 vf
->priv
->lumaParam
.msizeX
=
285 vf
->priv
->lumaParam
.msizeY
= 0;
288 args2
= strchr( args
, 'c' );
290 parse( &vf
->priv
->chromaParam
, args2
);
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
302 vf
->priv
->outfmt
= vf_match_csp( &vf
->next
, fmt_list
, IMGFMT_YV12
);
303 if( !vf
->priv
->outfmt
) {
305 return 0; // no csp match :(
311 const vf_info_t vf_info_unsharp
= {
312 "unsharp mask & gaussian blur",
320 //===========================================================================//