]> git.sesse.net Git - mlt/commitdiff
Major westley rewrite - allows attachable filters
authorlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Tue, 7 Sep 2004 13:12:32 +0000 (13:12 +0000)
committerlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Tue, 7 Sep 2004 13:12:32 +0000 (13:12 +0000)
git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@411 d19143bc-622f-0410-bfdd-b5b2a6649095

docs/services.txt
docs/westley.txt
src/modules/westley/producer_westley.c

index 8a235fee015be5bb48b7f6b61818a32a6515be5d..00b3e0835eddb2ac45ff67c24560f05421f17dfe 100644 (file)
@@ -1357,6 +1357,41 @@ Consumers
            
                none
 
            
                none
 
+       mcmpeg
+       
+           Description
+           
+               Mainconcept MPEG encoder.
+
+           Constructor Argument
+
+               string target - the filename to write to.
+
+           Initialisation Properties
+           
+               int buffer - the number of frames to buffer, minimum 1, default 25.
+               string rescale - a rescale method, see the Filters/rescale.
+               string format - vcd [default], svcd or dvd provide base settings
+               int motion_search_type - 0 to 16 - reduces quality/cpu usage
+               int gop - group of picture size (default: format dependent)
+
+           Mutable Properties
+           
+               int progressive - indicates whether to use progressive or field-
+                                 based rendering, default 0 (off).
+               
+           Read Only Properties
+           
+               none
+               
+           Dependencies
+           
+               Mainconcept MPEG SDK
+               
+           Known Bugs
+           
+               none
+
        sdl
 
            Description
        sdl
 
            Description
index 288e284365c46ed4d236f9a61a2ed73fafb0dcd4..d6b0360363466c289c66fa2ed748f2cac24e725e 100644 (file)
@@ -14,7 +14,7 @@ Preamble:
        as such, it closely mirrors the internal structure of the MLT API.
 
        If you just want to go straight to the DTD, then see 
        as such, it closely mirrors the internal structure of the MLT API.
 
        If you just want to go straight to the DTD, then see 
-       mlt/src/modules/westley.dtd, which gets installed at 
+       mlt/src/modules/westley/westley.dtd, which gets installed at 
        $(prefix)/share/mlt/modules/westley.dtd. Currently, the westley parser is
        non-validating.
 
        $(prefix)/share/mlt/modules/westley.dtd. Currently, the westley parser is
        non-validating.
 
index d2acdbb7ff8e5111ba4578783d5f892c1fc76b02..4d862dda5153a0f1ae49f0e689a9e7fecf3c8155 100644 (file)
 extern xmlDocPtr westley_make_doc( mlt_service service );
 #endif
 
 extern xmlDocPtr westley_make_doc( mlt_service service );
 #endif
 
+enum service_type
+{
+       mlt_invalid_type,
+       mlt_unknown_type,
+       mlt_producer_type,
+       mlt_playlist_type,
+       mlt_entry_type,
+       mlt_tractor_type,
+       mlt_multitrack_type,
+       mlt_filter_type,
+       mlt_transition_type,
+       mlt_consumer_type,
+       mlt_field_type,
+       mlt_service_type,
+       mlt_dummy_filter_type,
+       mlt_dummy_transition_type,
+       mlt_dummy_producer_type,
+};
+
 struct deserialise_context_s
 {
 struct deserialise_context_s
 {
+       enum service_type stack_types[ STACK_SIZE ];
        mlt_service stack_service[ STACK_SIZE ];
        int stack_service_size;
        mlt_properties producer_map;
        mlt_properties destructors;
        char *property;
        mlt_service stack_service[ STACK_SIZE ];
        int stack_service_size;
        mlt_properties producer_map;
        mlt_properties destructors;
        char *property;
-       mlt_properties producer_properties;
        int is_value;
        xmlDocPtr value_doc;
        xmlNodePtr stack_node[ STACK_SIZE ];
        int is_value;
        xmlDocPtr value_doc;
        xmlNodePtr stack_node[ STACK_SIZE ];
@@ -59,8 +78,6 @@ struct deserialise_context_s
        const xmlChar *publicId;
        const xmlChar *systemId;
        mlt_properties params;
        const xmlChar *publicId;
        const xmlChar *systemId;
        mlt_properties params;
-       mlt_deque filter_queue;
-       int in_producer;
 };
 typedef struct deserialise_context_s *deserialise_context;
 
 };
 typedef struct deserialise_context_s *deserialise_context;
 
@@ -82,15 +99,16 @@ static char *serialise_branch( deserialise_context this, char *s )
 /** Push a service.
 */
 
 /** Push a service.
 */
 
