]> git.sesse.net Git - ffmpeg/blob - libavfilter/libmpcodecs/vf_unsharp.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavfilter / libmpcodecs / vf_unsharp.c
1 /*
2  * Copyright (C) 2002 Remi Guyomarch <rguyom@pobox.com>
3  *
4  * This file is part of MPlayer.
5  *
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.
10  *
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.
15  *
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.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <inttypes.h>
25 #include <math.h>
26
27 #include "config.h"
28 #include "mp_msg.h"
29 #include "cpudetect.h"
30
31 #if HAVE_MALLOC_H
32 #include <malloc.h>
33 #endif
34
35 #include "img_format.h"
36 #include "mp_image.h"
37 #include "vf.h"
38 #include "libvo/fastmemcpy.h"
39 #include "libavutil/common.h"
40
41 //===========================================================================//
42
43 #define MIN_MATRIX_SIZE 3
44 #define MAX_MATRIX_SIZE 63
45
46 typedef struct FilterParam {
47     int msizeX, msizeY;
48     double amount;
49     uint32_t *SC[MAX_MATRIX_SIZE-1];
50 } FilterParam;
51
52 struct vf_priv_s {
53     FilterParam lumaParam;
54     FilterParam chromaParam;
55     unsigned int outfmt;
56 };
57
58
59 //===========================================================================//
60
61 /* This code is based on :
62
63 An Efficient algorithm for Gaussian blur using finite-state machines
64 Frederick M. Waltz and John W. V. Miller
65
66 SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII
67 Originally published Boston, Nov 98
68
69 */
70
71 static void unsharp( uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp ) {
72
73     uint32_t **SC = fp->SC;
74     uint32_t SR[MAX_MATRIX_SIZE-1], Tmp1, Tmp2;
75     uint8_t* src2 = src; // avoid gcc warning
76
77     int32_t res;
78     int x, y, z;
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);
84
85     if( !fp->amount ) {
86         if( src == dst )
87             return;
88         if( dstStride == srcStride )
89             fast_memcpy( dst, src, srcStride*height );
90         else
91             for( y=0; y<height; y++, dst+=dstStride, src+=srcStride )
92                 fast_memcpy( dst, src, width );
93         return;
94     }
95
96     for( y=0; y<2*stepsY; y++ )
97         memset( SC[y], 0, sizeof(SC[y][0]) * (width+2*stepsX) );
98
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;
107             }
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;
111             }
112             if( x>=stepsX && y>=stepsY ) {
113                 uint8_t* srx = src - stepsY*srcStride + x - stepsX;
114                 uint8_t* dsx = dst - stepsY*dstStride + x - stepsX;
115
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;
118             }
119         }
120         if( y >= 0 ) {
121             dst += dstStride;
122             src += srcStride;
123         }
124     }
125 }
126
127 //===========================================================================//
128
129 static int config( struct vf_instance *vf,
130                    int width, int height, int d_width, int d_height,
131                    unsigned int flags, unsigned int outfmt ) {
132
133     int z, stepsX, stepsY;
134     FilterParam *fp;
135     const char *effect;
136
137     // allocate buffers
138
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] = av_malloc(sizeof(*(fp->SC[z])) * (width+2*stepsX));
147
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] = av_malloc(sizeof(*(fp->SC[z])) * (width+2*stepsX));
156
157     return vf_next_config( vf, width, height, d_width, d_height, flags, outfmt );
158 }
159
160 //===========================================================================//
161
162 static void get_image( struct vf_instance *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
167
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];
177     }
178     mpi->flags |= MP_IMGFLAG_DIRECT;
179 }
180
181 static int put_image( struct vf_instance *vf, mp_image_t *mpi, double pts) {
182     mp_image_t *dmpi;
183
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);
187     dmpi= vf->dmpi;
188
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 );
192
193     vf_clone_mpi_attributes(dmpi, mpi);
194
195 #if HAVE_MMX
196     if(gCpuCaps.hasMMX)
197         __asm__ volatile ("emms\n\t");
198 #endif
199 #if HAVE_MMX2
200     if(gCpuCaps.hasMMX2)
201         __asm__ volatile ("sfence\n\t");
202 #endif
203
204     return vf_next_put_image( vf, dmpi, pts);
205 }
206
207 static void uninit( struct vf_instance *vf ) {
208     unsigned int z;
209     FilterParam *fp;
210
211     if( !vf->priv ) return;
212
213     fp = &vf->priv->lumaParam;
214     for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
215         av_free( fp->SC[z] );
216         fp->SC[z] = NULL;
217     }
218     fp = &vf->priv->chromaParam;
219     for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) {
220         av_free( fp->SC[z] );
221         fp->SC[z] = NULL;
222     }
223
224     free( vf->priv );
225     vf->priv = NULL;
226 }
227
228 //===========================================================================//
229
230 static int query_format( struct vf_instance *vf, unsigned int fmt ) {
231     switch(fmt) {
232     case IMGFMT_YV12:
233     case IMGFMT_I420:
234     case IMGFMT_IYUV:
235         return vf_next_query_format( vf, vf->priv->outfmt );
236     }
237     return 0;
238 }
239
240 //===========================================================================//
241
242 static void parse( FilterParam *fp, char* args ) {
243
244     // l7x5:0.8:c3x3:-0.2
245
246     char *z;
247     char *pos = args;
248     char *max = args + strlen(args);
249
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;
254
255     // min/max & odd
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);
258
259     // parse amount
260     pos = strchr( pos+1, ':' );
261     fp->amount = ( pos && pos+1<max ) ? atof( pos+1 ) : 0;
262 }
263
264 //===========================================================================//
265
266 static const unsigned int fmt_list[] = {
267     IMGFMT_YV12,
268     IMGFMT_I420,
269     IMGFMT_IYUV,
270     0
271 };
272
273 static int vf_open( vf_instance_t *vf, char *args ) {
274     vf->config       = config;
275     vf->put_image    = put_image;
276     vf->get_image    = get_image;
277     vf->query_format = query_format;
278     vf->uninit       = uninit;
279     vf->priv         = malloc( sizeof(struct vf_priv_s) );
280     memset( vf->priv, 0, sizeof(struct vf_priv_s) );
281
282     if( args ) {
283         char *args2 = strchr( args, 'l' );
284         if( args2 )
285             parse( &vf->priv->lumaParam, args2 );
286         else {
287             vf->priv->lumaParam.amount =
288             vf->priv->lumaParam.msizeX =
289             vf->priv->lumaParam.msizeY = 0;
290         }
291
292         args2 = strchr( args, 'c' );
293         if( args2 )
294             parse( &vf->priv->chromaParam, args2 );
295         else {
296             vf->priv->chromaParam.amount =
297             vf->priv->chromaParam.msizeX =
298             vf->priv->chromaParam.msizeY = 0;
299         }
300
301         if( !vf->priv->lumaParam.msizeX && !vf->priv->chromaParam.msizeX )
302             return 0; // nothing to do
303     }
304
305     // check csp:
306     vf->priv->outfmt = vf_match_csp( &vf->next, fmt_list, IMGFMT_YV12 );
307     if( !vf->priv->outfmt ) {
308         uninit( vf );
309         return 0; // no csp match :(
310     }
311
312     return 1;
313 }
314
315 const vf_info_t vf_info_unsharp = {
316     "unsharp mask & gaussian blur",
317     "unsharp",
318     "Remi Guyomarch",
319     "",
320     vf_open,
321     NULL
322 };
323
324 //===========================================================================//