X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fframework%2Fmlt_producer.c;h=98498c459214fa9ba778a2fa0c577f54a71660bb;hb=42ed8e7a15a5e2ba693c644e73948ff6ffb0fed4;hp=843a2451a9286d90046d1813a2cb5debab539b6d;hpb=519393231e6ab626f19bd01d4622d1c3759fcc93;p=melted diff --git a/src/framework/mlt_producer.c b/src/framework/mlt_producer.c index 843a245..98498c4 100644 --- a/src/framework/mlt_producer.c +++ b/src/framework/mlt_producer.c @@ -22,6 +22,7 @@ #include "mlt_producer.h" #include "mlt_factory.h" #include "mlt_frame.h" +#include "mlt_parser.h" #include #include #include @@ -109,7 +110,7 @@ int mlt_producer_init( mlt_producer this, void *child ) static void mlt_producer_property_changed( mlt_service owner, mlt_producer this, char *name ) { if ( !strcmp( name, "in" ) || !strcmp( name, "out" ) || !strcmp( name, "length" ) ) - mlt_events_fire( mlt_producer_properties( this ), "producer-changed", NULL ); + mlt_events_fire( mlt_producer_properties( mlt_producer_cut_parent( this ) ), "producer-changed", NULL ); } /** Listener for service changes. @@ -117,7 +118,19 @@ static void mlt_producer_property_changed( mlt_service owner, mlt_producer this, static void mlt_producer_service_changed( mlt_service owner, mlt_producer this ) { - mlt_events_fire( mlt_producer_properties( this ), "producer-changed", NULL ); + mlt_events_fire( mlt_producer_properties( mlt_producer_cut_parent( this ) ), "producer-changed", NULL ); +} + +/** Special case destructor +*/ + +static void mlt_cut_destroy( void *obj ) +{ + mlt_producer this = obj; + this->close = NULL; + this->parent.close = NULL; + mlt_service_close( &this->parent ); + free( this ); } /** Create a new producer. @@ -127,6 +140,7 @@ mlt_producer mlt_producer_new( ) { mlt_producer this = malloc( sizeof( struct mlt_producer_s ) ); mlt_producer_init( this, NULL ); + this->close = mlt_cut_destroy; return this; } @@ -138,6 +152,16 @@ int mlt_producer_is_cut( mlt_producer this ) return mlt_properties_get_int( mlt_producer_properties( this ), "_cut" ); } +/** Determine if producer is a mix. +*/ + +int mlt_producer_is_mix( mlt_producer this ) +{ + mlt_properties properties = this != NULL ? mlt_producer_properties( this ) : NULL; + mlt_tractor tractor = properties != NULL ? mlt_properties_get_data( properties, "mlt_mix", NULL ) : NULL; + return tractor != NULL; +} + /** Obtain the parent producer. */ @@ -300,10 +324,26 @@ int mlt_producer_set_in_and_out( mlt_producer this, mlt_position in, mlt_positio // Set the values mlt_events_block( properties, properties ); mlt_properties_set_position( properties, "in", in ); - mlt_properties_set_position( properties, "out", out ); mlt_events_unblock( properties, properties ); - mlt_events_fire( properties, "producer-changed", NULL ); + mlt_properties_set_position( properties, "out", out ); + + return 0; +} + +/** Physically reduce the producer (typically a cut) to a 0 length. + Essentially, all 0 length cuts should be immediately removed by containers. +*/ +int mlt_producer_clear( mlt_producer this ) +{ + if ( this != NULL ) + { + mlt_properties properties = mlt_producer_properties( this ); + mlt_events_block( properties, properties ); + mlt_properties_set_position( properties, "in", 0 ); + mlt_events_unblock( properties, properties ); + mlt_properties_set_position( properties, "out", -1 ); + } return 0; } @@ -389,15 +429,26 @@ static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int ind mlt_properties_set_double( properties, "fps", mlt_producer_get_fps( this ) ); mlt_properties_set_int( properties, "test_audio", mlt_frame_is_test_audio( *frame ) ); mlt_properties_set_int( properties, "test_image", mlt_frame_is_test_card( *frame ) ); + if ( mlt_properties_get_data( properties, "_producer", NULL ) == NULL ) + mlt_properties_set_data( properties, "_producer", service, 0, NULL, NULL ); } else { mlt_properties properties = mlt_producer_properties( this ); - mlt_producer_seek( this, mlt_properties_get_int( properties, "_position" ) ); - result = producer_get_frame( mlt_producer_service( mlt_producer_cut_parent( this ) ), frame, index ); + int clone_index = mlt_properties_get_int( properties, "_clone" ); + mlt_producer clone = this; + if ( clone_index > 0 ) + { + char key[ 25 ]; + sprintf( key, "_clone.%d", clone_index - 1 ); + clone = mlt_properties_get_data( mlt_producer_properties( mlt_producer_cut_parent( this ) ), key, NULL ); + clone = clone == NULL ? this : clone; + } + mlt_producer_seek( clone, mlt_properties_get_int( properties, "_position" ) ); + result = producer_get_frame( mlt_producer_service( mlt_producer_cut_parent( clone ) ), frame, index ); double speed = mlt_producer_get_speed( this ); mlt_properties_set_double( mlt_frame_properties( *frame ), "_speed", speed ); - mlt_producer_prepare_next( this ); + mlt_producer_prepare_next( clone ); } return result; @@ -427,6 +478,271 @@ mlt_filter mlt_producer_filter( mlt_producer this, int index ) return mlt_service_filter( mlt_producer_service( this ), index ); } +/** Clone this producer. +*/ + +static mlt_producer mlt_producer_clone( mlt_producer this ) +{ + mlt_producer clone = NULL; + mlt_properties properties = mlt_producer_properties( this ); + char *resource = mlt_properties_get( properties, "resource" ); + char *service = mlt_properties_get( properties, "mlt_service" ); + + if ( service != NULL ) + { + char temp[ 1024 ]; + strncpy( temp, service, 1024 ); + if ( resource != NULL ) + { + strcat( temp, ":" ); + strncat( temp, resource, 1023 - strlen( temp ) ); + } + clone = mlt_factory_producer( "fezzik", temp ); + } + + if ( clone == NULL && resource != NULL ) + clone = mlt_factory_producer( "fezzik", resource ); + + return clone; +} + +/** Create clones. +*/ + +static void mlt_producer_set_clones( mlt_producer this, int clones ) +{ + mlt_producer parent = mlt_producer_cut_parent( this ); + mlt_properties properties = mlt_producer_properties( parent ); + int existing = mlt_properties_get_int( properties, "_clones" ); + int i = 0; + char key[ 25 ]; + + // If the number of existing clones is different, the create/remove as necessary + if ( existing != clones ) + { + if ( existing < clones ) + { + for ( i = existing; i < clones; i ++ ) + { + mlt_producer clone = mlt_producer_clone( parent ); + sprintf( key, "_clone.%d", i ); + mlt_properties_set_data( properties, key, clone, 0, ( mlt_destructor )mlt_producer_close, NULL ); + } + } + else + { + for ( i = clones; i < existing; i ++ ) + { + sprintf( key, "_clone.%d", i ); + mlt_properties_set_data( properties, key, NULL, 0, NULL, NULL ); + } + } + } + + // Ensure all properties on the parent are passed to the clones + for ( i = 0; i < clones; i ++ ) + { + mlt_producer clone = NULL; + sprintf( key, "_clone.%d", i ); + clone = mlt_properties_get_data( properties, key, NULL ); + if ( clone != NULL ) + mlt_properties_pass( mlt_producer_properties( clone ), properties, "" ); + } + + // Update the number of clones on the properties + mlt_properties_set_int( properties, "_clones", clones ); +} + +/** Optimise for overlapping cuts from the same clip. +*/ + +typedef struct +{ + int multitrack; + int track; + int position; + int length; + int offset; +} +track_info; + +typedef struct +{ + mlt_producer cut; + int start; + int end; +} +clip_references; + +static int intersect( clip_references *a, clip_references *b ) +{ + int diff = ( a->start - b->start ) + ( a->end - b->end ); + return diff >= 0 && diff < ( a->end - a->start + 1 ); +} + +static int push( mlt_parser this, int multitrack, int track, int position ) +{ + mlt_properties properties = mlt_parser_properties( this ); + mlt_deque stack = mlt_properties_get_data( properties, "stack", NULL ); + track_info *info = malloc( sizeof( track_info ) ); + info->multitrack = multitrack; + info->track = track; + info->position = position; + info->length = 0; + info->offset = 0; + return mlt_deque_push_back( stack, info ); +} + +static track_info *pop( mlt_parser this ) +{ + mlt_properties properties = mlt_parser_properties( this ); + mlt_deque stack = mlt_properties_get_data( properties, "stack", NULL ); + return mlt_deque_pop_back( stack ); +} + +static track_info *peek( mlt_parser this ) +{ + mlt_properties properties = mlt_parser_properties( this ); + mlt_deque stack = mlt_properties_get_data( properties, "stack", NULL ); + return mlt_deque_peek_back( stack ); +} + +static int on_start_multitrack( mlt_parser this, mlt_multitrack object ) +{ + track_info *info = peek( this ); + return push( this, info->multitrack ++, info->track, info->position ); +} + +static int on_start_track( mlt_parser this ) +{ + track_info *info = peek( this ); + info->position -= info->offset; + info->length -= info->offset; + return push( this, info->multitrack, info->track ++, info->position ); +} + +static int on_start_producer( mlt_parser this, mlt_producer object ) +{ + mlt_properties properties = mlt_parser_properties( this ); + mlt_properties producers = mlt_properties_get_data( properties, "producers", NULL ); + mlt_producer parent = mlt_producer_cut_parent( object ); + if ( !mlt_producer_is_mix( mlt_producer_cut_parent( object ) ) && mlt_producer_is_cut( object ) ) + { + int ref_count = 0; + clip_references *old_refs = NULL; + clip_references *refs = NULL; + char key[ 50 ]; + int count = 0; + track_info *info = peek( this ); + sprintf( key, "%p", parent ); + mlt_properties_get_data( producers, key, &count ); + mlt_properties_set_data( producers, key, parent, ++ count, NULL, NULL ); + old_refs = mlt_properties_get_data( properties, key, &ref_count ); + refs = malloc( ( ref_count + 1 ) * sizeof( clip_references ) ); + if ( old_refs != NULL ) + memcpy( refs, old_refs, ref_count * sizeof( clip_references ) ); + mlt_properties_set_int( mlt_producer_properties( object ), "_clone", -1 ); + refs[ ref_count ].cut = object; + refs[ ref_count ].start = info->position; + refs[ ref_count ].end = info->position + mlt_producer_get_playtime( object ) - 1; + mlt_properties_set_data( properties, key, refs, ++ ref_count, free, NULL ); + info->position += mlt_producer_get_playtime( object ); + info->length += mlt_producer_get_playtime( object ); + } + return 0; +} + +static int on_end_track( mlt_parser this ) +{ + track_info *track = pop( this ); + track_info *multi = peek( this ); + multi->length += track->length; + multi->position += track->length; + multi->offset = track->length; + free( track ); + return 0; +} + +static int on_end_multitrack( mlt_parser this, mlt_multitrack object ) +{ + track_info *multi = pop( this ); + track_info *track = peek( this ); + track->position += multi->length; + track->length += multi->length; + free( multi ); + return 0; +} + +int mlt_producer_optimise( mlt_producer this ) +{ + int error = 1; + mlt_parser parser = mlt_parser_new( ); + if ( parser != NULL ) + { + int i = 0, j = 0, k = 0; + mlt_properties properties = mlt_parser_properties( parser ); + mlt_properties producers = mlt_properties_new( ); + mlt_deque stack = mlt_deque_init( ); + mlt_properties_set_data( properties, "producers", producers, 0, ( mlt_destructor )mlt_properties_close, NULL ); + mlt_properties_set_data( properties, "stack", stack, 0, ( mlt_destructor )mlt_deque_close, NULL ); + parser->on_start_producer = on_start_producer; + parser->on_start_track = on_start_track; + parser->on_end_track = on_end_track; + parser->on_start_multitrack = on_start_multitrack; + parser->on_end_multitrack = on_end_multitrack; + push( parser, 0, 0, 0 ); + mlt_parser_start( parser, mlt_producer_service( this ) ); + free( pop( parser ) ); + for ( k = 0; k < mlt_properties_count( producers ); k ++ ) + { + char *name = mlt_properties_get_name( producers, k ); + int count = 0; + int clones = 0; + int max_clones = 0; + mlt_producer producer = mlt_properties_get_data( producers, name, &count ); + if ( producer != NULL && count > 1 ) + { + clip_references *refs = mlt_properties_get_data( properties, name, &count ); + for ( i = 0; i < count; i ++ ) + { + clones = 0; + for ( j = i + 1; j < count; j ++ ) + { + if ( intersect( &refs[ i ], &refs[ j ] ) ) + { + clones ++; + mlt_properties_set_int( mlt_producer_properties( refs[ j ].cut ), "_clone", clones ); + } + } + if ( clones > max_clones ) + max_clones = clones; + } + + for ( i = 0; i < count; i ++ ) + { + mlt_producer cut = refs[ i ].cut; + if ( mlt_properties_get_int( mlt_producer_properties( cut ), "_clone" ) == -1 ) + mlt_properties_set_int( mlt_producer_properties( cut ), "_clone", 0 ); + } + + mlt_producer_set_clones( producer, max_clones ); + } + else if ( producer != NULL ) + { + clip_references *refs = mlt_properties_get_data( properties, name, &count ); + for ( i = 0; i < count; i ++ ) + { + mlt_producer cut = refs[ i ].cut; + mlt_properties_set_int( mlt_producer_properties( cut ), "_clone", 0 ); + } + mlt_producer_set_clones( producer, 0 ); + } + } + mlt_parser_close( parser ); + } + return error; +} + /** Close the producer. */