]> git.sesse.net Git - mlt/blobdiff - src/framework/mlt_multitrack.c
src/framework/*: improve the doxygen documentation (work in progress). This also...
[mlt] / src / framework / mlt_multitrack.c
index 84f23893c1e97c0ad3e5b04aef639f14344c5794..432b90c9a103dc8e28d4c2a95f32a555e7d2eb32 100644 (file)
@@ -1,25 +1,25 @@
-/*
- * mlt_multitrack.c -- multitrack service class
- * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
- * Author: Charles Yates <charles.yates@pandora.be>
+/**
+ * \file mlt_multitrack.c
+ * \brief multitrack service class
  *
  *
- * 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.
+ * Copyright (C) 2003-2008 Ushodaya Enterprises Limited
+ * \author Charles Yates <charles.yates@pandora.be>
  *
  *
- * This program is distributed in the hope that it will be useful,
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * 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.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser 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.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
  */
 
-#include "config.h"
-
 #include "mlt_multitrack.h"
 #include "mlt_playlist.h"
 #include "mlt_frame.h"
 #include "mlt_multitrack.h"
 #include "mlt_playlist.h"
 #include "mlt_frame.h"
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 
-/** Private definition.
-*/
-
-struct mlt_multitrack_s
-{
-       // We're extending producer here
-       struct mlt_producer_s parent;
-       mlt_producer *list;
-       int size;
-       int count;
-};
-
 /** Forward reference.
 */
 
 /** Forward reference.
 */
 
@@ -57,11 +45,15 @@ mlt_multitrack mlt_multitrack_init( )
                mlt_producer producer = &this->parent;
                if ( mlt_producer_init( producer, this ) == 0 )
                {
                mlt_producer producer = &this->parent;
                if ( mlt_producer_init( producer, this ) == 0 )
                {
-                       mlt_properties properties = mlt_multitrack_properties( this );
+                       mlt_properties properties = MLT_MULTITRACK_PROPERTIES( this );
                        producer->get_frame = producer_get_frame;
                        mlt_properties_set_data( properties, "multitrack", this, 0, NULL, NULL );
                        mlt_properties_set( properties, "log_id", "multitrack" );
                        mlt_properties_set( properties, "resource", "<multitrack>" );
                        producer->get_frame = producer_get_frame;
                        mlt_properties_set_data( properties, "multitrack", this, 0, NULL, NULL );
                        mlt_properties_set( properties, "log_id", "multitrack" );
                        mlt_properties_set( properties, "resource", "<multitrack>" );
+                       mlt_properties_set_int( properties, "in", 0 );
+                       mlt_properties_set_int( properties, "out", -1 );
+                       mlt_properties_set_int( properties, "length", 0 );
+                       producer->close = ( mlt_destructor )mlt_multitrack_close;
                }
                else
                {
                }
                else
                {
@@ -69,7 +61,7 @@ mlt_multitrack mlt_multitrack_init( )
                        this = NULL;
                }
        }
                        this = NULL;
                }
        }
-       
+
        return this;
 }
 
        return this;
 }
 
