]> git.sesse.net Git - mlt/commitdiff
Producer filter attach/detach methods; major rework on westley consumer, minor on...
authorlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Fri, 27 Aug 2004 20:35:29 +0000 (20:35 +0000)
committerlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Fri, 27 Aug 2004 20:35:29 +0000 (20:35 +0000)
git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@390 d19143bc-622f-0410-bfdd-b5b2a6649095

src/framework/mlt_playlist.c
src/framework/mlt_producer.c
src/framework/mlt_producer.h
src/modules/fezzik/producer_fezzik.c
src/modules/westley/consumer_westley.c
src/modules/westley/producer_westley.c

index 04e61d49236b0089437f6f128fee5bd52e86e41e..1347a0e3dcebe6bb1fde44370cd3eae63c35e652 100644 (file)
@@ -203,7 +203,6 @@ static mlt_service mlt_playlist_virtual_seek( mlt_playlist this )
 {
        // Default producer to blank
        mlt_producer producer = NULL;
-       mlt_service service = NULL;
 
        // Map playlist position to real producer in virtual playlist
        mlt_position position = mlt_producer_frame( &this->parent );
@@ -271,14 +270,7 @@ static mlt_service mlt_playlist_virtual_seek( mlt_playlist this )
                producer = &this->blank;
        }
 
-       if ( producer != NULL )
-       {
-               service = mlt_producer_service( producer );
-               while ( mlt_service_consumer( service ) != NULL )
-                       service = mlt_service_consumer( service );
-       }
-
-       return service;
+       return mlt_producer_service( producer );
 }
 
 /** Invoked when a producer indicates that it has prematurely reached its end.
@@ -671,21 +663,7 @@ int mlt_playlist_join( mlt_playlist this, int clip, int count, int merge )
                for ( i = 0; i <= count; i ++ )
                {
                        playlist_entry *entry = this->list[ clip ];
-                       char *resource = mlt_properties_get( mlt_producer_properties( entry->producer ), "resource" );
-                       if ( merge && resource != NULL && !strcmp( resource, "<playlist>" ) )
-                       {
-                               mlt_playlist old_clip = ( mlt_playlist )entry->producer;
-                               while( old_clip->count )
-                               {
-                                       entry = old_clip->list[ 0 ];
-                                       mlt_playlist_append_io( new_clip, entry->producer, entry->frame_in, entry->frame_out );
-                                       mlt_playlist_remove( old_clip, 0 );
-                               }
-                       }
-                       else
-                       {
-                               mlt_playlist_append_io( new_clip, entry->producer, entry->frame_in, entry->frame_out );
-                       }
+                       mlt_playlist_append_io( new_clip, entry->producer, entry->frame_in, entry->frame_out );
                        mlt_playlist_remove( this, clip );
                }
                mlt_playlist_insert( this, mlt_playlist_producer( new_clip ), clip, 0, -1 );
index 8ff5dc1fc8368c6b422f6a5d4573ce08fa17b90c..c07b2b2f8c30c51b026cc738f057719cbd3f7757 100644 (file)
@@ -296,8 +296,18 @@ static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int ind
        }
        else
        {
+               mlt_properties properties = mlt_producer_properties( this );
+               mlt_filter *filters = mlt_properties_get_data( properties, "_filters", NULL );
+               int count = mlt_properties_get_int( properties, "_filter_count" );
+               int i;
+
                // Get the frame from the implementation
                result = this->get_frame( this, frame, index );
+
+               // Process the frame with the attached filters
+               for ( i = 0; i < count; i ++ )
+                       if ( filters[ i ] != NULL )
+                               mlt_filter_process( filters[ i ], *frame );
        }
 
        // Copy the fps and speed of the producer onto the frame
@@ -311,6 +321,96 @@ static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int ind
        return 0;
 }
 
+/** Attach a filter.
+*/
+
+int mlt_producer_attach( mlt_producer this, mlt_filter filter )
+{
+       int error = this == NULL || filter == NULL;
+       if ( error == 0 )
+       {
+               int i = 0;
+               int size = 0;
+               mlt_properties properties = mlt_producer_properties( this );
+               mlt_filter *filters = mlt_properties_get_data( properties, "_filters", &size );
+               int count = mlt_properties_get_int( properties, "_filter_count" );
+
+               for ( i = 0; error == 0 && i < count; i ++ )
+                       if ( filters[ i ] == filter )
+                               error = 1;
+
+               if ( error == 0 )
+               {
+                       if ( count == size )
+                       {
+                               size += 10;
+                               filters = realloc( filters, size * sizeof( mlt_filter ) );
+                               mlt_properties_set_data( properties, "_filters", filters, size, NULL, NULL );
+                       }
+
+                       if ( filters != NULL )
+                       {
+                               mlt_properties_inc_ref( mlt_filter_properties( filter ) );
+                               filters[ count ++ ] = filter;
+                               mlt_properties_set_int( properties, "_filter_count", count );
+                       }
+                       else
+                       {
+                               error = 2;
+                       }
+               }
+       }
+       return error;
+}
+
+/** Detach a filter.
+*/
+
+int mlt_producer_detach( mlt_producer this, mlt_filter filter )
+{
+       int error = this == NULL || filter == NULL;
+       if ( error == 0 )
+       {
+               int i = 0;
+               int size = 0;
+               mlt_properties properties = mlt_producer_properties( this );
+               mlt_filter *filters = mlt_properties_get_data( properties, "_filters", &size );
+               int count = mlt_properties_get_int( properties, "_filter_count" );
+
+               for ( i = 0; i < count; i ++ )
+                       if ( filters[ i ] == filter )
+                               break;
+
+               if ( i < count )
+               {
+                       mlt_filter filter = filters[ i ];
+                       filters[ i ] = NULL;
+                       for ( i ++ ; i < count; i ++ )
+                               filters[ i - 1 ] = filters[ i ];
+                       mlt_properties_set_int( properties, "_filter_count", -- count );
+                       mlt_filter_close( filter );
+               }
+       }
+       return error;
+}
+
+/** Retrieve a filter.
+*/
+
+mlt_filter mlt_producer_filter( mlt_producer this, int index )
+{
+       mlt_filter filter = NULL;
+       if ( this != NULL )
+       {
+               mlt_properties properties = mlt_producer_properties( this );
+               mlt_filter *filters = mlt_properties_get_data( properties, "_filters", NULL );
+               int count = mlt_properties_get_int( properties, "_filter_count" );
+               if ( index >= 0 && index < count )
+                       filter = filters[ index ];
+       }
+       return filter;
+}
+
 /** Close the producer.
 */
 
