From 3e00d7e35326b6fecbd95f459266f91fc60e6f15 Mon Sep 17 00:00:00 2001 From: lilo_booter Date: Tue, 5 Oct 2004 07:28:51 +0000 Subject: [PATCH] Cloning optimisations and introduction of the service parser git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@460 d19143bc-622f-0410-bfdd-b5b2a6649095 --- src/framework/Makefile | 2 + src/framework/mlt.h | 1 + src/framework/mlt_factory.c | 4 +- src/framework/mlt_frame.c | 6 + src/framework/mlt_frame.h | 1 + src/framework/mlt_multitrack.c | 10 +- src/framework/mlt_parser.c | 245 ++++++++++++++++++++ src/framework/mlt_parser.h | 52 +++++ src/framework/mlt_playlist.c | 6 +- src/framework/mlt_producer.c | 306 ++++++++++++++++++++++++- src/framework/mlt_producer.h | 2 + src/framework/mlt_service.c | 35 +++ src/framework/mlt_service.h | 1 + src/framework/mlt_types.h | 16 ++ src/modules/data_fx.properties | 2 +- src/modules/inigo/producer_inigo.c | 1 + src/modules/plus/filter_affine.c | 2 +- src/modules/westley/consumer_westley.c | 2 +- src/modules/westley/producer_westley.c | 5 +- 19 files changed, 678 insertions(+), 21 deletions(-) create mode 100644 src/framework/mlt_parser.c create mode 100644 src/framework/mlt_parser.h diff --git a/src/framework/Makefile b/src/framework/Makefile index 2f3e1e39..d16c7e8d 100644 --- a/src/framework/Makefile +++ b/src/framework/Makefile @@ -7,6 +7,7 @@ OBJS = mlt_frame.o \ mlt_property.o \ mlt_properties.o \ mlt_events.o \ + mlt_parser.o \ mlt_service.o \ mlt_producer.o \ mlt_multitrack.o \ @@ -29,6 +30,7 @@ INCS = mlt_consumer.h \ mlt_pool.h \ mlt_properties.h \ mlt_events.h \ + mlt_parser.h \ mlt_repository.h \ mlt_tractor.h \ mlt_types.h \ diff --git a/src/framework/mlt.h b/src/framework/mlt.h index 332f773a..73e5a6ba 100644 --- a/src/framework/mlt.h +++ b/src/framework/mlt.h @@ -39,6 +39,7 @@ extern "C" #include "mlt_field.h" #include "mlt_tractor.h" #include "mlt_tokeniser.h" +#include "mlt_parser.h" #ifdef __cplusplus } diff --git a/src/framework/mlt_factory.c b/src/framework/mlt_factory.c index f183baab..dbaf2dbd 100644 --- a/src/framework/mlt_factory.c +++ b/src/framework/mlt_factory.c @@ -170,11 +170,13 @@ mlt_consumer mlt_factory_consumer( char *service, void *input ) if ( obj != NULL ) { + mlt_filter filter = mlt_factory_filter( "data_show", NULL ); mlt_properties properties = mlt_consumer_properties( obj ); mlt_properties_set_int( properties, "_unique_id", ++ unique_id ); mlt_properties_set( properties, "mlt_type", "consumer" ); mlt_properties_set( properties, "mlt_service", service ); - mlt_service_attach( mlt_consumer_service( obj ), mlt_factory_filter( "data_show", NULL ) ); + mlt_service_attach( mlt_consumer_service( obj ), filter ); + mlt_filter_close( filter ); } return obj; } diff --git a/src/framework/mlt_frame.c b/src/framework/mlt_frame.c index e61db675..4fb656c1 100644 --- a/src/framework/mlt_frame.c +++ b/src/framework/mlt_frame.c @@ -400,6 +400,12 @@ unsigned char *mlt_frame_get_waveform( mlt_frame this, int w, int h ) return bitmap; } +mlt_producer mlt_frame_get_original_producer( mlt_frame this ) +{ + if ( this != NULL ) + return mlt_properties_get_data( mlt_frame_properties( this ), "_producer", NULL ); + return NULL; +} void mlt_frame_close( mlt_frame this ) { diff --git a/src/framework/mlt_frame.h b/src/framework/mlt_frame.h index cf86fbac..6da256b9 100644 --- a/src/framework/mlt_frame.h +++ b/src/framework/mlt_frame.h @@ -60,6 +60,7 @@ extern int mlt_frame_push_service( mlt_frame self, void *that ); extern void *mlt_frame_pop_service( mlt_frame self ); extern int mlt_frame_push_audio( mlt_frame self, void *that ); extern void *mlt_frame_pop_audio( mlt_frame self ); +extern mlt_producer mlt_frame_get_original_producer( mlt_frame self ); extern void mlt_frame_close( mlt_frame self ); /* convenience functions */ diff --git a/src/framework/mlt_multitrack.c b/src/framework/mlt_multitrack.c index a54a6959..50a9426d 100644 --- a/src/framework/mlt_multitrack.c +++ b/src/framework/mlt_multitrack.c @@ -391,17 +391,14 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int ind // Check if we have a track for this index if ( index < this->count && this->list[ index ] != NULL ) { - // Determine the in point - int in = mlt_producer_is_cut( this->list[ index ]->producer ) ? mlt_producer_get_in( this->list[ index ]->producer ) : 0; - // Get the producer for this track - mlt_producer producer = mlt_producer_cut_parent( this->list[ index ]->producer ); + mlt_producer producer = this->list[ index ]->producer; // Obtain the current position mlt_position position = mlt_producer_frame( parent ); // Make sure we're at the same point - mlt_producer_seek( producer, in + position ); + mlt_producer_seek( producer, position ); // Get the frame from the producer mlt_service_get_frame( mlt_producer_service( producer ), frame, 0 ); @@ -431,9 +428,6 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int ind // Move to the next frame mlt_producer_prepare_next( parent ); } - - // Refresh our stats - //mlt_multitrack_refresh( this ); } return 0; diff --git a/src/framework/mlt_parser.c b/src/framework/mlt_parser.c new file mode 100644 index 00000000..ff073aa7 --- /dev/null +++ b/src/framework/mlt_parser.c @@ -0,0 +1,245 @@ +/* + * mlt_parser.c -- service parsing functionality + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "mlt.h" +#include + +static int on_invalid( mlt_parser this, mlt_service object ) +{ + return 0; +} + +static int on_unknown( mlt_parser this, mlt_service object ) +{ + return 0; +} + +static int on_start_producer( mlt_parser this, mlt_producer object ) +{ + if ( !mlt_producer_is_mix( mlt_producer_cut_parent( object ) ) && mlt_producer_is_cut( object ) ) + mlt_properties_debug( mlt_producer_properties( object ), "cut", stderr ); + return 0; +} + +static int on_end_producer( mlt_parser this, mlt_producer object ) +{ + return 0; +} + +static int on_start_playlist( mlt_parser this, mlt_playlist object ) +{ + return 0; +} + +static int on_end_playlist( mlt_parser this, mlt_playlist object ) +{ + return 0; +} + +static int on_start_tractor( mlt_parser this, mlt_tractor object ) +{ + return 0; +} + +static int on_end_tractor( mlt_parser this, mlt_tractor object ) +{ + return 0; +} + +static int on_start_multitrack( mlt_parser this, mlt_multitrack object ) +{ + return 0; +} + +static int on_end_multitrack( mlt_parser this, mlt_multitrack object ) +{ + return 0; +} + +static int on_start_track( mlt_parser this ) +{ + return 0; +} + +static int on_end_track( mlt_parser this ) +{ + return 0; +} + +static int on_start_filter( mlt_parser this, mlt_filter object ) +{ + return 0; +} + +static int on_end_filter( mlt_parser this, mlt_filter object ) +{ + return 0; +} + +static int on_start_transition( mlt_parser this, mlt_transition object ) +{ + return 0; +} + +static int on_end_transition( mlt_parser this, mlt_transition object ) +{ + return 0; +} + +mlt_parser mlt_parser_new( ) +{ + mlt_parser this = calloc( 1, sizeof( struct mlt_parser_s ) ); + if ( this != NULL && mlt_properties_init( &this->parent, this ) == 0 ) + { + this->on_invalid = on_invalid; + this->on_unknown = on_unknown; + this->on_start_producer = on_start_producer; + this->on_end_producer = on_end_producer; + this->on_start_playlist = on_start_playlist; + this->on_end_playlist = on_end_playlist; + this->on_start_tractor = on_start_tractor; + this->on_end_tractor = on_end_tractor; + this->on_start_multitrack = on_start_multitrack; + this->on_end_multitrack = on_end_multitrack; + this->on_start_track = on_start_track; + this->on_end_track = on_end_track; + this->on_start_filter = on_start_filter; + this->on_end_filter = on_end_filter; + this->on_start_transition = on_start_transition; + this->on_end_transition = on_end_transition; + } + return this; +} + +mlt_properties mlt_parser_properties( mlt_parser this ) +{ + return &this->parent; +} + +int mlt_parser_start( mlt_parser this, mlt_service object ) +{ + int error = 0; + mlt_service_type type = mlt_service_identify( object ); + switch( type ) + { + case invalid_type: + error = this->on_invalid( this, object ); + break; + case unknown_type: + error = this->on_unknown( this, object ); + break; + case producer_type: + if ( mlt_producer_is_cut( ( mlt_producer )object ) ) + error = mlt_parser_start( this, ( mlt_service )mlt_producer_cut_parent( ( mlt_producer )object ) ); + error = this->on_start_producer( this, ( mlt_producer )object ); + if ( error == 0 ) + { + int i = 0; + while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) + error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + } + error = this->on_end_producer( this, ( mlt_producer )object ); + break; + case playlist_type: + error = this->on_start_playlist( this, ( mlt_playlist )object ); + if ( error == 0 ) + { + int i = 0; + while ( error == 0 && i < mlt_playlist_count( ( mlt_playlist )object ) ) + mlt_parser_start( this, ( mlt_service )mlt_playlist_get_clip( ( mlt_playlist )object, i ++ ) ); + i = 0; + while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) + error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + } + error = this->on_end_playlist( this, ( mlt_playlist )object ); + break; + case tractor_type: + error = this->on_start_tractor( this, ( mlt_tractor )object ); + if ( error == 0 ) + { + int i = 0; + mlt_service next = mlt_service_producer( object ); + mlt_parser_start( this, ( mlt_service )mlt_tractor_multitrack( ( mlt_tractor )object ) ); + while ( next != ( mlt_service )mlt_tractor_multitrack( ( mlt_tractor )object ) ) + { + mlt_parser_start( this, next ); + next = mlt_service_producer( next ); + } + while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) + error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + } + error = this->on_end_tractor( this, ( mlt_tractor )object ); + break; + case multitrack_type: + error = this->on_start_multitrack( this, ( mlt_multitrack )object ); + if ( error == 0 ) + { + int i = 0; + while ( i < mlt_multitrack_count( ( mlt_multitrack )object ) ) + { + this->on_start_track( this ); + mlt_parser_start( this, ( mlt_service )mlt_multitrack_track( ( mlt_multitrack )object , i ++ ) ); + this->on_end_track( this ); + } + i = 0; + while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) + error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + } + error = this->on_end_multitrack( this, ( mlt_multitrack )object ); + break; + case filter_type: + error = this->on_start_filter( this, ( mlt_filter )object ); + if ( error == 0 ) + { + int i = 0; + while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) + error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + } + error = this->on_end_filter( this, ( mlt_filter )object ); + break; + case transition_type: + error = this->on_start_transition( this, ( mlt_transition )object ); + if ( error == 0 ) + { + int i = 0; + while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) + error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + } + error = this->on_end_transition( this, ( mlt_transition )object ); + break; + case field_type: + break; + case consumer_type: + break; + } + return error; +} + +void mlt_parser_close( mlt_parser this ) +{ + if ( this != NULL ) + { + mlt_properties_close( &this->parent ); + free( this ); + } +} + + diff --git a/src/framework/mlt_parser.h b/src/framework/mlt_parser.h new file mode 100644 index 00000000..35cdd9dc --- /dev/null +++ b/src/framework/mlt_parser.h @@ -0,0 +1,52 @@ +/* + * mlt_parser.h -- service parsing functionality + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _MLT_PARSER_H_ +#define _MLT_PARSER_H_ + +#include "mlt_types.h" + +struct mlt_parser_s +{ + struct mlt_properties_s parent; + int ( *on_invalid )( mlt_parser self, mlt_service object ); + int ( *on_unknown )( mlt_parser self, mlt_service object ); + int ( *on_start_producer )( mlt_parser self, mlt_producer object ); + int ( *on_end_producer )( mlt_parser self, mlt_producer object ); + int ( *on_start_playlist )( mlt_parser self, mlt_playlist object ); + int ( *on_end_playlist )( mlt_parser self, mlt_playlist object ); + int ( *on_start_tractor )( mlt_parser self, mlt_tractor object ); + int ( *on_end_tractor )( mlt_parser self, mlt_tractor object ); + int ( *on_start_multitrack )( mlt_parser self, mlt_multitrack object ); + int ( *on_end_multitrack )( mlt_parser self, mlt_multitrack object ); + int ( *on_start_track )( mlt_parser self ); + int ( *on_end_track )( mlt_parser self ); + int ( *on_start_filter )( mlt_parser self, mlt_filter object ); + int ( *on_end_filter )( mlt_parser self, mlt_filter object ); + int ( *on_start_transition )( mlt_parser self, mlt_transition object ); + int ( *on_end_transition )( mlt_parser self, mlt_transition object ); +}; + +extern mlt_parser mlt_parser_new( ); +extern mlt_properties mlt_parser_properties( mlt_parser self ); +extern int mlt_parser_start( mlt_parser self, mlt_service object ); +extern void mlt_parser_close( mlt_parser self ); + +#endif diff --git a/src/framework/mlt_playlist.c b/src/framework/mlt_playlist.c index 7f71d494..b59ee0d8 100644 --- a/src/framework/mlt_playlist.c +++ b/src/framework/mlt_playlist.c @@ -835,10 +835,6 @@ int mlt_playlist_mix( mlt_playlist this, int clip, int length, mlt_transition tr track_a = mlt_producer_cut( clip_a->producer, clip_a->frame_out - length + 1, clip_a->frame_out ); track_b = mlt_producer_cut( clip_b->producer, clip_b->frame_in, clip_b->frame_in + length - 1 ); - // Temporary - for the benefit of westley serialisation - mlt_properties_set_int( mlt_producer_properties( track_a ), "cut", 1 ); - mlt_properties_set_int( mlt_producer_properties( track_b ), "cut", 1 ); - // Set the tracks on the tractor mlt_tractor_set_track( tractor, track_a, 0 ); mlt_tractor_set_track( tractor, track_b, 1 ); @@ -913,7 +909,7 @@ int mlt_playlist_mix_add( mlt_playlist this, int clip, mlt_transition transition mlt_producer mlt_playlist_get_clip( mlt_playlist this, int clip ) { - if ( clip > 0 && clip < this->count ) + if ( clip >= 0 && clip < this->count ) return this->list[ clip ]->producer; return NULL; } diff --git a/src/framework/mlt_producer.c b/src/framework/mlt_producer.c index bb6462c4..d0cb522e 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 @@ -120,6 +121,18 @@ static void mlt_producer_service_changed( mlt_service owner, mlt_producer this ) 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. */ @@ -405,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 ); + 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; @@ -443,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_clone, 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. */ diff --git a/src/framework/mlt_producer.h b/src/framework/mlt_producer.h index c74228b1..f79e1920 100644 --- a/src/framework/mlt_producer.h +++ b/src/framework/mlt_producer.h @@ -67,7 +67,9 @@ extern int mlt_producer_detach( mlt_producer self, mlt_filter filter ); extern mlt_filter mlt_producer_filter( mlt_producer self, int index ); extern mlt_producer mlt_producer_cut( mlt_producer self, int in, int out ); extern int mlt_producer_is_cut( mlt_producer self ); +extern int mlt_producer_is_mix( mlt_producer self ); extern mlt_producer mlt_producer_cut_parent( mlt_producer self ); +extern int mlt_producer_optimise( mlt_producer self ); extern void mlt_producer_close( mlt_producer self ); #endif diff --git a/src/framework/mlt_service.c b/src/framework/mlt_service.c index 06fd7d58..9a1cc376 100644 --- a/src/framework/mlt_service.c +++ b/src/framework/mlt_service.c @@ -99,6 +99,41 @@ static void mlt_service_property_changed( mlt_listener listener, mlt_properties listener( owner, this, ( char * )args[ 0 ] ); } +mlt_service_type mlt_service_identify( mlt_service this ) +{ + mlt_service_type type = invalid_type; + if ( this != NULL ) + { + mlt_properties properties = mlt_service_properties( this ); + char *mlt_type = mlt_properties_get( properties, "mlt_type" ); + char *resource = mlt_properties_get( properties, "resource" ); + if ( mlt_type == NULL ) + type = unknown_type; + else if ( !strcmp( mlt_type, "producer" ) ) + type = producer_type; + else if ( !strcmp( mlt_type, "mlt_producer" ) ) + { + if ( resource == NULL || !strcmp( resource, "" ) ) + type = producer_type; + else if ( !strcmp( resource, "" ) ) + type = playlist_type; + else if ( !strcmp( resource, "" ) ) + type = tractor_type; + else if ( !strcmp( resource, "" ) ) + type = multitrack_type; + } + else if ( !strcmp( mlt_type, "filter" ) ) + type = filter_type; + else if ( !strcmp( mlt_type, "transition" ) ) + type = transition_type; + else if ( !strcmp( mlt_type, "consumer" ) ) + type = consumer_type; + else + type = unknown_type; + } + return type; +} + /** Connect a producer service. Returns: > 0 warning, == 0 success, < 0 serious error 1 = this service does not accept input diff --git a/src/framework/mlt_service.h b/src/framework/mlt_service.h index 00e50015..4fa7c4a9 100644 --- a/src/framework/mlt_service.h +++ b/src/framework/mlt_service.h @@ -45,6 +45,7 @@ struct mlt_service_s */ extern int mlt_service_init( mlt_service self, void *child ); +extern mlt_service_type mlt_service_identify( mlt_service self ); extern int mlt_service_connect_producer( mlt_service self, mlt_service producer, int index ); extern int mlt_service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); extern mlt_properties mlt_service_properties( mlt_service self ); diff --git a/src/framework/mlt_types.h b/src/framework/mlt_types.h index 5954f5fc..7d233594 100644 --- a/src/framework/mlt_types.h +++ b/src/framework/mlt_types.h @@ -50,6 +50,21 @@ typedef enum } mlt_whence; +typedef enum +{ + invalid_type, + unknown_type, + producer_type, + playlist_type, + tractor_type, + multitrack_type, + filter_type, + transition_type, + consumer_type, + field_type +} +mlt_service_type; + typedef int32_t mlt_position; typedef struct mlt_frame_s *mlt_frame, **mlt_frame_ptr; typedef struct mlt_properties_s *mlt_properties; @@ -64,6 +79,7 @@ typedef struct mlt_transition_s *mlt_transition; typedef struct mlt_tractor_s *mlt_tractor; typedef struct mlt_field_s *mlt_field; typedef struct mlt_consumer_s *mlt_consumer; +typedef struct mlt_parser_s *mlt_parser; typedef struct mlt_deque_s *mlt_deque; typedef void ( *mlt_destructor )( void * ); diff --git a/src/modules/data_fx.properties b/src/modules/data_fx.properties index dd8cbbc8..b0167804 100644 --- a/src/modules/data_fx.properties +++ b/src/modules/data_fx.properties @@ -44,7 +44,7 @@ top-titles=region top-titles.description=Top Titles top-titles.properties.markup=filter[1].producer.markup top-titles.type.markup=text -titles.period=2 +top-titles.period=2 top-titles.properties.length[0]=filter[0].composite.out top-titles.properties.length[1]=filter[1].composite.out top-titles.composite.start=5%,5%:90%x20% diff --git a/src/modules/inigo/producer_inigo.c b/src/modules/inigo/producer_inigo.c index 31368cb0..80aee87c 100644 --- a/src/modules/inigo/producer_inigo.c +++ b/src/modules/inigo/producer_inigo.c @@ -402,6 +402,7 @@ mlt_producer producer_inigo_init( char **argv ) mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist ), track ); mlt_producer prod = mlt_tractor_producer( tractor ); + mlt_producer_optimise( prod ); mlt_properties props = mlt_tractor_properties( tractor ); mlt_properties_set_data( props, "group", group, 0, ( mlt_destructor )mlt_properties_close, NULL ); mlt_properties_set_position( props, "length", mlt_producer_get_out( mlt_multitrack_producer( multitrack ) ) + 1 ); diff --git a/src/modules/plus/filter_affine.c b/src/modules/plus/filter_affine.c index a3053e1d..2e76c51c 100644 --- a/src/modules/plus/filter_affine.c +++ b/src/modules/plus/filter_affine.c @@ -70,7 +70,7 @@ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format * mlt_properties_pass( mlt_producer_properties( producer ), properties, "producer." ); mlt_properties_pass( mlt_transition_properties( transition ), properties, "transition." ); mlt_service_get_frame( mlt_producer_service( producer ), &a_frame, 0 ); - mlt_properties_set( mlt_frame_properties( a_frame ), "rescale_interp", "nearest" ); + mlt_properties_set( mlt_frame_properties( a_frame ), "rescale.interp", "nearest" ); mlt_properties_set( mlt_frame_properties( a_frame ), "distort", "true" ); mlt_properties_set_double( mlt_frame_properties( a_frame ), "consumer_aspect_ratio", mlt_properties_get_double( frame_properties, "consumer_aspect_ratio" ) ); diff --git a/src/modules/westley/consumer_westley.c b/src/modules/westley/consumer_westley.c index 6a9644c1..f0b15e1b 100644 --- a/src/modules/westley/consumer_westley.c +++ b/src/modules/westley/consumer_westley.c @@ -313,7 +313,7 @@ static void serialise_multitrack( serialise_context context, mlt_service service char *id = westley_get_id( context, MLT_SERVICE( parent ), westley_existing ); xmlNewProp( track, "producer", id ); - if ( mlt_properties_get_int( properties, "cut" ) == 1 ) + if ( mlt_properties_get_int( properties, "_cut" ) == 1 ) { xmlNewProp( track, "in", mlt_properties_get( properties, "in" ) ); xmlNewProp( track, "out", mlt_properties_get( properties, "out" ) ); diff --git a/src/modules/westley/producer_westley.c b/src/modules/westley/producer_westley.c index fa404065..dc6baa5c 100644 --- a/src/modules/westley/producer_westley.c +++ b/src/modules/westley/producer_westley.c @@ -54,7 +54,7 @@ enum service_type 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, @@ -1384,6 +1384,9 @@ mlt_producer producer_westley_init( int info, char *data ) // Assign the title mlt_properties_set( properties, "title", title ); + // Optimise for overlapping producers + mlt_producer_optimise( MLT_PRODUCER( service ) ); + // Handle deep copies if ( getenv( "MLT_WESTLEY_DEEP" ) == NULL ) { -- 2.39.2