-static int context_push_service( deserialise_context this, mlt_service that )
+static int context_push_service( deserialise_context this, mlt_service that, enum service_type type )
 {
        int ret = this->stack_service_size >= STACK_SIZE - 1;
        if ( ret == 0 )
        {
 {
        int ret = this->stack_service_size >= STACK_SIZE - 1;
        if ( ret == 0 )
        {
-               this->stack_service[ this->stack_service_size++ ] = that;
+               this->stack_service[ this->stack_service_size ] = that;
+               this->stack_types[ this->stack_service_size++ ] = type;
                
                // Record the tree branch on which this service lives
                
                // Record the tree branch on which this service lives
-               if ( mlt_properties_get( mlt_service_properties( that ), "_westley_branch" ) == NULL )
+               if ( that != NULL && mlt_properties_get( mlt_service_properties( that ), "_westley_branch" ) == NULL )
                {
                        char s[ BRANCH_SIG_LEN ];
                        mlt_properties_set( mlt_service_properties( that ), "_westley_branch", serialise_branch( this, s ) );
                {
                        char s[ BRANCH_SIG_LEN ];
                        mlt_properties_set( mlt_service_properties( that ), "_westley_branch", serialise_branch( this, s ) );
@@ -102,11 +120,15 @@ static int context_push_service( deserialise_context this, mlt_service that )
 /** Pop a service.
 */
 
 /** Pop a service.
 */
 
-static mlt_service context_pop_service( deserialise_context this )
+static mlt_service context_pop_service( deserialise_context this, enum service_type *type )
 {
        mlt_service result = NULL;
        if ( this->stack_service_size > 0 )
 {
        mlt_service result = NULL;
        if ( this->stack_service_size > 0 )
+       {
                result = this->stack_service[ -- this->stack_service_size ];
                result = this->stack_service[ -- this->stack_service_size ];
+               if ( type != NULL )
+                       *type = this->stack_types[ this->stack_service_size ];
+       }
        return result;
 }
 
        return result;
 }
 
@@ -170,13 +192,100 @@ static inline void qualify_property( deserialise_context context, mlt_properties
 }
 
 
 }
 
 
-// Forward declarations
-static void on_end_track( deserialise_context context, const xmlChar *name );
-static void on_end_entry( deserialise_context context, const xmlChar *name );
+/** This function adds a producer to a playlist or multitrack when
+    there is no entry or track element.
+*/
+
+static int add_producer( deserialise_context context, mlt_service service, mlt_position in, mlt_position out )
+{
+       // Return value (0 = service remains top of stack, 1 means it can be removed)
+       int result = 0;
+
+       // Get the parent producer
+       enum service_type type;
+       mlt_service container = context_pop_service( context, &type );
+       int contained = 0;
+
+       if ( service != NULL && container != NULL )
+       {
+               char *container_branch = mlt_properties_get( mlt_service_properties( container ), "_westley_branch" );
+               char *service_branch = mlt_properties_get( mlt_service_properties( service ), "_westley_branch" );
+               contained = !strncmp( container_branch, service_branch, strlen( container_branch ) );
+       }
+
+       if ( contained )
+       {
+               mlt_properties properties = mlt_service_properties( service );
+               char *hide_s = mlt_properties_get( properties, "hide" );
+
+               // Indicate that this service is no longer top of stack
+               result = 1;
+
+               switch( type )
+               {
+                       case mlt_tractor_type: 
+                               {
+                                       mlt_multitrack multitrack = mlt_tractor_multitrack( MLT_TRACTOR( container ) );
+                                       mlt_multitrack_connect( multitrack, MLT_PRODUCER( service ), mlt_multitrack_count( multitrack ) );
+                               }
+                               break;
+                       case mlt_multitrack_type:
+                               {
+                                       mlt_multitrack_connect( MLT_MULTITRACK( container ),
+                                               MLT_PRODUCER( service ),
+                                               mlt_multitrack_count( MLT_MULTITRACK( container ) ) );
+                               }
+                               break;
+                       case mlt_playlist_type:
+                               {
+                                       mlt_playlist_append_io( MLT_PLAYLIST( container ), MLT_PRODUCER( service ), in, out );
+                               }
+                               break;
+                       default:
+                               result = 0;
+                               fprintf( stderr, "Producer defined inside something that isn't a container\n" );
+                               break;
+               };
+
+               // Set the hide state of the track producer
+               if ( hide_s != NULL )
+               {
+                       if ( strcmp( hide_s, "video" ) == 0 )
+                               mlt_properties_set_int( properties, "hide", 1 );
+                       else if ( strcmp( hide_s, "audio" ) == 0 )
+                               mlt_properties_set_int( properties, "hide", 2 );
+                       else if ( strcmp( hide_s, "both" ) == 0 )
+                               mlt_properties_set_int( properties, "hide", 3 );
+               }
+       }
+
+       // Put the parent producer back
+       if ( container != NULL )
+               context_push_service( context, container, type );
+
+       return result;
+}
+
+/** Attach filters defined on that to this.
+*/
+
+static void attach_filters( mlt_service this, mlt_service that )
+{
+       if ( that != NULL )
+       {
+               int i = 0;
+               mlt_filter filter = NULL;
+               for ( i = 0; ( filter = mlt_service_filter( that, i ) ) != NULL; i ++ )
+               {
+                       mlt_service_attach( this, filter );
+                       attach_filters( mlt_filter_service( filter ), mlt_filter_service( filter ) );
+               }
+       }
+}
 
 static void on_start_tractor( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
 
 static void on_start_tractor( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
-       mlt_service service = mlt_tractor_service( mlt_tractor_init() );
+       mlt_service service = mlt_tractor_service( mlt_tractor_new( ) );
        mlt_properties properties = mlt_service_properties( service );
 
        track_service( context->destructors, service, (mlt_destructor) mlt_tractor_close );
        mlt_properties properties = mlt_service_properties( service );
 
        track_service( context->destructors, service, (mlt_destructor) mlt_tractor_close );
@@ -195,25 +304,72 @@ static void on_start_tractor( deserialise_context context, const xmlChar *name,
        if ( mlt_properties_get( properties, "id" ) != NULL )
                mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL );
        
        if ( mlt_properties_get( properties, "id" ) != NULL )
                mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL );
        
-       context_push_service( context, service );
+       context_push_service( context, service, mlt_tractor_type );
+}
+
+static void on_end_tractor( deserialise_context context, const xmlChar *name )
+{
+       // Get the tractor
+       enum service_type type;
+       mlt_service tractor = context_pop_service( context, &type );
+
+       if ( tractor != NULL && type == mlt_tractor_type )
+       {
+               // See if the tractor should be added to a playlist or multitrack
+               if ( add_producer( context, tractor, 0, mlt_producer_get_out( MLT_PRODUCER( tractor ) ) ) == 0 )
+                       context_push_service( context, tractor, type );
+       }
 }
 
 static void on_start_multitrack( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
 }
 
 static void on_start_multitrack( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
-       mlt_service service = mlt_multitrack_service( mlt_multitrack_init() );
-       mlt_properties properties = mlt_service_properties( service );
+       enum service_type type;
+       mlt_service parent = context_pop_service( context, &type );
 
 
-       track_service( context->destructors, service, (mlt_destructor) mlt_multitrack_close );
+       // If we don't have a parent, then create one now, providing we're in a state where we can
+       if ( parent == NULL || ( type == mlt_playlist_type || type == mlt_multitrack_type ) )
+       {
+               // Push the parent back
+               if ( parent != NULL )
+                       context_push_service( context, parent, type );
 
 
-       mlt_properties_set_position( properties, "length", 0 );
+               // Create a tractor to contain the multitrack
+               parent = mlt_tractor_service( mlt_tractor_new( ) );
+               track_service( context->destructors, parent, (mlt_destructor) mlt_tractor_close );
+               type = mlt_tractor_type;
 
 
-       for ( ; atts != NULL && *atts != NULL; atts += 2 )
-               mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
+               // Flag it as a synthesised tractor for clean up later
+               mlt_properties_set_int( mlt_service_properties( parent ), "fezzik_synth", 1 );
+       }
 
 
-       if ( mlt_properties_get( properties, "id" ) != NULL )
-               mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL );
+       if ( type == mlt_tractor_type )
+       {
+               mlt_service service = MLT_SERVICE( mlt_tractor_multitrack( MLT_TRACTOR( parent ) ) );
+               mlt_properties properties = mlt_service_properties( service );
+               mlt_properties_set_position( properties, "length", 0 );
+               for ( ; atts != NULL && *atts != NULL; atts += 2 )
+                       mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
+
+               if ( mlt_properties_get( properties, "id" ) != NULL )
+                       mlt_properties_set_data( context->producer_map, mlt_properties_get( properties,"id" ), service, 0, NULL, NULL );
 
 
-       context_push_service( context, service );
+               context_push_service( context, parent, type );
+               context_push_service( context, service, mlt_multitrack_type );
+       }
+       else
+       {
+               fprintf( stderr, "Invalid multitrack position\n" );
+       }
+}
+
+static void on_end_multitrack( deserialise_context context, const xmlChar *name )
+{
+       // Get the multitrack from the stack
+       enum service_type type;
+       mlt_service service = context_pop_service( context, &type );
+
+       if ( service == NULL || type != mlt_multitrack_type )
+               fprintf( stderr, "End multitrack in the wrong state...\n" );
 }
 
 static void on_start_playlist( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 }
 
 static void on_start_playlist( deserialise_context context, const xmlChar *name, const xmlChar **atts)
@@ -237,55 +393,218 @@ static void on_start_playlist( deserialise_context context, const xmlChar *name,
        if ( mlt_properties_get( properties, "id" ) != NULL )
                mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL );
 
        if ( mlt_properties_get( properties, "id" ) != NULL )
                mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL );
 
-       context_push_service( context, service );
+       context_push_service( context, service, mlt_playlist_type );
+}
+
+static void on_end_playlist( deserialise_context context, const xmlChar *name )
+{
+       // Get the playlist from the stack
+       enum service_type type;
+       mlt_service service = context_pop_service( context, &type );
+
+       if ( service != NULL && type == mlt_playlist_type )
+       {
+               mlt_properties properties = mlt_service_properties( service );
+               mlt_position in = mlt_properties_get_position( properties, "in" );
+               mlt_position out;
+
+               if ( mlt_properties_get( properties, "_westley.out" ) != NULL )
+                       out = mlt_properties_get_position( properties, "_westley.out" );
+               else
+                       out = mlt_properties_get_position( properties, "length" ) - 1;
+
+               if ( mlt_properties_get_position( properties, "length" ) < out )
+                       mlt_properties_set_position( properties, "length", out  + 1 );
+
+               mlt_producer_set_in_and_out( MLT_PRODUCER( service ), in, out );
+       
+               // See if the playlist should be added to a playlist or multitrack
+               if ( add_producer( context, service, in, out ) == 0 )
+                       context_push_service( context, service, type );
+       }
+       else
+       {
+               fprintf( stderr, "Invalid state of playlist end\n" );
+       }
 }
 
 static void on_start_producer( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
 }
 
 static void on_start_producer( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
-       mlt_properties properties = context->producer_properties = mlt_properties_new();
+       // use a dummy service to hold properties to allow arbitrary nesting
+       mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) );
+       mlt_service_init( service, NULL );
+
+       mlt_properties properties = mlt_service_properties( service );
 
 
-       context->in_producer ++;
+       context_push_service( context, service, mlt_dummy_producer_type );
 
        for ( ; atts != NULL && *atts != NULL; atts += 2 )
 
        for ( ; atts != NULL && *atts != NULL; atts += 2 )
-       {
                mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
                mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
+}
+
+static void on_end_producer( deserialise_context context, const xmlChar *name )
+{
+       enum service_type type;
+       mlt_service service = context_pop_service( context, &type );
+       mlt_properties properties = mlt_service_properties( service );
+
+       if ( service != NULL && type == mlt_dummy_producer_type )
+       {
+               mlt_service producer = NULL;
+
+               qualify_property( context, properties, "resource" );
+               char *resource = mlt_properties_get( properties, "resource" );
+
+               // Let Kino-SMIL src be a synonym for resource
+               if ( resource == NULL )
+               {
+                       qualify_property( context, properties, "src" );
+                       resource = mlt_properties_get( properties, "src" );
+               }
+
+               // Instantiate the producer
+               if ( mlt_properties_get( properties, "mlt_service" ) != NULL )
+               {
+                       char temp[ 1024 ];
+                       strncpy( temp, mlt_properties_get( properties, "mlt_service" ), 1024 );
+                       if ( resource != NULL )
+                       {
+                               strcat( temp, ":" );
+                               strncat( temp, resource, 1023 - strlen( temp ) );
+                       }
+                       producer = MLT_SERVICE( mlt_factory_producer( "fezzik", temp ) );
+               }
+
+               // Just in case the plugin requested doesn't exist...
+               if ( producer == NULL && resource != NULL )
+                       producer = MLT_SERVICE( mlt_factory_producer( "fezzik", resource ) );
+       
+               // Track this producer
+               track_service( context->destructors, producer, (mlt_destructor) mlt_producer_close );
+
+               // Propogate the properties
+               qualify_property( context, properties, "resource" );
+               qualify_property( context, properties, "luma" );
+               qualify_property( context, properties, "luma.resource" );
+               qualify_property( context, properties, "composite.luma" );
+               qualify_property( context, properties, "producer.resource" );
+
+               // Handle in/out properties separately
+               mlt_position in = -1;
+               mlt_position out = -1;
+       
+               // Get in
+               if ( mlt_properties_get( properties, "in" ) != NULL )
+                       in = mlt_properties_get_position( properties, "in" );
+               // Let Kino-SMIL clipBegin be a synonym for in
+               if ( mlt_properties_get( properties, "clipBegin" ) != NULL )
+                       in = mlt_properties_get_position( properties, "clipBegin" );
+               // Get out
+               if ( mlt_properties_get( properties, "out" ) != NULL )
+                       out = mlt_properties_get_position( properties, "out" );
+               // Let Kino-SMIL clipEnd be a synonym for out
+               if ( mlt_properties_get( properties, "clipEnd" ) != NULL )
+                       out = mlt_properties_get_position( properties, "clipEnd" );
+       
+               // Remove in and out
+               mlt_properties_set( properties, "in", NULL );
+               mlt_properties_set( properties, "out", NULL );
+
+               // Inherit the properties
+               mlt_properties_inherit( mlt_service_properties( producer ), properties );
+
+               // Attach all filters from service onto producer
+               attach_filters( producer, service );
+
+               // Add the producer to the producer map
+               if ( mlt_properties_get( properties, "id" ) != NULL )
+                       mlt_properties_set_data( context->producer_map, mlt_properties_get(properties, "id"), producer, 0, NULL, NULL );
+
+               // See if the producer should be added to a playlist or multitrack
+               if ( add_producer( context, producer, in, out ) == 0 )
+               {
+                       // Otherwise, set in and out on...
+                       if ( in != -1 || out != -1 )
+                       {
+                               // Get the parent service
+                               enum service_type type;
+                               mlt_service parent = context_pop_service( context, &type );
+                               if ( parent != NULL )
+                               {
+                                       // Get the parent properties
+                                       properties = mlt_service_properties( parent );
+                               
+                                       char *resource = mlt_properties_get( properties, "resource" );
+                               
+                                       // Put the parent producer back
+                                       context_push_service( context, parent, type );
+                                       
+                                       // If the parent is a track or entry
+                                       if ( resource && ( strcmp( resource, "<entry>" ) == 0 ) )
+                                       {
+                                               mlt_properties_set_position( properties, "in", in );
+                                               mlt_properties_set_position( properties, "out", out );
+                                       }
+                                       else
+                                       {
+                                               // Otherwise, set in and out on producer directly
+                                               mlt_producer_set_in_and_out( MLT_PRODUCER( service ), in, out );
+                                       }
+                               }
+                               else
+                               {
+                                       // Otherwise, set in and out on producer directly
+                                       mlt_producer_set_in_and_out( MLT_PRODUCER( producer ), in, out );
+                               }
+                       }
+       
+                       // Push the producer onto the stack
+                       context_push_service( context, producer, mlt_producer_type );
+               }
+
+               mlt_service_close( service );
        }
 }
 
 static void on_start_blank( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
        // Get the playlist from the stack
        }
 }
 
 static void on_start_blank( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
        // Get the playlist from the stack
-       mlt_service service = context_pop_service( context );
+       enum service_type type;
+       mlt_service service = context_pop_service( context, &type );
        mlt_position length = 0;
        
        mlt_position length = 0;
        
-       if ( service == NULL )
-               return;
-       
-       // Look for the length attribute
-       for ( ; atts != NULL && *atts != NULL; atts += 2 )
+       if ( type == mlt_playlist_type && service != NULL )
        {
        {
-               if ( strcmp( atts[0], "length" ) == 0 )
+               // Look for the length attribute
+               for ( ; atts != NULL && *atts != NULL; atts += 2 )
                {
                {
-                       length = atoll( atts[1] );
-                       break;
+                       if ( strcmp( atts[0], "length" ) == 0 )
+                       {
+                               length = atoll( atts[1] );
+                               break;
+                       }
                }
                }
-       }
 
 
-       // Append a blank to the playlist
-       mlt_playlist_blank( MLT_PLAYLIST( service ), length - 1 );
+               // Append a blank to the playlist
+               mlt_playlist_blank( MLT_PLAYLIST( service ), length - 1 );
 
 
-       // Push the playlist back onto the stack
-       context_push_service( context, service );
+               // Push the playlist back onto the stack
+               context_push_service( context, service, type );
+       }
+       else
+       {
+               fprintf( stderr, "blank without a playlist - a definite no no\n" );
+       }
 }
 
 static void on_start_entry_track( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
 }
 
 static void on_start_entry_track( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
-       // Use a dummy service to hold properties to allow arbitrary nesting
+       // use a dummy service to hold properties to allow arbitrary nesting
        mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) );
        mlt_service_init( service, NULL );
 
        // Push the dummy service onto the stack
        mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) );
        mlt_service_init( service, NULL );
 
        // Push the dummy service onto the stack
