#include <string.h>
#include <stdio.h>
#include <ctype.h>
+#include <unistd.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h> // for xmlCreateFileParserCtxt
mlt_transition_type,
mlt_consumer_type,
mlt_field_type,
- mlt_service_type,
+ mlt_services_type,
mlt_dummy_filter_type,
mlt_dummy_transition_type,
mlt_dummy_producer_type,
if ( resource != NULL )
{
// Qualify file name properties
- char *root = mlt_properties_get( context->producer_map, "_root" );
- if ( root != NULL )
+ char *root = mlt_properties_get( context->producer_map, "root" );
+ if ( root != NULL && strcmp( root, "" ) )
{
- char *full_resource = malloc( strlen( root ) + strlen( resource ) + 1 );
- if ( resource[ 0 ] != '/' )
+ char *full_resource = malloc( strlen( root ) + strlen( resource ) + 2 );
+ if ( resource[ 0 ] != '/' && strchr( resource, ':' ) == NULL )
{
strcpy( full_resource, root );
+ strcat( full_resource, "/" );
strcat( full_resource, resource );
}
else
else
{
// Otherwise, set in and out on producer directly
- mlt_producer_set_in_and_out( MLT_PRODUCER( service ), in, out );
+ mlt_producer_set_in_and_out( MLT_PRODUCER( producer ), in, out );
}
}
else
mlt_producer_set_in_and_out( MLT_PRODUCER( producer ), in, out );
}
}
-
+
// Push the producer onto the stack
context_push_service( context, producer, mlt_producer_type );
}
}
}
-static void on_start_entry_track( deserialise_context context, const xmlChar *name, const xmlChar **atts)
+static void on_start_entry( deserialise_context context, const xmlChar *name, const xmlChar **atts)
+{
+ mlt_producer entry = NULL;
+ mlt_properties temp = mlt_properties_new( );
+
+ for ( ; atts != NULL && *atts != NULL; atts += 2 )
+ {
+ mlt_properties_set( temp, (char*) atts[0], (char*) atts[1] );
+
+ // Look for the producer attribute
+ if ( strcmp( atts[ 0 ], "producer" ) == 0 )
+ {
+ mlt_producer producer = mlt_properties_get_data( context->producer_map, (char*) atts[1], NULL );
+ if ( producer != NULL )
+ mlt_properties_set_data( temp, "producer", producer, 0, NULL, NULL );
+ }
+ }
+
+ // If we have a valid entry
+ if ( mlt_properties_get_data( temp, "producer", NULL ) != NULL )
+ {
+ mlt_playlist_clip_info info;
+ enum service_type parent_type;
+ mlt_service parent = context_pop_service( context, &parent_type );
+ mlt_producer producer = mlt_properties_get_data( temp, "producer", NULL );
+
+ if ( parent_type == mlt_playlist_type )
+ {
+ // Append the producer to the playlist
+ if ( mlt_properties_get( temp, "in" ) != NULL || mlt_properties_get( temp, "out" ) != NULL )
+ {
+ mlt_playlist_append_io( MLT_PLAYLIST( parent ), producer,
+ mlt_properties_get_position( temp, "in" ),
+ mlt_properties_get_position( temp, "out" ) );
+ }
+ else
+ {
+ mlt_playlist_append( MLT_PLAYLIST( parent ), producer );
+ }
+
+ // Handle the repeat property
+ if ( mlt_properties_get_int( temp, "repeat" ) > 0 )
+ {
+ mlt_playlist_repeat_clip( MLT_PLAYLIST( parent ),
+ mlt_playlist_count( MLT_PLAYLIST( parent ) ) - 1,
+ mlt_properties_get_int( temp, "repeat" ) );
+ }
+
+ mlt_playlist_get_clip_info( MLT_PLAYLIST( parent ), &info, mlt_playlist_count( MLT_PLAYLIST( parent ) ) - 1 );
+ entry = info.cut;
+ }
+ else
+ {
+ fprintf( stderr, "Entry not part of a playlist...\n" );
+ }
+
+ context_push_service( context, parent, parent_type );
+ }
+
+ // Push the cut onto the stack
+ context_push_service( context, mlt_producer_service( entry ), mlt_entry_type );
+
+ mlt_properties_close( temp );
+}
+
+static void on_end_entry( deserialise_context context, const xmlChar *name )
+{
+ // Get the entry from the stack
+ enum service_type entry_type;
+ mlt_service entry = context_pop_service( context, &entry_type );
+
+ if ( entry == NULL && entry_type != mlt_entry_type )
+ {
+ fprintf( stderr, "Invalid state at end of entry\n" );
+ }
+}
+
+static void on_start_track( deserialise_context context, const xmlChar *name, const xmlChar **atts)
{
// use a dummy service to hold properties to allow arbitrary nesting
mlt_service service = calloc( 1, sizeof( struct mlt_service_s ) );
// Push the dummy service onto the stack
context_push_service( context, service, mlt_entry_type );
- if ( strcmp( name, "entry" ) == 0 )
- mlt_properties_set( mlt_service_properties( service ), "resource", "<entry>" );
- else
- mlt_properties_set( mlt_service_properties( service ), "resource", "<track>" );
+ mlt_properties_set( mlt_service_properties( service ), "resource", "<track>" );
for ( ; atts != NULL && *atts != NULL; atts += 2 )
{
if ( multitrack != NULL )
{
- // Set the track on the multitrack
- mlt_multitrack_connect( multitrack, producer, mlt_multitrack_count( multitrack ) );
-
// Set producer i/o if specified
if ( mlt_properties_get( track_props, "in" ) != NULL ||
- mlt_properties_get( track_props, "out" ) != NULL )
+ mlt_properties_get( track_props, "out" ) != NULL )
{
- mlt_producer_set_in_and_out( MLT_PRODUCER( producer ),
+ if ( mlt_properties_get( track_props, "out" ) == NULL )
+ mlt_properties_set_position( track_props, "out", mlt_properties_get_position( track_props, "length" ) - 1 );
+ mlt_producer cut = mlt_producer_cut( MLT_PRODUCER( producer ),
mlt_properties_get_position( track_props, "in" ),
mlt_properties_get_position( track_props, "out" ) );
+ mlt_properties_set_int( mlt_producer_properties( cut ), "cut", 1 );
+ mlt_multitrack_connect( multitrack, cut, mlt_multitrack_count( multitrack ) );
+ mlt_producer_close( cut );
}
-
+ else
+ {
+ mlt_multitrack_connect( multitrack, producer, mlt_multitrack_count( multitrack ) );
+ }
+
// Set the hide state of the track producer
char *hide_s = mlt_properties_get( track_props, "hide" );
if ( hide_s != NULL )
}
}
-static void on_end_entry( deserialise_context context, const xmlChar *name )
-{
- // Get the entry from the stack
- enum service_type entry_type;
- mlt_service entry = context_pop_service( context, &entry_type );
-
- if ( entry != NULL && entry_type == mlt_entry_type )
- {
- mlt_properties entry_props = mlt_service_properties( entry );
- enum service_type parent_type;
- mlt_service parent = context_pop_service( context, &parent_type );
- mlt_producer producer = mlt_properties_get_data( entry_props, "producer", NULL );
-
- if ( parent_type == mlt_playlist_type )
- {
- // Append the producer to the playlist
- if ( mlt_properties_get( mlt_service_properties( entry ), "in" ) != NULL ||
- mlt_properties_get( mlt_service_properties( entry ), "out" ) != NULL )
- {
- mlt_playlist_append_io( MLT_PLAYLIST( parent ), producer,
- mlt_properties_get_position( mlt_service_properties( entry ), "in" ),
- mlt_properties_get_position( mlt_service_properties( entry ), "out" ) );
- }
- else
- {
- mlt_playlist_append( MLT_PLAYLIST( parent ), producer );
- }
- }
- else
- {
- fprintf( stderr, "Invalid position for an entry...\n" );
- }
-
- if ( parent != NULL )
- context_push_service( context, parent, parent_type );
-
- mlt_service_close( entry );
- }
- else
- {
- fprintf( stderr, "Invalid state at end of entry\n" );
- }
-}
-
static void on_start_filter( deserialise_context context, const xmlChar *name, const xmlChar **atts)
{
// use a dummy service to hold properties to allow arbitrary nesting
if ( parent_type == mlt_tractor_type )
{
mlt_field field = mlt_tractor_field( MLT_TRACTOR( parent ) );
+ if ( mlt_properties_get_int( properties, "a_track" ) == mlt_properties_get_int( properties, "b_track" ) )
+ mlt_properties_set_int( properties, "b_track", mlt_properties_get_int( properties, "a_track" ) + 1 );
mlt_field_plant_transition( field, MLT_TRANSITION( effect ),
mlt_properties_get_int( properties, "a_track" ),
mlt_properties_get_int( properties, "b_track" ) );
on_start_producer( context, name, atts );
else if ( strcmp( name, "blank" ) == 0 )
on_start_blank( context, name, atts );
- else if ( strcmp( name, "entry" ) == 0 || strcmp( name, "track" ) == 0 )
- on_start_entry_track( context, name, atts );
+ else if ( strcmp( name, "entry" ) == 0 )
+ on_start_entry( context, name, atts );
+ else if ( strcmp( name, "track" ) == 0 )
+ on_start_track( context, name, atts );
else if ( strcmp( name, "filter" ) == 0 )
on_start_filter( context, name, atts );
else if ( strcmp( name, "transition" ) == 0 )
on_start_transition( context, name, atts );
else if ( strcmp( name, "property" ) == 0 )
on_start_property( context, name, atts );
+ else if ( strcmp( name, "westley" ) == 0 )
+ for ( ; atts != NULL && *atts != NULL; atts += 2 )
+ mlt_properties_set( context->producer_map, ( char * )atts[ 0 ], ( char * )atts[ 1 ] );
}
static void on_end_element( void *ctx, const xmlChar *name )
mlt_properties_set( properties, name, value );
}
-mlt_producer producer_westley_init( char *url )
+mlt_producer producer_westley_init( int info, char *data )
{
- if ( url == NULL )
+ if ( data == NULL )
return NULL;
xmlSAXHandler *sax = calloc( 1, sizeof( xmlSAXHandler ) );
struct deserialise_context_s *context = calloc( 1, sizeof( struct deserialise_context_s ) );
int i = 0;
struct _xmlParserCtxt *xmlcontext;
int well_formed = 0;
- char *filename = strdup( url );
-
+ char *filename = NULL;
+
context->producer_map = mlt_properties_new();
context->destructors = mlt_properties_new();
context->params = mlt_properties_new();
- // Decode URL and parse parameters
- parse_url( context->params, url_decode( filename, url ) );
+ // Decode URL and parse parameters
+ mlt_properties_set( context->producer_map, "root", "" );
+ if ( info == 0 )
+ {
+ filename = strdup( data );
+ parse_url( context->params, url_decode( filename, data ) );
- // We need to track the number of registered filters
- mlt_properties_set_int( context->destructors, "registered", 0 );
+ // We need the directory prefix which was used for the westley
+ if ( strchr( filename, '/' ) )
+ {
+ char *root = NULL;
+ mlt_properties_set( context->producer_map, "root", filename );
+ root = mlt_properties_get( context->producer_map, "root" );
+ *( strrchr( root, '/' ) ) = '\0';
- // We need the directory prefix which was used for the westley
- mlt_properties_set( context->producer_map, "_root", "" );
- if ( strchr( filename, '/' ) )
- {
- char *root = NULL;
- mlt_properties_set( context->producer_map, "_root", filename );
- root = mlt_properties_get( context->producer_map, "_root" );
- *( strrchr( root, '/' ) + 1 ) = '\0';
+ // If we don't have an absolute path here, we're heading for disaster...
+ if ( root[ 0 ] != '/' )
+ {
+ char *cwd = getcwd( NULL, 0 );
+ char *real = malloc( strlen( cwd ) + strlen( root ) + 2 );
+ sprintf( real, "%s/%s", cwd, root );
+ mlt_properties_set( context->producer_map, "root", real );
+ free( real );
+ free( cwd );
+ }
+ }
}
+ // We need to track the number of registered filters
+ mlt_properties_set_int( context->destructors, "registered", 0 );
+
// Setup SAX callbacks
sax->startElement = on_start_element;
sax->endElement = on_end_element;
xmlSubstituteEntitiesDefault( 1 );
// This is used to facilitate entity substitution in the SAX parser
context->entity_doc = xmlNewDoc( "1.0" );
- xmlcontext = xmlCreateFileParserCtxt( filename );
+ if ( info == 0 )
+ xmlcontext = xmlCreateFileParserCtxt( filename );
+ else
+ xmlcontext = xmlCreateMemoryParserCtxt( data, strlen( data ) );
+
xmlcontext->sax = sax;
xmlcontext->_private = ( void* )context;
if ( well_formed && service != NULL )
{
+ char *title = mlt_properties_get( context->producer_map, "title" );
// Need the complete producer list for various reasons
properties = context->destructors;
// 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", url );
+ // Assign the title
+ mlt_properties_set( properties, "title", title );
- // This tells consumer_westley not to deep copy
- mlt_properties_set( properties, "westley", "was here" );
+ // Optimise for overlapping producers
+ mlt_producer_optimise( MLT_PRODUCER( service ) );
+
+ // Handle deep copies
+ if ( getenv( "MLT_WESTLEY_DEEP" ) == NULL )
+ {
+ // Now assign additional properties
+ if ( info == 0 )
+ mlt_properties_set( properties, "resource", data );
+
+ // This tells consumer_westley not to deep copy
+ mlt_properties_set( properties, "westley", "was here" );
+ }
+ else
+ {
+ // Allow the project to be edited
+ mlt_properties_set( properties, "_westley", "was here" );
+ mlt_properties_set_int( properties, "_mlt_service_hidden", 1 );
+ }
}
else
{