field and playlist enhancements, producer pixbuf reorg
[melted] / src / modules / gtk2 / producer_pixbuf.c
1 /*
2 * producer_pixbuf.c -- raster image loader based upon gdk-pixbuf
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Dan Dennedy <dan@dennedy.org>
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 * along 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 "producer_pixbuf.h"
22 #include <framework/mlt_frame.h>
23 #include <gdk-pixbuf/gdk-pixbuf.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <math.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32
33 static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
34 static void producer_close( mlt_producer parent );
35
36 typedef enum
37 {
38 SIGNAL_FORMAT_PAL,
39 SIGNAL_FORMAT_NTSC
40 } mlt_signal_format;
41
42 mlt_producer producer_pixbuf_init( const char *filename )
43 {
44 producer_pixbuf this = calloc( sizeof( struct producer_pixbuf_s ), 1 );
45 if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 )
46 {
47 mlt_producer producer = &this->parent;
48
49 producer->get_frame = producer_get_frame;
50 producer->close = producer_close;
51
52 // Get the properties interface
53 mlt_properties properties = mlt_producer_properties( &this->parent );
54
55 // Set the default properties
56 mlt_properties_set_int( properties, "video_standard", mlt_video_standard_pal );
57 mlt_properties_set_double( properties, "ttl", 5 );
58
59 // Obtain filenames
60 if ( strchr( filename, '%' ) != NULL )
61 {
62 // handle picture sequences
63 int i = 0;
64 int gap = 0;
65 char full[1024];
66
67 while ( gap < 100 )
68 {
69 struct stat buf;
70 snprintf( full, 1023, filename, i ++ );
71 if ( stat( full, &buf ) == 0 )
72 {
73 this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) );
74 this->filenames[ this->count ++ ] = strdup( full );
75 gap = 0;
76 }
77 else
78 {
79 gap ++;
80 }
81 }
82 }
83 else
84 {
85 this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) );
86 this->filenames[ this->count ++ ] = strdup( filename );
87 }
88
89 // Initialise gobject types
90 g_type_init();
91
92 return producer;
93 }
94 free( this );
95 return NULL;
96 }
97
98 static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
99 {
100 // Obtain properties of frame
101 mlt_properties properties = mlt_frame_properties( this );
102
103 // May need to know the size of the image to clone it
104 int size = 0;
105
106 // Get the image
107 uint8_t *image = mlt_properties_get_data( properties, "image", &size );
108
109 // Get width and height
110 *width = mlt_properties_get_int( properties, "width" );
111 *height = mlt_properties_get_int( properties, "height" );
112
113 // Clone if necessary
114 if ( writable )
115 {
116 // Clone our image
117 uint8_t *copy = malloc( size );
118 memcpy( copy, image, size );
119
120 // We're going to pass the copy on
121 image = copy;
122
123 // Now update properties so we free the copy after
124 mlt_properties_set_data( properties, "image", copy, size, free, NULL );
125 }
126
127 // Pass on the image
128 *buffer = image;
129
130 return 0;
131 }
132
133 static uint8_t *producer_get_alpha_mask( mlt_frame this )
134 {
135 // Obtain properties of frame
136 mlt_properties properties = mlt_frame_properties( this );
137
138 // Return the alpha mask
139 return mlt_properties_get_data( properties, "alpha", NULL );
140 }
141
142 static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
143 {
144 producer_pixbuf this = producer->child;
145 GdkPixbuf *pixbuf = NULL;
146 GError *error = NULL;
147
148 // Generate a frame
149 *frame = mlt_frame_init( );
150
151 // Obtain properties of frame
152 mlt_properties properties = mlt_frame_properties( *frame );
153
154 // Get the time to live for each frame
155 double ttl = mlt_properties_get_double( mlt_producer_properties( producer ), "ttl" );
156
157 // Image index
158 int image_idx = ( int )floor( mlt_producer_position( producer ) / ttl ) % this->count;
159
160 // Update timecode on the frame we're creating
161 mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) );
162
163 // optimization for subsequent iterations on single picture
164 if ( this->image != NULL && image_idx == this->image_idx )
165 {
166 // Set width/height
167 mlt_properties_set_int( properties, "width", this->width );
168 mlt_properties_set_int( properties, "height", this->height );
169
170 // if picture sequence pass the image and alpha data without destructor
171 mlt_properties_set_data( properties, "image", this->image, 0, NULL, NULL );
172 mlt_properties_set_data( properties, "alpha", this->alpha, 0, NULL, NULL );
173
174 // Set alpha mask call back
175 ( *frame )->get_alpha_mask = producer_get_alpha_mask;
176
177 // Stack the get image callback
178 mlt_frame_push_get_image( *frame, producer_get_image );
179
180 }
181 else
182 {
183 free( this->image );
184 free( this->alpha );
185 this->image_idx = image_idx;
186 pixbuf = gdk_pixbuf_new_from_file( this->filenames[ image_idx ], &error );
187 }
188
189 // If we have a pixbuf
190 if ( pixbuf )
191 {
192 // Scale to adjust for sample aspect ratio
193 if ( mlt_properties_get_int( properties, "video_standard" ) == mlt_video_standard_pal )
194 {
195 GdkPixbuf *temp = pixbuf;
196 GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf,
197 (gint) ( (float) gdk_pixbuf_get_width( pixbuf ) * 54.0/59.0),
198 gdk_pixbuf_get_height( pixbuf ), GDK_INTERP_HYPER );
199 pixbuf = scaled;
200 g_object_unref( temp );
201 }
202 else
203 {
204 GdkPixbuf *temp = pixbuf;
205 GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf,
206 (gint) ( (float) gdk_pixbuf_get_width( pixbuf ) * 11.0/10.0 ),
207 gdk_pixbuf_get_height( pixbuf ), GDK_INTERP_HYPER );
208 pixbuf = scaled;
209 g_object_unref( temp );
210 }
211
212 // Store width and height
213 this->width = gdk_pixbuf_get_width( pixbuf );
214 this->height = gdk_pixbuf_get_height( pixbuf );
215
216 // Allocate/define image and alpha
217 uint8_t *image = malloc( this->width * this->height * 2 );
218 uint8_t *alpha = NULL;
219
220 // Extract YUV422 and alpha
221 if ( gdk_pixbuf_get_has_alpha( pixbuf ) )
222 {
223 // Allocate the alpha mask
224 alpha = malloc( this->width * this->height );
225
226 // Convert the image
227 mlt_convert_rgb24a_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ),
228 this->width, this->height,
229 gdk_pixbuf_get_rowstride( pixbuf ),
230 image, alpha );
231 }
232 else
233 {
234 // No alpha to extract
235 mlt_convert_rgb24_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ),
236 this->width, this->height,
237 gdk_pixbuf_get_rowstride( pixbuf ),
238 image );
239 }
240
241 // Finished with pixbuf now
242 g_object_unref( pixbuf );
243
244 // Set width/height of frame
245 mlt_properties_set_int( properties, "width", this->width );
246 mlt_properties_set_int( properties, "height", this->height );
247
248 // Pass alpha and image on properties with or without destructor
249 this->image = image;
250 this->alpha = alpha;
251
252 // pass the image and alpha data without destructor
253 mlt_properties_set_data( properties, "image", image, 0, NULL, NULL );
254 mlt_properties_set_data( properties, "alpha", alpha, 0, NULL, NULL );
255
256 // Set alpha call back
257 ( *frame )->get_alpha_mask = producer_get_alpha_mask;
258
259 // Push the get_image method
260 mlt_frame_push_get_image( *frame, producer_get_image );
261 }
262
263 // Calculate the next timecode
264 mlt_producer_prepare_next( producer );
265
266 return 0;
267 }
268
269 static void producer_close( mlt_producer parent )
270 {
271 producer_pixbuf this = parent->child;
272 if ( this->image )
273 free( this->image );
274 if ( this->alpha )
275 free( this->alpha );
276 parent->close = NULL;
277 mlt_producer_close( parent );
278 free( this );
279 }
280