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