-       context_push_service( context, service );
+       context_push_service( context, service, mlt_entry_type );
        
        if ( strcmp( name, "entry" ) == 0 )
                mlt_properties_set( mlt_service_properties( service ), "resource", "<entry>" );
        
        if ( strcmp( name, "entry" ) == 0 )
                mlt_properties_set( mlt_service_properties( service ), "resource", "<entry>" );
@@ -299,660 +618,336 @@ static void on_start_entry_track( deserialise_context context, const xmlChar *na
                // Look for the producer attribute
                if ( strcmp( atts[ 0 ], "producer" ) == 0 )
                {
                // Look for the producer attribute
                if ( strcmp( atts[ 0 ], "producer" ) == 0 )
                {
-                       if ( mlt_properties_get_data( context->producer_map, (char*) atts[1], NULL ) !=  NULL )
-                               // Push the referenced producer onto the stack
-                               context_push_service( context, MLT_SERVICE( mlt_properties_get_data( context->producer_map, (char*) atts[1], NULL ) ) );
-                       else
-                               // Remove the dummy service to cause end element failure
-                               context_pop_service( context );
+                       mlt_producer producer = mlt_properties_get_data( context->producer_map, (char*) atts[1], NULL );
+                       if ( producer !=  NULL )
+                               mlt_properties_set_data( mlt_service_properties( service ), "producer", producer, 0, NULL, NULL );
                }
        }
 }
 
                }
        }
 }
 
