Producer filter attach/detach methods; major rework on westley consumer, minor on...
[melted] / src / modules / westley / producer_westley.c
index 1f1d6dc..e19f95c 100644 (file)
@@ -53,11 +53,14 @@ struct deserialise_context_s
        xmlNodePtr stack_node[ STACK_SIZE ];
        int stack_node_size;
        xmlDocPtr entity_doc;
+       int entity_is_replace;
        int depth;
        int branch[ STACK_SIZE ];
        const xmlChar *publicId;
        const xmlChar *systemId;
        mlt_properties params;
+       mlt_deque filter_queue;
+       int in_producer;
 };
 typedef struct deserialise_context_s *deserialise_context;
 
@@ -140,6 +143,33 @@ static void track_service( mlt_properties properties, void *service, mlt_destruc
 }
 
 
+// Prepend the property value with the document root
+static inline void qualify_property( deserialise_context context, mlt_properties properties, char *name )
+{
+       char *resource = mlt_properties_get( properties, name );
+       if ( resource != NULL )
+       {
+               // Qualify file name properties 
+               char *root = mlt_properties_get( context->producer_map, "_root" );
+               if ( root != NULL )
+               {
+                       char *full_resource = malloc( strlen( root ) + strlen( resource ) + 1 );
+                       if ( resource[ 0 ] != '/' )
+                       {
+                               strcpy( full_resource, root );
+                               strcat( full_resource, resource );
+                       }
+                       else
+                       {
+                               strcpy( full_resource, resource );
+                       }
+                       mlt_properties_set( properties, name, full_resource );
+                       free( full_resource );
+               }
+       }
+}
+
+
 // Forward declarations
 static void on_end_track( deserialise_context context, const xmlChar *name );
 static void on_end_entry( deserialise_context context, const xmlChar *name );
@@ -214,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] );
@@ -279,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 )
@@ -634,14 +671,20 @@ 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;
                
+       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 )
        {
@@ -656,20 +699,9 @@ static void on_end_producer( deserialise_context context, const xmlChar *name )
        }
        if ( service == NULL && resource != NULL )
        {
-               char *root = mlt_properties_get( context->producer_map, "_root" );
-               char *full_resource = malloc( strlen( root ) + strlen( resource ) + 1 );
-               if ( resource[ 0 ] != '/' )
-               {
-                       strcpy( full_resource, root );
-                       strcat( full_resource, resource );
-               }
-               else
-               {
-                       strcpy( full_resource, resource );
-               }
-               service = MLT_SERVICE( mlt_factory_producer( "fezzik", full_resource ) );
-               free( full_resource );
+               service = MLT_SERVICE( mlt_factory_producer( "fezzik", resource ) );
        }
+       
        if ( service == NULL )
                return;
        track_service( context->destructors, service, (mlt_destructor) mlt_producer_close );
@@ -740,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 );
        }
@@ -748,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;
 
@@ -792,6 +851,11 @@ static void on_end_filter( deserialise_context context, const xmlChar *name )
                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;
@@ -860,6 +924,11 @@ static void on_end_transition( deserialise_context context, const xmlChar *name
        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;
@@ -978,12 +1047,30 @@ static void on_characters( void *ctx, const xmlChar *ch, int len )
 
        value[ len ] = 0;
        strncpy( value, (const char*) ch, len );
-       
+
        if ( context->stack_node_size > 0 )
                xmlNodeAddContent( context->stack_node[ context->stack_node_size - 1 ], ( xmlChar* )value );
 
-       else if ( context->property != NULL && context->producer_properties != NULL )
-               mlt_properties_set( context->producer_properties, context->property, value );
+       // 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 )
+       {
+               char *s = mlt_properties_get( context->producer_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 );
+                       mlt_properties_set( context->producer_properties, context->property, new );
+                       free( new );
+               }
+               else
+                       mlt_properties_set( context->producer_properties, context->property, value );
+       }
+       context->entity_is_replace = 0;
                
        free( value);
 }
@@ -1038,6 +1125,7 @@ xmlEntityPtr on_get_entity( void *ctx, const xmlChar* name )
 {
        struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx;
        deserialise_context context = ( deserialise_context )( xmlcontext->_private );
+       xmlEntityPtr e = NULL;
 
        // Setup for entity declarations if not ready
        if ( xmlGetIntSubset( context->entity_doc ) == NULL )
@@ -1050,7 +1138,13 @@ xmlEntityPtr on_get_entity( void *ctx, const xmlChar* name )
        // Add our parameters if not already
        params_to_entities( context );
        
-       return xmlGetDocEntity( context->entity_doc, name );
+       e = xmlGetDocEntity( context->entity_doc, name );
+       
+       // Send signal to on_characters that an entity substitutin is pending
+       if ( e != NULL )
+               context->entity_is_replace = 1;
+       
+       return e;
 }
 
 /** Convert a hexadecimal character to its value.
@@ -1122,6 +1216,8 @@ static void parse_url( mlt_properties properties, char *url )
 
 mlt_producer producer_westley_init( char *url )
 {
+       if ( url == NULL )
+               return NULL;
        xmlSAXHandler *sax = calloc( 1, sizeof( xmlSAXHandler ) );
        struct deserialise_context_s *context = calloc( 1, sizeof( struct deserialise_context_s ) );
        mlt_properties properties = NULL;
@@ -1133,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 ) );
@@ -1241,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 );