]> git.sesse.net Git - mlt/commitdiff
Mlt Ref Counts and Playlist split/join
authorlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Thu, 26 Aug 2004 14:16:56 +0000 (14:16 +0000)
committerlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Thu, 26 Aug 2004 14:16:56 +0000 (14:16 +0000)
git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@387 d19143bc-622f-0410-bfdd-b5b2a6649095

25 files changed:
docs/framework.txt
setenv_mc
src/framework/mlt_consumer.c
src/framework/mlt_field.c
src/framework/mlt_filter.c
src/framework/mlt_frame.c
src/framework/mlt_multitrack.c
src/framework/mlt_playlist.c
src/framework/mlt_playlist.h
src/framework/mlt_producer.c
src/framework/mlt_producer.h
src/framework/mlt_properties.c
src/framework/mlt_properties.h
src/framework/mlt_service.c
src/framework/mlt_service.h
src/framework/mlt_tractor.c
src/framework/mlt_transition.c
src/modules/core/producer_colour.c
src/modules/core/producer_noise.c
src/modules/core/producer_ppm.c
src/modules/dv/producer_libdv.c
src/modules/fezzik/producer_hold.c
src/modules/gtk2/producer_pango.c
src/modules/gtk2/producer_pixbuf.c
src/modules/westley/consumer_westley.c

index 07cc71282241f5fe64dabaeb6249915db67c15b3..4ffff1f5e595408e4f23fd66555d8353b4330ac3 100644 (file)
@@ -23,8 +23,8 @@ Preamble:
 
        This document is split roughly into 3 sections. The first section provides a
        basic overview of MLT, the second section shows how it's used and the final
-       section shows shows structure and design, with an emphasis on how the system
-       is extended.
+       section shows structure and design, with an emphasis on how the system is 
+       extended.
 
 
 Target Audience:
@@ -303,11 +303,7 @@ Playlists:
 
        Instead of invoking mlt_factory_producer directly, we'll create a new
        function called create_playlist. This function is responsible for creating
-       the playlist, creating each producer, appending to the playlist and ensuring
-       that all the producers are cleaned up when the playlist is destroyed. The
-       last point is important - a close on the playlist won't explicitly close these 
-       producers. In this example, we use unique "data" properties with destructors
-       to ensure closing.
+       the playlist, creating each producer and appending to the playlist.
 
        mlt_producer create_playlist( int argc, char **argv )
        {
@@ -321,26 +317,28 @@ Playlists:
            int i = 0;
            for ( i = 1; i < argc; i ++ )
            {
-               // Define the unique key
-               char key[ 256 ];
-
                // Create the producer
                mlt_producer producer = mlt_factory_producer( NULL, argv[ i ] );
 
                // Add it to the playlist
                mlt_playlist_append( playlist, producer );
 
-               // Create a unique key for this producer
-               sprintf( key, "producer%d", i );
-
-               // Now we need to ensure the producers are destroyed
-               mlt_properties_set_data( properties, key, producer, 0, ( mlt_destructor )mlt_producer_close, NULL );
+                       // Close the producer (see below)
+                       mlt_producer_close( producer );
            }
 
            // Return the playlist as a producer
            return mlt_playlist_producer( playlist );
        }
 
+       Notice that we close the producer after the append. Actually, what we're 
+       doing is closing our reference to it - the playlist creates its own reference
+       to the producer on append and insert, and it will close its reference 
+       when the playlist is destroyed[*].
+
+       Note also that if you append multiple instances of the same producer, it 
+       will create multiple references to it.
+
        Now all we need do is to replace these lines in the main function:
 
            // Create a normalised producer
@@ -353,6 +351,10 @@ Playlists:
 
        and we have a means to play multiple clips.
 
+       [*] This reference functionality was introduced in mlt 0.1.2 - it is 100%
+       compatable with the early mechanism of registering the reference and 
+       destructor with the properties of the playlist object.
+
 
 Filters:
 
@@ -579,6 +581,9 @@ Multiple Tracks and Transitions:
        and we have a means to play multiple clips with a horribly obtrusive
        watermark - just what the world needed, right? ;-)
 
+       Incidentally, the same thing could be achieved with the more trivial
+       watermark filter inserted between the producer and the consumer.
+
 
 SECTION 3 - STRUCTURE AND DESIGN
 --------------------------------
