X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fmodules%2Fwestley%2Fproducer_westley.c;h=8c7d9ca64fc740bc1e2903f3a9ec1ad5a63bfb81;hb=0bd5d91026b8bd143f957f119d61d5fedd45cf70;hp=acc921513d38db8d87f30eec827b2909ce2146c1;hpb=1fd5d30c5326f73a3889e3bf4f377f96e551a6d1;p=melted diff --git a/src/modules/westley/producer_westley.c b/src/modules/westley/producer_westley.c index acc9215..8c7d9ca 100644 --- a/src/modules/westley/producer_westley.c +++ b/src/modules/westley/producer_westley.c @@ -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 * @@ -18,6 +18,8 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +// TODO: destroy unreferenced producers + #include "producer_westley.h" #include #include @@ -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 );