]> git.sesse.net Git - mlt/blob - src/modules/qimage/producer_qimage.c
02abbed2a4a3687d7ffb742379d07c6e575a8391
[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( sizeof( struct producer_qimage_s ), 1 );
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                 
64                 // Validate the resource
65                 if ( filename )
66                         load_filenames( self, properties );
67                 if ( self->count )
68                 {
69                         mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
70                         if ( frame )
71                         {
72                                 mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
73                                 mlt_properties_set_data( frame_properties, "producer_qimage", self, 0, NULL, NULL );
74                                 mlt_frame_set_position( frame, mlt_producer_position( producer ) );
75                                 mlt_properties_set_position( frame_properties, "qimage_position", mlt_producer_position( producer ) );
76                                 refresh_qimage( self, frame );
77                                 mlt_frame_close( frame );
78                         }
79                 }
80                 if ( self->current_width == 0 )
81                 {
82                         producer_close( producer );
83                         producer = NULL;
84                 }
85                 return producer;
86         }
87         free( self );
88         return NULL;
89 }
90
91 static int load_svg( producer_qimage self, mlt_properties properties, const char *filename )
92 {
93         int result = 0;
94
95         // Read xml string
96         if ( strstr( filename, "<svg" ) )
97         {
98                 make_tempfile( self, filename );
99                 result = 1;
100         }
101         return result;
102 }
103
104 static int load_sequence( producer_qimage self, mlt_properties properties, const char *filename )
105 {
106         int result = 0;
107
108         // Obtain filenames with pattern
109         if ( strchr( filename, '%' ) != NULL )
110         {
111                 // handle picture sequences
112                 int i = mlt_properties_get_int( properties, "begin" );
113                 int gap = 0;
114                 char full[1024];
115                 int keyvalue = 0;
116                 char key[ 50 ];
117
118                 while ( gap < 100 )
119                 {
120                         struct stat buf;
121                         snprintf( full, 1023, filename, i ++ );
122                         if ( stat( full, &buf ) == 0 )
123                         {
124                                 sprintf( key, "%d", keyvalue ++ );
125                                 mlt_properties_set( self->filenames, key, full );
126                                 gap = 0;
127                         }
128                         else
129                         {
130                                 gap ++;
131                         }
132                 }
133                 if ( mlt_properties_count( self->filenames ) > 0 )
134                 {
135                         mlt_properties_set_int( properties, "ttl", 1 );
136                         result = 1;
137                 }
138         }
139         return result;
140 }
141
142 static int load_sequence2( producer_qimage self, mlt_properties properties, const char *filename )
143 {
144         int result = 0;
145         const char *start;
146
147         // Obtain filenames with pattern containing a begin value, e.g. foo%1234d.png
148         if ( ( start = strchr( filename, '%' ) ) )
149         {
150                 const char *end = ++start;
151                 while ( isdigit( *end ) ) end++;
152                 if ( end > start && ( end[0] == 'd' || end[0] == 'i' || end[0] == 'u' ) )
153                 {
154                         int n = end - start;
155                         char *s = calloc( 1, n + 1 );
156                         strncpy( s, start, n );
157                         mlt_properties_set( properties, "begin", s );
158                         free( s );
159                         s = calloc( 1, strlen( filename ) );
160                         strncpy( s, filename, start - filename );
161                         sprintf( s + ( start - filename ), ".%d%s", n, end );
162                         result = load_sequence( self, properties, s );
163                         free( s );
164                 }
165         }
166         return result;
167 }
168
169 static int load_folder( producer_qimage self, mlt_properties properties, const char *filename )
170 {
171         int result = 0;
172
173         // Obtain filenames within folder
174         if ( strstr( filename, "/.all." ) != NULL )
175         {
176                 char wildcard[ 1024 ];
177                 char *dir_name = strdup( filename );
178                 char *extension = strrchr( dir_name, '.' );
179
180                 *( strstr( dir_name, "/.all." ) + 1 ) = '\0';
181                 sprintf( wildcard, "*%s", extension );
182
183                 mlt_properties_dir_list( self->filenames, dir_name, wildcard, 1 );
184
185                 free( dir_name );
186                 result = 1;
187         }
188         return result;
189 }
190
191 static void load_filenames( producer_qimage self, mlt_properties properties )
192 {
193         char *filename = mlt_properties_get( properties, "resource" );
194         self->filenames = mlt_properties_new( );
195
196         if (!load_svg( self, properties, filename ) &&
197                 !load_sequence( self, properties, filename ) &&
198                 !load_sequence2( self, properties, filename ) &&
199                 !load_folder( self, properties, filename ) )
200         {
201                 mlt_properties_set( self->filenames, "0", filename );
202         }
203         self->count = mlt_properties_count( self->filenames );
204 }
205
206 static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
207 {
208         int error = 0;
209         
210         // Obtain properties of frame and producer
211         mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
212         producer_qimage self = mlt_properties_get_data( properties, "producer_qimage", NULL );
213         mlt_producer producer = &self->parent;
214
215         *width = mlt_properties_get_int( properties, "rescale_width" );
216         *height = mlt_properties_get_int( properties, "rescale_height" );
217
218         mlt_service_lock( MLT_PRODUCER_SERVICE( &self->parent ) );
219
220         // Refresh the image
221         self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" );
222         self->qimage = mlt_cache_item_data( self->qimage_cache, NULL );
223         self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.image" );
224         self->current_image = mlt_cache_item_data( self->image_cache, NULL );
225         self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha" );
226         self->current_alpha = mlt_cache_item_data( self->alpha_cache, NULL );
227         refresh_image( self, frame, *format, *width, *height );
228
229         // Get width and height (may have changed during the refresh)
230         *width = mlt_properties_get_int( properties, "width" );
231         *height = mlt_properties_get_int( properties, "height" );
232         *format = self->format;
233
234         // NB: Cloning is necessary with this producer (due to processing of images ahead of use)
235         // The fault is not in the design of mlt, but in the implementation of the qimage producer...
236         if ( self->current_image )
237         {
238                 // Clone the image and the alpha
239                 int image_size = mlt_image_format_size( self->format, self->current_width, self->current_height, NULL );
240                 uint8_t *image_copy = mlt_pool_alloc( image_size );
241                 memcpy( image_copy, self->current_image, image_size );
242                 // Now update properties so we free the copy after
243                 mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release );
244                 // We're going to pass the copy on
245                 *buffer = image_copy;
246                 mlt_log_debug( MLT_PRODUCER_SERVICE( &self->parent ), "%dx%d (%s)\n",
247                         self->current_width, self->current_height, mlt_image_format_name( *format ) );
248                 // Clone the alpha channel
249                 if ( self->current_alpha )
250                 {
251                         image_copy = mlt_pool_alloc( self->current_width * self->current_height );
252                         memcpy( image_copy, self->current_alpha, self->current_width * self->current_height );
253                         mlt_frame_set_alpha( frame, image_copy, self->current_width * self->current_height, mlt_pool_release );
254                 }
255         }
256         else
257         {
258                 error = 1;
259         }
260
261         // Release references and locks
262         mlt_cache_item_close( self->qimage_cache );
263         mlt_cache_item_close( self->image_cache );
264         mlt_cache_item_close( self->alpha_cache );
265         mlt_service_unlock( MLT_PRODUCER_SERVICE( &self->parent ) );
266
267         return error;
268 }
269
270 static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
271 {
272         // Get the real structure for this producer
273         producer_qimage self = producer->child;
274
275         // Fetch the producers properties
276         mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
277
278         if ( self->filenames == NULL && mlt_properties_get( producer_properties, "resource" ) != NULL )
279                 load_filenames( self, producer_properties );
280
281         // Generate a frame
282         *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
283
284         if ( *frame != NULL && self->count > 0 )
285         {
286                 // Obtain properties of frame and producer
287                 mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );
288
289                 // Set the producer on the frame properties
290                 mlt_properties_set_data( properties, "producer_qimage", self, 0, NULL, NULL );
291
292                 // Update timecode on the frame we're creating
293                 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
294
295                 // Ensure that we have a way to obtain the position in the get_image
296                 mlt_properties_set_position( properties, "qimage_position", mlt_producer_position( producer ) );
297
298                 // Refresh the image
299                 self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" );
300                 self->qimage = mlt_cache_item_data( self->qimage_cache, NULL );
301                 refresh_qimage( self, *frame );
302                 mlt_cache_item_close( self->qimage_cache );
303
304                 // Set producer-specific frame properties
305                 mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( producer_properties, "progressive" ) );
306                 double force_ratio = mlt_properties_get_double( producer_properties, "force_aspect_ratio" );
307                 if ( force_ratio > 0.0 )
308                         mlt_properties_set_double( properties, "aspect_ratio", force_ratio );
309                 else
310                         mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_properties, "aspect_ratio" ) );
311
312                 // Push the get_image method
313                 mlt_frame_push_get_image( *frame, producer_get_image );
314         }
315
316         // Calculate the next timecode
317         mlt_producer_prepare_next( producer );
318
319         return 0;
320 }
321
322 static void producer_close( mlt_producer parent )
323 {
324         producer_qimage self = parent->child;
325         parent->close = NULL;
326         mlt_service_cache_purge( MLT_PRODUCER_SERVICE(parent) );
327         mlt_producer_close( parent );
328         mlt_properties_close( self->filenames );
329         free( self );
330 }