-static void on_start_filter( deserialise_context context, const xmlChar *name, const xmlChar **atts)
+static void on_end_track( deserialise_context context, const xmlChar *name )
 {
 {
-       mlt_properties properties = mlt_properties_new();
+       // Get the track from the stack
+       enum service_type track_type;
+       mlt_service track = context_pop_service( context, &track_type );
 
 
-       if ( context->in_producer != 0 )
-               mlt_deque_push_front( context->filter_queue, context->producer_properties );
-
-       context->producer_properties = properties;
-
-       // Set the properties
-       for ( ; atts != NULL && *atts != NULL; atts += 2 )
-               mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
-}
+       if ( track != NULL && track_type == mlt_entry_type )
+       {
+               mlt_properties track_props = mlt_service_properties( track );
+               enum service_type parent_type;
+               mlt_service parent = context_pop_service( context, &parent_type );
+               mlt_multitrack multitrack = NULL;
+
+               mlt_producer producer = mlt_properties_get_data( track_props, "producer", NULL );
+               mlt_properties producer_props = mlt_producer_properties( producer );
+
+               if ( parent_type == mlt_tractor_type )
+                       multitrack = mlt_tractor_multitrack( MLT_TRACTOR( parent ) );
+               else if ( parent_type == mlt_multitrack_type )
+                       multitrack = MLT_MULTITRACK( parent );
+               else
+                       fprintf( stderr, "track contained in an invalid container\n" );
 
 
-static void on_start_transition( deserialise_context context, const xmlChar *name, const xmlChar **atts)
-{
-       mlt_properties properties = context->producer_properties = mlt_properties_new();
+               if ( multitrack != NULL )
+               {
+                       // Set the track on the multitrack
+                       mlt_multitrack_connect( multitrack, producer, mlt_multitrack_count( multitrack ) );
 
 
-       // Set the properties
-       for ( ; atts != NULL && *atts != NULL; atts += 2 )
-               mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
-}
+                       // Set producer i/o if specified
+                       if ( mlt_properties_get( track_props, "in" ) != NULL ||
+                               mlt_properties_get( track_props, "out" ) != NULL )
+                       {
+                               mlt_producer_set_in_and_out( MLT_PRODUCER( producer ),
+                                       mlt_properties_get_position( track_props, "in" ),
+                                       mlt_properties_get_position( track_props, "out" ) );
+                       }
+       
+                       // Set the hide state of the track producer
+                       char *hide_s = mlt_properties_get( track_props, "hide" );
+                       if ( hide_s != NULL )
+                       {
+                               if ( strcmp( hide_s, "video" ) == 0 )
+                                       mlt_properties_set_int( producer_props, "hide", 1 );
+                               else if ( strcmp( hide_s, "audio" ) == 0 )
+                                       mlt_properties_set_int( producer_props, "hide", 2 );
+                               else if ( strcmp( hide_s, "both" ) == 0 )
+                                       mlt_properties_set_int( producer_props, "hide", 3 );
+                       }
+               }
 
 
-static void on_start_property( deserialise_context context, const xmlChar *name, const xmlChar **atts)
-{
-       mlt_properties properties = context->producer_properties;
-       char *value = NULL;
+               if ( parent != NULL )
+                       context_push_service( context, parent, parent_type );
 
 
-       if ( properties == NULL )
-               return;
-       
-       // Set the properties
-       for ( ; atts != NULL && *atts != NULL; atts += 2 )
+               mlt_service_close( track );
+       }
+       else
        {
        {
-               if ( strcmp( atts[ 0 ], "name" ) == 0 )
-               {
-                       context->property = strdup( atts[ 1 ] );
-               }
-               else if ( strcmp( atts[ 0 ], "value" ) == 0 )
-               {
-                       value = (char*) atts[ 1 ];
-               }
+               fprintf( stderr, "Invalid state at end of track\n" );
        }
        }
-
-       if ( context->property != NULL && value != NULL )
-               mlt_properties_set( properties, context->property, value );
-       
-       // Tell parser to collect any further nodes for serialisation
-       context->is_value = 1;
 }
 
 }
 
-
-/** This function adds a producer to a playlist or multitrack when
-    there is no entry or track element.
-*/
-
-static int add_producer( deserialise_context context, mlt_service service, mlt_position in, mlt_position out )
+static void on_end_entry( deserialise_context context, const xmlChar *name )
 {
 {
-       // Get the parent producer
-       mlt_service producer = context_pop_service( context );
+       // Get the entry from the stack
+       enum service_type entry_type;
+       mlt_service entry = context_pop_service( context, &entry_type );
 
 
-       if ( producer != NULL )
+       if ( entry != NULL && entry_type == mlt_entry_type )
        {
        {
-               char current_branch[ BRANCH_SIG_LEN ];
-               char *service_branch = mlt_properties_get( mlt_service_properties( producer ), "_westley_branch" );
+               mlt_properties entry_props = mlt_service_properties( entry );
+               enum service_type parent_type;
+               mlt_service parent = context_pop_service( context, &parent_type );
+               mlt_producer producer = mlt_properties_get_data( entry_props, "producer", NULL );
 
 
-               // Validate the producer from the stack is an ancestor and not predecessor
-               serialise_branch( context, current_branch );
-               if ( service_branch != NULL && strncmp( service_branch, current_branch, strlen( service_branch ) ) == 0 )
+               if ( parent_type == mlt_playlist_type )
                {
                {
-                       char *resource = mlt_properties_get( mlt_service_properties( producer ), "resource" );
-                       
-                       // Put the parent producer back
-                       context_push_service( context, producer );
-                               
-                       // If the parent producer is a multitrack or playlist (not a track or entry)
-                       if ( resource && ( strcmp( resource, "<playlist>" ) == 0 ||
-                               strcmp( resource, "<multitrack>" ) == 0 ) )
+                       // Append the producer to the playlist
+                       if ( mlt_properties_get( mlt_service_properties( entry ), "in" ) != NULL ||
+                               mlt_properties_get( mlt_service_properties( entry ), "out" ) != NULL )
                        {
                        {
-//printf( "add_producer: current branch %s service branch %s (%d)\n", current_branch, service_branch, strncmp( service_branch, current_branch, strlen( service_branch ) ) );
-                               if ( strcmp( resource, "<playlist>" ) == 0 )
-                               {
-                                       // Append this producer to the playlist
-                                       mlt_playlist_append_io( MLT_PLAYLIST( producer ), 
-                                               MLT_PRODUCER( service ), in, out );
-                               }
-                               else
-                               {
-                                       mlt_properties properties = mlt_service_properties( service );
-                                       
-                                       // Set this producer on the multitrack
-                                       mlt_multitrack_connect( MLT_MULTITRACK( producer ),
-                                               MLT_PRODUCER( service ),
-                                               mlt_multitrack_count( MLT_MULTITRACK( producer ) ) );
-                                       
-                                       // Set the hide state of the track producer
-                                       char *hide_s = mlt_properties_get( properties, "hide" );
-                                       if ( hide_s != NULL )
-                                       {
-                                               if ( strcmp( hide_s, "video" ) == 0 )
-                                                       mlt_properties_set_int( properties, "hide", 1 );
-                                               else if ( strcmp( hide_s, "audio" ) == 0 )
-                                                       mlt_properties_set_int( properties, "hide", 2 );
-                                               else if ( strcmp( hide_s, "both" ) == 0 )
-                                                       mlt_properties_set_int( properties, "hide", 3 );
-                                       }
-       
-                               }
-                               // Normally, the enclosing entry or track will pop this service off
-                               // In its absence we do not push it on.
-                               return 1;
+                               mlt_playlist_append_io( MLT_PLAYLIST( parent ), producer,
+                                       mlt_properties_get_position( mlt_service_properties( entry ), "in" ), 
+                                       mlt_properties_get_position( mlt_service_properties( entry ), "out" ) );
+                       }
+                       else
+                       {
+                               mlt_playlist_append( MLT_PLAYLIST( parent ), producer );
                        }
                }
                        }
                }
-       }
-       return 0;
-}
+               else
+               {
+                       fprintf( stderr, "Invalid position for an entry...\n" );
+               }
 
 
-static void on_end_multitrack( deserialise_context context, const xmlChar *name )
-{
-       // Get the multitrack from the stack
-       mlt_service producer = context_pop_service( context );
-       if ( producer == NULL )
-               return;
-       
-       // Get the tractor from the stack
-       mlt_service service = context_pop_service( context );
-       
-       // Create a tractor if one does not exist
-       char *resource = NULL;
-       if ( service != NULL )
-               resource = mlt_properties_get( mlt_service_properties( service ), "resource" );
-       if ( service == NULL || resource == NULL || strcmp( resource, "<tractor>" ) )
+               if ( parent != NULL )
+                       context_push_service( context, parent, parent_type );
+
+               mlt_service_close( entry );
+       }
+       else
        {
        {
-//printf("creating a tractor\n");
-               char current_branch[ BRANCH_SIG_LEN ];
-               
-               // Put the anonymous service back onto the stack!
-               if ( service != NULL )
-                       context_push_service( context, service );
-               
-               // Fabricate the tractor
-               service = mlt_tractor_service( mlt_tractor_init() );
-               track_service( context->destructors, service, (mlt_destructor) mlt_tractor_close );
-               
-               // Inherit the producer's properties
-               mlt_properties properties = mlt_service_properties( service );
-               mlt_properties_set_position( properties, "length", mlt_producer_get_out( MLT_PRODUCER( producer ) ) + 1 );
-               mlt_producer_set_in_and_out( MLT_PRODUCER( service ), 0, mlt_producer_get_out( MLT_PRODUCER( producer ) ) );
-               mlt_properties_set_double( properties, "fps", mlt_producer_get_fps( MLT_PRODUCER( producer ) ) );
-               
-               mlt_properties_set( properties, "_westley_branch", serialise_branch( context, current_branch ) );
+               fprintf( stderr, "Invalid state at end of entry\n" );
        }
        }
-       
-       // Connect the tractor to the multitrack
-       mlt_tractor_connect( MLT_TRACTOR( service ), producer );
-       mlt_properties_set_data( mlt_service_properties( service ), "multitrack",
-               MLT_MULTITRACK( producer ), 0, NULL, NULL );
-
-       // See if the tractor should be added to a playlist or multitrack
-       add_producer( context, service, 0, mlt_producer_get_out( MLT_PRODUCER( producer ) ) );
-       
-       // Always push the multitrack back onto the stack for filters and transitions
-       context_push_service( context, producer );
-       
-       // Always push the tractor back onto the stack for filters and transitions
-       context_push_service( context, service );
 }
 
 }
 
