]> git.sesse.net Git - mlt/blobdiff - src/framework/mlt_service.c
Mlt Ref Counts and Playlist split/join
[mlt] / src / framework / mlt_service.c
index 62112d9653f20f66a572c50bb436b28f8de4b724..7a66a577e417b40224d71bd2ce121080a9ddb26e 100644 (file)
@@ -47,7 +47,7 @@ typedef struct
 }
 mlt_service_base;
 
-/** Friends?
+/** Private methods
 */
 
 static void mlt_service_disconnect( mlt_service this );
@@ -59,20 +59,29 @@ 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 ) );
 
        // Assign the child
        this->child = child;
 
-       // Generate private space
-       this->private = calloc( sizeof( mlt_service_base ), 1 );
+       // Generate local space
+       this->local = calloc( sizeof( mlt_service_base ), 1 );
 
        // Associate the methods
        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.
@@ -87,15 +96,7 @@ int mlt_service_connect_producer( mlt_service this, mlt_service producer, int in
        int i = 0;
 
        // Get the service base
-       mlt_service_base *base = this->private;
-
-       // Does this service accept input?
-       if ( mlt_service_accepts_input( this ) == 0 )
-               return 1;
-
-       // Does the producer service accept output connections?
-       if ( mlt_service_accepts_output( producer ) == 0 )
-               return 2;
+       mlt_service_base *base = this->local;
 
        // Check if the producer is already registered with this service
        for ( i = 0; i < base->count; i ++ )
@@ -118,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 );
                
@@ -131,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;
        }
@@ -143,120 +154,79 @@ int mlt_service_connect_producer( mlt_service this, mlt_service producer, int in
 /** Disconnect this service from its consumer.
 */
 
-void mlt_service_disconnect( mlt_service this )
+static void mlt_service_disconnect( mlt_service this )
 {
-       // Get the service base
-       mlt_service_base *base = this->private;
+       if ( this != NULL )
+       {
+               // Get the service base
+               mlt_service_base *base = this->local;
 
-       // There's a bit more required here...
-       base->out = NULL;
+               // Disconnect
+               base->out = NULL;
+       }
 }
 
-/** Associate this service to the its consumer.
+/** Obtain the consumer this service is connected to.
 */
 
-void mlt_service_connect( mlt_service this, mlt_service that )
+mlt_service mlt_service_consumer( mlt_service this )
 {
        // Get the service base
-       mlt_service_base *base = this->private;
+       mlt_service_base *base = this->local;
 
-       // There's a bit more required here...
-       base->out = that;
+       // Return the connected consumer
+       return base->out;
 }
 
-
-/** Get the first connected producer service.
+/** Obtain the producer this service is connected to.
 */
 
-mlt_service mlt_service_get_producer( mlt_service this )
+mlt_service mlt_service_producer( mlt_service this )
 {
-       mlt_service producer = NULL;
-
        // Get the service base
-       mlt_service_base *base = this->private;
+       mlt_service_base *base = this->local;
 
-       if ( base->in != NULL )
-               producer = base->in[ 0 ];
-       
-       return producer;
-}
-
-/** Get the service state.
-*/
-
-mlt_service_state mlt_service_get_state( mlt_service this )
-{
-       mlt_service_state state = mlt_state_unknown;
-       if ( mlt_service_has_input( this ) )
-               state |= mlt_state_providing;
-       if ( mlt_service_has_output( this ) )
-               state |= mlt_state_connected;
-       if ( state != ( mlt_state_providing | mlt_state_connected ) )
-               state |= mlt_state_dormant;
-       return state;
+       // Return the connected producer
+       return base->count > 0 ? base->in[ base->count - 1 ] : NULL;
 }
 
-/** Get the maximum number of inputs accepted.
-       Returns: -1 for many, 0 for none or n for fixed.
+/** Associate this service to the consumer.
 */
 
-int mlt_service_accepts_input( mlt_service this )
+static void mlt_service_connect( mlt_service this, mlt_service that )
 {
-       if ( this->accepts_input == NULL )
-               return -1;
-       else
-               return this->accepts_input( this );
-}
-
-/** Get the maximum number of outputs accepted.
-*/
-
-int mlt_service_accepts_output( mlt_service this )
-{
-       if ( this->accepts_output == NULL )
-               return 1;
-       else
-               return this->accepts_output( this );
-}
-
-/** Determines if this service has input
-*/
+       if ( this != NULL )
+       {
+               // Get the service base
+               mlt_service_base *base = this->local;
 
-int mlt_service_has_input( mlt_service this )
-{
-       if ( this->has_input == NULL )
-               return 1;
-       else
-               return this->has_input( this );
+               // There's a bit more required here...
+               base->out = that;
+       }
 }
 
-/** Determine if this service has output
+/** Get the first connected producer service.
 */
 
-int mlt_service_has_output( mlt_service this )
+mlt_service mlt_service_get_producer( mlt_service this )
 {
-       mlt_service_base *base = this->private;
-       if ( this->has_output == NULL )
-               return base->out != NULL;
-       else
-               return this->has_output( this );
-}
+       mlt_service producer = NULL;
 
-/** Check if the service is active.
-*/
+       // Get the service base
+       mlt_service_base *base = this->local;
 
-int mlt_service_is_active( mlt_service this )
-{
-       return !( mlt_service_get_state( this ) & mlt_state_dormant );
+       if ( base->in != NULL )
+               producer = base->in[ 0 ];
+       
+       return producer;
 }
 
-/** Obtain a frame to pass on.
+/** Default implementation of get_frame.
 */
 
 static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
 {
-       mlt_service_base *base = this->private;
+       mlt_service_base *base = this->local;
        if ( index < base->count )
        {
                mlt_service producer = base->in[ index ];
@@ -267,9 +237,23 @@ static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
        return 0;
 }
 
+/** Return the properties object.
+*/
+
+mlt_properties mlt_service_properties( mlt_service self )
+{
+       return self != NULL ? &self->parent : NULL;
+}
+
+/** Obtain a frame.
+*/
+
 int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
 {
-       return this->get_frame( this, frame, index );
+       if ( this != NULL )
+               return this->get_frame( this, frame, index );
+       *frame = mlt_frame_init( );
+       return 0;
 }
 
 /** Close the service.
@@ -277,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->private;
-       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 );
+               }
+       }
 }