for ( i = 0; i < mlt_multitrack_count( MLT_MULTITRACK( service ) ); i++ )
serialise_service( context, MLT_SERVICE( mlt_multitrack_track( MLT_MULTITRACK( service ), i ) ), node );
}
-
else
{
+ // Create the multitrack node
child = xmlNewChild( node, NULL, "multitrack", NULL );
-
+
// Set the id
if ( mlt_properties_get( properties, "id" ) == NULL )
{
{
if ( ! mlt_playlist_get_clip_info( MLT_PLAYLIST( service ), &info, i ) )
{
- if ( info.producer && strcmp( mlt_properties_get( mlt_producer_properties( info.producer ), "mlt_service" ), "blank" ) != 0 )
+ if ( info.producer != NULL )
{
- serialise_service( context, MLT_SERVICE( info.producer ), node );
+ char *service_s = mlt_properties_get( mlt_producer_properties( info.producer ), "mlt_service" );
+ if ( service_s != NULL && strcmp( service_s, "blank" ) != 0 )
+ serialise_service( context, MLT_SERVICE( info.producer ), node );
}
}
}
{
if ( ! mlt_playlist_get_clip_info( MLT_PLAYLIST( service ), &info, i ) )
{
- if ( strcmp( mlt_properties_get( mlt_producer_properties( info.producer ), "mlt_service" ), "blank" ) == 0 )
+ char *service_s = mlt_properties_get( mlt_producer_properties( info.producer ), "mlt_service" );
+ if ( service_s != NULL && strcmp( service_s, "blank" ) == 0 )
{
char length[ 20 ];
length[ 19 ] = '\0';
}
}
+xmlDocPtr westley_make_doc( mlt_service service )
+{
+ xmlDocPtr doc = xmlNewDoc( "1.0" );
+ xmlNodePtr root = xmlNewNode( NULL, "westley" );
+ struct serialise_context_s *context = calloc( 1, sizeof( struct serialise_context_s ) );
+
+ xmlDocSetRootElement( doc, root );
+
+ // Construct the context maps
+ context->producer_map = mlt_properties_new();
+ context->hide_map = mlt_properties_new();
+
+ // Ensure producer is a framework producer
+ mlt_properties_set( mlt_service_properties( service ), "mlt_type", "mlt_producer" );
+
+ // In pass one, we serialise the end producers and playlists,
+ // adding them to a map keyed by address.
+ serialise_service( context, service, root );
+
+ // In pass two, we serialise the tractor and reference the
+ // producers and playlists
+ context->pass++;
+ serialise_service( context, service, root );
+
+ // Cleanup resource
+ mlt_properties_close( context->producer_map );
+ mlt_properties_close( context->hide_map );
+ free( context );
+
+ return doc;
+}
+
+
static int consumer_start( mlt_consumer this )
{
mlt_service inigo = NULL;
- xmlDoc *doc = xmlNewDoc( "1.0" );
- xmlNode *root = xmlNewNode( NULL, "westley" );
- xmlDocSetRootElement( doc, root );
+ xmlDocPtr doc = NULL;
// Get the producer service
mlt_service service = mlt_service_get_producer( mlt_consumer_service( this ) );
if ( service != NULL )
{
- struct serialise_context_s *context = calloc( 1, sizeof( struct serialise_context_s ) );
-
- // Construct the context maps
- context->producer_map = mlt_properties_new();
- context->hide_map = mlt_properties_new();
-
// Remember inigo
if ( mlt_properties_get( mlt_service_properties( service ), "mlt_service" ) != NULL &&
strcmp( mlt_properties_get( mlt_service_properties( service ), "mlt_service" ), "inigo" ) == 0 )
inigo = service;
- // Ensure producer is a framework producer
- mlt_properties_set( mlt_service_properties( service ), "mlt_type", "mlt_producer" );
-
- // In pass one, we serialise the end producers and playlists,
- // adding them to a map keyed by address.
- serialise_service( context, service, root );
-
- // In pass two, we serialise the tractor and reference the
- // producers and playlists
- context->pass++;
- serialise_service( context, service, root );
-
- // Cleanup resource
- mlt_properties_close( context->producer_map );
- mlt_properties_close( context->hide_map );
- free( context );
+ doc = westley_make_doc( service );
if ( mlt_properties_get( mlt_consumer_properties( this ), "resource" ) == NULL )
xmlDocFormatDump( stdout, doc, 1 );
else
xmlSaveFormatFile( mlt_properties_get( mlt_consumer_properties( this ), "resource" ), doc, 1 );
+
+ xmlFreeDoc( doc );
}
-
- xmlFreeDoc( doc );
+
mlt_consumer_stop( this );
return 0;
#include <libxml/tree.h>
#define STACK_SIZE 1000
+#define BRANCH_SIG_LEN 4000
+
+#undef DEBUG
+#ifdef DEBUG
+extern xmlDocPtr westley_make_doc( mlt_service service );
+#endif
struct deserialise_context_s
{
xmlNodePtr stack_node[ STACK_SIZE ];
int stack_node_size;
xmlDocPtr entity_doc;
+ int depth;
+ int branch[ STACK_SIZE ];
};
typedef struct deserialise_context_s *deserialise_context;
+/** Convert the numerical current branch address to a dot-delimited string.
+*/
+static char *serialise_branch( deserialise_context this, char *s )
+{
+ int i;
+
+ s[0] = 0;
+ for ( i = 0; i < this->depth; i++ )
+ {
+ int len = strlen( s );
+ snprintf( s + len, BRANCH_SIG_LEN - len, "%d.", this->branch[ i ] );
+ }
+ return s;
+}
/** Push a service.
*/
{
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;
+
+ // Record the tree branch on which this service lives
+ if ( 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 ) );
+ }
+ }
return ret;
}
{
// Get the parent producer
mlt_service producer = context_pop_service( context );
+
if ( producer != NULL )
{
- 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 ) )
+ char current_branch[ BRANCH_SIG_LEN ];
+ char *service_branch = mlt_properties_get( mlt_service_properties( producer ), "_westley_branch" );
+
+ // 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 ( 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 ) ) );
+ char *resource = mlt_properties_get( mlt_service_properties( producer ), "resource" );
+
+ // Put the parent producer back
+ context_push_service( context, producer );
- // Set the hide state of the track producer
- char *hide_s = mlt_properties_get( properties, "hide" );
- if ( hide_s != NULL )
+ // If the parent producer is a multitrack or playlist (not a track or entry)
+ if ( resource && ( strcmp( resource, "<playlist>" ) == 0 ||
+ strcmp( resource, "<multitrack>" ) == 0 ) )
+ {
+//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 )
{
- 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 );
+ // 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;
}
- // Normally, the enclosing entry or track will pop this service off
- // In its absence we do not push it on.
- return 1;
}
}
return 0;
mlt_service producer = context_pop_service( context );
if ( producer == NULL )
return;
-
+
// Get the tractor from the stack
mlt_service service = context_pop_service( context );
resource = mlt_properties_get( mlt_service_properties( service ), "resource" );
if ( service == NULL || resource == NULL || strcmp( resource, "<tractor>" ) )
{
+//printf("creating a tractor\n");
+ char current_branch[ BRANCH_SIG_LEN ];
+
// Put the anonymous service back onto the stack!
- context_push_service( context, service );
+ 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 );
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 ) );
}
// Connect the tractor to the multitrack
mlt_properties_set_data( mlt_service_properties( service ), "multitrack",
MLT_MULTITRACK( producer ), 0, NULL, NULL );
- // See if the producer should be added to a playlist or multitrack
+ // 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
struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx;
deserialise_context context = ( deserialise_context )( xmlcontext->_private );
+//printf("on_start_element: %s\n", name );
+ context->branch[ context->depth ] ++;
+ context->depth ++;
+
// Build a tree from nodes within a property value
if ( context->is_value == 1 )
{
struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx;
deserialise_context context = ( deserialise_context )( xmlcontext->_private );
+//printf("on_end_element: %s\n", name );
if ( context->is_value == 1 && strcmp( name, "property" ) != 0 )
context_pop_node( context );
else if ( strcmp( name, "multitrack" ) == 0 )
on_end_filter( context, name );
else if ( strcmp( name, "transition" ) == 0 )
on_end_transition( context, name );
+
+ context->branch[ context->depth ] = 0;
+ context->depth --;
}
static void on_characters( void *ctx, const xmlChar *ch, int len )
// Verify it is a producer service (mlt_type="mlt_producer")
// (producer, playlist, multitrack)
char *type = mlt_properties_get( mlt_service_properties( service ), "mlt_type" );
- if ( type == NULL || ( strcmp( type, "mlt_producer" ) != 0 ) )
+ if ( type == NULL || ( strcmp( type, "mlt_producer" ) != 0 && strcmp( type, "producer" ) != 0 ) )
service = NULL;
}
+#ifdef DEBUG
+ xmlDocPtr doc = westley_make_doc( service );
+ xmlDocFormatDump( stdout, doc, 1 );
+ xmlFreeDoc( doc );
+ service = NULL;
+#endif
+
if ( well_formed && service != NULL )
{
+
// Need the complete producer list for various reasons
properties = context->destructors;