-static void on_end_playlist( deserialise_context context, const xmlChar *name )
+static void on_start_filter( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
 {
-       // Get the playlist from the stack
-       mlt_service producer = context_pop_service( context );
-       if ( producer == NULL )
-               return;
-       mlt_properties properties = mlt_service_properties( producer );
-
-       mlt_position in = mlt_properties_get_position( properties, "in" );
-       mlt_position out;
+       // use a dummy service to hold properties to allow arbitrary nesting
+       mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) );
+       mlt_service_init( service, NULL );
 
 
-       if ( mlt_properties_get( properties, "_westley.out" ) != NULL )
-               out = mlt_properties_get_position( properties, "_westley.out" );
-       else
-               out = mlt_properties_get_position( properties, "length" ) - 1;
+       mlt_properties properties = mlt_service_properties( service );
 
 
-       if ( mlt_properties_get_position( properties, "length" ) < out )
-               mlt_properties_set_position( properties, "length", out  + 1 );
+       context_push_service( context, service, mlt_dummy_filter_type );
 
 
-       mlt_producer_set_in_and_out( MLT_PRODUCER( producer ), in, out );
-       
-       // See if the playlist should be added to a playlist or multitrack
-       if ( add_producer( context, producer, in, out ) == 0 )
-               
-               // Otherwise, push the playlist back onto the stack
-               context_push_service( context, producer );
+       // Set the properties
+       for ( ; atts != NULL && *atts != NULL; atts += 2 )
+               mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
 }
 
 }
 
-static void on_end_track( deserialise_context context, const xmlChar *name )
+static void on_end_filter( deserialise_context context, const xmlChar *name )
 {
 {
-       // Get the producer from the stack
-       mlt_service producer = context_pop_service( context );
-       if ( producer == NULL )
-               return;
-       mlt_properties producer_props = mlt_service_properties( producer );
-
-       // See if the producer is a tractor
-       char *resource = mlt_properties_get( producer_props, "resource" );
-       if ( resource && strcmp( resource, "<tractor>" ) == 0 )
-               // If so chomp its producer
-               context_pop_service( context );
-
-       // Get the dummy track service from the stack
-       mlt_service track = context_pop_service( context );
-       if ( track == NULL || strcmp( mlt_properties_get( mlt_service_properties( track ), "resource" ), "<track>" ) )
-       {
-               context_push_service( context, producer );
-               return;
-       }
-       mlt_properties track_props = mlt_service_properties( track );
+       enum service_type type;
+       mlt_service service = context_pop_service( context, &type );
+       mlt_properties properties = mlt_service_properties( service );
 
 
-       // Get the multitrack from the stack
-       mlt_service service = context_pop_service( context );
-       if ( service == NULL )
-       {
-               context_push_service( context, producer );
-               return;
-       }
-       
-       // Set the track on the multitrack
-       mlt_multitrack_connect( MLT_MULTITRACK( service ),
-               MLT_PRODUCER( producer ),
-               mlt_multitrack_count( MLT_MULTITRACK( service ) ) );
-
-       // Set producer i/o if specified
-       if ( mlt_properties_get( track_props, "in" ) != NULL ||
-               mlt_properties_get( track_props, "out" ) != NULL )
-       {
-               mlt_producer_set_in_and_out( MLT_PRODUCER( producer ),
-                       mlt_properties_get_position( track_props, "in" ),
-                       mlt_properties_get_position( track_props, "out" ) );
-       }
-       
-       // Set the hide state of the track producer
-       char *hide_s = mlt_properties_get( track_props, "hide" );
-       if ( hide_s != NULL )
+       enum service_type parent_type;
+       mlt_service parent = context_pop_service( context, &parent_type );
+
+       if ( service != NULL && type == mlt_dummy_filter_type )
        {
        {
-               if ( strcmp( hide_s, "video" ) == 0 )
-                       mlt_properties_set_int( producer_props, "hide", 1 );
-               else if ( strcmp( hide_s, "audio" ) == 0 )
-                       mlt_properties_set_int( producer_props, "hide", 2 );
-               else if ( strcmp( hide_s, "both" ) == 0 )
-                       mlt_properties_set_int( producer_props, "hide", 3 );
-       }
+               mlt_service filter = MLT_SERVICE( mlt_factory_filter( mlt_properties_get( properties, "mlt_service" ), NULL ) );
+               mlt_properties filter_props = mlt_service_properties( filter );
 
 
-       // Push the multitrack back onto the stack
-       context_push_service( context, service );
+               track_service( context->destructors, filter, (mlt_destructor) mlt_filter_close );
 
 
-       mlt_service_close( track );
-}
+               // Propogate the properties
+               qualify_property( context, properties, "resource" );
+               qualify_property( context, properties, "luma" );
+               qualify_property( context, properties, "luma.resource" );
+               qualify_property( context, properties, "composite.luma" );
+               qualify_property( context, properties, "producer.resource" );
+               mlt_properties_inherit( filter_props, properties );
 
 
-static void on_end_entry( deserialise_context context, const xmlChar *name )
-{
-       // Get the producer from the stack
-       mlt_service producer = context_pop_service( context );
-       if ( producer == NULL )
-               return;
-       
-       // See if the producer is a tractor
-       char *resource = mlt_properties_get( mlt_service_properties( producer ), "resource" );
-       if ( resource && strcmp( resource, "<tractor>" ) == 0 )
-               // If so chomp its producer
-               context_pop_service( context );
-
-       // Get the dummy entry service from the stack
-       mlt_service entry = context_pop_service( context );
-       if ( entry == NULL || strcmp( mlt_properties_get( mlt_service_properties( entry ), "resource" ), "<entry>" ) )
-       {
-               context_push_service( context, producer );
-               return;
-       }
+               // Attach all filters from service onto filter
+               attach_filters( filter, service );
 
 
-       // Get the playlist from the stack
-       mlt_service service = context_pop_service( context );
-       if ( service == NULL )
-       {
-               context_push_service( context, producer );
-               return;
-       }
+               // Associate the filter with the parent
+               if ( parent != NULL )
+               {
+                       if ( parent_type == mlt_tractor_type )
+                       {
+                               mlt_field field = mlt_tractor_field( MLT_TRACTOR( parent ) );
+                               mlt_field_plant_filter( field, MLT_FILTER( filter ), mlt_properties_get_int( properties, "track" ) );
+                               mlt_filter_set_in_and_out( MLT_FILTER( filter ), 
+                                                                                  mlt_properties_get_int( properties, "in" ),
+                                                                                  mlt_properties_get_int( properties, "out" ) );
+                       }
+                       else
+                       {
+                               mlt_service_attach( parent, MLT_FILTER( filter ) );
+                       }
 
 
-       // Append the producer to the playlist
-       if ( mlt_properties_get( mlt_service_properties( entry ), "in" ) != NULL ||
-               mlt_properties_get( mlt_service_properties( entry ), "out" ) != NULL )
-       {
-               mlt_playlist_append_io( MLT_PLAYLIST( service ),
-                       MLT_PRODUCER( producer ),
-                       mlt_properties_get_position( mlt_service_properties( entry ), "in" ), 
-                       mlt_properties_get_position( mlt_service_properties( entry ), "out" ) );
+                       // Put the parent back on the stack
+                       context_push_service( context, parent, parent_type );
+               }
+               else
+               {
+                       fprintf( stderr, "filter closed with invalid parent...\n" );
+               }
+
+               // Close the dummy filter service
+               mlt_service_close( service );
        }
        else
        {
        }
        else
        {
-               mlt_playlist_append( MLT_PLAYLIST( service ), MLT_PRODUCER( producer ) );
+               fprintf( stderr, "Invalid top of stack on filter close\n" );
        }
        }
-
-       // Push the playlist back onto the stack
-       context_push_service( context, service );
-
-       mlt_service_close( entry );
 }
 
 }
 
