]> git.sesse.net Git - mlt/blob - src/modules/qimage/producer_qimage.c
Fix calloc() parameter ordering
[mlt] / src / modules / qimage / producer_qimage.c
1 /*
2  * producer_image.c -- a QT/QImage based producer for MLT
3  * Copyright (C) 2006 Visual Media
4  * Author: Charles Yates <charles.yates@gmail.com>
5  *
6  * NB: This module is designed to be functionally equivalent to the 
7  * gtk2 image loading module so it can be used as replacement.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  */
23
24 #include <framework/mlt_producer.h>
25 #include <framework/mlt_cache.h>
26 #include "qimage_wrapper.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <ctype.h>
36
37 static void load_filenames( producer_qimage self, mlt_properties producer_properties );
38 static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
39 static void producer_close( mlt_producer parent );
40
41 mlt_producer producer_qimage_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename )
42 {
43         producer_qimage self = calloc( 1, sizeof( struct producer_qimage_s ) );
44         if ( self != NULL && mlt_producer_init( &self->parent, self ) == 0 )
45         {
46                 mlt_producer producer = &self->parent;
47
48                 // Get the properties interface
49                 mlt_properties properties = MLT_PRODUCER_PROPERTIES( &self->parent );
50         
51                 // Callback registration
52 #ifdef USE_KDE
53                 init_qimage();
54 #endif
55                 producer->get_frame = producer_get_frame;
56                 producer->close = ( mlt_destructor )producer_close;
57
58                 // Set the default properties
59                 mlt_properties_set( properties, "resource", filename );
60                 mlt_properties_set_int( properties, "ttl", 25 );
61                 mlt_properties_set_int( properties, "aspect_ratio", 1 );
62                 mlt_properties_set_int( properties, "progressive", 1 );
63                 mlt_properties_set_int( properties, "seekable", 1 );
64
65                 // Validate the resource
66                 if ( filename )
67                         load_filenames( self, properties );
68                 if ( self->count )
69                 {
70                         mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
71                         if ( frame )
72                         {
73                                 mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
74                                 mlt_properties_set_data( frame_properties, "producer_qimage", self, 0, NULL, NULL );
75                                 mlt_frame_set_position( frame, mlt_producer_position( producer ) );
76                                 mlt_properties_set_position( frame_properties, "qimage_position", mlt_producer_position( producer ) );
77                                 refresh_qimage( self, frame );
78                                 mlt_cache_item_close( self->qimage_cache );
79                                 mlt_frame_close( frame );
80                         }
81                 }
82                 if ( self->current_width == 0 )
83                 {
84                         producer_close( producer );
85                         producer = NULL;
86                 }
87                 return producer;
88         }
89         free( self );
90         return NULL;
91 }
92
93 static int load_svg( producer_qimage self, mlt_properties properties, const char *filename )
94 {
95         int result = 0;
96
97         // Read xml string
98         if ( strstr( filename, "<svg" ) )
99         {
100                 make_tempfile( self, filename );
101                 result = 1;
102         }
103         return result;
104 }
105
106 static int load_sequence( producer_qimage self, mlt_properties properties, const char *filename )
107 {
108         int result = 0;
109
110         // Obtain filenames with pattern
111         if ( strchr( filename, '%' ) != NULL )
112         {
113                 // handle picture sequences
114                 int i = mlt_properties_get_int( properties, "begin" );
115                 int gap = 0;
116                 char full[1024];
117                 int keyvalue = 0;
118                 char key[ 50 ];
119
120                 while ( gap < 100 )
121                 {
122                         struct stat buf;
123                         snprintf( full, 1023, filename, i ++ );
124                         if ( stat( full, &buf ) == 0 )
125                         {
126                                 sprintf( key, "%d", keyvalue ++ );
127                                 mlt_properties_set( self->filenames, key, full );
128                                 gap = 0;
129                         }
130                         else
131                         {
132                                 gap ++;
133                         }
134                 }
135                 if ( mlt_properties_count( self->filenames ) > 0 )
136                 {
137                         mlt_properties_set_int( properties, "ttl", 1 );
138                         result = 1;
139                 }
140         }
141         return result;
142 }
143
144 static int load_sequence2( producer_qimage self, mlt_properties properties, const char *filename )
145 {
146         int result = 0;
147         const char *start;
148
149         // Obtain filenames with pattern containing a begin value, e.g. foo%1234d.png
150         if ( ( start = strchr( filename, '%' ) ) )
151         {
152                 const char *end = ++start;
153                 while ( isdigit( *end ) ) end++;
154                 if ( end > start && ( end[0] == 'd' || end[0] == 'i' || end[0] == 'u' ) )
155                 {
156                         int n = end - start;
157                         char *s = calloc( 1, n + 1 );
158                         strncpy( s, start, n );
159                         mlt_properties_set( properties, "begin", s );
160                         free( s );
161                         s = calloc( 1, strlen( filename ) );
162                         strncpy( s, filename, start - filename );
163                         sprintf( s + ( start - filename ), ".%d%s", n, end );
164                         result = load_sequence( self, properties, s );
165                         free( s );
166                 }
167         }
168         return result;
169 }
170
171 static int load_folder( producer_qimage self, mlt_properties properties, const char *filename )
172 {
173         int result = 0;
174
175         // Obtain filenames within folder
176         if ( strstr( filename, "/.all." ) != NULL )
177         {
178                 char wildcard[ 1024 ];
179                 char *dir_name = strdup( filename );
180                 char *extension = strrchr( dir_name, '.' );
181
182                 *( strstr( dir_name, "/.all." ) + 1 ) = '\0';
183                 sprintf( wildcard, "*%s", extension );
184
185                 mlt_properties_dir_list( self->filenames, dir_name, wildcard, 1 );
186
187                 free( dir_name );
188                 result = 1;
189         }
190         return result;
191 }
192
193 static void load_filenames( producer_qimage self, mlt_properties properties )
194 {
195         char *filename = mlt_properties_get( properties, "resource" );
196         self->filenames = mlt_properties_new( );
197
198         if (!load_svg( self, properties, filename ) &&
199                 !load_sequence( self, properties, filename ) &&
200                 !load_sequence2( self, properties, filename ) &&
201                 !load_folder( self, properties, filename ) )
202         {
203                 mlt_properties_set( self->filenames, "0", filename );
204         }
205         self->count = mlt_properties_count( self->filenames );
206 }
207
208 static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
209 {
210         int error = 0;
211         
212         // Obtain properties of frame and producer
213         mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
214         producer_qimage self = mlt_properties_get_data( properties, "producer_qimage", NULL );
215         mlt_producer producer = &self->parent;
216
217         *width = mlt_properties_get_int( properties, "rescale_width" );
218         *height = mlt_properties_get_int( properties, "rescale_height" );
219
220         mlt_service_lock( MLT_PRODUCER_SERVICE( &self->parent ) );
221
222         // Refresh the image
223         self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" );
224         self->qimage = mlt_cache_item_data( self->qimage_cache, NULL );
225         self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.image" );
226         self->current_image = mlt_cache_item_data( self->image_cache, NULL );
227         self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha" );
228         self->current_alpha = mlt_cache_item_data( self->alpha_cache, NULL );
229         refresh_image( self, frame, *format, *width, *height );
230
231         // Get width and height (may have changed during the refresh)
232         *width = mlt_properties_get_int( properties, "width" );
233         *height = mlt_properties_get_int( properties, "height" );
234         *format = self->format;
235
236         // NB: Cloning is necessary with this producer (due to processing of images ahead of use)
237         // The fault is not in the design of mlt, but in the implementation of the qimage producer...
238         if ( self->current_image )
239         {
240                 // Clone the image and the alpha
241                 int image_size = mlt_image_format_size( self->format, self->current_width, self->current_height, NULL );
242                 uint8_t *image_copy = mlt_pool_alloc( image_size );
243                 memcpy( image_copy, self->current_image, image_size );
244                 // Now update properties so we free the copy after
245                 mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release );
246                 // We're going to pass the copy on
247                 *buffer = image_copy;
248                 mlt_log_debug( MLT_PRODUCER_SERVICE( &self->parent ), "%dx%d (%s)\n",
249                         self->current_width, self->current_height, mlt_image_format_name( *format ) );
250                 // Clone the alpha channel
251                 if ( self->current_alpha )
252                 {
253                         image_copy = mlt_pool_alloc( self->current_width * self->current_height );
254                         memcpy( image_copy, self->current_alpha, self->current_width * self->current_height );
255                         mlt_frame_set_alpha( frame, image_copy, self->current_width * self->current_height, mlt_pool_release );
256                 }
257         }
258         else
259         {
260                 error = 1;
261         }
262
263         // Release references and locks
264         mlt_cache_item_close( self->qimage_cache );
265         mlt_cache_item_close( self->image_cache );
266         mlt_cache_item_close( self->alpha_cache );
267         mlt_service_unlock( MLT_PRODUCER_SERVICE( &self->parent ) );
268
269         return error;
270 }
271
272 static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
273 {
274         // Get the real structure for this producer
275         producer_qimage self = producer->child;
276
277         // Fetch the producers properties
278         mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
279
280         if ( self->filenames == NULL && mlt_properties_get( producer_properties, "resource" ) != NULL )
281                 load_filenames( self, producer_properties );
282
283         // Generate a frame
284         *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
285
286         if ( *frame != NULL && self->count > 0 )
287         {
288                 // Obtain properties of frame and producer
289                 mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );
290
291                 // Set the producer on the frame properties
292                 mlt_properties_set_data( properties, "producer_qimage", self, 0, NULL, NULL );
293
294                 // Update timecode on the frame we're creating
295                 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
296
297                 // Ensure that we have a way to obtain the position in the get_image
298                 mlt_properties_set_position( properties, "qimage_position", mlt_producer_position( producer ) );
299
300                 // Refresh the image
301                 self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" );
302                 self->qimage = mlt_cache_item_data( self->qimage_cache, NULL );
303                 refresh_qimage( self, *frame );
304                 mlt_cache_item_close( self->qimage_cache );
305
306                 // Set producer-specific frame properties
307                 mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( producer_properties, "progressive" ) );
308                 double force_ratio = mlt_properties_get_double( producer_properties, "force_aspect_ratio" );
309                 if ( force_ratio > 0.0 )
310                         mlt_properties_set_double( properties, "aspect_ratio", force_ratio );
311                 else
312                         mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_properties, "aspect_ratio" ) );
313
314                 // Push the get_image method
315                 mlt_frame_push_get_image( *frame, producer_get_image );
316         }
317
318         // Calculate the next timecode
319         mlt_producer_prepare_next( producer );
320
321         return 0;
322 }
323
324 static void producer_close( mlt_producer parent )
325 {
326         producer_qimage self = parent->child;
327         parent->close = NULL;
328         mlt_service_cache_purge( MLT_PRODUCER_SERVICE(parent) );
329         mlt_producer_close( parent );
330         mlt_properties_close( self->filenames );
331         free( self );
332 }