Fixed crash in slowmotion producer
[melted] / 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