-static void on_end_tractor( deserialise_context context, const xmlChar *name )
+static void on_start_transition( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
 {
-       // Get the tractor
-       mlt_service tractor = context_pop_service( context );
-       if ( tractor == NULL )
-               return;
-       
-       // Get the tractor's multitrack
-       mlt_producer multitrack = mlt_properties_get_data( mlt_service_properties( tractor ), "multitrack", NULL );
-       if ( multitrack != NULL )
-       {
-               // Inherit the producer's properties
-               mlt_properties properties = mlt_producer_properties( MLT_PRODUCER( tractor ) );
-               mlt_properties_set_position( properties, "length", mlt_producer_get_out( multitrack ) + 1 );
-               mlt_producer_set_in_and_out( multitrack, 0, mlt_producer_get_out( multitrack ) );
-               mlt_properties_set_double( properties, "fps", mlt_producer_get_fps( multitrack ) );
-       }
+       // use a dummy service to hold properties to allow arbitrary nesting
+       mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) );
+       mlt_service_init( service, NULL );
 
 
-       // See if the tractor should be added to a playlist or multitrack
-       if ( add_producer( context, tractor, 0, mlt_producer_get_out( MLT_PRODUCER( tractor ) ) ) == 0 )
-               
-               // Otherwise, push the tractor back onto the stack
-               context_push_service( context, tractor );
-}
+       mlt_properties properties = mlt_service_properties( service );
 
 
-static void on_end_property( deserialise_context context, const xmlChar *name )
-{
-       // Tell parser to stop building a tree
-       context->is_value = 0;
-       
-       // See if there is a xml tree for the value
-       if ( context->property != NULL && context->value_doc != NULL )
-       {
-               xmlChar *value;
-               int size;
-               
-               // Serialise the tree to get value
-               xmlDocDumpMemory( context->value_doc, &value, &size );
-               mlt_properties_set( context->producer_properties, context->property, value );
-               xmlFree( value );
-               xmlFreeDoc( context->value_doc );
-               context->value_doc = NULL;
-       }
-       
-       // Close this property handling
-       free( context->property );
-       context->property = NULL;
+       context_push_service( context, service, mlt_dummy_transition_type );
+
+       // Set the properties
+       for ( ; atts != NULL && *atts != NULL; atts += 2 )
+               mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
 }
 
 }
 
