]> git.sesse.net Git - mlt/blob - src/modules/swfdec/producer_swfdec.c
A little debugging.
[mlt] / src / modules / swfdec / producer_swfdec.c
1 /*
2  * producer_swfdec.c -- swfdec producer for Flash files
3  * Copyright (C) 2010 Dan Dennedy <dan@dennedy.org>
4  *
5  * swfdec library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * swfdec library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with swfdec library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <framework/mlt.h>
21 #include <swfdec/swfdec.h>
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <math.h>
27 #include <limits.h>
28
29 typedef struct
30 {
31         struct mlt_producer_s parent;
32     SwfdecPlayer *player;
33     SwfdecURL *url;
34     cairo_surface_t *surface;
35     cairo_t *cairo;
36     mlt_position last_position;
37         guint width;
38         guint height;
39 } *producer_swfdec;
40
41 void swfdec_open( producer_swfdec swfdec, mlt_profile profile )
42 {
43         mlt_properties properties = MLT_PRODUCER_PROPERTIES( &swfdec->parent );
44
45         // Setup the swfdec player
46         swfdec->player = swfdec_player_new( NULL );
47         if ( mlt_properties_get( properties, "variables") )
48                 swfdec_player_set_variables( swfdec->player, mlt_properties_get( properties, "variables" ) );
49         swfdec_player_set_url( swfdec->player, swfdec->url );
50         swfdec_player_set_maximum_runtime( swfdec->player, 10000 );
51
52         // Setup size
53         swfdec_player_get_default_size( swfdec->player, &swfdec->width, &swfdec->height );
54         if ( swfdec->width == 0 || swfdec->height == 0 )
55         {
56                 swfdec_player_set_size( swfdec->player, profile->width, profile->height );
57                 swfdec->width = profile->width;
58                 swfdec->height = profile->height;
59         }
60
61         // Setup scaling
62         double scale = 1.0;
63         if ( swfdec->width > 2 * swfdec->height )
64                 scale = 0.5 * profile->width / swfdec->height;
65         else if ( swfdec->height > 2 * swfdec->width )
66                 scale = 0.5 * profile->height / swfdec->width;
67         else
68                 scale = (double) profile->width / MAX( swfdec->width, swfdec->height );
69         swfdec->width = ceil( scale * swfdec->width );
70         swfdec->height = ceil( scale * swfdec->height );
71
72         // Compute the centering translation
73         double x = swfdec->width > profile->width ? (swfdec->width - profile->width) / 2 : 0;
74         double y = swfdec->height > profile->height ? (swfdec->height - profile->height) / 2 : 0;
75
76         // Setup cairo
77         swfdec->surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, MIN(profile->width, swfdec->width), MIN(profile->height, swfdec->height) );
78         swfdec->cairo = cairo_create( swfdec->surface );
79         cairo_translate( swfdec->cairo, -x, -y );
80         cairo_scale( swfdec->cairo, scale, scale );
81 }
82
83 void swfdec_close( producer_swfdec swfdec )
84 {
85         if ( swfdec->cairo )
86                 cairo_destroy( swfdec->cairo );
87         swfdec->cairo = NULL;
88         if ( swfdec->player )
89                 g_object_unref( swfdec->player );
90         swfdec->player = NULL;
91         if ( swfdec->surface )
92                 cairo_surface_destroy( swfdec->surface );
93         swfdec->surface = NULL;
94 }
95
96 // Cairo uses 32 bit native endian ARGB
97 static void bgra_to_rgba( uint8_t *src, uint8_t* dst, int width, int height )
98 {
99         int n = width * height + 1;
100
101         while ( --n )
102         {
103                 *dst++ = src[2];
104                 *dst++ = src[1];
105                 *dst++ = src[0];
106                 *dst++ = src[3];
107                 src += 4;
108         }       
109 }
110
111 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
112 {
113         producer_swfdec swfdec = mlt_frame_pop_service( frame );
114         mlt_service service = MLT_PRODUCER_SERVICE( &swfdec->parent );
115         mlt_profile profile = mlt_service_profile( service );
116
117         mlt_service_lock( service );
118         
119         if ( !swfdec->player )
120                 swfdec_open( swfdec, profile );
121
122         // Set width and height
123         *width = swfdec->width;
124         *height = swfdec->height;
125         *format = mlt_image_rgb24a;
126
127         *buffer = mlt_pool_alloc( *width * ( *height + 1 ) * 4 );
128         mlt_frame_set_image( frame, *buffer, *width * ( *height + 1 ) * 4, mlt_pool_release );
129
130         // Seek
131         mlt_position pos = mlt_frame_original_position( frame );
132         if ( pos > swfdec->last_position )
133         {
134                 gulong msec = 1000UL * ( pos - swfdec->last_position ) * profile->frame_rate_den / profile->frame_rate_num;
135                 while ( msec > 0 )
136                         msec -= swfdec_player_advance( swfdec->player, msec );
137         }
138         else if ( pos < swfdec->last_position )
139         {
140                 swfdec_close( swfdec );
141                 swfdec_open( swfdec, mlt_service_profile( service ) );
142                 gulong msec = 1000UL * pos * profile->frame_rate_den / profile->frame_rate_num;
143                 while ( msec > 0 )
144                         msec -= swfdec_player_advance( swfdec->player, msec );
145         }
146         swfdec->last_position = pos;
147
148         // Render
149         cairo_save( swfdec->cairo );
150         //cairo_set_source_rgba( swfdec->cairo, r, g, b, a );
151         cairo_set_operator( swfdec->cairo, CAIRO_OPERATOR_CLEAR );
152         cairo_paint( swfdec->cairo );
153         cairo_restore( swfdec->cairo );
154         swfdec_player_render( swfdec->player, swfdec->cairo );
155
156         // Get image from surface
157         uint8_t *image = cairo_image_surface_get_data( swfdec->surface );
158         
159         mlt_service_unlock( service );
160         
161         // Convert to RGBA
162         bgra_to_rgba( image, *buffer, swfdec->width, swfdec->height );
163
164         return 0;
165 }
166
167 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
168 {
169         // Access the private data
170         producer_swfdec swfdec = producer->child;
171
172         // Create an empty frame
173         *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
174
175         // Get the frames properties
176         mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );
177
178         // Update other info on the frame
179         mlt_properties_set_int( properties, "test_image", 0 );
180         mlt_properties_set_int( properties, "width", swfdec->width );
181         mlt_properties_set_int( properties, "height", swfdec->height );
182         mlt_properties_set_int( properties, "progressive", 1 );
183         mlt_properties_set_double( properties, "aspect_ratio", 1.0 );
184
185         // Push the get_image method on to the stack
186         mlt_frame_push_service( *frame, swfdec );
187         mlt_frame_push_get_image( *frame, get_image );
188         
189         // Update timecode on the frame we're creating
190         mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
191
192         // Calculate the next timecode
193         mlt_producer_prepare_next( producer );
194
195         return 0;
196 }
197
198 static void producer_close( mlt_producer parent )
199 {
200         // Obtain swfdec
201         producer_swfdec swfdec = parent->child;
202
203         // Close the file
204         swfdec_close( swfdec );
205         if ( swfdec->url )
206                 swfdec_url_free( swfdec->url );
207
208         // Close the parent
209         parent->close = NULL;
210         mlt_producer_close( parent );
211
212         // Free the memory
213         free( swfdec );
214 }
215
216 mlt_producer producer_swfdec_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename )
217 {
218         if ( !filename ) return NULL;
219         producer_swfdec swfdec = calloc( 1, sizeof( *swfdec ) );
220         mlt_producer producer = NULL;
221
222         if ( swfdec && mlt_producer_init( &swfdec->parent, swfdec ) == 0 )
223         {
224                 // Initialize swfdec and try to open the file
225                 swfdec->url = swfdec_url_new_from_input( filename );
226                 if ( swfdec->url )
227                 {
228                         // Set the return value
229                         producer = &swfdec->parent;
230
231                         // Set the resource property (required for all producers)
232                         mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
233                         mlt_properties_set( properties, "resource", filename );
234
235                         // Set the callbacks
236                         producer->close = (mlt_destructor) producer_close;
237                         producer->get_frame = get_frame;
238
239                         // Set the meta media attributes
240                         swfdec->width = profile->width;
241                         swfdec->height = profile->height;
242                         mlt_properties_set_int( properties, "meta.media.nb_streams", 1 );
243                         mlt_properties_set( properties, "meta.media.0.stream.type", "video" );
244                         mlt_properties_set( properties, "meta.media.0.codec.name", "swf" );
245                         mlt_properties_set( properties, "meta.media.0.codec.long_name", "Adobe Flash" );
246                         mlt_properties_set( properties, "meta.media.0.codec.pix_fmt", "bgra" );
247                         mlt_properties_set_int( properties, "meta.media.width", profile->width );
248                         mlt_properties_set_int( properties, "meta.media.height", profile->height );
249                         mlt_properties_set_double( properties, "meta.media.sample_aspect_num", 1.0 );
250                         mlt_properties_set_double( properties, "meta.media.sample_aspect_den", 1.0 );
251                         mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num );
252                         mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den );
253                         mlt_properties_set_int( properties, "meta.media.progressive", 1 );
254                 }
255                 else
256                 {
257                         g_object_unref( swfdec->player );
258                         mlt_producer_close( &swfdec->parent );
259                         free( swfdec );
260                 }
261         }
262         else
263         {
264                 free( swfdec );
265         }
266
267         return producer;
268 }
269
270 static mlt_properties metadata( mlt_service_type type, const char *id, void *data )
271 {
272         char file[ PATH_MAX ];
273         snprintf( file, PATH_MAX, "%s/swfdec/%s", mlt_environment( "MLT_DATA" ), (char*) data );
274         return mlt_properties_parse_yaml( file );
275 }
276
277 MLT_REPOSITORY
278 {
279         swfdec_init();
280         MLT_REGISTER( producer_type, "swfdec", producer_swfdec_init );
281         MLT_REGISTER_METADATA( producer_type, "swfdec", metadata, "producer_swfdec.yml" );
282 }