2 * producer_swfdec.c -- swfdec producer for Flash files
3 * Copyright (C) 2010 Dan Dennedy <dan@dennedy.org>
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.
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.
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
20 #include <framework/mlt.h>
21 #include <swfdec/swfdec.h>
31 struct mlt_producer_s parent;
34 cairo_surface_t *surface;
36 mlt_position last_position;
41 void swfdec_open( producer_swfdec swfdec, mlt_profile profile )
43 mlt_properties properties = MLT_PRODUCER_PROPERTIES( &swfdec->parent );
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 );
53 swfdec_player_get_default_size( swfdec->player, &swfdec->width, &swfdec->height );
54 if ( swfdec->width == 0 || swfdec->height == 0 )
56 swfdec_player_set_size( swfdec->player, profile->width, profile->height );
57 swfdec->width = profile->width;
58 swfdec->height = profile->height;
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;
68 scale = (double) profile->width / MAX( swfdec->width, swfdec->height );
69 swfdec->width = ceil( scale * swfdec->width );
70 swfdec->height = ceil( scale * swfdec->height );
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;
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 );
83 void swfdec_close( producer_swfdec swfdec )
86 cairo_destroy( swfdec->cairo );
89 g_object_unref( swfdec->player );
90 swfdec->player = NULL;
91 if ( swfdec->surface )
92 cairo_surface_destroy( swfdec->surface );
93 swfdec->surface = NULL;
96 // Cairo uses 32 bit native endian ARGB
97 static void bgra_to_rgba( uint8_t *src, uint8_t* dst, int width, int height )
99 int n = width * height + 1;
111 static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
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 mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
118 mlt_service_lock( service );
120 if ( !swfdec->player )
121 swfdec_open( swfdec, profile );
123 // Set width and height
124 *width = swfdec->width;
125 *height = swfdec->height;
126 *format = mlt_image_rgb24a;
128 *buffer = mlt_pool_alloc( *width * ( *height + 1 ) * 4 );
129 mlt_frame_set_image( frame, *buffer, *width * ( *height + 1 ) * 4, mlt_pool_release );
132 mlt_position pos = mlt_properties_get_position( properties, "swfdec.position" );
133 if ( pos > swfdec->last_position )
135 gulong msec = 1000UL * ( pos - swfdec->last_position ) * profile->frame_rate_den / profile->frame_rate_num;
137 msec -= swfdec_player_advance( swfdec->player, msec );
139 else if ( pos < swfdec->last_position )
141 swfdec_close( swfdec );
142 swfdec_open( swfdec, mlt_service_profile( service ) );
143 gulong msec = 1000UL * pos * profile->frame_rate_den / profile->frame_rate_num;
145 msec -= swfdec_player_advance( swfdec->player, msec );
147 swfdec->last_position = pos;
150 cairo_save( swfdec->cairo );
151 //cairo_set_source_rgba( swfdec->cairo, r, g, b, a );
152 cairo_set_operator( swfdec->cairo, CAIRO_OPERATOR_CLEAR );
153 cairo_paint( swfdec->cairo );
154 cairo_restore( swfdec->cairo );
155 swfdec_player_render( swfdec->player, swfdec->cairo );
157 // Get image from surface
158 uint8_t *image = cairo_image_surface_get_data( swfdec->surface );
160 mlt_service_unlock( service );
163 bgra_to_rgba( image, *buffer, swfdec->width, swfdec->height );
168 static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
170 // Access the private data
171 producer_swfdec swfdec = producer->child;
173 // Create an empty frame
174 *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
176 // Get the frames properties
177 mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );
179 // Update other info on the frame
180 mlt_properties_set_int( properties, "test_image", 0 );
181 mlt_properties_set_int( properties, "width", swfdec->width );
182 mlt_properties_set_int( properties, "height", swfdec->height );
183 mlt_properties_set_int( properties, "real_width", swfdec->width );
184 mlt_properties_set_int( properties, "real_height", swfdec->height );
185 mlt_properties_set_int( properties, "progressive", 1 );
186 mlt_properties_set_double( properties, "aspect_ratio", 1.0 );
187 mlt_properties_set_position( properties, "swfdec.position", mlt_producer_frame( producer ) );
189 // Push the get_image method on to the stack
190 mlt_frame_push_service( *frame, swfdec );
191 mlt_frame_push_get_image( *frame, get_image );
193 // Update timecode on the frame we're creating
194 mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
196 // Calculate the next timecode
197 mlt_producer_prepare_next( producer );
202 static void producer_close( mlt_producer parent )
205 producer_swfdec swfdec = parent->child;
208 swfdec_close( swfdec );
210 swfdec_url_free( swfdec->url );
213 parent->close = NULL;
214 mlt_producer_close( parent );
220 mlt_producer producer_swfdec_init( mlt_profile profile, mlt_service_type type, const char *id, char *filename )
222 if ( !filename ) return NULL;
223 producer_swfdec swfdec = calloc( 1, sizeof( *swfdec ) );
224 mlt_producer producer = NULL;
226 if ( swfdec && mlt_producer_init( &swfdec->parent, swfdec ) == 0 )
228 // Initialize swfdec and try to open the file
229 swfdec->url = swfdec_url_new_from_input( filename );
232 // Set the return value
233 producer = &swfdec->parent;
235 // Set the resource property (required for all producers)
236 mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
237 mlt_properties_set( properties, "resource", filename );
240 producer->close = (mlt_destructor) producer_close;
241 producer->get_frame = get_frame;
243 // Set the meta media attributes
244 swfdec->width = profile->width;
245 swfdec->height = profile->height;
246 mlt_properties_set_int( properties, "meta.media.nb_streams", 1 );
247 mlt_properties_set( properties, "meta.media.0.stream.type", "video" );
248 mlt_properties_set( properties, "meta.media.0.codec.name", "swf" );
249 mlt_properties_set( properties, "meta.media.0.codec.long_name", "Adobe Flash" );
250 mlt_properties_set( properties, "meta.media.0.codec.pix_fmt", "bgra" );
251 mlt_properties_set_int( properties, "meta.media.width", profile->width );
252 mlt_properties_set_int( properties, "meta.media.height", profile->height );
253 mlt_properties_set_double( properties, "meta.media.sample_aspect_num", 1.0 );
254 mlt_properties_set_double( properties, "meta.media.sample_aspect_den", 1.0 );
255 mlt_properties_set_int( properties, "meta.media.frame_rate_num", profile->frame_rate_num );
256 mlt_properties_set_int( properties, "meta.media.frame_rate_den", profile->frame_rate_den );
257 mlt_properties_set_int( properties, "meta.media.progressive", 1 );
261 g_object_unref( swfdec->player );
262 mlt_producer_close( &swfdec->parent );
274 static mlt_properties metadata( mlt_service_type type, const char *id, void *data )
276 char file[ PATH_MAX ];
277 snprintf( file, PATH_MAX, "%s/swfdec/%s", mlt_environment( "MLT_DATA" ), (char*) data );
278 return mlt_properties_parse_yaml( file );
284 MLT_REGISTER( producer_type, "swfdec", producer_swfdec_init );
285 MLT_REGISTER_METADATA( producer_type, "swfdec", metadata, "producer_swfdec.yml" );