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>
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.
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.
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.
21 #include "producer_westley.h"
22 #include <framework/mlt.h>
27 #include <libxml/parser.h>
29 #define STACK_SIZE 1000
31 struct deserialise_context_s
33 mlt_service stack_service
[ STACK_SIZE
];
34 int stack_service_size
;
36 mlt_properties producer_map
;
40 typedef struct deserialise_context_s
*deserialise_context
;
46 static int context_push_service( deserialise_context
this, mlt_service that
)
48 int ret
= this->stack_service_size
>= STACK_SIZE
;
50 this->stack_service
[ this->stack_service_size
++ ] = that
;
57 static mlt_service
context_pop_service( deserialise_context
this )
59 mlt_service result
= NULL
;
60 if ( this->stack_service_size
> 0 )
61 result
= this->stack_service
[ -- this->stack_service_size
];
65 static void on_start_tractor( deserialise_context context
, const xmlChar
*name
, const xmlChar
**atts
)
67 mlt_service service
= mlt_tractor_service( mlt_tractor_init() );
69 for ( ; atts
!= NULL
&& *atts
!= NULL
; atts
+= 2 )
70 mlt_properties_set( mlt_service_properties( service
), (char*) atts
[0], (char*) atts
[1] );
72 context_push_service( context
, service
);
75 static void on_start_multitrack( deserialise_context context
, const xmlChar
*name
, const xmlChar
**atts
)
77 mlt_service service
= mlt_multitrack_service( mlt_multitrack_init() );
79 for ( ; atts
!= NULL
&& *atts
!= NULL
; atts
+= 2 )
80 mlt_properties_set( mlt_service_properties( service
), (char*) atts
[0], (char*) atts
[1] );
82 context_push_service( context
, service
);
85 static void on_start_playlist( deserialise_context context
, const xmlChar
*name
, const xmlChar
**atts
)
87 mlt_service service
= mlt_playlist_service( mlt_playlist_init() );
88 mlt_properties properties
= mlt_service_properties( service
);
90 for ( ; atts
!= NULL
&& *atts
!= NULL
; atts
+= 2 )
91 mlt_properties_set( properties
, (char*) atts
[0], (char*) atts
[1] );
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
);
96 context_push_service( context
, service
);
99 static void on_start_producer( deserialise_context context
, const xmlChar
*name
, const xmlChar
**atts
)
101 mlt_properties properties
= mlt_properties_new();
102 mlt_service service
= NULL
;
104 for ( ; atts
!= NULL
&& *atts
!= NULL
; atts
+= 2 )
105 mlt_properties_set( properties
, (char*) atts
[0], (char*) atts
[1] );
107 if ( mlt_properties_get( properties
, "mlt_service" ) != NULL
)
109 service
= MLT_SERVICE( mlt_factory_producer( mlt_properties_get( properties
, "mlt_service" ),
110 mlt_properties_get( properties
, "resource" ) ) );
114 // Unspecified producer, use inigo
115 char *args
[2] = { mlt_properties_get( properties
, "resource" ), 0 };
116 service
= MLT_SERVICE( mlt_factory_producer( "inigo", args
) );
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
);
122 mlt_properties_inherit( mlt_service_properties( service
), properties
);
123 mlt_properties_close( properties
);
125 context_push_service( context
, service
);
128 static void on_start_blank( deserialise_context context
, const xmlChar
*name
, const xmlChar
**atts
)
130 // Get the playlist from the stack
131 mlt_service service
= context_pop_service( context
);
132 mlt_position length
= 0;
134 // Look for the length attribute
135 for ( ; atts
!= NULL
&& *atts
!= NULL
; atts
+= 2 )
137 if ( strcmp( atts
[0], "length" ) == 0 )
139 length
= atoll( atts
[1] );
144 // Append a blank to the playlist
145 mlt_playlist_blank( MLT_PLAYLIST( service
), length
);
147 // Push the playlist back onto the stack
148 context_push_service( context
, service
);
151 static void on_start_entry_track( deserialise_context context
, const xmlChar
*name
, const xmlChar
**atts
)
153 // Look for the producer attribute
154 for ( ; atts
!= NULL
&& *atts
!= NULL
; atts
+= 2 )
156 if ( strcmp( atts
[0], "producer" ) == 0 )
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
) ) );
166 static void on_start_filter( deserialise_context context
, const xmlChar
*name
, const xmlChar
**atts
)
169 mlt_properties properties
= mlt_properties_new();
171 // Get the producer from the stack
172 mlt_service producer
= context_pop_service( context
);
174 // Set the properties
175 for ( ; atts
!= NULL
&& *atts
!= NULL
; atts
+= 2 )
176 mlt_properties_set( properties
, (char*) atts
[0], (char*) atts
[1] );
179 mlt_service service
= MLT_SERVICE( mlt_factory_filter( mlt_properties_get( properties
, "mlt_service" ), NULL
) );
181 // Connect the filter to the producer
182 mlt_filter_connect( MLT_FILTER( service
), producer
,
183 mlt_properties_get_int( properties
, "track" ) );
185 // Generate an id if one does not exist
186 if ( mlt_properties_get( properties
, "id" ) == NULL
)
190 snprintf( id
, 30, "filter%d", context
->filter_count
++ );
191 mlt_properties_set( properties
, "id", id
);
194 // Propogate the properties
195 mlt_properties_inherit( mlt_service_properties( service
), properties
);
196 mlt_properties_close( properties
);
198 // Get the parent producer from the stack
199 mlt_service tractor
= context_pop_service( context
);
201 if ( tractor
!= NULL
)
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
);
207 // Push the parent producer back onto the stack
208 context_push_service( context
, tractor
);
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
)
215 mlt_properties_set_data( context
->producer_map
, id
, service
, 0, NULL
, NULL
);
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
);
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
)
227 mlt_properties_set_data( context
->producer_map
, id
, service
, 0, NULL
, NULL
);
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
);
235 // Push the filter onto the stack
236 context_push_service( context
, service
);
239 static void on_start_transition( deserialise_context context
, const xmlChar
*name
, const xmlChar
**atts
)
241 mlt_properties properties
= mlt_properties_new();
243 // Get the producer from the stack
244 mlt_service producer
= context_pop_service( context
);
246 // Set the properties
247 for ( ; atts
!= NULL
&& *atts
!= NULL
; atts
+= 2 )
248 mlt_properties_set( properties
, (char*) atts
[0], (char*) atts
[1] );
250 // Create the transition
251 mlt_service service
= MLT_SERVICE( mlt_factory_transition( mlt_properties_get( properties
, "mlt_service" ), NULL
) );
253 // Generate an id if one does not exist
254 if ( mlt_properties_get( properties
, "id" ) == NULL
)
258 snprintf( id
, 30, "transition%d", context
->transition_count
++ );
259 mlt_properties_set( properties
, "id", id
);
262 // Propogate the properties
263 mlt_properties_inherit( mlt_service_properties( service
), properties
);
264 mlt_properties_close( properties
);
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" ) );
271 // Get the tractor from the stack
272 mlt_service tractor
= context_pop_service( context
);
274 // Connect the tractor to the transition
275 mlt_tractor_connect( MLT_TRACTOR( tractor
), service
);
277 // Push the tractor back onto the stack
278 context_push_service( context
, tractor
);
280 // Push the transition onto the stack
281 context_push_service( context
, service
);
284 static void on_end_multitrack( deserialise_context context
, const xmlChar
*name
)
286 // Get the producer (multitrack) from the stack
287 mlt_service producer
= context_pop_service( context
);
289 // Get the tractor from the stack
290 mlt_service service
= context_pop_service( context
);
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
);
297 // Push the tractor back onto the stack
298 context_push_service( context
, service
);
300 // Push the producer back onto the stack
301 context_push_service( context
, producer
);
304 static void on_end_playlist( deserialise_context context
, const xmlChar
*name
)
306 // Get the producer (playlist) from the stack
307 mlt_service producer
= context_pop_service( context
);
309 // Push the producer back onto the stack
310 context_push_service( context
, producer
);
313 static void on_end_track( deserialise_context context
, const xmlChar
*name
)
315 // Get the producer from the stack
316 mlt_service producer
= context_pop_service( context
);
318 // Get the multitrack from the stack
319 mlt_service service
= context_pop_service( context
);
321 // Set the track on the multitrack
322 mlt_multitrack_connect( MLT_MULTITRACK( service
),
323 MLT_PRODUCER( producer
),
324 context
->track_count
++ );
326 // Push the multitrack back onto the stack
327 context_push_service( context
, service
);
330 static void on_end_entry( deserialise_context context
, const xmlChar
*name
)
332 // Get the producer from the stack
333 mlt_service producer
= context_pop_service( context
);
335 // Get the playlist from the stack
336 mlt_service service
= context_pop_service( context
);
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" ) );
344 // Push the playlist back onto the stack
345 context_push_service( context
, service
);
348 static void on_start_element( void *ctx
, const xmlChar
*name
, const xmlChar
**atts
)
350 deserialise_context context
= ( deserialise_context
) ctx
;
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
);
370 static void on_end_element( void *ctx
, const xmlChar
*name
)
372 deserialise_context context
= ( deserialise_context
) ctx
;
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 )
384 // Discard the last producer
385 context_pop_service( context
);
390 mlt_producer
producer_westley_init( char *filename
)
392 xmlSAXHandler
*sax
= calloc( 1, sizeof( xmlSAXHandler
) );
393 struct deserialise_context_s
*context
= calloc( 1, sizeof( struct deserialise_context_s
) );
395 context
->producer_map
= mlt_properties_new();
396 sax
->startElement
= on_start_element
;
397 sax
->endElement
= on_end_element
;
400 xmlSAXUserParseFile( sax
, context
, filename
);
404 mlt_properties_close( context
->producer_map
);
406 mlt_service service
= context_pop_service( context
);
409 return MLT_PRODUCER( service
);