index 5a26dde73784a0bc743dc865d51ab44f8623c98e..7b015e5b23819ef375bb3df5f087a2481e95e04c 100644 (file)
--- a/setenv_mc
+++ b/setenv_mc
@@ -3,5 +3,6 @@
 
 export LD_LIBRARY_PATH=\
 `pwd`/../mpeg_sdk_release/bin:\
-`pwd`/../dvcpro_sdk_release/lib
+`pwd`/../dvcpro_sdk_release/lib:\
+`pwd`/../sr_sdk_release/lib
 
index a07f72d10ca9d5dfb1a688597c0d4577a2c9d530..f363248122d9f7813fe69cef25c3fb8cbb16b707 100644 (file)
@@ -520,15 +520,19 @@ int mlt_consumer_is_stopped( mlt_consumer this )
 
 void mlt_consumer_close( mlt_consumer this )
 {
-       // Get the childs close function
-       void ( *consumer_close )( ) = this->close;
+       if ( this != NULL && mlt_properties_dec_ref( mlt_consumer_properties( this ) ) <= 0 )
+       {
+               // Get the childs close function
+               void ( *consumer_close )( ) = this->close;
 
-       // Make sure it only gets called once
-       this->close = NULL;
+               // Make sure it only gets called once
+               this->close = NULL;
+               this->parent.close = NULL;
 
-       // Call the childs close if available
-       if ( consumer_close != NULL )
-               consumer_close( this );
-       else
-               mlt_service_close( &this->parent );
+               // Call the childs close if available
+               if ( consumer_close != NULL )
+                       consumer_close( this );
+               else
+                       mlt_service_close( &this->parent );
+       }
 }