-static void on_end_producer( deserialise_context context, const xmlChar *name )
+static void on_end_transition( deserialise_context context, const xmlChar *name )
 {
 {
-       mlt_properties properties = context->producer_properties;
-       mlt_service service = NULL;
-       
-       context->in_producer --;
+       enum service_type type;
+       mlt_service service = context_pop_service( context, &type );
+       mlt_properties properties = mlt_service_properties( service );
 
 
-       if ( properties == NULL )
-               return;
-               
-       qualify_property( context, properties, "resource" );
-       char *resource = mlt_properties_get( properties, "resource" );
-       // Let Kino-SMIL src be a synonym for resource
-       if ( resource == NULL )
-       {
-               qualify_property( context, properties, "src" );
-               resource = mlt_properties_get( properties, "src" );
-       }
+       enum service_type parent_type;
+       mlt_service parent = context_pop_service( context, &parent_type );
 
 
-       // Instantiate the producer
-       if ( mlt_properties_get( properties, "mlt_service" ) != NULL )
-       {
-               char temp[ 1024 ];
-               strncpy( temp, mlt_properties_get( properties, "mlt_service" ), 1024 );
-               if ( resource != NULL )
-               {
-                       strcat( temp, ":" );
-                       strncat( temp, resource, 1023 - strlen( temp ) );
-               }
-               service = MLT_SERVICE( mlt_factory_producer( "fezzik", temp ) );
-       }
-       if ( service == NULL && resource != NULL )
+       if ( service != NULL && type == mlt_dummy_transition_type )
        {
        {
-               service = MLT_SERVICE( mlt_factory_producer( "fezzik", resource ) );
-       }
-       
-       if ( service == NULL )
-               return;
-       track_service( context->destructors, service, (mlt_destructor) mlt_producer_close );
+               mlt_service effect = MLT_SERVICE( mlt_factory_transition(mlt_properties_get(properties,"mlt_service"), NULL ) );
+               mlt_properties effect_props = mlt_service_properties( effect );
 
 
-       // Add the producer to the producer map
-       if ( mlt_properties_get( properties, "id" ) != NULL )
-               mlt_properties_set_data( context->producer_map, mlt_properties_get( properties, "id" ), service, 0, NULL, NULL );
+               track_service( context->destructors, effect, (mlt_destructor) mlt_transition_close );
 
 
-       // Handle in/out properties separately
-       mlt_position in = -1;
-       mlt_position out = -1;
-       
-       // Get in
-       if ( mlt_properties_get( properties, "in" ) != NULL )
-               in = mlt_properties_get_position( properties, "in" );
-       // Let Kino-SMIL clipBegin be a synonym for in
-       if ( mlt_properties_get( properties, "clipBegin" ) != NULL )
-               in = mlt_properties_get_position( properties, "clipBegin" );
-       // Get out
-       if ( mlt_properties_get( properties, "out" ) != NULL )
-               out = mlt_properties_get_position( properties, "out" );
-       // Let Kino-SMIL clipEnd be a synonym for out
-       if ( mlt_properties_get( properties, "clipEnd" ) != NULL )
-               out = mlt_properties_get_position( properties, "clipEnd" );
-       
-       // Remove in and out
-       mlt_properties_set( properties, "in", NULL );
-       mlt_properties_set( properties, "out", NULL );
-       
-       mlt_properties_inherit( mlt_service_properties( service ), properties );
-       mlt_properties_close( properties );
-       context->producer_properties = NULL;
+               // Propogate the properties
+               qualify_property( context, properties, "resource" );
+               qualify_property( context, properties, "luma" );
+               qualify_property( context, properties, "luma.resource" );
+               qualify_property( context, properties, "composite.luma" );
+               qualify_property( context, properties, "producer.resource" );
+               mlt_properties_inherit( effect_props, properties );
 
 
-       // See if the producer should be added to a playlist or multitrack
-       if ( add_producer( context, service, in, out ) == 0 )
-       {
-               // Otherwise, set in and out on...
-               if ( in != -1 || out != -1 )
+               // Attach all filters from service onto effect
+               attach_filters( effect, service );
+
+               // Associate the filter with the parent
+               if ( parent != NULL )
                {
                {
-                       // Get the parent service
-                       mlt_service parent = context_pop_service( context );
-                       if ( parent != NULL )
+                       if ( parent_type == mlt_tractor_type )
                        {
                        {
-                               // Get the parent properties
-                               properties = mlt_service_properties( parent );
-                               
-                               char *resource = mlt_properties_get( properties, "resource" );
-                               
-                               // Put the parent producer back
-                               context_push_service( context, parent );
-                                       
-                               // If the parent is a track or entry
-                               if ( resource && ( strcmp( resource, "<entry>" ) == 0 ) )
-                               {
-                                       mlt_properties_set_position( properties, "in", in );
-                                       mlt_properties_set_position( properties, "out", out );
-                               }
-                               else
-                               {
-                                       // Otherwise, set in and out on producer directly
-                                       mlt_producer_set_in_and_out( MLT_PRODUCER( service ), in, out );
-                               }
+                               mlt_field field = mlt_tractor_field( MLT_TRACTOR( parent ) );
+                               mlt_field_plant_transition( field, MLT_TRANSITION( effect ), 
+                                                                                       mlt_properties_get_int( properties, "a_track" ),
+                                                                                       mlt_properties_get_int( properties, "b_track" ) );
+                               mlt_transition_set_in_and_out( MLT_TRANSITION( effect ), 
+                                                                                  mlt_properties_get_int( properties, "in" ),
+                                                                                  mlt_properties_get_int( properties, "out" ) );
                        }
                        else
                        {
                        }
                        else
                        {
-                               // Otherwise, set in and out on producer directly
-                               mlt_producer_set_in_and_out( MLT_PRODUCER( service ), in, out );
+                               fprintf( stderr, "Misplaced transition - ignoring\n" );
                        }
                        }
+
+                       // Put the parent back on the stack
+                       context_push_service( context, parent, parent_type );
                }
                }
-       
-               // Allow for embedded filters
-               while( mlt_deque_count( context->filter_queue ) )
+               else
                {
                {
-                       mlt_properties filter_properties = mlt_deque_pop_front( context->filter_queue );
-                       mlt_filter filter = mlt_factory_filter( mlt_properties_get( filter_properties, "mlt_service" ), NULL );
-                       if ( filter != NULL )
-                       {
-                               track_service( context->destructors, filter, (mlt_destructor) mlt_filter_close );
-                               qualify_property( context, filter_properties, "resource" );
-                               qualify_property( context, filter_properties, "luma" );
-                               qualify_property( context, filter_properties, "luma.resource" );
-                               qualify_property( context, filter_properties, "composite.luma" );
-                               qualify_property( context, filter_properties, "producer.resource" );
-                               mlt_properties_inherit( mlt_filter_properties( filter ), filter_properties );
-                               mlt_properties_close( filter_properties );
-                               mlt_producer_attach( MLT_PRODUCER( service ), filter );
-                       }
+                       fprintf( stderr, "transition closed with invalid parent...\n" );
                }
 
                }
 
-               // Push the producer onto the stack
-               context_push_service( context, service );
+               // Close the dummy filter service
+               mlt_service_close( service );
        }
        }
-}
-
-static void on_end_filter( deserialise_context context, const xmlChar *name )
-{
-       mlt_properties properties = context->producer_properties;
-       if ( context->in_producer )
+       else
        {
        {
-               mlt_deque_push_back( context->filter_queue, properties );
-               context->producer_properties = mlt_deque_pop_front( context->filter_queue );
-               return;
+               fprintf( stderr, "Invalid top of stack on transition close\n" );
        }
        }
+}
 
 
-       if ( properties == NULL )
-               return;
+static void on_start_property( deserialise_context context, const xmlChar *name, const xmlChar **atts)
+{
+       enum service_type type;
+       mlt_service service = context_pop_service( context, &type );
+       mlt_properties properties = mlt_service_properties( service );
+       char *value = NULL;
 
 
-       char *id;
-       char key[11];
-       key[ 10 ] = '\0';
-       mlt_service tractor = NULL;
-       
-       // Get the producer from the stack
-       mlt_service producer = context_pop_service( context );
-       if ( producer == NULL )
-               return;
-       
-       // See if the producer is a tractor
-       char *resource = mlt_properties_get( mlt_service_properties( producer ), "resource" );
-       if ( resource != NULL && strcmp( resource, "<tractor>" ) == 0 )
+       if ( service != NULL )
        {
        {
-               // If so, then get the next producer
-               tractor = producer;
-               producer = context_pop_service( context );
-       }
+               // Set the properties
+               for ( ; atts != NULL && *atts != NULL; atts += 2 )
+               {
+                       if ( strcmp( atts[ 0 ], "name" ) == 0 )
+                               context->property = strdup( atts[ 1 ] );
+                       else if ( strcmp( atts[ 0 ], "value" ) == 0 )
+                               value = (char*) atts[ 1 ];
+               }
+
+               if ( context->property != NULL && value != NULL )
+                       mlt_properties_set( properties, context->property, value );
        
        
-//fprintf( stderr, "connecting filter to %s\n", mlt_properties_get( mlt_service_properties( producer ), "resource" ) );
+               // Tell parser to collect any further nodes for serialisation
+               context->is_value = 1;
 
 
-       // Create the filter
-       mlt_service service = MLT_SERVICE( mlt_factory_filter( mlt_properties_get( properties, "mlt_service" ), NULL ) );
-       if ( service == NULL )
-       {
-               context_push_service( context, producer );
-               return;
+               context_push_service( context, service, type );
        }
        }
-       track_service( context->destructors, service, (mlt_destructor) mlt_filter_close );
-
-       // Connect the filter to the producer
-       mlt_filter_connect( MLT_FILTER( service ), producer,
-               mlt_properties_get_int( properties, "track" ) );
-
-       // Set in and out from producer if non existant
-       if ( mlt_properties_get( properties, "in" ) == NULL )
-               mlt_properties_set_position( properties, "in", mlt_producer_get_in( MLT_PRODUCER( producer ) ) );
-       if ( mlt_properties_get( properties, "out" ) == NULL )
-               mlt_properties_set_position( properties, "out", mlt_producer_get_out( MLT_PRODUCER( producer ) ) );
-
-       // Propogate the properties
-       qualify_property( context, properties, "resource" );
-       qualify_property( context, properties, "luma" );
-       qualify_property( context, properties, "luma.resource" );
-       qualify_property( context, properties, "composite.luma" );
-       qualify_property( context, properties, "producer.resource" );
-       mlt_properties_inherit( mlt_service_properties( service ), properties );
-       mlt_properties_close( properties );
-       context->producer_properties = NULL;
-       properties = mlt_service_properties( service );
-
-       // Set in and out again due to inheritance
-       mlt_filter_set_in_and_out( MLT_FILTER( service ), 
-               mlt_properties_get_position( properties, "in" ),
-               mlt_properties_get_position( properties, "out" ) );
-
-       // If a producer alias is in the producer_map, get it
-       snprintf( key, 10, "%p", producer );
-       if ( mlt_properties_get_data( context->producer_map, key, NULL ) != NULL )
-               producer = mlt_properties_get_data( context->producer_map, key, NULL );
-
-       // Put the producer in the producer map
-       id = mlt_properties_get( mlt_service_properties( producer ), "id" );
-       if ( id != NULL )
-               mlt_properties_set_data( context->producer_map, id, service, 0, NULL, NULL );
-
-       // For filter chain support, add an alias to the producer map
-       snprintf( key, 10, "%p", service );
-       mlt_properties_set_data( context->producer_map, key, producer, 0, NULL, NULL );
-       
-       // Push the filter onto the stack
-       context_push_service( context, service );
-       
-       if ( tractor != NULL )
+       else
        {
        {
-               // Connect the tractor to the filter
-               mlt_tractor_connect( MLT_TRACTOR( tractor ), service );
-
-               // Push the tractor back onto the stack
-               context_push_service( context, tractor );
+               fprintf( stderr, "Property without a service '%s'?\n", ( char * )name );
        }
 }
 
        }
 }
 
