bugfixes to westley
[melted] / src / modules / westley / producer_westley.c
index acc9215..8c7d9ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * producer_libdv.c -- a libxml2 parser of mlt service networks
+ * producer_westley.c -- a libxml2 parser of mlt service networks
  * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
  * Author: Dan Dennedy <dan@dennedy.org>
  *
@@ -18,6 +18,8 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+// TODO: destroy unreferenced producers
 #include "producer_westley.h"
 #include <framework/mlt.h>
 #include <stdlib.h>
@@ -34,8 +36,7 @@ struct deserialise_context_s
        int stack_service_size;
        int track_count;
        mlt_properties producer_map;
-       int filter_count;
-       int transition_count;
+       mlt_properties destructors;
 };
 typedef struct deserialise_context_s *deserialise_context;
 
@@ -62,10 +63,21 @@ static mlt_service context_pop_service( deserialise_context this )
        return result;
 }
 
+// Set the destructor on a new service
+static void track_service( mlt_properties properties, void *service, mlt_destructor destructor )
+{
+       int registered = mlt_properties_get_int( properties, "registered" );
+       char *key = mlt_properties_get( properties, "registered" );
+       mlt_properties_set_data( properties, key, service, 0, destructor, NULL );
+       mlt_properties_set_int( properties, "registered", ++ registered );
+}
+
 static void on_start_tractor( deserialise_context context, const xmlChar *name, const xmlChar **atts)
 {
        mlt_service service = mlt_tractor_service( mlt_tractor_init() );
 
+       track_service( context->destructors, service, (mlt_destructor) mlt_tractor_close );
+
        for ( ; atts != NULL && *atts != NULL; atts += 2 )
                mlt_properties_set( mlt_service_properties( service ), (char*) atts[0], (char*) atts[1] );
 
@@ -76,6 +88,8 @@ static void on_start_multitrack( deserialise_context context, const xmlChar *nam
 {
        mlt_service service = mlt_multitrack_service( mlt_multitrack_init() );
 
+       track_service( context->destructors, service, (mlt_destructor) mlt_multitrack_close );
+
        for ( ; atts != NULL && *atts != NULL; atts += 2 )
                mlt_properties_set( mlt_service_properties( service ), (char*) atts[0], (char*) atts[1] );
 
@@ -87,6 +101,8 @@ static void on_start_playlist( deserialise_context context, const xmlChar *name,
        mlt_service service = mlt_playlist_service( mlt_playlist_init() );
        mlt_properties properties = mlt_service_properties( service );
 
+       track_service( context->destructors, service, (mlt_destructor) mlt_playlist_close );
+
        for ( ; atts != NULL && *atts != NULL; atts += 2 )
                mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
 
@@ -102,7 +118,9 @@ static void on_start_producer( deserialise_context context, const xmlChar *name,
        mlt_service service = NULL;
 
        for ( ; atts != NULL && *atts != NULL; atts += 2 )
+       {
                mlt_properties_set( properties, (char*) atts[0], (char*) atts[1] );
+       }
 
        if ( mlt_properties_get( properties, "mlt_service" ) != NULL )
        {
@@ -116,6 +134,9 @@ static void on_start_producer( deserialise_context context, const xmlChar *name,
                service = MLT_SERVICE( mlt_factory_producer( "inigo", args ) );
        }
 
+       track_service( context->destructors, service, (mlt_destructor) mlt_producer_close );
+
+       // 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 );
 
@@ -167,6 +188,8 @@ static void on_start_filter( deserialise_context context, const xmlChar *name, c
 {
        char *id;
        mlt_properties properties = mlt_properties_new();
+       char key[11];
+       key[ 10 ] = '\0';
 
        // Get the producer from the stack
        mlt_service producer = context_pop_service( context );
@@ -178,18 +201,17 @@ static void on_start_filter( deserialise_context context, const xmlChar *name, c
        // Create the filter
        mlt_service service = MLT_SERVICE( mlt_factory_filter( mlt_properties_get( properties, "mlt_service" ), NULL ) );
 
+       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" ) );
 
-       // Generate an id if one does not exist
-       if ( mlt_properties_get( properties, "id" ) == NULL )
-       {
-               char id[ 31 ];
-               id[ 30 ] = '\0';
-               snprintf( id, 30, "filter%d", context->filter_count++ );
-               mlt_properties_set( properties, "id", id );
-       }
+       // 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
        mlt_properties_inherit( mlt_service_properties( service ), properties );
@@ -209,28 +231,18 @@ static void on_start_filter( deserialise_context context, const xmlChar *name, c
        }
 
        // If a producer alias is in the producer_map, get it
-       id = mlt_properties_get( context->producer_map, mlt_properties_get( mlt_service_properties( producer ), "id" ) );
-       if ( id != NULL && mlt_properties_get_data( context->producer_map, id, NULL ) != NULL )
-       {
+       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
-               // alias the filter id as the producer id
-               mlt_properties_set( context->producer_map, mlt_properties_get( mlt_service_properties( service ), "id" ), id );
-       }
-       else
-       {
-               // If the producer is in the producer_map, update it
-               id = mlt_properties_get( mlt_service_properties( producer ), "id" );
-               if ( id != NULL && mlt_properties_get_data( context->producer_map, id, NULL ) != NULL )
-               {
-                       mlt_properties_set_data( context->producer_map, id, service, 0, NULL, NULL );
-
-                       // For filter chain support, add an alias to the producer map
-                       // alias the filter id as the producer id
-                       mlt_properties_set( context->producer_map, mlt_properties_get( mlt_service_properties( service ), "id" ), id );
-               }
-       }
+       
+       // 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 );
@@ -250,14 +262,7 @@ static void on_start_transition( deserialise_context context, const xmlChar *nam
        // Create the transition
        mlt_service service = MLT_SERVICE( mlt_factory_transition( mlt_properties_get( properties, "mlt_service" ), NULL ) );
 
-       // Generate an id if one does not exist
-       if ( mlt_properties_get( properties, "id" ) == NULL )
-       {
-               char id[ 31 ];
-               id[ 30 ] = '\0';
-               snprintf( id, 30, "transition%d", context->transition_count++ );
-               mlt_properties_set( properties, "id", id );
-       }
+       track_service( context->destructors, service, (mlt_destructor) mlt_transition_close );
 
        // Propogate the properties
        mlt_properties_inherit( mlt_service_properties( service ), properties );
@@ -345,6 +350,18 @@ static void on_end_entry( deserialise_context context, const xmlChar *name )
        context_push_service( context, service );
 }
 
+static void on_end_tractor( deserialise_context context, const xmlChar *name )
+{
+       // Get and discard the last producer
+       mlt_producer multitrack = MLT_PRODUCER( context_pop_service( context ) );
+
+       // Inherit the producer's properties
+       mlt_properties properties = mlt_producer_properties( multitrack );
+       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 ) );
+}
+
 static void on_start_element( void *ctx, const xmlChar *name, const xmlChar **atts)
 {
        deserialise_context context = ( deserialise_context ) ctx;
@@ -380,30 +397,75 @@ static void on_end_element( void *ctx, const xmlChar *name )
        else if ( strcmp( name, "entry" ) == 0 )
                on_end_entry( context, name );
        else if ( strcmp( name, "tractor" ) == 0 )
-       {
-               // Discard the last producer
-               context_pop_service( context );
-       }
+               on_end_tractor( context, name );
 }
 
 
 mlt_producer producer_westley_init( char *filename )
 {
+       static int init = 0;
        xmlSAXHandler *sax = calloc( 1, sizeof( xmlSAXHandler ) );
        struct deserialise_context_s *context = calloc( 1, sizeof( struct deserialise_context_s ) );
+       mlt_properties properties = NULL;
+       int i = 0;
 
        context->producer_map = mlt_properties_new();
+       context->destructors = mlt_properties_new();
+       // We need to track the number of registered filters
+       mlt_properties_set_int( context->destructors, "registered", 0 );
        sax->startElement = on_start_element;
        sax->endElement = on_end_element;
 
-       xmlInitParser();
+       if ( !init )
+       {
+               xmlInitParser();
+               init = 1;
+       }
+
        xmlSAXUserParseFile( sax, context, filename );
-       xmlCleanupParser();
        free( sax );
 
-       mlt_properties_close( context->producer_map );
+       // Need the complete producer list for various reasons
+       properties = context->destructors;
 
+       // Get the last producer on the stack
        mlt_service service = context_pop_service( context );
+
+       // Do we actually have a producer here?
+       if ( service != NULL )
+       {
+               // Now make sure we don't have a reference to the service in the properties
+               for ( i = mlt_properties_count( properties ) - 1; i >= 1; i -- )
+               {
+                       char *name = mlt_properties_get_name( properties, i );
+                       if ( mlt_properties_get_data( properties, name, NULL ) == service )
+                       {
+                               mlt_properties_set_data( properties, name, service, 0, NULL, NULL );
+                               break;
+                       }
+               }
+
+               // We are done referencing destructor property list
+               // Set this var to service properties for convenience
+               properties = mlt_service_properties( service );
+       
+               // make the returned service destroy the connected services
+               mlt_properties_set_data( properties, "__destructors__", context->destructors, 0, (mlt_destructor) mlt_properties_close, NULL );
+
+               // Now assign additional properties
+               mlt_properties_set( properties, "resource", filename );
+
+               // This tells consumer_westley not to deep copy
+               mlt_properties_set( properties, "westley", "was here" );
+       }
+       else
+       {
+               // Clean up
+               mlt_properties_close( properties );
+       }
+
+       free( context->stack_service );
+       mlt_properties_close( context->producer_map );
        free( context );
 
        return MLT_PRODUCER( service );