index 94c4cb8bb752ae098cc380daa691df811889bebf..05a41e5503e64cde9c673e3cea0c8543ed905b56 100644 (file)
@@ -152,6 +152,11 @@ int mlt_field_plant_transition( mlt_field this, mlt_transition that, int a_track
 
 void mlt_field_close( mlt_field this )
 {
-       free( this );
+       if ( this != NULL && mlt_properties_dec_ref( mlt_field_properties( this ) ) <= 0 )
+       {
+               //mlt_tractor_close( this->tractor );
+               //mlt_multitrack_close( this->multitrack );
+               free( this );
+       }
 }
 
index f140df52658eb011bc45e0651f4a02d3180264a9..37f91db3b8ed7cbd63660b0a907fb42d586fcb98 100644 (file)
@@ -44,6 +44,10 @@ int mlt_filter_init( mlt_filter this, void *child )
                // Override the get_frame method
                service->get_frame = filter_get_frame;
 
+               // Define the destructor
+               service->close = ( mlt_destructor )mlt_filter_close;
+               service->close_object = this;
+
                // Default in, out, track properties
                mlt_properties_set_position( properties, "in", 0 );
                mlt_properties_set_position( properties, "out", 0 );
@@ -192,9 +196,17 @@ static int filter_get_frame( mlt_service service, mlt_frame_ptr frame, int index
 
 void mlt_filter_close( mlt_filter this )
 {
-       if ( this->close != NULL )
-               this->close( this );
-       else
-               mlt_service_close( &this->parent );
-       free( this );
+       if ( this != NULL && mlt_properties_dec_ref( mlt_filter_properties( this ) ) <= 0 )
+       {
+               if ( this->close != NULL )
+               {
+                       this->close( this );
+               }
+               else
+               {
+                       this->parent.close = NULL;
+                       mlt_service_close( &this->parent );
+               }
+               free( this );
+       }
 }
index 401c8647ea230cf897dd6adcb252831961713878..f0092ed90e564287a2e17f7f0f3dec4019610ebd 100644 (file)
@@ -341,7 +341,7 @@ int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *for
 
 void mlt_frame_close( mlt_frame this )
 {
-       if ( this != NULL )
+       if ( this != NULL && mlt_properties_dec_ref( mlt_frame_properties( this ) ) <= 0 )
        {
                mlt_deque_close( this->stack_image );
                mlt_deque_close( this->stack_audio );
index 2c3d927b0b59c12da543d0ad8af7c48e74e7e127..d00525d60c85e701cdc87654cf13935dcc2ed0ce 100644 (file)
@@ -407,12 +407,15 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int ind
 
 void mlt_multitrack_close( mlt_multitrack this )
 {
-       // Close the producer
-       mlt_producer_close( &this->parent );
+       if ( this != NULL && mlt_properties_dec_ref( mlt_multitrack_properties( this ) ) <= 0 )
+       {
+               // Close the producer
+               mlt_producer_close( &this->parent );
 
-       // Free the list
-       free( this->list );
+               // Free the list
+               free( this->list );
 
-       // Free the object
-       free( this );
+               // Free the object
+               free( this );
+       }
 }
index 440c92459c98db83658ecb9746dd388e702dd03a..04e61d49236b0089437f6f128fee5bd52e86e41e 100644 (file)
@@ -73,6 +73,10 @@ mlt_playlist mlt_playlist_init( )
                // Override the producer get_frame
                producer->get_frame = producer_get_frame;
 
+               // Define the destructor
+               producer->close = ( mlt_destructor )mlt_playlist_close;
+               producer->close_object = this;
+
                // Initialise blank
                mlt_producer_init( &this->blank, NULL );
                mlt_properties_set( mlt_producer_properties( &this->blank ), "mlt_service", "blank" );
@@ -187,6 +191,8 @@ static int mlt_playlist_virtual_append( mlt_playlist this, mlt_producer producer
 
        this->count ++;
 
+       mlt_properties_inc_ref( mlt_producer_properties( producer ) );
+
        return mlt_playlist_virtual_refresh( this );
 }
 
@@ -442,6 +448,9 @@ int mlt_playlist_count( mlt_playlist this )
 
 int mlt_playlist_clear( mlt_playlist this )
 {
+       int i;
+       for ( i = 0; i < this->count; i ++ )
+               mlt_producer_close( this->list[ i ]->producer );
        this->count = 0;
        mlt_properties_set_double( mlt_playlist_properties( this ), "first_fps", 0 );
        return mlt_playlist_virtual_refresh( this );
@@ -515,6 +524,9 @@ int mlt_playlist_remove( mlt_playlist this, int where )
                // Get the clip info of the clip to be removed
                mlt_playlist_get_clip_info( this, &where_info, where );
 
+               // Close the producer associated to the clip info
+               mlt_producer_close( where_info.producer );
+
                // Reorganise the list
                for ( i = where + 1; i < this->count; i ++ )
                        this->list[ i - 1 ] = this->list[ i ];
@@ -620,6 +632,68 @@ int mlt_playlist_resize_clip( mlt_playlist this, int clip, mlt_position in, mlt_
        return error;
 }
 
+/** Split a clip on the playlist at the given position.
+*/
+
+int mlt_playlist_split( mlt_playlist this, int clip, mlt_position position )
+{
+       int error = clip < 0 || clip >= this->count;
+       if ( error == 0 )
+       {
+               playlist_entry *entry = this->list[ clip ];
+               if ( position > 0 && position < entry->frame_count )
+               {
+                       int in = entry->frame_in;
+                       int out = entry->frame_out;
+                       mlt_playlist_resize_clip( this, clip, in, in + position );
+                       mlt_playlist_insert( this, entry->producer, clip + 1, in + position + 1, out );
+               }
+               else
+               {
+                       error = 1;
+               }
+       }
+       return error;
+}
+
+/** Join 1 or more consecutive clips.
+*/
+
+int mlt_playlist_join( mlt_playlist this, int clip, int count, int merge )
+{
+       int error = clip < 0 || ( clip + 1 ) >= this->count;
+       if ( error == 0 )
+       {
+               int i = clip;
+               mlt_playlist new_clip = mlt_playlist_init( );
+               if ( clip + count >= this->count )
+                       count = this->count - clip;
+               for ( i = 0; i <= count; i ++ )
+               {
+                       playlist_entry *entry = this->list[ clip ];
+                       char *resource = mlt_properties_get( mlt_producer_properties( entry->producer ), "resource" );
+                       if ( merge && resource != NULL && !strcmp( resource, "<playlist>" ) )
+                       {
+                               mlt_playlist old_clip = ( mlt_playlist )entry->producer;
+                               while( old_clip->count )
+                               {
+                                       entry = old_clip->list[ 0 ];
+                                       mlt_playlist_append_io( new_clip, entry->producer, entry->frame_in, entry->frame_out );
+                                       mlt_playlist_remove( old_clip, 0 );
+                               }
+                       }
+                       else
+                       {
+                               mlt_playlist_append_io( new_clip, entry->producer, entry->frame_in, entry->frame_out );
+                       }
+                       mlt_playlist_remove( this, clip );
+               }
+               mlt_playlist_insert( this, mlt_playlist_producer( new_clip ), clip, 0, -1 );
+               mlt_playlist_close( new_clip );
+       }
+       return error;
+}
+
 /** Get the current frame.
 */
 
@@ -662,11 +736,18 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i
 
 void mlt_playlist_close( mlt_playlist this )
 {
-       int i = 0;
-       mlt_producer_close( &this->parent );
-       mlt_producer_close( &this->blank );
-       for ( i = 0; i < this->count; i ++ )
-               free( this->list[ i ] );
-       free( this->list );
-       free( this );
+       if ( this != NULL && mlt_properties_dec_ref( mlt_playlist_properties( this ) ) <= 0 )
+       {
+               int i = 0;
+               this->parent.close = NULL;
+               mlt_producer_close( &this->parent );
+               mlt_producer_close( &this->blank );
+               for ( i = 0; i < this->count; i ++ )
+               {
+                       mlt_producer_close( this->list[ i ]->producer );
+                       free( this->list[ i ] );
+               }
+               free( this->list );
+               free( this );
+       }
 }
index 913b60899df709a3d4bdd0332ad6364bb05dd717..bfa61c03a92d8394506e95ccf55b7b1008b33ba8 100644 (file)
@@ -61,6 +61,8 @@ extern int mlt_playlist_insert( mlt_playlist self, mlt_producer producer, int wh
 extern int mlt_playlist_remove( mlt_playlist self, int where );
 extern int mlt_playlist_move( mlt_playlist self, int from, int to );
 extern int mlt_playlist_resize_clip( mlt_playlist self, int clip, mlt_position in, mlt_position out );
+extern int mlt_playlist_split( mlt_playlist self, int clip, mlt_position position );
+extern int mlt_playlist_join( mlt_playlist self, int clip, int count, int merge );
 extern void mlt_playlist_close( mlt_playlist self );
 
 #endif
index fc161f5d534c90b28631f19d99fb90394802eb97..8ff5dc1fc8368c6b422f6a5d4573ce08fa17b90c 100644 (file)
@@ -58,6 +58,13 @@ int mlt_producer_init( mlt_producer this, void *child )
                        // The parent is the service
                        mlt_service parent = &this->parent;
        
+                       // Define the parent close
+                       parent->close = ( mlt_destructor )mlt_producer_close;
+                       parent->close_object = this;
+
+                       // For convenience, we'll assume the close_object is this
+                       this->close_object = this;
+
                        // Get the properties of the parent
                        mlt_properties properties = mlt_service_properties( parent );
        
@@ -309,8 +316,13 @@ static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int ind
 
 void mlt_producer_close( mlt_producer this )
 {
-       if ( this->close != NULL )
-               this->close( this );
-       else
-               mlt_service_close( &this->parent );
+       if ( this != NULL && mlt_properties_dec_ref( mlt_producer_properties( this ) ) <= 0 )
+       {
+               this->parent.close = NULL;
+
+               if ( this->close != NULL )
+                       this->close( this->close_object );
+               else
+                       mlt_service_close( &this->parent );
+       }
 }
index e94174c6eb169c241265958c07e7fff1b6e771ec..9bbcda80d8d88ecd5dd2b8a534423c26db952393 100644 (file)
@@ -33,7 +33,8 @@ struct mlt_producer_s
 
        // Public virtual methods
        int ( *get_frame )( mlt_producer, mlt_frame_ptr, int );
-       void ( *close )( mlt_producer );
+       mlt_destructor close;
+       void *close_object;
 
        // Private data
        void *local;
index 895be28a0abb846a7019621bcce440c517f83fc2..189f8affac439b041b8961c9bf1b25a34ec274e2 100644 (file)
@@ -40,12 +40,15 @@ typedef struct
        int count;
        int size;
        mlt_properties mirror;
+       int ref_count;
 }
 property_list;
 
 /** Memory leak checks.
 */
 
+//#define _MLT_PROPERTY_CHECKS_
+
 #ifdef _MLT_PROPERTY_CHECKS_
 static int properties_created = 0;
 static int properties_destroyed = 0;
@@ -71,6 +74,9 @@ int mlt_properties_init( mlt_properties this, void *child )
 
                // Allocate the local structure
                this->local = calloc( sizeof( property_list ), 1 );
+
+               // Increment the ref count
+               ( ( property_list * )this->local )->ref_count = 1;
        }
 
        // Check that initialisation was successful
@@ -156,6 +162,32 @@ static inline void mlt_properties_do_mirror( mlt_properties this, char *name )
        }
 }
 
+/** Maintain ref count to allow multiple uses of an mlt object.
+*/
+
+int mlt_properties_inc_ref( mlt_properties this )
+{
+       if ( this != NULL )
+       {
+               property_list *list = this->local;
+               return ++ list->ref_count;
+       }
+       return 0;
+}
+
+/** Maintain ref count to allow multiple uses of an mlt object.
+*/
+
+int mlt_properties_dec_ref( mlt_properties this )
+{
+       if ( this != NULL )
+       {
+               property_list *list = this->local;
+               return -- list->ref_count;
+       }
+       return 0;
+}
+
 /** Allow the specification of a mirror.
 */
 
@@ -595,39 +627,65 @@ void mlt_properties_dump( mlt_properties this, FILE *output )
                        fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) );
 }
 
