bugfix segfault in core/filter_rescale scaling alpha already scaled in gtk2/filter_re...
[melted] / src / modules / core / filter_rescale.c
1 /*
2 * filter_rescale.c -- scale the producer video frame size to match the consumer
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Dan Dennedy <dan@dennedy.org>
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 "filter_rescale.h"
22
23 #include <framework/mlt_frame.h>
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <math.h>
29
30 typedef int ( *image_scaler )( mlt_frame this, uint8_t **image, mlt_image_format iformat, mlt_image_format oformat, int iwidth, int iheight, int owidth, int oheight );
31
32 static int filter_scale( mlt_frame this, uint8_t **image, mlt_image_format iformat, mlt_image_format oformat, int iwidth, int iheight, int owidth, int oheight )
33 {
34 // Get the properties
35 mlt_properties properties = MLT_FRAME_PROPERTIES( this );
36
37 // Get the rescaling interpolsation
38 char *interps = mlt_properties_get( properties, "rescale.interp" );
39
40 // Carry out the rescaling
41 if ( iformat == mlt_image_yuv422 && oformat == mlt_image_yuv422 )
42 {
43 // Scale the frame
44 mlt_frame_rescale_yuv422( this, owidth, oheight );
45
46 // Return the output
47 *image = mlt_properties_get_data( properties, "image", NULL );
48 }
49 else if ( iformat == mlt_image_rgb24 || iformat == mlt_image_rgb24a )
50 {
51 int bpp = (iformat == mlt_image_rgb24a ? 4 : 3 );
52
53 // Create the yuv image
54 uint8_t *output = mlt_pool_alloc( iwidth * ( iheight + 1 ) * 2 );
55
56 if ( strcmp( interps, "none" ) && ( iwidth != owidth || iheight != oheight ) )
57 {
58 // Extract YUV422 and alpha
59 if ( bpp == 4 )
60 {
61 // Allocate the alpha mask
62 uint8_t *alpha = mlt_pool_alloc( iwidth * ( iheight + 1 ) );
63
64 // Convert the image and extract alpha
65 mlt_convert_rgb24a_to_yuv422( *image, iwidth, iheight, iwidth * 4, output, alpha );
66
67 mlt_properties_set_data( properties, "alpha", alpha, iwidth * ( iheight + 1 ), ( mlt_destructor )mlt_pool_release, NULL );
68 }
69 else
70 {
71 // No alpha to extract
72 mlt_convert_rgb24_to_yuv422( *image, iwidth, iheight, iwidth * 3, output );
73 }
74
75 mlt_properties_set_data( properties, "image", output, iwidth * ( iheight + 1 ) * 2, ( mlt_destructor )mlt_pool_release, NULL );
76
77 // Scale the frame
78 output = mlt_frame_rescale_yuv422( this, owidth, oheight );
79
80 }
81 else
82 {
83 // Extract YUV422 and alpha
84 if ( bpp == 4 )
85 {
86 // Allocate the alpha mask
87 uint8_t *alpha = mlt_pool_alloc( owidth * ( oheight + 1 ) );
88
89 // Convert the image and extract alpha
90 mlt_convert_rgb24a_to_yuv422( *image, owidth, oheight, owidth * 4, output, alpha );
91
92 mlt_properties_set_data( properties, "alpha", alpha, owidth * ( oheight + 1 ), ( mlt_destructor )mlt_pool_release, NULL );
93 }
94 else
95 {
96 // No alpha to extract
97 mlt_convert_rgb24_to_yuv422( *image, owidth, oheight, owidth * 3, output );
98 }
99 }
100
101 // Now update the frame
102 mlt_properties_set_data( properties, "image", output, owidth * ( oheight + 1 ) * 2, ( mlt_destructor )mlt_pool_release, NULL );
103 mlt_properties_set_int( properties, "width", owidth );
104 mlt_properties_set_int( properties, "height", oheight );
105
106 *image = output;
107 }
108
109 // Scale the alpha
110 uint8_t *output = NULL;
111 uint8_t *input = mlt_frame_get_alpha_mask( this );
112
113 if ( input != NULL )
114 {
115 uint8_t *out_line;
116 int x, y;
117 int ox = ( iwidth << 10 ) / owidth;
118 int oy = ( iheight << 10 ) / oheight;
119
120 output = mlt_pool_alloc( owidth * oheight );
121 out_line = output;
122
123 // Loop for the entirety of our output height.
124 for ( y = 0; y < oheight; y ++ )
125 for ( x = 0; x < owidth; x ++ )
126 *out_line ++ = *( input + ( ( 512 + ( y * oy * iwidth ) + x * ox ) >> 10 ) );
127
128 // Set it back on the frame
129 mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "alpha", output, owidth * oheight, mlt_pool_release, NULL );
130 }
131
132 return 0;
133 }
134
135 /** Do it :-).
136 */
137
138 static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
139 {
140 // Get the frame properties
141 mlt_properties properties = MLT_FRAME_PROPERTIES( this );
142
143 // Get the filter from the stack
144 mlt_filter filter = mlt_frame_pop_service( this );
145
146 // Get the filter properties
147 mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter );
148
149 // Get the image scaler method
150 image_scaler scaler_method = mlt_properties_get_data( filter_properties, "method", NULL );
151
152 // Correct Width/height if necessary
153 if ( *width == 0 || *height == 0 )
154 {
155 *width = mlt_properties_get_int( properties, "normalised_width" );
156 *height = mlt_properties_get_int( properties, "normalised_height" );
157 }
158
159 // There can be problems with small images - avoid them (by hacking - gah)
160 if ( *width >= 6 && *height >= 6 )
161 {
162 int iwidth = *width;
163 int iheight = *height;
164 int owidth = *width;
165 int oheight = *height;
166 char *interps = mlt_properties_get( properties, "rescale.interp" );
167 int wanted_format = *format;
168
169 // Default from the scaler if not specifed on the frame
170 if ( interps == NULL )
171 {
172 interps = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "interpolation" );
173 mlt_properties_set( properties, "rescale.interp", interps );
174 }
175
176 // If real_width/height exist, we want that as minimum information
177 if ( mlt_properties_get_int( properties, "real_width" ) )
178 {
179 iwidth = mlt_properties_get_int( properties, "real_width" );
180 iheight = mlt_properties_get_int( properties, "real_height" );
181 }
182
183 // Let the producer know what we are actually requested to obtain
184 if ( *format == mlt_image_yuv422 && strcmp( interps, "none" ) )
185 {
186 mlt_properties_set_int( properties, "rescale_width", *width );
187 mlt_properties_set_int( properties, "rescale_height", *height );
188 }
189 else
190 {
191 // When no scaling is requested, revert the requested dimensions if possible
192 mlt_properties_set_int( properties, "rescale_width", iwidth );
193 mlt_properties_set_int( properties, "rescale_height", iheight );
194 }
195
196 // Get the image as requested
197 mlt_frame_get_image( this, image, format, &iwidth, &iheight, writable );
198
199 // Get rescale interpretation again, in case the producer wishes to override scaling
200 interps = mlt_properties_get( properties, "rescale.interp" );
201
202 if ( *image != NULL && ( *format != mlt_image_yuv422 || ( iwidth != owidth || iheight != oheight ) ) )
203 {
204 // If the colour space is correct and scaling is off, do nothing
205 if ( *format == mlt_image_yuv422 && !strcmp( interps, "none" ) )
206 {
207 *width = iwidth;
208 *height = iheight;
209 }
210 else if ( *format == mlt_image_yuv422 )
211 {
212 // Call the local scaler
213 scaler_method( this, image, *format, mlt_image_yuv422, iwidth, iheight, owidth, oheight );
214 *width = owidth;
215 *height = oheight;
216 }
217 else if ( *format == mlt_image_rgb24 && wanted_format == mlt_image_rgb24 )
218 {
219 // Call the local scaler
220 scaler_method( this, image, *format, mlt_image_rgb24, iwidth, iheight, owidth, oheight );
221
222 // Return the output
223 *width = owidth;
224 *height = oheight;
225 }
226 else if ( *format == mlt_image_rgb24 || *format == mlt_image_rgb24a )
227 {
228 // Call the local scaler
229 scaler_method( this, image, *format, mlt_image_yuv422, iwidth, iheight, owidth, oheight );
230
231 // Return the output
232 *format = mlt_image_yuv422;
233 *width = owidth;
234 *height = oheight;
235 }
236 else
237 {
238 *width = iwidth;
239 *height = iheight;
240 }
241 }
242 else
243 {
244 *width = iwidth;
245 *height = iheight;
246 }
247 }
248 else
249 {
250 // Store the requested width/height
251 int iwidth = *width;
252 int iheight = *height;
253
254 // Get the image as requested
255 mlt_frame_get_image( this, image, format, &iwidth, &iheight, writable );
256
257 // Too small - for now just assign as though we got what we wanted
258 *width = iwidth;
259 *height = iheight;
260 }
261
262
263 return 0;
264 }
265
266 /** Filter processing.
267 */
268
269 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
270 {
271 // Push the filter
272 mlt_frame_push_service( frame, this );
273
274 // Push the get image method
275 mlt_frame_push_service( frame, filter_get_image );
276
277 return frame;
278 }
279
280 /** Constructor for the filter.
281 */
282
283 mlt_filter filter_rescale_init( char *arg )
284 {
285 // Create a new scaler
286 mlt_filter this = mlt_filter_new( );
287
288 // If successful, then initialise it
289 if ( this != NULL )
290 {
291 // Get the properties
292 mlt_properties properties = MLT_FILTER_PROPERTIES( this );
293
294 // Set the process method
295 this->process = filter_process;
296
297 // Set the inerpolation
298 mlt_properties_set( properties, "interpolation", arg == NULL ? "bilinear" : arg );
299
300 // Set the method
301 mlt_properties_set_data( properties, "method", filter_scale, 0, NULL, NULL );
302 }
303
304 return this;
305 }
306