]> git.sesse.net Git - mlt/blob - src/modules/qimage/producer_qimage.c
550df36b2265f238acf5700a49f3be43593c1322
[mlt] / src / modules / qimage / producer_qimage.c
1 /*
2  * producer_image.c -- a QT/QImage based producer for MLT
3  * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4  * Author: Dan Dennedy <dan@dennedy.org>
5  *         Charles Yates <charles.yates@gmail.com>
6  *
7  * NB: This module is designed to be functionally equivalent to the 
8  * gtk2 image loading module so it can be used as replacement.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  */
24
25 #include "producer_qimage.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
36 static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
37 static void producer_close( mlt_producer parent );
38
39 mlt_producer producer_qimage_init( char *filename )
40 {
41         producer_qimage this = calloc( sizeof( struct producer_qimage_s ), 1 );
42         if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 )
43         {
44                 mlt_producer producer = &this->parent;
45
46                 // Get the properties interface
47                 mlt_properties properties = MLT_PRODUCER_PROPERTIES( &this->parent );
48         
49                 // Callback registration
50                 producer->get_frame = producer_get_frame;
51                 producer->close = ( mlt_destructor )producer_close;
52
53                 // Set the default properties
54                 mlt_properties_set( properties, "resource", filename );
55                 mlt_properties_set_int( properties, "ttl", 25 );
56                 mlt_properties_set_int( properties, "aspect_ratio", 1 );
57                 mlt_properties_set_int( properties, "progressive", 1 );
58                 
59                 return producer;
60         }
61         free( this );
62         return NULL;
63 }
64
65 static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
66 {
67         // Obtain properties of frame
68         mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
69
70         // We need to know the size of the image to clone it
71         int image_size = 0;
72         int alpha_size = 0;
73
74         // Alpha channel
75         uint8_t *alpha = NULL;
76
77         *width = mlt_properties_get_int( properties, "rescale_width" );
78         *height = mlt_properties_get_int( properties, "rescale_height" );
79
80         // Refresh the image
81         refresh_qimage( frame, *width, *height );
82
83         // Get the image
84         *buffer = mlt_properties_get_data( properties, "image", &image_size );
85         alpha = mlt_properties_get_data( properties, "alpha", &alpha_size );
86
87         // Get width and height (may have changed during the refresh)
88         *width = mlt_properties_get_int( properties, "width" );
89         *height = mlt_properties_get_int( properties, "height" );
90
91         // NB: Cloning is necessary with this producer (due to processing of images ahead of use)
92         // The fault is not in the design of mlt, but in the implementation of the qimage producer...
93         if ( *buffer != NULL )
94         {
95                 if ( *format == mlt_image_yuv422 || *format == mlt_image_yuv420p )
96                 {
97                         // Clone the image and the alpha
98                         uint8_t *image_copy = mlt_pool_alloc( image_size );
99                         uint8_t *alpha_copy = mlt_pool_alloc( alpha_size );
100
101                         memcpy( image_copy, *buffer, image_size );
102
103                         // Copy or default the alpha
104                         if ( alpha != NULL )
105                                 memcpy( alpha_copy, alpha, alpha_size );
106                         else
107                                 memset( alpha_copy, 255, alpha_size );
108
109                         // Now update properties so we free the copy after
110                         mlt_properties_set_data( properties, "image", image_copy, image_size, mlt_pool_release, NULL );
111                         mlt_properties_set_data( properties, "alpha", alpha_copy, alpha_size, mlt_pool_release, NULL );
112
113                         // We're going to pass the copy on
114                         *buffer = image_copy;
115                 }
116                 else if ( *format == mlt_image_rgb24a )
117                 {
118                         // Clone the image and the alpha
119                         image_size = *width * ( *height + 1 ) * 4;
120                         alpha_size = *width * ( *height + 1 );
121                         uint8_t *image_copy = mlt_pool_alloc( image_size );
122                         uint8_t *alpha_copy = mlt_pool_alloc( alpha_size );
123
124                         mlt_convert_yuv422_to_rgb24a(*buffer, image_copy, (*width)*(*height));
125
126                         // Now update properties so we free the copy after
127                         mlt_properties_set_data( properties, "image", image_copy, image_size, mlt_pool_release, NULL );
128                         mlt_properties_set_data( properties, "alpha", alpha_copy, alpha_size, mlt_pool_release, NULL );
129
130                         // We're going to pass the copy on
131                         *buffer = image_copy;
132                 }
133         }
134         else
135         {
136                 // TODO: Review all cases of invalid images
137                 *buffer = mlt_pool_alloc( 50 * 50 * 2 );
138                 mlt_properties_set_data( properties, "image", *buffer, image_size, mlt_pool_release, NULL );
139                 *width = 50;
140                 *height = 50;
141         }
142
143         return 0;
144 }
145
146 static uint8_t *producer_get_alpha_mask( mlt_frame this )
147 {
148         // Obtain properties of frame
149         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
150
151         // Return the alpha mask
152         return mlt_properties_get_data( properties, "alpha", NULL );
153 }
154
155 static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
156 {
157         // Get the real structure for this producer
158         producer_qimage this = producer->child;
159
160         // Fetch the producers properties
161         mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer );
162
163         if ( this->filenames == NULL && mlt_properties_get( producer_properties, "resource" ) != NULL )
164         {
165                 char *filename = mlt_properties_get( producer_properties, "resource" );
166                 this->filenames = mlt_properties_new( );
167
168                 // Read xml string
169                 if ( strstr( filename, "<svg" ) )
170                 {
171                         // Generate a temporary file for the svg
172                         char fullname[ 1024 ] = "/tmp/mlt.XXXXXX";
173                         int fd = mkstemp( fullname );
174
175                         if ( fd > -1 )
176                         {
177                                 // Write the svg into the temp file
178                                 ssize_t remaining_bytes;
179                                 char *xml = filename;
180                                 
181                                 // Strip leading crap
182                                 while ( xml[0] != '<' )
183                                         xml++;
184                                 
185                                 remaining_bytes = strlen( xml );
186                                 while ( remaining_bytes > 0 )
187                                         remaining_bytes -= write( fd, xml + strlen( xml ) - remaining_bytes, remaining_bytes );
188                                 close( fd );
189
190                                 mlt_properties_set( this->filenames, "0", fullname );
191
192                                 // Teehe - when the producer closes, delete the temp file and the space allo
193                                 mlt_properties_set_data( producer_properties, "__temporary_file__", fullname, 0, ( mlt_destructor )unlink, NULL );
194                         }
195                 }
196                 // Obtain filenames
197                 else if ( strchr( filename, '%' ) != NULL )
198                 {
199                         // handle picture sequences
200                         int i = mlt_properties_get_int( producer_properties, "begin" );
201                         int gap = 0;
202                         char full[1024];
203                         int keyvalue = 0;
204                         char key[ 50 ];
205
206                         while ( gap < 100 )
207                         {
208                                 struct stat buf;
209                                 snprintf( full, 1023, filename, i ++ );
210                                 if ( stat( full, &buf ) == 0 )
211                                 {
212                                         sprintf( key, "%d", keyvalue ++ );
213                                         mlt_properties_set( this->filenames, "0", full );
214                                         gap = 0;
215                                 }
216                                 else
217                                 {
218                                         gap ++;
219                                 }
220                         }
221                 }
222                 else if ( strstr( filename, "/.all." ) != NULL )
223                 {
224                         char wildcard[ 1024 ];
225                         char *dir_name = strdup( filename );
226                         char *extension = strrchr( dir_name, '.' );
227
228                         *( strstr( dir_name, "/.all." ) + 1 ) = '\0';
229                         sprintf( wildcard, "*%s", extension );
230
231                         mlt_properties_dir_list( this->filenames, dir_name, wildcard, 1 );
232
233                         free( dir_name );
234                 }
235                 else
236                 {
237                         mlt_properties_set( this->filenames, "0", filename );
238                 }
239
240                 this->count = mlt_properties_count( this->filenames );
241         }
242
243         // Generate a frame
244         *frame = mlt_frame_init( );
245
246         if ( *frame != NULL && this->count > 0 )
247         {
248                 // Obtain properties of frame and producer
249                 mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );
250
251                 // Set the producer on the frame properties
252                 mlt_properties_set_data( properties, "producer_qimage", this, 0, NULL, NULL );
253
254                 // Update timecode on the frame we're creating
255                 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
256
257                 // Ensure that we have a way to obtain the position in the get_image
258                 mlt_properties_set_position( properties, "qimage_position", mlt_producer_position( producer ) );
259
260                 // Refresh the image
261                 refresh_qimage( *frame, 0, 0 );
262
263                 // Set producer-specific frame properties
264                 mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( producer_properties, "progressive" ) );
265                 mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_properties, "aspect_ratio" ) );
266
267                 // Set alpha call back
268                 ( *frame )->get_alpha_mask = producer_get_alpha_mask;
269
270                 // Push the get_image method
271                 mlt_frame_push_get_image( *frame, producer_get_image );
272         }
273
274         // Calculate the next timecode
275         mlt_producer_prepare_next( producer );
276
277         return 0;
278 }
279
280 static void producer_close( mlt_producer parent )
281 {
282         producer_qimage this = parent->child;
283         parent->close = NULL;
284         mlt_producer_close( parent );
285         mlt_properties_close( this->filenames );
286         free( this );
287 }