+void mlt_properties_debug( mlt_properties this, char *title, FILE *output )
+{
+       fprintf( stderr, "%s: ", title );
+       if ( this != NULL )
+       {
+               property_list *list = this->local;
+               int i = 0;
+               fprintf( output, "[ ref=%d", list->ref_count );
+               for ( i = 0; i < list->count; i ++ )
+                       if ( mlt_properties_get( this, list->name[ i ] ) != NULL )
+                               fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) );
+               fprintf( output, " ]" );
+       }
+       fprintf( stderr, "\n" );
+}
+
 /** Close the list.
 */
 
 void mlt_properties_close( mlt_properties this )
 {
-       if ( this != NULL )
+       if ( this != NULL && mlt_properties_dec_ref( this ) <= 0 )
        {
-               property_list *list = this->local;
-               int index = 0;
-
-               // Clean up names and values
-               for ( index = list->count - 1; index >= 0; index -- )
+               if ( this->close != NULL )
                {
-                       free( list->name[ index ] );
-                       mlt_property_close( list->value[ index ] );
+                       this->close( this->close_object );
                }
-
-               // Clear up the list
-               free( list->name );
-               free( list->value );
-               free( list );
-
-               // Free this now if this has no child
-               if ( this->child == NULL )
-                       free( this );
+               else
+               {
+                       property_list *list = this->local;
+                       int index = 0;
 
 #ifdef _MLT_PROPERTY_CHECKS_
-               // Increment destroyed count
-               properties_destroyed ++;
+                       // Show debug info
+                       mlt_properties_debug( this, "Closing", stderr );
 
-               // Show current stats - these should match when the app is closed
-               fprintf( stderr, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
+                       // Increment destroyed count
+                       properties_destroyed ++;
+
+                       // Show current stats - these should match when the app is closed
+                       fprintf( stderr, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
 #endif
+
+                       // Clean up names and values
+                       for ( index = list->count - 1; index >= 0; index -- )
+                       {
+                               free( list->name[ index ] );
+                               mlt_property_close( list->value[ index ] );
+                       }
+       
+                       // Clear up the list
+                       free( list->name );
+                       free( list->value );
+                       free( list );
+       
+                       // Free this now if this has no child
+                       if ( this->child == NULL )
+                               free( this );
+               }
        }
 }
 
index c0be46e5d20b6605b5a8c3a24192fa9f77f10eda..c57208e5cbb99d2aed3735b9e1b44285e9becb32 100644 (file)
@@ -32,6 +32,8 @@ struct mlt_properties_s
 {
        void *child;
        void *local;
+       mlt_destructor close;
+       void *close_object;
 };
 
 /** Public interface.
@@ -40,6 +42,8 @@ struct mlt_properties_s
 extern int mlt_properties_init( mlt_properties, void *child );
 extern mlt_properties mlt_properties_new( );
 extern mlt_properties mlt_properties_load( char *file );
+extern int mlt_properties_inc_ref( mlt_properties self );
+extern int mlt_properties_dec_ref( mlt_properties self );
 extern void mlt_properties_mirror( mlt_properties self, mlt_properties that );
 extern int mlt_properties_inherit( mlt_properties self, mlt_properties that );
 extern int mlt_properties_pass( mlt_properties self, mlt_properties that, char *prefix );
@@ -61,6 +65,7 @@ extern void *mlt_properties_get_data( mlt_properties self, char *name, int *leng
 extern int mlt_properties_rename( mlt_properties self, char *source, char *dest );
 extern int mlt_properties_count( mlt_properties self );
 extern void mlt_properties_dump( mlt_properties self, FILE *output );
+extern void mlt_properties_debug( mlt_properties self, char *title, FILE *output );
 extern void mlt_properties_close( mlt_properties self );
 
 #endif
index 14ae45f5e0131505b1c549e53cee450b78931e4c..7a66a577e417b40224d71bd2ce121080a9ddb26e 100644 (file)
@@ -59,6 +59,8 @@ static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
 
 int mlt_service_init( mlt_service this, void *child )
 {
+       int error = 0;
+
        // Initialise everything to NULL
        memset( this, 0, sizeof( struct mlt_service_s ) );
 
@@ -72,7 +74,14 @@ int mlt_service_init( mlt_service this, void *child )
        this->get_frame = service_get_frame;
        
        // Initialise the properties
-       return mlt_properties_init( &this->parent, this );
+       error = mlt_properties_init( &this->parent, this );
+       if ( error == 0 )
+       {
+               this->parent.close = ( mlt_destructor )mlt_service_close;
+               this->parent.close_object = this;
+       }
+
+       return error;
 }
 
 /** Connect a producer service.
@@ -110,6 +119,13 @@ int mlt_service_connect_producer( mlt_service this, mlt_service producer, int in
        // If we have space, assign the input
        if ( base->in != NULL && index >= 0 && index < base->size )
        {
+               // Get the current service
+               mlt_service current = base->in[ index ];
+
+               // Increment the reference count on this producer
+               if ( producer != NULL )
+                       mlt_properties_inc_ref( mlt_service_properties( producer ) );
+
                // Now we disconnect the producer service from its consumer
                mlt_service_disconnect( producer );
                
@@ -123,6 +139,9 @@ int mlt_service_connect_producer( mlt_service this, mlt_service producer, int in
                // Now we connect the producer to its connected consumer
                mlt_service_connect( producer, this );
 
+               // Close the current service
+               mlt_service_close( current );
+
                // Inform caller that all went well
                return 0;
        }
@@ -142,7 +161,7 @@ static void mlt_service_disconnect( mlt_service this )
                // Get the service base
                mlt_service_base *base = this->local;
 
-               // There's a bit more required here...
+               // Disconnect
                base->out = NULL;
        }
 }
@@ -242,9 +261,24 @@ int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
 
 void mlt_service_close( mlt_service this )
 {
-       mlt_service_base *base = this->local;
-       free( base->in );
-       free( base );
-       mlt_properties_close( &this->parent );
+       if ( this != NULL && mlt_properties_dec_ref( mlt_service_properties( this ) ) <= 0 )
+       {
+               if ( this->close != NULL )
+               {
+                       this->close( this->close_object );
+               }
+               else
+               {
+                       mlt_service_base *base = this->local;
+                       int i = 0;
+                       for ( i = 0; i < base->count; i ++ )
+                               if ( base->in[ i ] != NULL )
+                                       mlt_service_close( base->in[ i ] );
+                       free( base->in );
+                       free( base );
+                       this->parent.close = NULL;
+                       mlt_properties_close( &this->parent );
+               }
+       }
 }
 
index 627bbbeb977d5ee584f4c721f2d59b1ad391d29f..a4a1ee0eed3ce32ccb86090930bf1b5c3d809de7 100644 (file)
@@ -33,6 +33,8 @@ struct mlt_service_s
 
        // Protected virtual
        int ( *get_frame )( mlt_service self, mlt_frame_ptr frame, int index );
+       mlt_destructor close;
+       void *close_object;
 
        // Private data
        void *local;
index 91438680064e1d3147851decbb625ca7516bdd66..5b571be9e3eb66ac9ee50008fc25b8192a035c37 100644 (file)
@@ -41,7 +41,6 @@ struct mlt_tractor_s
 */
 
 static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int track );
-static void producer_close( mlt_producer this );
 
 /** Constructor for the tractor.
 */
@@ -59,7 +58,8 @@ mlt_tractor mlt_tractor_init( )
                        mlt_properties_set( mlt_producer_properties( producer ), "mlt_service", "tractor" );
 
                        producer->get_frame = producer_get_frame;
-                       producer->close = producer_close;
+                       producer->close = ( mlt_destructor )mlt_tractor_close;
+                       producer->close_object = this;
                }
                else
                {
@@ -252,16 +252,11 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int tra
 
 void mlt_tractor_close( mlt_tractor this )
 {
-       this->parent.close = NULL;
-       mlt_producer_close( &this->parent );
-       free( this );
-}
-
-/** Close the producer.
-*/
-
-static void producer_close( mlt_producer this )
-{
-       mlt_tractor_close( this->child );
+       if ( this != NULL && mlt_properties_dec_ref( mlt_tractor_properties( this ) ) <= 0 )
+       {
+               this->parent.close = NULL;
+               mlt_producer_close( &this->parent );
+               free( this );
+       }
 }
 
index afafc230aae2aa8fd5f591fbc6da044aa22cf910..13957752d2c39a5a1c428e0be31fa94f76c4b5fc 100644 (file)
@@ -45,6 +45,8 @@ int mlt_transition_init( mlt_transition this, void *child )
                mlt_properties properties = mlt_transition_properties( this );
 
                service->get_frame = transition_get_frame;
+               service->close = ( mlt_destructor )mlt_transition_close;
+               service->close_object = this;
 
                mlt_properties_set_position( properties, "in", 0 );
                mlt_properties_set_position( properties, "out", 0 );
@@ -230,8 +232,12 @@ static int transition_get_frame( mlt_service service, mlt_frame_ptr frame, int i
 
 void mlt_transition_close( mlt_transition this )
 {
-       if ( this->close != NULL )
-               this->close( this );
-       else
-               mlt_service_close( &this->parent );
+       if ( this != NULL && mlt_properties_dec_ref( mlt_transition_properties( this ) ) <= 0 )
+       {
+               this->parent.close = NULL;
+               if ( this->close != NULL )
+                       this->close( this );
+               else
+                       mlt_service_close( &this->parent );
+       }
 }
index ecd9a3ff3b208270f771922cc87660717060f797..29bde448814828e990c25fe378a52cc4b41a4854 100644 (file)
@@ -45,7 +45,7 @@ mlt_producer producer_colour_init( char *colour )
        
                // Callback registration
                producer->get_frame = producer_get_frame;
-               producer->close = producer_close;
+               producer->close = ( mlt_destructor )producer_close;
 
                // Set the default properties
                mlt_properties_set( properties, "resource", colour == NULL ? "0x000000ff" : colour );
index fe86075bfca7d5b5685f55e7ff8549f9b8584e9c..54d0474dc8882964360452b8c211b034c74c9353 100644 (file)
@@ -60,7 +60,7 @@ mlt_producer producer_noise_init( void *arg )
 
                // Callback registration
                this->get_frame = producer_get_frame;
-               this->close = producer_close;
+               this->close = ( mlt_destructor )producer_close;
        }
 
        return this;
index 4155783b377cb0daccfca30ccea0cf87ebf1ff06..a0a9896fdba941c96c13e5e7c2086ecf10c0fa78 100644 (file)
@@ -48,7 +48,7 @@ mlt_producer producer_ppm_init( void *command )
                mlt_properties properties = mlt_producer_properties( producer );
 
                producer->get_frame = producer_get_frame;
-               producer->close = producer_close;
+               producer->close = ( mlt_destructor )producer_close;
 
                if ( command != NULL )
                {
index 3891681ed35364924c46c16045841f5d3e53f186..4abf75ae17c7e405195c9ceb49c8703e36ee1ef1 100644 (file)
@@ -139,7 +139,7 @@ mlt_producer producer_libdv_init( char *filename )
                mlt_properties properties = mlt_producer_properties( producer );
 
                // Register transport implementation with the producer
-               producer->close = producer_close;
+               producer->close = ( mlt_destructor )producer_close;
 
                // Register our get_frame implementation with the producer
                producer->get_frame = producer_get_frame;
index 6c3387794ecf8a4affea7009bf50947bbdc4f5f5..08c0247d53d496faae118ae400d66b25a977f7a0 100644 (file)
@@ -62,7 +62,7 @@ mlt_producer producer_hold_init( char *arg )
 
                // Override the get_frame method
                this->get_frame = producer_get_frame;
-               this->close = producer_close;
+               this->close = ( mlt_destructor )producer_close;
        }
        else
        {
index 7c81c290d8f69da69aa741e22164f91c4d9fce99..e4969aba59b287ab9c35692c85faf2e0f93ae986 100644 (file)
@@ -95,7 +95,7 @@ mlt_producer producer_pango_init( const char *filename )
                mlt_producer producer = &this->parent;
 
                producer->get_frame = producer_get_frame;
-               producer->close = producer_close;
+               producer->close = ( mlt_destructor )producer_close;
 
                // This is required to initialise gdk-pixbuf
                g_type_init();
index 95cae13ade88d59a3322b3d80a086b4b75a5d378..3fc0fb07d3445f5d9c6ed905a71c9d820311bdd1 100644 (file)
@@ -71,7 +71,7 @@ mlt_producer producer_pixbuf_init( char *filename )
        
                // Callback registration
                producer->get_frame = producer_get_frame;
-               producer->close = producer_close;
+               producer->close = ( mlt_destructor )producer_close;
 
                // Set the default properties
                mlt_properties_set( properties, "resource", filename );
index 85f21c8facb3a2d60e20fbd83bc3786e6d7a5eb8..9b4adeb6f7b49a0fa285dbdfd8f198fa4321519e 100644 (file)
@@ -205,8 +205,11 @@ 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" );
                                        if ( service_s != NULL && strcmp( service_s, "blank" ) != 0 )
                                                serialise_service( context, MLT_SERVICE( info.producer ), node );
+                                       else if ( resource_s != NULL && !strcmp( resource_s, "<playlist>" ) )
+                                               serialise_playlist( context, MLT_SERVICE( info.producer ), node );
                                }
                        }
                }