@@ -318,6 +418,13 @@ void mlt_producer_close( mlt_producer this )
 {
        if ( this != NULL && mlt_properties_dec_ref( mlt_producer_properties( this ) ) <= 0 )
        {
+               mlt_properties properties = mlt_producer_properties( this );
+               mlt_filter *filters = mlt_properties_get_data( properties, "_filters", NULL );
+               int count = mlt_properties_get_int( properties, "_filter_count" );
+
+               while( count -- )
+                       mlt_producer_detach( this, filters[ 0 ] );
+
                this->parent.close = NULL;
 
                if ( this->close != NULL )
index 9bbcda80d8d88ecd5dd2b8a534423c26db952393..aabd557227c8d14773155e7f3837ec6a3334b63e 100644 (file)
@@ -22,6 +22,7 @@
 #define _MLT_PRODUCER_H_
 
 #include "mlt_service.h"
+#include "mlt_filter.h"
 
 /** The interface definition for all producers.
 */
@@ -60,6 +61,9 @@ extern mlt_position mlt_producer_get_out( mlt_producer self );
 extern mlt_position mlt_producer_get_playtime( mlt_producer self );
 extern mlt_position mlt_producer_get_length( mlt_producer self );
 extern void mlt_producer_prepare_next( mlt_producer self );
+extern int mlt_producer_attach( mlt_producer self, mlt_filter filter );
+extern int mlt_producer_detach( mlt_producer self, mlt_filter filter );
+extern mlt_filter mlt_producer_filter( mlt_producer self, int index );
 extern void mlt_producer_close( mlt_producer self );
 
 #endif
index 429cf802b4588cf2773db2842db97482393da88c..22c3510bb4d7236f74e5b9b013016d56726cc233 100644 (file)
 static mlt_properties dictionary = NULL;
 static mlt_properties normalisers = NULL;
 
-static void track_service( mlt_tractor tractor, void *service, mlt_destructor destructor )
-{
-       mlt_properties properties = mlt_tractor_properties( tractor );
-       int registered = mlt_properties_get_int( properties, "_registered" );
-       char *key = mlt_properties_get( properties, "_registered" );
-       char *real = malloc( strlen( key ) + 2 );
-       sprintf( real, "_%s", key );
-       mlt_properties_set_data( properties, real, service, 0, destructor, NULL );
-       mlt_properties_set_int( properties, "_registered", ++ registered );
-       free( real );
-}
-
 static mlt_producer create_from( char *file, char *services )
 {
        mlt_producer producer = NULL;
@@ -117,7 +105,7 @@ static mlt_producer create_producer( char *file )
        return result;
 }
 
-static mlt_service create_filter( mlt_tractor tractor, mlt_service last, char *effect, int *created )
+static void create_filter( mlt_producer producer, char *effect, int *created )
 {
        char *id = strdup( effect );
        char *arg = strchr( id, ':' );
@@ -126,16 +114,15 @@ static mlt_service create_filter( mlt_tractor tractor, mlt_service last, char *e
        mlt_filter filter = mlt_factory_filter( id, arg );
        if ( filter != NULL )
        {
-               mlt_filter_connect( filter, last, 0 );
-               track_service( tractor, filter, ( mlt_destructor )mlt_filter_close );
-               last = mlt_filter_service( filter );
+               mlt_properties_set_int( mlt_filter_properties( filter ), "_fezzik", 1 );
+               mlt_producer_attach( producer, filter );
+               mlt_filter_close( filter );
                *created = 1;
        }
        free( id );
-       return last;
 }
 
-static mlt_service attach_normalisers( mlt_tractor tractor, mlt_service last )
+static void attach_normalisers( mlt_producer producer )
 {
        // Loop variable
        int i;
@@ -160,71 +147,33 @@ static mlt_service attach_normalisers( mlt_tractor tractor, mlt_service last )
                char *value = mlt_properties_get_value( normalisers, i );
                mlt_tokeniser_parse_new( tokeniser, value, "," );
                for ( j = 0; !created && j < mlt_tokeniser_count( tokeniser ); j ++ )
-                       last = create_filter( tractor, last, mlt_tokeniser_get_string( tokeniser, j ), &created );
+                       create_filter( producer, mlt_tokeniser_get_string( tokeniser, j ), &created );
        }
 
        // Close the tokeniser
        mlt_tokeniser_close( tokeniser );
-
-       return last;
 }
 
 mlt_producer producer_fezzik_init( char *arg )
 {
-       // Create the producer that the tractor will contain
+       // Create the producer 
        mlt_producer producer = NULL;
+       mlt_properties properties = NULL;
 
        if ( arg != NULL )
                producer = create_producer( arg );
 
-       // Build the tractor if we have a producer and it isn't already westley'd :-)
-       if ( producer != NULL && mlt_properties_get( mlt_producer_properties( producer ), "westley" ) == NULL )
-       {
-               // Construct the tractor
-               mlt_tractor tractor = mlt_tractor_init( );
-
-               // Sanity check
-               if ( tractor != NULL )
-               {
-                       // Extract the tractor properties
-                       mlt_properties properties = mlt_tractor_properties( tractor );
-
-                       // Our producer will be the last service
-                       mlt_service last = mlt_producer_service( producer );
-
-                       // Set the registered count
-                       mlt_properties_set_int( properties, "_registered", 0 );
+       if ( producer != NULL )
+               properties = mlt_producer_properties( producer );
 
-                       // Register our producer for seeking in the tractor
-                       mlt_properties_set_data( properties, "producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL );
+       // Attach filters if we have a producer and it isn't already westley'd :-)
+       if ( producer != NULL && mlt_properties_get( properties, "westley" ) == NULL )
+               attach_normalisers( producer );
 
-                       // Now attach normalising filters
-                       last = attach_normalisers( tractor, last );
-
-                       // Connect the tractor to the last
-                       mlt_tractor_connect( tractor, last );
-
-                       // Finally, inherit properties from producer
-                       mlt_properties_inherit( properties, mlt_producer_properties( producer ) );
-
-                       // Now make sure we don't lose our inherited identity
-                       mlt_properties_set_int( properties, "_mlt_service_hidden", 1 );
-
-                       // This is a temporary hack to ensure that westley doesn't dig too deep
-                       // and fezzik doesn't overdo it with throwing rocks...
-                       mlt_properties_set( properties, "westley", "was here" );
-
-                       // We need to ensure that all further properties are mirrored in the producer
-                       mlt_properties_mirror( properties, mlt_producer_properties( producer ) );
-
-                       // Ensure that the inner producer ignores the in point
-                       mlt_properties_set_int( mlt_producer_properties( producer ), "ignore_points", 1 );
-
-                       // Now, we return the producer of the tractor
-                       producer = mlt_tractor_producer( tractor );
-               }
-       }
+       // Now make sure we don't lose our identity
+       if ( properties != NULL )
+               mlt_properties_set_int( properties, "_mlt_service_hidden", 1 );
 
-       // Return the tractor's producer
+       // Return the producer
        return producer;
 }
index 9b4adeb6f7b49a0fa285dbdfd8f198fa4321519e..c90d584d81ee1fd7cbe8e1aa9593da5eda0b1a56 100644 (file)
@@ -31,6 +31,7 @@
 // This maintains counters for adding ids to elements
 struct serialise_context_s
 {
+       mlt_properties id_map;
        int producer_count;
        int multitrack_count;
        int playlist_count;
@@ -38,7 +39,6 @@ struct serialise_context_s
        int filter_count;
        int transition_count;
        int pass;
-       mlt_properties producer_map;
        mlt_properties hide_map;
 };
 typedef struct serialise_context_s* serialise_context;
@@ -50,6 +50,92 @@ static int consumer_start( mlt_consumer parent );
 static int consumer_is_stopped( mlt_consumer this );
 static void serialise_service( serialise_context context, mlt_service service, xmlNode *node );
 
+typedef enum 
+{
+       westley_existing,
+       westley_producer,
+       westley_multitrack,
+       westley_playlist,
+       westley_tractor,
+       westley_filter,
+       westley_transition
+}
+westley_type;
+
+/** Create or retrieve an id associated to this service.
+*/
+
+static char *westley_get_id( serialise_context context, mlt_service service, westley_type type )
+{
+       char *id = NULL;
+       int i = 0;
+       mlt_properties map = context->id_map;
+
+       // Search the map for the service
+       for ( i = 0; i < mlt_properties_count( map ); i ++ )
+               if ( mlt_properties_get_data_at( map, i, NULL ) == service )
+                       break;
+
+       // If the service is not in the map, and the type indicates a new id is needed...
+       if ( i >= mlt_properties_count( map ) && type != westley_existing )
+       {
+               // Attempt to reuse existing id
+               id = mlt_properties_get( mlt_service_properties( service ), "id" );
+
+               // If no id, or the id is used in the map (for another service), then 
+               // create a new one.
+               if ( id == NULL || mlt_properties_get_data( map, id, NULL ) != NULL )
+               {
+                       char temp[ ID_SIZE ];
+                       do
+                       {
+                               switch( type )
+                               {
+                                       case westley_producer:
+                                               sprintf( temp, "producer%d", context->producer_count ++ );
+                                               break;
+                                       case westley_multitrack:
+                                               sprintf( temp, "multitrack%d", context->multitrack_count ++ );
+                                               break;
+                                       case westley_playlist:
+                                               sprintf( temp, "playlist%d", context->playlist_count ++ );
+                                               break;
+                                       case westley_tractor:
+                                               sprintf( temp, "tractor%d", context->tractor_count ++ );
+                                               break;
+                                       case westley_filter:
+                                               sprintf( temp, "filter%d", context->filter_count ++ );
+                                               break;
+                                       case westley_transition:
+                                               sprintf( temp, "transition%d", context->transition_count ++ );
+                                               break;
+                                       case westley_existing:
+                                               // Never gets here
+                                               break;
+                               }
+                       }
+                       while( mlt_properties_get_data( map, temp, NULL ) != NULL );
+
+                       // Set the data at the generated name
+                       mlt_properties_set_data( map, temp, service, 0, NULL, NULL );
+
+                       // Get the pointer to the name (i is the end of the list)
+                       id = mlt_properties_get_name( map, i );
+               }
+               else
+               {
+                       // Store the existing id in the map
+                       mlt_properties_set_data( map, id, service, 0, NULL, NULL );
+               }
+       }
+       else if ( type == westley_existing )
+       {
+               id = mlt_properties_get_name( map, i );
+       }
+
+       return id;
+}
+
 /** This is what will be called by the factory - anything can be passed in
        via the argument, but keep it simple.
 */
@@ -102,39 +188,57 @@ static inline void serialise_properties( mlt_properties properties, xmlNode *nod
        }
 }
 
+static inline void serialise_producer_filters( serialise_context context, mlt_service service, xmlNode *node )
+{
+       int i;
+       xmlNode *p;
+       mlt_filter filter = NULL;
+       
+       // Enumerate the filters
+       for ( i = 0; ( filter = mlt_producer_filter( MLT_PRODUCER( service ), i ) ) != NULL; i ++ )
+       {
+               mlt_properties properties = mlt_filter_properties( filter );
+               if ( mlt_properties_get_int( properties, "_fezzik" ) == 0 )
+               {
+                       // Get a new id - if already allocated, do nothing
+                       char *id = westley_get_id( context, mlt_filter_service( filter ), westley_filter );
+                       if ( id == NULL )
+                               continue;
+
+                       p = xmlNewChild( node, NULL, "filter", NULL );
+                       xmlNewProp( p, "id", id );
+                       serialise_properties( properties, p );
+               }
+       }
+}
+
 static void serialise_producer( serialise_context context, mlt_service service, xmlNode *node )
 {
        xmlNode *child = node;
-       char id[ ID_SIZE + 1 ];
-       char key[ 11 ];
        mlt_properties properties = mlt_service_properties( service );
        
-       id[ ID_SIZE ] = '\0';
-       key[ 10 ] = '\0';
-       
        if ( context->pass == 0 )
        {
+               // Get a new id - if already allocated, do nothing
+               char *id = westley_get_id( context, service, westley_producer );
+               if ( id == NULL )
+                       return;
+
                child = xmlNewChild( node, NULL, "producer", NULL );
 
                // Set the id
-               if ( mlt_properties_get( properties, "id" ) == NULL )
-               {
-                       snprintf( id, ID_SIZE, "producer%d", context->producer_count++ );
-                       xmlNewProp( child, "id", id );
-               }
-               else
-                       strncpy( id, mlt_properties_get( properties, "id" ), ID_SIZE );
+               xmlNewProp( child, "id", id );
                serialise_properties( properties, child );
+               serialise_producer_filters( context, service, child );
 
                // Add producer to the map
-               snprintf( key, 10, "%p", service );
-               mlt_properties_set( context->producer_map, key, id );
-               mlt_properties_set_int( context->hide_map, key, mlt_properties_get_int( properties, "hide" ) );
+               mlt_properties_set_int( context->hide_map, id, mlt_properties_get_int( properties, "hide" ) );
        }
        else
        {
-               snprintf( key, 10, "%p", service );
-               xmlNewProp( node, "producer", mlt_properties_get( context->producer_map, key ) );
+               // Get a new id - if already allocated, do nothing
+               char *id = westley_get_id( context, service, westley_existing );
+               xmlNewProp( node, "producer", id );
        }
 }
 
@@ -142,13 +246,7 @@ static void serialise_multitrack( serialise_context context, mlt_service service
 {
        int i;
        xmlNode *child = node;
-       char id[ ID_SIZE + 1 ];
-       char key[ 11 ];
-       mlt_properties properties = mlt_service_properties( service );
        
-       id[ ID_SIZE ] = '\0';
-       key[ 10 ] = '\0';
-
        if ( context->pass == 0 )
        {
                // Iterate over the tracks to collect the producers
@@ -157,26 +255,28 @@ static void serialise_multitrack( serialise_context context, mlt_service service
        }
        else
        {
+               // Get a new id - if already allocated, do nothing
+               char *id = westley_get_id( context, service, westley_multitrack );
+               if ( id == NULL )
+                       return;
+
                // Create the multitrack node
                child = xmlNewChild( node, NULL, "multitrack", NULL );
                
                // Set the id
-               if ( mlt_properties_get( properties, "id" ) == NULL )
-               {
-                       snprintf( id, ID_SIZE, "multitrack%d", context->multitrack_count++ );
-                       xmlNewProp( child, "id", id );
-               }
+               xmlNewProp( child, "id", id );
 
                // Serialise the tracks
                for ( i = 0; i < mlt_multitrack_count( MLT_MULTITRACK( service ) ); i++ )
                {
                        xmlNode *track = xmlNewChild( child, NULL, "track", NULL );
                        int hide = 0;
-                                               
-                       snprintf( key, 10, "%p", MLT_SERVICE( mlt_multitrack_track( MLT_MULTITRACK( service ), i ) ) );
-                       xmlNewProp( track, "producer", mlt_properties_get( context->producer_map, key ) );
+                       mlt_producer producer = mlt_multitrack_track( MLT_MULTITRACK( service ), i );
+
+                       char *id = westley_get_id( context, MLT_SERVICE( producer ), westley_existing );
+                       xmlNewProp( track, "producer", id );
                        
-                       hide = mlt_properties_get_int( context->hide_map, key );
+                       hide = mlt_properties_get_int( context->hide_map, id );
                        if ( hide )
                                xmlNewProp( track, "hide", hide == 1 ? "video" : ( hide == 2 ? "audio" : "both" ) );
                }
@@ -187,16 +287,16 @@ static void serialise_playlist( serialise_context context, mlt_service service,
 {
        int i;
        xmlNode *child = node;
-       char id[ ID_SIZE + 1 ];
-       char key[ 11 ];
        mlt_playlist_clip_info info;
        mlt_properties properties = mlt_service_properties( service );
        
-       id[ ID_SIZE ] = '\0';
-       key[ 10 ] = '\0';
-
        if ( context->pass == 0 )
        {
+               // Get a new id - if already allocated, do nothing
+               char *id = westley_get_id( context, service, westley_playlist );
+               if ( id == NULL )
+                       return;
+
                // Iterate over the playlist entries to collect the producers
                for ( i = 0; i < mlt_playlist_count( MLT_PLAYLIST( service ) ); i++ )
                {
@@ -217,18 +317,10 @@ static void serialise_playlist( serialise_context context, mlt_service service,
                child = xmlNewChild( node, NULL, "playlist", NULL );
 
                // Set the id
-               if ( mlt_properties_get( properties, "id" ) == NULL )
-               {
-                       snprintf( id, ID_SIZE, "playlist%d", context->playlist_count++ );
-                       xmlNewProp( child, "id", id );
-               }
-               else
-                       strncpy( id, mlt_properties_get( properties, "id" ), ID_SIZE );
+               xmlNewProp( child, "id", id );
 
                // Add producer to the map
-               snprintf( key, 10, "%p", service );
-               mlt_properties_set( context->producer_map, key, id );
-               mlt_properties_set_int( context->hide_map, key, mlt_properties_get_int( properties, "hide" ) );
+               mlt_properties_set_int( context->hide_map, id, mlt_properties_get_int( properties, "hide" ) );
        
                // Iterate over the playlist entries
                for ( i = 0; i < mlt_playlist_count( MLT_PLAYLIST( service ) ); i++ )
@@ -248,8 +340,8 @@ static void serialise_playlist( serialise_context context, mlt_service service,
                                {
                                        char temp[ 20 ];
                                        xmlNode *entry = xmlNewChild( child, NULL, "entry", NULL );
-                                       snprintf( key, 10, "%p", MLT_SERVICE( info.producer ) );
-                                       xmlNewProp( entry, "producer", mlt_properties_get( context->producer_map, key ) );
+                                       id = westley_get_id( context, MLT_SERVICE( info.producer ), westley_existing );
+                                       xmlNewProp( entry, "producer", id );
                                        sprintf( temp, "%d", info.frame_in );
                                        xmlNewProp( entry, "in", temp );
                                        sprintf( temp, "%d", info.frame_out );
@@ -260,19 +352,16 @@ static void serialise_playlist( serialise_context context, mlt_service service,
        }
        else if ( strcmp( (const char*) node->name, "tractor" ) != 0 )
        {
-               snprintf( key, 10, "%p", service );
-               xmlNewProp( node, "producer", mlt_properties_get( context->producer_map, key ) );
+               char *id = westley_get_id( context, service, westley_existing );
+               xmlNewProp( node, "producer", id );
        }
 }
 
 static void serialise_tractor( serialise_context context, mlt_service service, xmlNode *node )
 {
        xmlNode *child = node;
-       char id[ ID_SIZE + 1 ];
        mlt_properties properties = mlt_service_properties( service );
        
-       id[ ID_SIZE ] = '\0';
-       
        if ( context->pass == 0 )
        {
                // Recurse on connected producer
@@ -280,15 +369,15 @@ static void serialise_tractor( serialise_context context, mlt_service service, x
        }
        else
        {
+               // Get a new id - if already allocated, do nothing
+               char *id = westley_get_id( context, service, westley_tractor );
+               if ( id == NULL )
+                       return;
+
                child = xmlNewChild( node, NULL, "tractor", NULL );
 
                // Set the id
-               if ( mlt_properties_get( properties, "id" ) == NULL )
-               {
-                       snprintf( id, ID_SIZE, "tractor%d", context->tractor_count++ );
-                       xmlNewProp( child, "id", id );
-               }
-               
+               xmlNewProp( child, "id", id );
                xmlNewProp( child, "in", mlt_properties_get( properties, "in" ) );
                xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
 
@@ -300,26 +389,24 @@ static void serialise_tractor( serialise_context context, mlt_service service, x
 static void serialise_filter( serialise_context context, mlt_service service, xmlNode *node )
 {
        xmlNode *child = node;
-       char id[ ID_SIZE + 1 ];
        mlt_properties properties = mlt_service_properties( service );
        
-       id[ ID_SIZE ] = '\0';
-       
        // Recurse on connected producer
        serialise_service( context, mlt_service_producer( service ), node );
 
        if ( context->pass == 1 )
        {
+               // Get a new id - if already allocated, do nothing
+               char *id = westley_get_id( context, service, westley_filter );
+               if ( id == NULL )
+                       return;
+
                child = xmlNewChild( node, NULL, "filter", NULL );
 
                // Set the id
-               if ( mlt_properties_get( properties, "id" ) == NULL )
-               {
-                       snprintf( id, ID_SIZE, "filter%d", context->filter_count++ );
-                       xmlNewProp( child, "id", id );
-                       xmlNewProp( child, "in", mlt_properties_get( properties, "in" ) );
-                       xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
-               }
+               xmlNewProp( child, "id", id );
+               xmlNewProp( child, "in", mlt_properties_get( properties, "in" ) );
+               xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
 
                serialise_properties( properties, child );
        }
@@ -328,26 +415,24 @@ static void serialise_filter( serialise_context context, mlt_service service, xm
 static void serialise_transition( serialise_context context, mlt_service service, xmlNode *node )
 {
        xmlNode *child = node;
-       char id[ ID_SIZE + 1 ];
        mlt_properties properties = mlt_service_properties( service );
        
-       id[ ID_SIZE ] = '\0';
-       
        // Recurse on connected producer
        serialise_service( context, MLT_SERVICE( MLT_TRANSITION( service )->producer ), node );
 
        if ( context->pass == 1 )
        {
+               // Get a new id - if already allocated, do nothing
+               char *id = westley_get_id( context, service, westley_transition );
+               if ( id == NULL )
+                       return;
+
                child = xmlNewChild( node, NULL, "transition", NULL );
        
                // Set the id
-               if ( mlt_properties_get( properties, "id" ) == NULL )
-               {
-                       snprintf( id, ID_SIZE, "transition%d", context->transition_count++ );
-                       xmlNewProp( child, "id", id );
-                       xmlNewProp( child, "in", mlt_properties_get( properties, "in" ) );
-                       xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
-               }
+               xmlNewProp( child, "id", id );
+               xmlNewProp( child, "in", mlt_properties_get( properties, "in" ) );
+               xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
 
                serialise_properties( properties, child );
        }
@@ -393,6 +478,12 @@ static void serialise_service( serialise_context context, mlt_service service, x
                                serialise_tractor( context, service, node );
                                break;
                        }
+
+                       // Treat it as a normal producer
+                       else
+                       {
+                               serialise_producer( context, service, node );
+                       }
                }
                
                // Tell about a filter
@@ -423,7 +514,7 @@ xmlDocPtr westley_make_doc( mlt_service service )
        xmlDocSetRootElement( doc, root );
                
        // Construct the context maps
-       context->producer_map = mlt_properties_new();
+       context->id_map = mlt_properties_new();
        context->hide_map = mlt_properties_new();
        
        // Ensure producer is a framework producer
@@ -439,7 +530,7 @@ xmlDocPtr westley_make_doc( mlt_service service )
        serialise_service( context, service, root );
 
        // Cleanup resource
-       mlt_properties_close( context->producer_map );
+       mlt_properties_close( context->id_map );
        mlt_properties_close( context->hide_map );
        free( context );
        
@@ -455,12 +546,14 @@ static int consumer_start( mlt_consumer this )
        mlt_service service = mlt_service_producer( mlt_consumer_service( this ) );
        if ( service != NULL )
        {
+               char *resource =  mlt_properties_get( mlt_consumer_properties( this ), "resource" );
+
                doc = westley_make_doc( service );
                
-               if ( mlt_properties_get( mlt_consumer_properties( this ), "resource" ) == NULL )
+               if ( resource == NULL || !strcmp( resource, "" ) )
                        xmlDocFormatDump( stdout, doc, 1 );
                else
-                       xmlSaveFormatFile( mlt_properties_get( mlt_consumer_properties( this ), "resource" ), doc, 1 );
+                       xmlSaveFormatFile( resource, doc, 1 );
                
                xmlFreeDoc( doc );
        }
index ff1649dee9a3d5c0c9ef8583e3568c6a1008aeb5..e19f95c86e0acdb2e09d3a73d5fef98df176f12b 100644 (file)
@@ -59,6 +59,8 @@ struct deserialise_context_s
        const xmlChar *publicId;
        const xmlChar *systemId;
        mlt_properties params;
+       mlt_deque filter_queue;
+       int in_producer;
 };
 typedef struct deserialise_context_s *deserialise_context;
 
@@ -242,6 +244,8 @@ static void on_start_producer( deserialise_context context, const xmlChar *name,
 {
        mlt_properties properties = context->producer_properties = mlt_properties_new();
 
+       context->in_producer ++;
+
        for ( ; atts != NULL && *atts != NULL; atts += 2 )
        {
                mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
@@ -307,7 +311,12 @@ static void on_start_entry_track( deserialise_context context, const xmlChar *na
 
 static void on_start_filter( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
-       mlt_properties properties = context->producer_properties = mlt_properties_new();
+       mlt_properties properties = mlt_properties_new();
+
+       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 )
@@ -662,6 +671,8 @@ static void on_end_producer( deserialise_context context, const xmlChar *name )
        mlt_properties properties = context->producer_properties;
        mlt_service service = NULL;
        
+       context->in_producer --;
+
        if ( properties == NULL )
                return;
                
@@ -761,6 +772,26 @@ static void on_end_producer( deserialise_context context, const xmlChar *name )
                        }
                }
        
+               // Allow for embedded filters
+               while( mlt_deque_count( context->filter_queue ) )
+               {
+                       mlt_properties filter_properties = mlt_deque_pop_front( context->filter_queue );
+                       mlt_properties_debug( filter_properties, "Filter?", stderr );
+                       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 );
+                       }
+               }
+
                // Push the producer onto the stack
                context_push_service( context, service );
        }
@@ -769,6 +800,13 @@ static void on_end_producer( deserialise_context context, const xmlChar *name )
 static void on_end_filter( deserialise_context context, const xmlChar *name )
 {
        mlt_properties properties = context->producer_properties;
+       if ( context->in_producer )
+       {
+               mlt_deque_push_back( context->filter_queue, properties );
+               context->producer_properties = mlt_deque_pop_front( context->filter_queue );
+               return;
+       }
+
        if ( properties == NULL )
                return;
 
@@ -1191,6 +1229,7 @@ mlt_producer producer_westley_init( char *url )
        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 ) );
@@ -1299,6 +1338,7 @@ mlt_producer producer_westley_init( char *url )
        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 );