-static void on_end_transition( deserialise_context context, const xmlChar *name )
+static void on_end_property( deserialise_context context, const xmlChar *name )
 {
 {
-       mlt_service tractor = NULL;
-       mlt_properties properties = context->producer_properties;
-       if ( properties == NULL )
-               return;
-
-       // Get the producer from the stack
-       mlt_service producer = context_pop_service( context );
-       if ( producer == NULL )
-               return;
-
-       // See if the producer is a tractor
-       char *resource = mlt_properties_get( mlt_service_properties( producer ), "resource" );
-       if ( resource != NULL && strcmp( resource, "<tractor>" ) == 0 )
+       enum service_type type;
+       mlt_service service = context_pop_service( context, &type );
+       mlt_properties properties = mlt_service_properties( service );
+
+       if ( service != NULL )
        {
        {
-               // If so, then get the next producer
-               tractor = producer;
-               producer = context_pop_service( context );
-       }
+               // Tell parser to stop building a tree
+               context->is_value = 0;
        
        
-       // Create the transition
-       mlt_service service = MLT_SERVICE( mlt_factory_transition( mlt_properties_get( properties, "mlt_service" ), NULL ) );
-       if ( service == NULL )
-       {
-               context_push_service( context, producer );
-               return;
-       }
-       track_service( context->destructors, service, (mlt_destructor) mlt_transition_close );
-
-       // Propogate the properties
-       qualify_property( context, properties, "resource" );
-       qualify_property( context, properties, "luma" );
-       qualify_property( context, properties, "luma.resource" );
-       qualify_property( context, properties, "composite.luma" );
-       qualify_property( context, properties, "producer.resource" );
-       mlt_properties_inherit( mlt_service_properties( service ), properties );
-       mlt_properties_close( properties );
-       context->producer_properties = NULL;
-       properties = mlt_service_properties( service );
-
-       // Set in and out again due to inheritance
-       mlt_transition_set_in_and_out( MLT_TRANSITION( service ),
-               mlt_properties_get_position( properties, "in" ),
-               mlt_properties_get_position( properties, "out" ) );
-
-       // Connect the transition to the producer
-       mlt_transition_connect( MLT_TRANSITION( service ), producer,
-               mlt_properties_get_int( properties, "a_track" ),
-               mlt_properties_get_int( properties, "b_track" ) );
-
-       // Push the transition onto the stack
-       context_push_service( context, service );
+               // See if there is a xml tree for the value
+               if ( context->property != NULL && context->value_doc != NULL )
+               {
+                       xmlChar *value;
+                       int size;
+               
+                       // Serialise the tree to get value
+                       xmlDocDumpMemory( context->value_doc, &value, &size );
+                       mlt_properties_set( properties, context->property, value );
+                       xmlFree( value );
+                       xmlFreeDoc( context->value_doc );
+                       context->value_doc = NULL;
+               }
        
        
-       if ( tractor != NULL )
-       {
-               // Connect the tractor to the transition
-               mlt_tractor_connect( MLT_TRACTOR( tractor ), service );
+               // Close this property handling
+               free( context->property );
+               context->property = NULL;
 
 
-               // Push the tractor back onto the stack
-               context_push_service( context, tractor );
+               context_push_service( context, service, type );
+       }
+       else
+       {
+               fprintf( stderr, "Property without a service '%s'??\n", (char *)name );
        }
 }
 
        }
 }
 
@@ -1043,6 +1038,12 @@ static void on_characters( void *ctx, const xmlChar *ch, int len )
        struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx;
        deserialise_context context = ( deserialise_context )( xmlcontext->_private );
        char *value = calloc( len + 1, 1 );
        struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx;
        deserialise_context context = ( deserialise_context )( xmlcontext->_private );
        char *value = calloc( len + 1, 1 );
+       enum service_type type;
+       mlt_service service = context_pop_service( context, &type );
+       mlt_properties properties = mlt_service_properties( service );
+
+       if ( service != NULL )
+               context_push_service( context, service, type );
 
        value[ len ] = 0;
        strncpy( value, (const char*) ch, len );
 
        value[ len ] = 0;
        strncpy( value, (const char*) ch, len );
@@ -1053,24 +1054,23 @@ static void on_characters( void *ctx, const xmlChar *ch, int len )
        // libxml2 generates an on_characters immediately after a get_entity within
        // an element value, and we ignore it because it is called again during
        // actual substitution.
        // libxml2 generates an on_characters immediately after a get_entity within
        // an element value, and we ignore it because it is called again during
        // actual substitution.
-       else if ( context->property != NULL && context->producer_properties != NULL
-               && context->entity_is_replace == 0 )
+       else if ( context->property != NULL && context->entity_is_replace == 0 )
        {
        {
-               char *s = mlt_properties_get( context->producer_properties, context->property );
+               char *s = mlt_properties_get( properties, context->property );
                if ( s != NULL )
                {
                        // Append new text to existing content
                        char *new = calloc( strlen( s ) + len + 1, 1 );
                        strcat( new, s );
                        strcat( new, value );
                if ( s != NULL )
                {
                        // Append new text to existing content
                        char *new = calloc( strlen( s ) + len + 1, 1 );
                        strcat( new, s );
                        strcat( new, value );
-                       mlt_properties_set( context->producer_properties, context->property, new );
+                       mlt_properties_set( properties, context->property, new );
                        free( new );
                }
                else
                        free( new );
                }
                else
-                       mlt_properties_set( context->producer_properties, context->property, value );
+                       mlt_properties_set( properties, context->property, value );
        }
        context->entity_is_replace = 0;
        }
        context->entity_is_replace = 0;
-               
+       
        free( value);
 }
 
        free( value);
 }
 
@@ -1228,7 +1228,6 @@ mlt_producer producer_westley_init( char *url )
        context->producer_map = mlt_properties_new();
        context->destructors = mlt_properties_new();
        context->params = mlt_properties_new();
        context->producer_map = mlt_properties_new();
        context->destructors = mlt_properties_new();
        context->params = mlt_properties_new();
-       context->filter_queue = mlt_deque_init();
 
        // Decode URL and parse parameters      
        parse_url( context->params, url_decode( filename, url ) );
 
        // Decode URL and parse parameters      
        parse_url( context->params, url_decode( filename, url ) );
@@ -1277,7 +1276,8 @@ mlt_producer producer_westley_init( char *url )
        xmlMemoryDump( ); // for debugging
 
        // Get the last producer on the stack
        xmlMemoryDump( ); // for debugging
 
        // Get the last producer on the stack
-       mlt_service service = context_pop_service( context );
+       enum service_type type;
+       mlt_service service = context_pop_service( context, &type );
        if ( well_formed && service != NULL )
        {
                // Verify it is a producer service (mlt_type="mlt_producer")
        if ( well_formed && service != NULL )
        {
                // Verify it is a producer service (mlt_type="mlt_producer")
@@ -1337,7 +1337,6 @@ mlt_producer producer_westley_init( char *url )
        mlt_properties_close( context->producer_map );
        if ( context->params != NULL )
                mlt_properties_close( context->params );
        mlt_properties_close( context->producer_map );
        if ( context->params != NULL )
                mlt_properties_close( context->params );
-       mlt_deque_close( context->filter_queue );
        free( context );
        free( filename );
 
        free( context );
        free( filename );