]> git.sesse.net Git - mlt/blob - src/modules/swfdec/producer_swfdec.c
Add support for swfdec variables.
[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
28 typedef struct
29 {
30         struct mlt_producer_s parent;
31     SwfdecPlayer *player;
32     SwfdecURL *url;
33     cairo_surface_t *surface;
34     cairo_t *cairo;
35     mlt_position last_position;
36         guint width;
37         guint height;
38 } *producer_swfdec;
39
40 void swfdec_open( producer_swfdec swfdec, mlt_profile profile )
41 {
42         mlt_properties properties = MLT_PRODUCER_PROPERTIES( &swfdec->parent );
43
44         // Setup the swfdec player
45         swfdec->player = swfdec_player_new( NULL );
46         if ( mlt_properties_get( properties, "variables") )
47                 swfdec_player_set_variables( swfdec->player, mlt_properties_get( properties, "variables" ) );
48         swfdec_player_set_url( swfdec->player, swfdec->url );
49         swfdec_player_set_maximum_runtime( swfdec->player, 10000 );
50
51         // Setup size
52         swfdec_player_get_default_size( swfdec->player, &swfdec->width, &swfdec->height );
53         if ( swfdec->width == 0 || swfdec->height == 0 )
54         {
55                 swfdec_player_set_size( swfdec->player, profile->width, profile->height );
56                 swfdec->width = profile->width;
57                 swfdec->height = profile->height;
58         }
59
60         // Setup scaling
61         double scale = 1.0;
62         if ( swfdec->width > 2 * swfdec->height )
63                 scale = 0.5 * profile->width / swfdec->height;
64         else if ( swfdec->height > 2 * swfdec->width )
65                 scale = 0.5 * profile->height / swfdec->width;
66         else
67                 scale = (double) profile->width / MAX( swfdec->width, swfdec->height );
68         swfdec->width = ceil( scale * swfdec->width );
69         swfdec->height = ceil( scale * swfdec->height );
70
71         // Compute the centering translation
72         double x = swfdec->width > profile->width ? (swfdec->width - profile->width) / 2 : 0;
73         double y = swfdec->height > profile->height ? (swfdec->height - profile->height) / 2 : 0;
74
75         // Setup cairo
76         swfdec->surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, MIN(profile->width, swfdec->width), MIN(profile->height, swfdec->height) );
77         swfdec->cairo = cairo_create( swfdec->surface );
78         cairo_translate( swfdec->cairo, -x, -y );
79         cairo_scale( swfdec->cairo, scale, scale );
80 }
81
82 void swfdec_close( producer_swfdec swfdec )
83 {
84         if ( swfdec->cairo )
85                 cairo_destroy( swfdec->cairo );
86         swfdec->cairo = NULL;
87         if ( swfdec->player )
88                 g_object_unref( swfdec->player );
89         swfdec->player = NULL;
90         if ( swfdec->surface )
91                 cairo_surface_destroy( swfdec->surface );
92         swfdec->surface = NULL;
93 }
94
95 // Cairo uses 32 bit native endian ARGB
96 static void bgra_to_rgba( uint8_t *src, uint8_t* dst, int width, int height )
97 {
98         int n = width * height + 1;
99
100         while ( --n )
101         {
102                 *dst++ = src[2];
103                 *dst++ = src[1];
104                 *dst++ = src[0];
105                 *dst++ = src[3];
106                 src += 4;
107         }       
108 }
109
110 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
111 {
112         producer_swfdec swfdec = mlt_frame_pop_service( frame );
113         mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
114
115         if ( !swfdec->player )
116                 swfdec_open( swfdec, mlt_service_profile( MLT_PRODUCER_SERVICE( &swfdec->parent ) ) );
117
118         // Set width and height
119         *width = swfdec->width;
120         *height = swfdec->height;
121         *format = mlt_image_rgb24a;
122
123         *buffer = mlt_pool_alloc( *width * ( *height + 1 ) * 4 );
124         mlt_properties_set_data( properties, "image", *buffer, *width * ( *height + 1 ) * 4, (mlt_destructor) mlt_pool_release, NULL );
125
126         // Seek
127         mlt_position pos = mlt_properties_get_position( properties, "swfdec.position" );
128         mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( &swfdec->parent ) );
129         if ( pos > swfdec->last_position )
130         {
131                 gulong msec = 1000UL * ( pos - swfdec->last_position ) * profile->frame_rate_den / profile->frame_rate_num;
132                 while ( msec > 0 )
133                         msec -= swfdec_player_advance( swfdec->player, msec );
134         }
135         else if ( pos < swfdec->last_position )
136         {
137                 swfdec_close( swfdec );
138                 swfdec_open( swfdec, mlt_service_profile( MLT_PRODUCER_SERVICE( &swfdec->parent ) ) );
139                 gulong msec = 1000UL * pos * profile->frame_rate_den / profile->frame_rate_num;
140                 while ( msec > 0 )
141                         msec -= swfdec_player_advance( swfdec->player, msec );
142         }
143         swfdec->last_position = pos;
144
145         // Render
146         cairo_save( swfdec->cairo );
147         //cairo_set_source_rgba( swfdec->cairo, r, g, b, a );
148         cairo_set_operator( swfdec->cairo, CAIRO_OPERATOR_CLEAR );
149         cairo_paint( swfdec->cairo );
150         cairo_restore( swfdec->cairo );
151         swfdec_player_render( swfdec->player, swfdec->cairo );
152
153         // Get image from surface
154         uint8_t *image = cairo_image_surface_get_data( swfdec->surface );
155         
156         // Convert to RGBA
157         bgra_to_rgba( image, *buffer, swfdec->width, swfdec->height );
158
159         return 0;
160 }
161
162 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
163 {
164         // Access the private data
165         producer_swfdec swfdec = producer->child;
166
167         // Create an empty frame
168         *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
169
170         // Get the frames properties
171         mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );
172
173         // Update other info on the frame
174         mlt_properties_set_int( properties, "test_image", 0 );
175         mlt_properties_set_int( properties, "width", swfdec->width );
176         mlt_properties_set_int( properties, "height", swfdec->height );
177         mlt_properties_set_int( properties, "real_width", swfdec->width );
178         mlt_properties_set_int( properties, "real_height", swfdec->height );
179         mlt_properties_set_int( properties, "progressive", 1 );
180         mlt_properties_set_double( properties, "aspect_ratio", 1.0 );
181         mlt_properties_set_position( properties, "swfdec.position", mlt_producer_frame( producer ) );
182
183         // Push the get_image method on to the stack
184         mlt_frame_push_service( *frame, swfdec );
185         mlt_frame_push_get_image( *frame, get_image );
186         
187         // Update timecode on the frame we're creating
188         mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
189
190         // Calculate the next timecode
191         mlt_producer_prepare_next( producer );
192
193         return 0;
194 }
195
196 static void producer_close( mlt_producer parent )
197 {
198         // Obtain swfdec
199         producer_swfdec swfdec = parent->child;
200
201         // Close the file
202         swfdec_close( swfdec );
203         if ( swfdec->url )
204                 swfdec_url_free( swfdec->url );
205
206         // Close the parent
207         parent->close = NULL;
208         mlt_producer_close( parent );
209
210         // Free the memory
211         free( swfdec );
212 }
213
214 mlt_producer producer_swfdec_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename )
215 {
216         if ( !filename ) return NULL;
217         producer_swfdec swfdec = calloc( 1, sizeof( *swfdec ) );
218         mlt_producer producer = NULL;
219
220         if ( swfdec && mlt_producer_init( &swfdec->parent, swfdec ) == 0 )
221         {
222                 // Initialize swfdec and try to open the file
223                 swfdec->url = swfdec_url_new_from_input( filename );
224                 if ( swfdec->url )
225                 {
226                         // Set the return value
227                         producer = &swfdec->parent;
228
229                         // Set the resource property (required for all producers)
230                         mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "resource", filename );
231
232                         // Set the callbacks
233                         producer->close = (mlt_destructor) producer_close;
234                         producer->get_frame = get_frame;
235                 }
236                 else
237                 {
238                         g_object_unref( swfdec->player );
239                         mlt_producer_close( &swfdec->parent );
240                         free( swfdec );
241                 }
242         }
243         else
244         {
245                 free( swfdec );
246         }
247
248         return producer;
249 }
250
251 MLT_REPOSITORY
252 {
253         swfdec_init();
254         MLT_REGISTER( producer_type, "swfdec", producer_swfdec_init );
255 }