@@ -243,11 +246,14 @@ static void serialise_playlist( serialise_context context, mlt_service service,
                                }
                                else
                                {
+                                       char temp[ 20 ];
                                        xmlNode *entry = xmlNewChild( child, NULL, "entry", NULL );
                                        snprintf( key, 10, "%p", MLT_SERVICE( info.producer ) );
                                        xmlNewProp( entry, "producer", mlt_properties_get( context->producer_map, key ) );
-                                       xmlNewProp( entry, "in", mlt_properties_get( mlt_producer_properties( info.producer ), "in" ) );
-                                       xmlNewProp( entry, "out", mlt_properties_get( mlt_producer_properties( info.producer ), "out" ) );
+                                       sprintf( temp, "%d", info.frame_in );
+                                       xmlNewProp( entry, "in", temp );
+                                       sprintf( temp, "%d", info.frame_out );
+                                       xmlNewProp( entry, "out", temp );
                                }
                        }
                }
@@ -270,7 +276,7 @@ static void serialise_tractor( serialise_context context, mlt_service service, x
        if ( context->pass == 0 )
        {
                // Recurse on connected producer
-               serialise_service( context, mlt_service_get_producer( service ), node );
+               serialise_service( context, mlt_service_producer( service ), node );
        }
        else
        {
@@ -287,7 +293,7 @@ static void serialise_tractor( serialise_context context, mlt_service service, x
                xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
 
                // Recurse on connected producer
-               serialise_service( context, mlt_service_get_producer( service ), child );
+               serialise_service( context, mlt_service_producer( service ), child );
        }
 }
 
@@ -404,7 +410,7 @@ static void serialise_service( serialise_context context, mlt_service service, x
                }
                
                // Get the next connected service
-               service = mlt_service_get_producer( service );
+               service = mlt_service_producer( service );
        }
 }
 
@@ -443,18 +449,12 @@ xmlDocPtr westley_make_doc( mlt_service service )
 
 static int consumer_start( mlt_consumer this )
 {
-       mlt_service inigo = NULL;
        xmlDocPtr doc = NULL;
        
        // Get the producer service
-       mlt_service service = mlt_service_get_producer( mlt_consumer_service( this ) );
+       mlt_service service = mlt_service_producer( mlt_consumer_service( this ) );
        if ( service != NULL )
        {
-               // 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;
-               
                doc = westley_make_doc( service );
                
                if ( mlt_properties_get( mlt_consumer_properties( this ), "resource" ) == NULL )