Fix a 64-bit segfault in kdenlive
[melted] / 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, int width, 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