From: lilo_booter Date: Fri, 24 Sep 2004 13:30:03 +0000 (+0000) Subject: Cut management part 1 X-Git-Url: http://research.m1stereo.tv/gitweb?a=commitdiff_plain;h=519393231e6ab626f19bd01d4622d1c3759fcc93;hp=f5da31bf950521eaef7fc1f7047603e28cbbb377;p=melted Cut management part 1 git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@441 d19143bc-622f-0410-bfdd-b5b2a6649095 --- diff --git a/src/framework/mlt_playlist.c b/src/framework/mlt_playlist.c index c9a9d1b..579aeb1 100644 --- a/src/framework/mlt_playlist.c +++ b/src/framework/mlt_playlist.c @@ -215,10 +215,19 @@ static void mlt_playlist_listener( mlt_producer producer, mlt_playlist this ) /** Append to the virtual playlist. */ -static int mlt_playlist_virtual_append( mlt_playlist this, mlt_producer producer, mlt_position in, mlt_position out ) +static int mlt_playlist_virtual_append( mlt_playlist this, mlt_producer source, mlt_position in, mlt_position out ) { + mlt_producer producer = mlt_producer_is_cut( source ) ? source : mlt_producer_cut( source, in, out ); mlt_properties properties = mlt_producer_properties( producer ); + // If we have a cut, then use the in/out points from the cut + if ( mlt_producer_is_cut( source ) ) + { + mlt_properties_inc_ref( properties ); + in = mlt_producer_get_in( source ); + out = mlt_producer_get_out( source ); + } + // Check that we have room if ( this->count >= this->size ) { @@ -243,7 +252,6 @@ static int mlt_playlist_virtual_append( mlt_playlist this, mlt_producer producer this->count ++; - mlt_properties_inc_ref( properties ); return mlt_playlist_virtual_refresh( this ); } @@ -296,7 +304,6 @@ static mlt_service mlt_playlist_virtual_seek( mlt_playlist this ) // Seek in real producer to relative position if ( producer != NULL ) { - position += this->list[ i ]->frame_in; mlt_producer_seek( producer, position ); } else if ( !strcmp( eof, "pause" ) && total > 0 ) @@ -315,7 +322,7 @@ static mlt_service mlt_playlist_virtual_seek( mlt_playlist this ) mlt_producer this_producer = mlt_playlist_producer( this ); mlt_producer_seek( this_producer, 0 ); producer = entry->producer; - mlt_producer_seek( producer, entry->frame_in ); + mlt_producer_seek( producer, 0 ); } else { diff --git a/src/framework/mlt_producer.c b/src/framework/mlt_producer.c index 79038fb..843a245 100644 --- a/src/framework/mlt_producer.c +++ b/src/framework/mlt_producer.c @@ -130,6 +130,53 @@ mlt_producer mlt_producer_new( ) return this; } +/** Determine if producer is a cut. +*/ + +int mlt_producer_is_cut( mlt_producer this ) +{ + return mlt_properties_get_int( mlt_producer_properties( this ), "_cut" ); +} + +/** Obtain the parent producer. +*/ + +mlt_producer mlt_producer_cut_parent( mlt_producer this ) +{ + mlt_properties properties = mlt_producer_properties( this ); + if ( mlt_producer_is_cut( this ) ) + return mlt_properties_get_data( properties, "_cut_parent", NULL ); + else + return this; +} + +/** Create a cut of this producer +*/ + +mlt_producer mlt_producer_cut( mlt_producer this, int in, int out ) +{ + mlt_producer result = mlt_producer_new( ); + mlt_producer parent = mlt_producer_cut_parent( this ); + mlt_properties properties = mlt_producer_properties( result ); + mlt_properties parent_props = mlt_producer_properties( parent ); + + // Special case - allow for a cut of the entire producer (this will squeeze all other cuts to 0) + if ( in <= 0 ) + in = 0; + if ( out >= mlt_producer_get_playtime( parent ) ) + out = mlt_producer_get_playtime( parent ) - 1; + + mlt_properties_inc_ref( parent_props ); + mlt_properties_set_int( properties, "_cut", 1 ); + mlt_properties_set_data( properties, "_cut_parent", parent, 0, ( mlt_destructor )mlt_producer_close, NULL ); + mlt_properties_set_position( properties, "length", mlt_properties_get_position( parent_props, "length" ) ); + mlt_properties_set_position( properties, "in", 0 ); + mlt_properties_set_position( properties, "out", 0 ); + mlt_producer_set_in_and_out( result, in, out ); + + return result; +} + /** Get the parent service object. */ @@ -152,8 +199,13 @@ mlt_properties mlt_producer_properties( mlt_producer this ) int mlt_producer_seek( mlt_producer this, mlt_position position ) { // Determine eof handling - char *eof = mlt_properties_get( mlt_producer_properties( this ), "eof" ); - int use_points = 1 - mlt_properties_get_int( mlt_producer_properties( this ), "ignore_points" ); + mlt_properties properties = mlt_producer_properties( this ); + char *eof = mlt_properties_get( properties, "eof" ); + int use_points = 1 - mlt_properties_get_int( properties, "ignore_points" ); + + // Recursive behaviour for cuts... + if ( mlt_producer_is_cut( this ) ) + mlt_producer_seek( mlt_producer_cut_parent( this ), position + mlt_producer_get_in( this ) ); // Check bounds if ( position < 0 ) @@ -303,40 +355,52 @@ static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int ind int result = 1; mlt_producer this = service->child; - // Determine eof handling - char *eof = mlt_properties_get( mlt_producer_properties( this ), "eof" ); - - // A properly instatiated producer will have a get_frame method... - if ( this->get_frame == NULL || ( !strcmp( eof, "continue" ) && mlt_producer_position( this ) > mlt_producer_get_out( this ) ) ) + if ( !mlt_producer_is_cut( this ) ) { - // Generate a test frame - *frame = mlt_frame_init( ); + // Determine eof handling + char *eof = mlt_properties_get( mlt_producer_properties( this ), "eof" ); + + // A properly instatiated producer will have a get_frame method... + if ( this->get_frame == NULL || ( !strcmp( eof, "continue" ) && mlt_producer_position( this ) > mlt_producer_get_out( this ) ) ) + { + // Generate a test frame + *frame = mlt_frame_init( ); - // Set the position - result = mlt_frame_set_position( *frame, mlt_producer_position( this ) ); + // Set the position + result = mlt_frame_set_position( *frame, mlt_producer_position( this ) ); - // Mark as a test card - mlt_properties_set_int( mlt_frame_properties( *frame ), "test_image", 1 ); - mlt_properties_set_int( mlt_frame_properties( *frame ), "test_audio", 1 ); + // Mark as a test card + mlt_properties_set_int( mlt_frame_properties( *frame ), "test_image", 1 ); + mlt_properties_set_int( mlt_frame_properties( *frame ), "test_audio", 1 ); - // Calculate the next position - mlt_producer_prepare_next( this ); + // Calculate the next position + mlt_producer_prepare_next( this ); + } + else + { + // Get the frame from the implementation + result = this->get_frame( this, frame, index ); + } + + // Copy the fps and speed of the producer onto the frame + mlt_properties properties = mlt_frame_properties( *frame ); + double speed = mlt_producer_get_speed( this ); + mlt_properties_set_double( properties, "_speed", speed ); + 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 ) ); } else { - // Get the frame from the implementation - result = this->get_frame( this, frame, index ); + 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 ); + double speed = mlt_producer_get_speed( this ); + mlt_properties_set_double( mlt_frame_properties( *frame ), "_speed", speed ); + mlt_producer_prepare_next( this ); } - // Copy the fps and speed of the producer onto the frame - mlt_properties properties = mlt_frame_properties( *frame ); - mlt_properties_set_double( properties, "fps", mlt_producer_get_fps( this ) ); - double speed = mlt_producer_get_speed( this ); - mlt_properties_set_double( properties, "_speed", speed ); - 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 ) ); - - return 0; + return result; } /** Attach a filter. diff --git a/src/framework/mlt_producer.h b/src/framework/mlt_producer.h index aabd557..fb2059f 100644 --- a/src/framework/mlt_producer.h +++ b/src/framework/mlt_producer.h @@ -64,6 +64,9 @@ extern void mlt_producer_prepare_next( mlt_producer self ); extern int mlt_producer_attach( mlt_producer self, mlt_filter filter ); 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 mlt_producer mlt_producer_cut_parent( mlt_producer self ); extern void mlt_producer_close( mlt_producer self ); #endif diff --git a/src/framework/mlt_properties.c b/src/framework/mlt_properties.c index 1d13714..972ad93 100644 --- a/src/framework/mlt_properties.c +++ b/src/framework/mlt_properties.c @@ -47,7 +47,7 @@ property_list; /** Memory leak checks. */ -//#define _MLT_PROPERTY_CHECKS_ +#define _MLT_PROPERTY_CHECKS_ #ifdef _MLT_PROPERTY_CHECKS_ static int properties_created = 0; diff --git a/src/framework/mlt_service.c b/src/framework/mlt_service.c index e91e441..9a0cd77 100644 --- a/src/framework/mlt_service.c +++ b/src/framework/mlt_service.c @@ -271,6 +271,10 @@ void mlt_service_apply_filters( mlt_service this, mlt_frame frame, int index ) mlt_service_base *base = this->local; mlt_position position = mlt_properties_get_position( frame_properties, "_position" ); + // Hmm - special case for cuts - apply filters from the parent first + if ( mlt_properties_get_int( filter_properties, "_cut" ) ) + mlt_service_apply_filters( ( mlt_service )mlt_properties_get_data( filter_properties, "_cut_parent", NULL ), frame, 0 ); + if ( index == 0 || mlt_properties_get_int( filter_properties, "_filter_private" ) == 0 ) { // Process the frame with the attached filters diff --git a/src/modules/westley/consumer_westley.c b/src/modules/westley/consumer_westley.c index 35afa6e..fe8d375 100644 --- a/src/modules/westley/consumer_westley.c +++ b/src/modules/westley/consumer_westley.c @@ -323,19 +323,20 @@ static void serialise_playlist( serialise_context context, mlt_service service, { if ( info.producer != NULL ) { - char *service_s = mlt_properties_get( mlt_producer_properties( info.producer ), "mlt_service" ); - char *resource_s = mlt_properties_get( mlt_producer_properties( info.producer ), "resource" ); + mlt_producer producer = mlt_producer_cut_parent( info.producer ); + char *service_s = mlt_properties_get( mlt_producer_properties( producer ), "mlt_service" ); + char *resource_s = mlt_properties_get( mlt_producer_properties( producer ), "resource" ); if ( resource_s != NULL && !strcmp( resource_s, "" ) ) { - serialise_tractor( context, MLT_SERVICE( info.producer ), node ); + serialise_tractor( context, MLT_SERVICE( producer ), node ); context->pass ++; - serialise_tractor( context, MLT_SERVICE( info.producer ), node ); + serialise_tractor( context, MLT_SERVICE( producer ), node ); context->pass --; } else if ( service_s != NULL && strcmp( service_s, "blank" ) != 0 ) - serialise_service( context, MLT_SERVICE( info.producer ), node ); + serialise_service( context, MLT_SERVICE( producer ), node ); else if ( resource_s != NULL && !strcmp( resource_s, "" ) ) - serialise_playlist( context, MLT_SERVICE( info.producer ), node ); + serialise_playlist( context, MLT_SERVICE( producer ), node ); } } } @@ -353,7 +354,8 @@ static void serialise_playlist( serialise_context context, mlt_service service, { if ( ! mlt_playlist_get_clip_info( MLT_PLAYLIST( service ), &info, i ) ) { - char *service_s = mlt_properties_get( mlt_producer_properties( info.producer ), "mlt_service" ); + mlt_producer producer = mlt_producer_cut_parent( info.producer ); + char *service_s = mlt_properties_get( mlt_producer_properties( producer ), "mlt_service" ); if ( service_s != NULL && strcmp( service_s, "blank" ) == 0 ) { char length[ 20 ]; @@ -366,12 +368,14 @@ static void serialise_playlist( serialise_context context, mlt_service service, { char temp[ 20 ]; xmlNode *entry = xmlNewChild( child, NULL, "entry", NULL ); - id = westley_get_id( context, MLT_SERVICE( info.producer ), westley_existing ); + id = westley_get_id( context, MLT_SERVICE( producer ), westley_existing ); xmlNewProp( entry, "producer", id ); sprintf( temp, "%d", info.frame_in ); xmlNewProp( entry, "in", temp ); sprintf( temp, "%d", info.frame_out ); xmlNewProp( entry, "out", temp ); + if ( mlt_producer_is_cut( info.producer ) ) + serialise_service_filters( context, mlt_producer_service( info.producer ), entry ); } } } diff --git a/src/modules/westley/producer_westley.c b/src/modules/westley/producer_westley.c index 46fd809..4e5bad8 100644 --- a/src/modules/westley/producer_westley.c +++ b/src/modules/westley/producer_westley.c @@ -599,7 +599,76 @@ static void on_start_blank( deserialise_context context, const xmlChar *name, co } } -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 ); + } + + mlt_playlist_get_clip_info( MLT_PLAYLIST( parent ), &info, mlt_playlist_count( MLT_PLAYLIST( parent ) ) - 1 ); + entry = info.producer; + } + 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 ) ); @@ -608,10 +677,7 @@ static void on_start_entry_track( deserialise_context context, const xmlChar *na // 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", "" ); - else - mlt_properties_set( mlt_service_properties( service ), "resource", "" ); + mlt_properties_set( mlt_service_properties( service ), "resource", "" ); for ( ; atts != NULL && *atts != NULL; atts += 2 ) { @@ -688,50 +754,6 @@ static void on_end_track( deserialise_context context, const xmlChar *name ) } } -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 @@ -994,8 +1016,10 @@ static void on_start_element( void *ctx, const xmlChar *name, const xmlChar **at 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 )