updated westley
[melted] / src / modules / westley / producer_westley.c
1 /*
2 * producer_libdv.c -- a libxml2 parser of mlt service networks
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_westley.h"
22 #include <framework/mlt.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26
27 #include <libxml/parser.h>
28
29 #define STACK_SIZE 1000
30
31 struct deserialise_context_s
32 {
33 mlt_service stack_service[ STACK_SIZE ];
34 int stack_service_size;
35 int track_count;
36 mlt_properties producer_map;
37 int filter_count;
38 int transition_count;
39 };
40 typedef struct deserialise_context_s *deserialise_context;
41
42
43 /** Push a service.
44 */
45
46 static int context_push_service( deserialise_context this, mlt_service that )
47 {
48 int ret = this->stack_service_size >= STACK_SIZE;
49 if ( ret == 0 )
50 this->stack_service[ this->stack_service_size ++ ] = that;
51 return ret;
52 }
53
54 /** Pop a service.
55 */
56
57 static mlt_service context_pop_service( deserialise_context this )
58 {
59 mlt_service result = NULL;
60 if ( this->stack_service_size > 0 )
61 result = this->stack_service[ -- this->stack_service_size ];
62 return result;
63 }
64
65 static void on_start_tractor( deserialise_context context, const xmlChar *name, const xmlChar **atts)
66 {
67 mlt_service service = mlt_tractor_service( mlt_tractor_init() );
68
69 for ( ; atts != NULL && *atts != NULL; atts += 2 )
70 mlt_properties_set( mlt_service_properties( service ), (char*) atts[0], (char*) atts[1] );
71
72 context_push_service( context, service );
73 }
74
75 static void on_start_multitrack( deserialise_context context, const xmlChar *name, const xmlChar **atts)
76 {
77 mlt_service service = mlt_multitrack_service( mlt_multitrack_init() );
78
79 for ( ; atts != NULL && *atts != NULL; atts += 2 )
80 mlt_properties_set( mlt_service_properties( service ), (char*) atts[0], (char*) atts[1] );
81
82 context_push_service( context, service );
83 }
84
85 static void on_start_playlist( deserialise_context context, const xmlChar *name, const xmlChar **atts)
86 {
87 mlt_service service = mlt_playlist_service( mlt_playlist_init() );
88 mlt_properties properties = mlt_service_properties( service );
89
90 for ( ; atts != NULL && *atts != NULL; atts += 2 )
91 mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
92
93 if ( mlt_properties_get( properties, "id" ) != NULL )
94 mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL );
95
96 context_push_service( context, service );
97 }
98
99 static void on_start_producer( deserialise_context context, const xmlChar *name, const xmlChar **atts)
100 {
101 mlt_properties properties = mlt_properties_new();
102 mlt_service service = NULL;
103
104 for ( ; atts != NULL && *atts != NULL; atts += 2 )
105 mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
106
107 if ( mlt_properties_get( properties, "mlt_service" ) != NULL )
108 {
109 service = MLT_SERVICE( mlt_factory_producer( mlt_properties_get( properties, "mlt_service" ),
110 mlt_properties_get( properties, "resource" ) ) );
111 }
112 else
113 {
114 // Unspecified producer, use inigo
115 char *args[2] = { mlt_properties_get( properties, "resource" ), 0 };
116 service = MLT_SERVICE( mlt_factory_producer( "inigo", args ) );
117 }
118
119 if ( mlt_properties_get( properties, "id" ) != NULL )
120 mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL );
121
122 mlt_properties_inherit( mlt_service_properties( service ), properties );
123 mlt_properties_close( properties );
124
125 context_push_service( context, service );
126 }
127
128 static void on_start_blank( deserialise_context context, const xmlChar *name, const xmlChar **atts)
129 {
130 // Get the playlist from the stack
131 mlt_service service = context_pop_service( context );
132 mlt_position length = 0;
133
134 // Look for the length attribute
135 for ( ; atts != NULL && *atts != NULL; atts += 2 )
136 {
137 if ( strcmp( atts[0], "length" ) == 0 )
138 {
139 length = atoll( atts[1] );
140 break;
141 }
142 }
143
144 // Append a blank to the playlist
145 mlt_playlist_blank( MLT_PLAYLIST( service ), length );
146
147 // Push the playlist back onto the stack
148 context_push_service( context, service );
149 }
150
151 static void on_start_entry_track( deserialise_context context, const xmlChar *name, const xmlChar **atts)
152 {
153 // Look for the producer attribute
154 for ( ; atts != NULL && *atts != NULL; atts += 2 )
155 {
156 if ( strcmp( atts[0], "producer" ) == 0 )
157 {
158 if ( mlt_properties_get_data( context->producer_map, (char*) atts[1], NULL ) != NULL )
159 // Push the referenced producer onto the stack
160 context_push_service( context, MLT_SERVICE( mlt_properties_get_data( context->producer_map, (char*) atts[1], NULL ) ) );
161 break;
162 }
163 }
164 }
165
166 static void on_start_filter( deserialise_context context, const xmlChar *name, const xmlChar **atts)
167 {
168 char *id;
169 mlt_properties properties = mlt_properties_new();
170
171 // Get the producer from the stack
172 mlt_service producer = context_pop_service( context );
173
174 // Set the properties
175 for ( ; atts != NULL && *atts != NULL; atts += 2 )
176 mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
177
178 // Create the filter
179 mlt_service service = MLT_SERVICE( mlt_factory_filter( mlt_properties_get( properties, "mlt_service" ), NULL ) );
180
181 // Connect the filter to the producer
182 mlt_filter_connect( MLT_FILTER( service ), producer,
183 mlt_properties_get_int( properties, "track" ) );
184
185 // Generate an id if one does not exist
186 if ( mlt_properties_get( properties, "id" ) == NULL )
187 {
188 char id[ 31 ];
189 id[ 30 ] = '\0';
190 snprintf( id, 30, "filter%d", context->filter_count++ );
191 mlt_properties_set( properties, "id", id );
192 }
193
194 // Propogate the properties
195 mlt_properties_inherit( mlt_service_properties( service ), properties );
196 mlt_properties_close( properties );
197
198 // Get the parent producer from the stack
199 mlt_service tractor = context_pop_service( context );
200
201 if ( tractor != NULL )
202 {
203 // Connect the filter to the tractor
204 if ( strcmp( mlt_properties_get( mlt_service_properties( tractor ), "resource" ), "<tractor>" ) == 0 )
205 mlt_tractor_connect( MLT_TRACTOR( tractor ), service );
206
207 // Push the parent producer back onto the stack
208 context_push_service( context, tractor );
209 }
210
211 // If a producer alias is in the producer_map, get it
212 id = mlt_properties_get( context->producer_map, mlt_properties_get( mlt_service_properties( producer ), "id" ) );
213 if ( id != NULL && mlt_properties_get_data( context->producer_map, id, NULL ) != NULL )
214 {
215 mlt_properties_set_data( context->producer_map, id, service, 0, NULL, NULL );
216
217 // For filter chain support, add an alias to the producer map
218 // alias the filter id as the producer id
219 mlt_properties_set( context->producer_map, mlt_properties_get( mlt_service_properties( service ), "id" ), id );
220 }
221 else
222 {
223 // If the producer is in the producer_map, update it
224 id = mlt_properties_get( mlt_service_properties( producer ), "id" );
225 if ( id != NULL && mlt_properties_get_data( context->producer_map, id, NULL ) != NULL )
226 {
227 mlt_properties_set_data( context->producer_map, id, service, 0, NULL, NULL );
228
229 // For filter chain support, add an alias to the producer map
230 // alias the filter id as the producer id
231 mlt_properties_set( context->producer_map, mlt_properties_get( mlt_service_properties( service ), "id" ), id );
232 }
233 }
234
235 // Push the filter onto the stack
236 context_push_service( context, service );
237 }
238
239 static void on_start_transition( deserialise_context context, const xmlChar *name, const xmlChar **atts)
240 {
241 mlt_properties properties = mlt_properties_new();
242
243 // Get the producer from the stack
244 mlt_service producer = context_pop_service( context );
245
246 // Set the properties
247 for ( ; atts != NULL && *atts != NULL; atts += 2 )
248 mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
249
250 // Create the transition
251 mlt_service service = MLT_SERVICE( mlt_factory_transition( mlt_properties_get( properties, "mlt_service" ), NULL ) );
252
253 // Generate an id if one does not exist
254 if ( mlt_properties_get( properties, "id" ) == NULL )
255 {
256 char id[ 31 ];
257 id[ 30 ] = '\0';
258 snprintf( id, 30, "transition%d", context->transition_count++ );
259 mlt_properties_set( properties, "id", id );
260 }
261
262 // Propogate the properties
263 mlt_properties_inherit( mlt_service_properties( service ), properties );
264 mlt_properties_close( properties );
265
266 // Connect the filter to the producer
267 mlt_transition_connect( MLT_TRANSITION( service ), producer,
268 mlt_properties_get_int( mlt_service_properties( service ), "a_track" ),
269 mlt_properties_get_int( mlt_service_properties( service ), "b_track" ) );
270
271 // Get the tractor from the stack
272 mlt_service tractor = context_pop_service( context );
273
274 // Connect the tractor to the transition
275 mlt_tractor_connect( MLT_TRACTOR( tractor ), service );
276
277 // Push the tractor back onto the stack
278 context_push_service( context, tractor );
279
280 // Push the transition onto the stack
281 context_push_service( context, service );
282 }
283
284 static void on_end_multitrack( deserialise_context context, const xmlChar *name )
285 {
286 // Get the producer (multitrack) from the stack
287 mlt_service producer = context_pop_service( context );
288
289 // Get the tractor from the stack
290 mlt_service service = context_pop_service( context );
291
292 // Connect the tractor to the producer
293 mlt_tractor_connect( MLT_TRACTOR( service ), producer );
294 mlt_properties_set_data( mlt_service_properties( service ), "multitrack",
295 MLT_MULTITRACK( producer ), 0, NULL, NULL );
296
297 // Push the tractor back onto the stack
298 context_push_service( context, service );
299
300 // Push the producer back onto the stack
301 context_push_service( context, producer );
302 }
303
304 static void on_end_playlist( deserialise_context context, const xmlChar *name )
305 {
306 // Get the producer (playlist) from the stack
307 mlt_service producer = context_pop_service( context );
308
309 // Push the producer back onto the stack
310 context_push_service( context, producer );
311 }
312
313 static void on_end_track( deserialise_context context, const xmlChar *name )
314 {
315 // Get the producer from the stack
316 mlt_service producer = context_pop_service( context );
317
318 // Get the multitrack from the stack
319 mlt_service service = context_pop_service( context );
320
321 // Set the track on the multitrack
322 mlt_multitrack_connect( MLT_MULTITRACK( service ),
323 MLT_PRODUCER( producer ),
324 context->track_count++ );
325
326 // Push the multitrack back onto the stack
327 context_push_service( context, service );
328 }
329
330 static void on_end_entry( deserialise_context context, const xmlChar *name )
331 {
332 // Get the producer from the stack
333 mlt_service producer = context_pop_service( context );
334
335 // Get the playlist from the stack
336 mlt_service service = context_pop_service( context );
337
338 // Append the producer to the playlist
339 mlt_playlist_append_io( MLT_PLAYLIST( service ),
340 MLT_PRODUCER( producer ),
341 mlt_properties_get_position( mlt_service_properties( producer ), "in" ),
342 mlt_properties_get_position( mlt_service_properties( producer ), "out" ) );
343
344 // Push the playlist back onto the stack
345 context_push_service( context, service );
346 }
347
348 static void on_start_element( void *ctx, const xmlChar *name, const xmlChar **atts)
349 {
350 deserialise_context context = ( deserialise_context ) ctx;
351
352 if ( strcmp( name, "tractor" ) == 0 )
353 on_start_tractor( context, name, atts );
354 else if ( strcmp( name, "multitrack" ) == 0 )
355 on_start_multitrack( context, name, atts );
356 else if ( strcmp( name, "playlist" ) == 0 )
357 on_start_playlist( context, name, atts );
358 else if ( strcmp( name, "producer" ) == 0 )
359 on_start_producer( context, name, atts );
360 else if ( strcmp( name, "blank" ) == 0 )
361 on_start_blank( context, name, atts );
362 else if ( strcmp( name, "entry" ) == 0 || strcmp( name, "track" ) == 0 )
363 on_start_entry_track( context, name, atts );
364 else if ( strcmp( name, "filter" ) == 0 )
365 on_start_filter( context, name, atts );
366 else if ( strcmp( name, "transition" ) == 0 )
367 on_start_transition( context, name, atts );
368 }
369
370 static void on_end_element( void *ctx, const xmlChar *name )
371 {
372 deserialise_context context = ( deserialise_context ) ctx;
373
374 if ( strcmp( name, "multitrack" ) == 0 )
375 on_end_multitrack( context, name );
376 else if ( strcmp( name, "playlist" ) == 0 )
377 on_end_playlist( context, name );
378 else if ( strcmp( name, "track" ) == 0 )
379 on_end_track( context, name );
380 else if ( strcmp( name, "entry" ) == 0 )
381 on_end_entry( context, name );
382 else if ( strcmp( name, "tractor" ) == 0 )
383 {
384 // Discard the last producer
385 context_pop_service( context );
386 }
387 }
388
389
390 mlt_producer producer_westley_init( char *filename )
391 {
392 xmlSAXHandler *sax = calloc( 1, sizeof( xmlSAXHandler ) );
393 struct deserialise_context_s *context = calloc( 1, sizeof( struct deserialise_context_s ) );
394
395 context->producer_map = mlt_properties_new();
396 sax->startElement = on_start_element;
397 sax->endElement = on_end_element;
398
399 xmlInitParser();
400 xmlSAXUserParseFile( sax, context, filename );
401 xmlCleanupParser();
402 free( sax );
403
404 mlt_properties_close( context->producer_map );
405
406 mlt_service service = context_pop_service( context );
407 free( context );
408
409 return MLT_PRODUCER( service );
410 }
411