@@ -78,7 +70,7 @@ mlt_multitrack mlt_multitrack_init( )
 
 mlt_producer mlt_multitrack_producer( mlt_multitrack this )
 {
 
 mlt_producer mlt_multitrack_producer( mlt_multitrack this )
 {
-       return &this->parent;
+       return this != NULL ? &this->parent : NULL;
 }
 
 /** Get the service associated this multitrack.
 }
 
 /** Get the service associated this multitrack.
@@ -86,7 +78,7 @@ mlt_producer mlt_multitrack_producer( mlt_multitrack this )
 
 mlt_service mlt_multitrack_service( mlt_multitrack this )
 {
 
 mlt_service mlt_multitrack_service( mlt_multitrack this )
 {
-       return mlt_producer_service( mlt_multitrack_producer( this ) );
+       return MLT_MULTITRACK_SERVICE( this );
 }
 
 /** Get the properties associated this multitrack.
 }
 
 /** Get the properties associated this multitrack.
@@ -94,7 +86,7 @@ mlt_service mlt_multitrack_service( mlt_multitrack this )
 
 mlt_properties mlt_multitrack_properties( mlt_multitrack this )
 {
 
 mlt_properties mlt_multitrack_properties( mlt_multitrack this )
 {
-       return mlt_service_properties( mlt_multitrack_service( this ) );
+       return MLT_MULTITRACK_PROPERTIES( this );
 }
 
 /** Initialise position related information.
 }
 
 /** Initialise position related information.
@@ -105,51 +97,44 @@ void mlt_multitrack_refresh( mlt_multitrack this )
        int i = 0;
 
        // Obtain the properties of this multitrack
        int i = 0;
 
        // Obtain the properties of this multitrack
-       mlt_properties properties = mlt_multitrack_properties( this );
+       mlt_properties properties = MLT_MULTITRACK_PROPERTIES( this );
 
        // We need to ensure that the multitrack reports the longest track as its length
        mlt_position length = 0;
 
 
        // We need to ensure that the multitrack reports the longest track as its length
        mlt_position length = 0;
 
-       // We need to ensure that fps are the same on all services
-       double fps = 0;
-       
        // Obtain stats on all connected services
        for ( i = 0; i < this->count; i ++ )
        {
                // Get the producer from this index
        // Obtain stats on all connected services
        for ( i = 0; i < this->count; i ++ )
        {
                // Get the producer from this index
-               mlt_producer producer = this->list[ i ];
+               mlt_track track = this->list[ i ];
+               mlt_producer producer = track->producer;
 
                // If it's allocated then, update our stats
                if ( producer != NULL )
                {
                        // If we have more than 1 track, we must be in continue mode
                        if ( this->count > 1 )
 
                // If it's allocated then, update our stats
                if ( producer != NULL )
                {
                        // If we have more than 1 track, we must be in continue mode
                        if ( this->count > 1 )
-                               mlt_properties_set( mlt_producer_properties( producer ), "eof", "continue" );
-                       
-                       // Determine the longest length
-                       length = mlt_producer_get_playtime( producer ) > length ? mlt_producer_get_playtime( producer ) : length;
-                       
-                       // Handle fps
-                       if ( fps == 0 )
-                       {
-                               // This is the first producer, so it controls the fps
-                               fps = mlt_producer_get_fps( producer );
-                       }
-                       else if ( fps != mlt_producer_get_fps( producer ) )
-                       {
-                               // Generate a warning for now - the following attempt to fix may fail
-                               fprintf( stderr, "Warning: fps mismatch on track %d\n", i );
+                               mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "continue" );
 
 
-                               // It should be safe to impose fps on an image producer, but not necessarily safe for video
-                               mlt_properties_set_double( mlt_producer_properties( producer ), "fps", fps );
-                       }
+                       // Determine the longest length
+                       //if ( !mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( producer ), "hide" ) )
+                               length = mlt_producer_get_playtime( producer ) > length ? mlt_producer_get_playtime( producer ) : length;
                }
        }
 
        // Update multitrack properties now - we'll not destroy the in point here
                }
        }
 
        // Update multitrack properties now - we'll not destroy the in point here
+       mlt_events_block( properties, properties );
        mlt_properties_set_position( properties, "length", length );
        mlt_properties_set_position( properties, "length", length );
+       mlt_events_unblock( properties, properties );
        mlt_properties_set_position( properties, "out", length - 1 );
        mlt_properties_set_position( properties, "out", length - 1 );
-       mlt_properties_set_double( properties, "fps", fps );
+}
+
+/** Listener for producers on the playlist.
+*/
+
+static void mlt_multitrack_listener( mlt_producer producer, mlt_multitrack this )
+{
+       mlt_multitrack_refresh( this );
 }
 
 /** Connect a producer to a given track.
 }
 
 /** Connect a producer to a given track.
@@ -161,7 +146,7 @@ void mlt_multitrack_refresh( mlt_multitrack this )
 int mlt_multitrack_connect( mlt_multitrack this, mlt_producer producer, int track )
 {
        // Connect to the producer to ourselves at the specified track
 int mlt_multitrack_connect( mlt_multitrack this, mlt_producer producer, int track )
 {
        // Connect to the producer to ourselves at the specified track
-       int result = mlt_service_connect_producer( mlt_multitrack_service( this ), mlt_producer_service( producer ), track );
+       int result = mlt_service_connect_producer( MLT_MULTITRACK_SERVICE( this ), MLT_PRODUCER_SERVICE( producer ), track );
 
        if ( result == 0 )
        {
 
        if ( result == 0 )
        {
@@ -169,19 +154,33 @@ int mlt_multitrack_connect( mlt_multitrack this, mlt_producer producer, int trac
                if ( track >= this->size )
                {
                        int i;
                if ( track >= this->size )
                {
                        int i;
-                       this->list = realloc( this->list, ( track + 10 ) * sizeof( mlt_producer ) );
+                       this->list = realloc( this->list, ( track + 10 ) * sizeof( mlt_track ) );
                        for ( i = this->size; i < track + 10; i ++ )
                                this->list[ i ] = NULL;
                        this->size = track + 10;
                }
                        for ( i = this->size; i < track + 10; i ++ )
                                this->list[ i ] = NULL;
                        this->size = track + 10;
                }
-               
+
+               if ( this->list[ track ] != NULL )
+               {
+                       mlt_event_close( this->list[ track ]->event );
+                       mlt_producer_close( this->list[ track ]->producer );
+               }
+               else
+               {
+                       this->list[ track ] = malloc( sizeof( struct mlt_track_s ) );
+               }
+
                // Assign the track in our list here
                // Assign the track in our list here
-               this->list[ track ] = producer;
-               
+               this->list[ track ]->producer = producer;
+               this->list[ track ]->event = mlt_events_listen( MLT_PRODUCER_PROPERTIES( producer ), this,
+                                                                        "producer-changed", ( mlt_listener )mlt_multitrack_listener );
+               mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( producer ) );
+               mlt_event_inc_ref( this->list[ track ]->event );
+
                // Increment the track count if need be
                if ( track >= this->count )
                        this->count = track + 1;
                // Increment the track count if need be
                if ( track >= this->count )
                        this->count = track + 1;
-                       
+
                // Refresh our stats
                mlt_multitrack_refresh( this );
        }
                // Refresh our stats
                mlt_multitrack_refresh( this );
        }
@@ -194,7 +193,7 @@ int mlt_multitrack_connect( mlt_multitrack this, mlt_producer producer, int trac
 
 int mlt_multitrack_count( mlt_multitrack this )
 {
 
 int mlt_multitrack_count( mlt_multitrack this )
 {
-       return this->count;     
+       return this->count;
 }
 
 /** Get an individual track as a producer.
 }
 
 /** Get an individual track as a producer.
@@ -203,9 +202,9 @@ int mlt_multitrack_count( mlt_multitrack this )
 mlt_producer mlt_multitrack_track( mlt_multitrack this, int track )
 {
        mlt_producer producer = NULL;
 mlt_producer mlt_multitrack_track( mlt_multitrack this, int track )
 {
        mlt_producer producer = NULL;
-       
+
        if ( this->list != NULL && track < this->count )
        if ( this->list != NULL && track < this->count )
-               producer = this->list[ track ];
+               producer = this->list[ track ]->producer;
 
        return producer;
 }
 
        return producer;
 }
@@ -228,9 +227,9 @@ static int add_unique( mlt_position *array, int size, mlt_position position )
 
 /** Determine the clip point.
 
 
 /** Determine the clip point.
 
-       Special case here: a 'producer' has no concept of multiple clips - only the 
-       playlist and multitrack producers have clip functionality. Further to that a 
-       multitrack determines clip information from any connected tracks that happen 
+       Special case here: a 'producer' has no concept of multiple clips - only the
+       playlist and multitrack producers have clip functionality. Further to that a
+       multitrack determines clip information from any connected tracks that happen
        to be playlists.
 
        Additionally, it must locate clips in the correct order, for example, consider
        to be playlists.
 
        Additionally, it must locate clips in the correct order, for example, consider
@@ -257,13 +256,13 @@ mlt_position mlt_multitrack_clip( mlt_multitrack this, mlt_whence whence, int in
        for ( i = 0; i < this->count; i ++ )
        {
                // Get the producer for this track
        for ( i = 0; i < this->count; i ++ )
        {
                // Get the producer for this track
-               mlt_producer producer = this->list[ i ];
+               mlt_producer producer = this->list[ i ]->producer;
 
 
-               // If it's assigned...
+               // If it's assigned and not a hidden track
                if ( producer != NULL )
                {
                        // Get the properties of this producer
                if ( producer != NULL )
                {
                        // Get the properties of this producer
-                       mlt_properties properties = mlt_producer_properties( producer );
+                       mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
 
                        // Determine if it's a playlist
                        mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
 
                        // Determine if it's a playlist
                        mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
@@ -297,8 +296,8 @@ mlt_position mlt_multitrack_clip( mlt_multitrack this, mlt_whence whence, int in
                        break;
 
                case mlt_whence_relative_current:
                        break;
 
                case mlt_whence_relative_current:
-                       position = mlt_producer_position( mlt_multitrack_producer( this ) );
-                       for ( i = 0; i < count - 2; i ++ ) 
+                       position = mlt_producer_position( MLT_MULTITRACK_PRODUCER( this ) );
+                       for ( i = 0; i < count - 2; i ++ )
                                if ( position >= map[ i ] && position < map[ i + 1 ] )
                                        break;
                        index += i;
                                if ( position >= map[ i ] && position < map[ i + 1 ] )
                                        break;
                        index += i;
@@ -333,10 +332,10 @@ mlt_position mlt_multitrack_clip( mlt_multitrack this, mlt_whence whence, int in
        Producer2 - multitrack - { filters/transitions } - tractor - consumer
        Producer3 /
 
        Producer2 - multitrack - { filters/transitions } - tractor - consumer
        Producer3 /
 
-       The get_frame of a tractor pulls frames from it's connected service on all tracks and 
-       will terminate as soon as it receives a test card with a last_track property. The 
+       The get_frame of a tractor pulls frames from it's connected service on all tracks and
+       will terminate as soon as it receives a test card with a last_track property. The
        important case here is that the mulitrack does not move to the next frame until all
        important case here is that the mulitrack does not move to the next frame until all
-       tracks have been pulled. 
+       tracks have been pulled.
 
        Reasoning: In order to seek on a network such as above, the multitrack needs to ensure
        that all producers are positioned on the same frame. It uses the 'last track' logic
 
        Reasoning: In order to seek on a network such as above, the multitrack needs to ensure
        that all producers are positioned on the same frame. It uses the 'last track' logic
@@ -358,28 +357,36 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int ind
        if ( index < this->count && this->list[ index ] != NULL )
        {
                // Get the producer for this track
        if ( index < this->count && this->list[ index ] != NULL )
        {
                // Get the producer for this track
-               mlt_producer producer = this->list[ index ];
+               mlt_producer producer = this->list[ index ]->producer;
+
+               // Get the track hide property
+               int hide = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( producer ) ), "hide" );
 
                // Obtain the current position
                mlt_position position = mlt_producer_frame( parent );
 
 
                // Obtain the current position
                mlt_position position = mlt_producer_frame( parent );
 
+               // Get the parent properties
+               mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( parent );
+
+               // Get the speed
+               double speed = mlt_properties_get_double( producer_properties, "_speed" );
+
                // Make sure we're at the same point
                mlt_producer_seek( producer, position );
 
                // Get the frame from the producer
                // Make sure we're at the same point
                mlt_producer_seek( producer, position );
 
                // Get the frame from the producer
-               mlt_service_get_frame( mlt_producer_service( producer ), frame, 0 );
+               mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), frame, 0 );
 
                // Indicate speed of this producer
 
                // Indicate speed of this producer
-               mlt_properties producer_properties = mlt_producer_properties( parent );
-               double speed = mlt_properties_get_double( producer_properties, "_speed" );
-               mlt_properties properties = mlt_frame_properties( *frame );
+               mlt_properties properties = MLT_FRAME_PROPERTIES( *frame );
                mlt_properties_set_double( properties, "_speed", speed );
                mlt_properties_set_double( properties, "_speed", speed );
-               mlt_properties_set_int( properties, "hide", mlt_properties_get_int( mlt_producer_properties( producer ), "hide" ) );
+               mlt_properties_set_position( properties, "_position", position );
+               mlt_properties_set_int( properties, "hide", hide );
        }
        else
        {
                // Generate a test frame
        }
        else
        {
                // Generate a test frame
-               *frame = mlt_frame_init( );
+               *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( parent ) );
 
                // Update position on the frame we're creating
                mlt_frame_set_position( *frame, mlt_producer_position( parent ) );
 
                // Update position on the frame we're creating
                mlt_frame_set_position( *frame, mlt_producer_position( parent ) );
@@ -388,14 +395,11 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int ind
                if ( index >= this->count )
                {
                        // Let tractor know if we've reached the end
                if ( index >= this->count )
                {
                        // Let tractor know if we've reached the end
-                       mlt_properties_set_int( mlt_frame_properties( *frame ), "last_track", 1 );
+                       mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "last_track", 1 );
 
                        // Move to the next frame
                        mlt_producer_prepare_next( parent );
                }
 
                        // Move to the next frame
                        mlt_producer_prepare_next( parent );
                }
-
-               // Refresh our stats
-               //mlt_multitrack_refresh( this );
        }
 
        return 0;
        }
 
        return 0;
@@ -406,12 +410,27 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int ind
 
 void mlt_multitrack_close( mlt_multitrack this )
 {
 
 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 )
+       {
+               int i = 0;
+               for ( i = 0; i < this->count; i ++ )
+               {
+                       if ( this->list[ i ] != NULL )
+                       {
+                               mlt_event_close( this->list[ i ]->event );
+                               mlt_producer_close( this->list[ i ]->producer );
+                               free( this->list[ i ] );
+                       }
+               }
 
 
-       // Free the list
-       free( this->list );
+               // Close the producer
+               this->parent.close = NULL;
+               mlt_producer_close( &this->parent );
 
 
-       // Free the object
-       free( this );
+               // Free the list
+               free( this->list );
+
+               // Free the object
+               free( this );
+       }
 }
 }