]> git.sesse.net Git - mlt/blob - src/modules/kdenlive/filter_boxblur.c
framework: remove global profile, rather share one mlt_profile across a service netwo...
[mlt] / src / modules / kdenlive / filter_boxblur.c
1 /*
2  * filter_boxblur.c -- blur filter
3  * Copyright (C) ?-2007 Leny Grisel <leny.grisel@laposte.net>
4  * Copyright (C) 2007 Jean-Baptiste Mardelle <jb@ader.ch>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <framework/mlt_filter.h>
22 #include <framework/mlt_frame.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27
28
29 static void PreCompute(uint8_t *yuv, int32_t *rgb, unsigned int width, unsigned int height)
30 {
31         register int x, y, z;
32         register int uneven = width % 2;
33         int w = (width - uneven ) / 2;
34         int yy, uu, vv;
35         int r, g, b;
36         int32_t pts[3];
37         for (y=0; y<height; y++)
38         {
39                 for (x=0; x<w; x++)
40                 {
41                         uu = yuv[1];
42                         vv = yuv[3];
43                         yy = yuv[0];
44                         YUV2RGB(yy, uu, vv, r, g, b);
45                         pts[0] = r;
46                         pts[1] = g;
47                         pts[2] = b;
48                         for (z = 0; z < 3; z++) 
49                         {
50                                 if (x>0) pts[z]+=rgb[-3];
51                                 if (y>0) pts[z]+=rgb[-(width*3)];
52                                 if (x>0 && y>0) pts[z]-=rgb[-((width+1)*3)];
53                                 *rgb++=pts[z];
54                         }
55
56                         yy = yuv[2];
57                         YUV2RGB(yy, uu, vv, r, g, b);
58                         pts[0] = r;
59                         pts[1] = g;
60                         pts[2] = b;
61                         for (z = 0; z < 3; z++)
62                         {
63                                 pts[z]+=rgb[-3];
64                                 if (y>0)
65                                 {
66                                         pts[z]+=rgb[-(width*3)];
67                                         pts[z]-=rgb[-((width+1)*3)];
68                                 }
69                                 *rgb++=pts[z];
70                         }
71                         yuv += 4;
72                 }
73                 if (uneven) 
74                 {
75                         uu = yuv[1];
76                         vv = yuv[3];
77                         yy = yuv[0];
78                         YUV2RGB(yy, uu, vv, r, g, b);
79                         pts[0] = r;
80                         pts[1] = g;
81                         pts[2] = b;
82                         for (z = 0; z < 3; z++)
83                         {
84                                 pts[z]+=rgb[-3];
85                                 if (y>0)
86                                 {
87                                         pts[z]+=rgb[-(width*3)];
88                                         pts[z]-=rgb[-((width+1)*3)];
89                                 }
90                                 *rgb++=pts[z];
91                         }
92                         yuv += 2;
93                 }
94         }
95 }
96
97 static int32_t GetRGB(int32_t *rgb, unsigned int w, unsigned int h, unsigned int x, int offsetx, unsigned int y, int offsety, unsigned int z)
98 {
99         int xtheo = x * 2 + offsetx;
100         int ytheo = y + offsety;
101         if (xtheo < 0) xtheo = 0; else if (xtheo >= w) xtheo = w - 1;
102         if (ytheo < 0) ytheo = 0; else if (ytheo >= h) ytheo = h - 1;
103         return rgb[3*(xtheo+ytheo*w)+z];
104 }
105
106 static int32_t GetRGB2(int32_t *rgb, unsigned int w, unsigned int h, unsigned int x, int offsetx, unsigned int y, int offsety, unsigned int z)
107 {
108         int xtheo = x * 2 + 1 + offsetx;
109         int ytheo = y + offsety;
110         if (xtheo < 0) xtheo = 0; else if (xtheo >= w) xtheo = w - 1;
111         if (ytheo < 0) ytheo = 0; else if (ytheo >= h) ytheo = h - 1;
112         return rgb[3*(xtheo+ytheo*w)+z];
113 }
114
115 static void DoBoxBlur(uint8_t *yuv, int32_t *rgb, unsigned int width, unsigned int height, unsigned int boxw, unsigned int boxh)
116 {
117         register int x, y;
118         int32_t r, g, b;
119         register int uneven = width % 2;
120         register int y0, y1, u0, u1, v0, v1;
121         int w = (width - uneven ) / 2;
122         float mul = 1.f / ((boxw*2) * (boxh*2));
123
124         for (y = 0; y < height; y++)
125         {
126                 for (x = 0; x < w; x++)
127                 {
128                         r = GetRGB(rgb, width, height, x, +boxw, y, +boxh, 0) + GetRGB(rgb, width, height, x, -boxw, y, -boxh, 0) - GetRGB(rgb, width, height, x, -boxw, y, + boxh, 0) - GetRGB(rgb, width, height, x, +boxw, y, -boxh, 0);
129                         g = GetRGB(rgb, width, height, x, +boxw, y, +boxh, 1) + GetRGB(rgb, width, height, x, -boxw, y, -boxh, 1) - GetRGB(rgb, width, height, x, -boxw, y, +boxh, 1) - GetRGB(rgb, width, height, x, +boxw, y, -boxh, 1);
130                         b = GetRGB(rgb, width, height, x, +boxw, y, +boxh, 2) + GetRGB(rgb, width, height, x, -boxw, y, -boxh, 2) - GetRGB(rgb, width, height, x, -boxw, y, +boxh, 2) - GetRGB(rgb, width, height, x, +boxw, y, -boxh, 2);
131                         r = (int32_t) (r * mul);
132                         g = (int32_t) (g * mul);
133                         b = (int32_t) (b * mul);
134                         RGB2YUV (r, g, b, y0, u0, v0);
135
136                         r = GetRGB2(rgb, width, height, x, +boxw, y, +boxh, 0) + GetRGB2(rgb, width, height, x, -boxw, y, -boxh, 0) - GetRGB2(rgb, width, height, x, -boxw, y, +boxh, 0) - GetRGB2(rgb, width, height, x, +boxw, y, -boxh, 0);
137                         g = GetRGB2(rgb, width, height, x, +boxw, y, +boxh, 1) + GetRGB2(rgb, width, height, x, -boxw, y, -boxh, 1) - GetRGB2(rgb, width, height, x, -boxw, y, +boxh, 1) - GetRGB2(rgb, width, height, x, +boxw, y, -boxh, 1);
138                         b = GetRGB2(rgb, width, height, x, +boxw, y, +boxh, 2) + GetRGB2(rgb, width, height, x, -boxw, y, -boxh, 2) - GetRGB2(rgb, width, height, x, -boxw, y, +boxh, 2) - GetRGB2(rgb, width, height, x, +boxw, y, -boxh, 2);
139                         r = (int32_t) (r * mul);
140                         g = (int32_t) (g * mul);
141                         b = (int32_t) (b * mul);
142                         RGB2YUV (r, g, b, y1, u1, v1);
143                         *yuv++ = y0;
144                         *yuv++ = (u0+u1) >> 1;
145                         *yuv++ = y1;
146                         *yuv++ = (v0+v1) >> 1;
147                 }
148                 if (uneven)
149                 {
150                         r =  GetRGB(rgb, width, height, x, +boxw, y, +boxh, 0) + GetRGB(rgb, width, height, x, -boxw, y, -boxh, 0) - GetRGB(rgb, width, height, x, -boxw, y, +boxh, 0) - GetRGB(rgb, width, height, x, +boxw, y, -boxh, 0);
151                         g =  GetRGB(rgb, width, height, x, +boxw, y, +boxh, 1) + GetRGB(rgb, width, height, x, -boxw, y, -boxh, 1) - GetRGB(rgb, width, height, x, -boxw, y, +boxh, 1) - GetRGB(rgb, width, height, x, +boxw, y, -boxh, 1);
152                         b =  GetRGB(rgb, width, height, x, +boxw, y, +boxh, 2) + GetRGB(rgb, width, height, x, -boxw, y, -boxh, 2) - GetRGB(rgb, width, height, x, -boxw, y, +boxh, 2) - GetRGB(rgb, width, height, x, +boxw, y, -boxh, 2);
153                         r = (int32_t) (r * mul);
154                         g = (int32_t) (g * mul);
155                         b = (int32_t) (b * mul);
156                         RGB2YUV (r, g, b, y0, u0, v0);
157                         *yuv++ = mul * y0;
158                         *yuv++ = mul * u0;
159                 }
160         }
161 }
162
163 static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
164 {
165         // Get the image
166         int error = mlt_frame_get_image( this, image, format, width, height, 1 );
167         short hori = mlt_properties_get_int(MLT_FRAME_PROPERTIES( this ), "hori" );
168         short vert = mlt_properties_get_int(MLT_FRAME_PROPERTIES( this ), "vert" );
169
170         // Only process if we have no error and a valid colour space
171         if ( error == 0 && *format == mlt_image_yuv422 )
172         {
173                 double factor = mlt_properties_get_double( MLT_FRAME_PROPERTIES( this ), "boxblur" );
174                 if (factor != 0) {
175                         int h = *height + 1;
176                         int32_t *rgb = mlt_pool_alloc (3 * *width * h * sizeof(int32_t));
177                         PreCompute (*image, rgb, *width, h);
178                         DoBoxBlur (*image, rgb, *width, h, (int) factor*hori, (int) factor*vert);
179                         mlt_pool_release (rgb);
180                 }
181         }
182         return error;
183 }
184
185 /** Filter processing.
186 */
187
188 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
189 {
190         // Get the starting blur level
191         double blur = (double) mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "start" );
192         short hori = mlt_properties_get_int(MLT_FILTER_PROPERTIES( this ), "hori" );
193         short vert = mlt_properties_get_int(MLT_FILTER_PROPERTIES( this ), "vert" );
194
195         // If there is an end adjust gain to the range
196         if ( mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "end" ) != NULL )
197         {
198                 // Determine the time position of this frame in the transition duration
199                 mlt_position in = mlt_filter_get_in( this );
200                 mlt_position out = mlt_filter_get_out( this );
201                 mlt_position time = mlt_frame_get_position( frame );
202                 double position = (double) ( time - in ) / ( out - in + 1.0 );
203                 double end = (double) mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "end" );
204                 blur += ( end - blur ) * position;
205         }
206
207         // Push the frame filter
208         mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), "boxblur", blur );
209         mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "hori", hori );
210         mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "vert", vert );
211         mlt_frame_push_get_image( frame, filter_get_image );
212
213         return frame;
214 }
215
216 /** Constructor for the filter.
217 */
218
219 mlt_filter filter_boxblur_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
220 {
221         mlt_filter this = mlt_filter_new( );
222         if ( this != NULL )
223         {
224                 this->process = filter_process;
225                 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "start", arg == NULL ? "10" : arg);
226                 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "hori", arg == NULL ? "1" : arg);
227                 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "vert", arg == NULL ? "1" : arg);
228         }
229         return this;
230 }
231
232
233