static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index );
static int mlt_playlist_unmix( mlt_playlist self, int clip );
static int mlt_playlist_resize_mix( mlt_playlist self, int clip, int in, int out );
+static void mlt_playlist_next( mlt_listener listener, mlt_properties owner, mlt_service self, void **args );
/** Construct a playlist.
*
mlt_playlist mlt_playlist_init( )
{
- mlt_playlist self = calloc( sizeof( struct mlt_playlist_s ), 1 );
+ mlt_playlist self = calloc( 1, sizeof( struct mlt_playlist_s ) );
if ( self != NULL )
{
mlt_producer producer = &self->parent;
// Construct the producer
- mlt_producer_init( producer, self );
+ if ( mlt_producer_init( producer, self ) != 0 ) goto error1;
// Override the producer get_frame
producer->get_frame = producer_get_frame;
producer->close_object = self;
// Initialise blank
- mlt_producer_init( &self->blank, NULL );
+ if ( mlt_producer_init( &self->blank, NULL ) != 0 ) goto error1;
mlt_properties_set( MLT_PRODUCER_PROPERTIES( &self->blank ), "mlt_service", "blank" );
mlt_properties_set( MLT_PRODUCER_PROPERTIES( &self->blank ), "resource", "blank" );
mlt_properties_set_position( MLT_PLAYLIST_PROPERTIES( self ), "length", 0 );
self->size = 10;
- self->list = malloc( self->size * sizeof( playlist_entry * ) );
+ self->list = calloc( self->size, sizeof( playlist_entry * ) );
+ if ( self->list == NULL ) goto error2;
+
+ mlt_events_register( MLT_PLAYLIST_PROPERTIES( self ), "playlist-next", (mlt_transmitter) mlt_playlist_next );
}
return self;
+error2:
+ free( self->list );
+error1:
+ free( self );
+ return NULL;
+}
+
+/** Construct a playlist with a profile.
+ *
+ * Sets the resource property to "<playlist>".
+ * Set the mlt_type to property to "mlt_producer".
+ * \public \memberof mlt_playlist_s
+ * \param profile the profile to use with the profile
+ * \return a new playlist
+ */
+
+mlt_playlist mlt_playlist_new( mlt_profile profile )
+{
+ mlt_playlist self = mlt_playlist_init();
+ if ( self )
+ mlt_properties_set_data( MLT_PLAYLIST_PROPERTIES( self ), "_profile", profile, 0, NULL, NULL );
+ return self;
}
/** Get the producer associated to this playlist.
mlt_producer producer = self->list[ i ]->producer;
if ( producer )
{
- int current_length = mlt_producer_get_out( producer ) - mlt_producer_get_in( producer ) + 1;
+ int current_length = mlt_producer_get_playtime( producer );
// Check if the length of the producer has changed
if ( self->list[ i ]->frame_in != mlt_producer_get_in( producer ) ||
// If we have a cut, then use the in/out points from the cut
if ( mlt_producer_is_blank( source ) )
{
+ mlt_position length = out - in + 1;
+
// Make sure the blank is long enough to accomodate the length specified
- if ( out - in + 1 > mlt_producer_get_length( &self->blank ) )
+ if ( length > mlt_producer_get_length( &self->blank ) )
{
mlt_properties blank_props = MLT_PRODUCER_PROPERTIES( &self->blank );
mlt_events_block( blank_props, blank_props );
}
properties = MLT_PRODUCER_PROPERTIES( producer );
+
+ // Make sure this cut of blank is long enough
+ if ( length > mlt_producer_get_length( producer ) )
+ mlt_properties_set_int( properties, "length", length );
}
else if ( mlt_producer_is_cut( source ) )
{
}
// Create the entry
- self->list[ self->count ] = calloc( sizeof( playlist_entry ), 1 );
+ self->list[ self->count ] = calloc( 1, sizeof( playlist_entry ) );
if ( self->list[ self->count ] != NULL )
{
self->list[ self->count ]->producer = producer;
self->list[ self->count ]->frame_out = out;
self->list[ self->count ]->frame_count = out - in + 1;
self->list[ self->count ]->repeat = 1;
- self->list[ self->count ]->producer_length = mlt_producer_get_out( producer ) - mlt_producer_get_in( producer ) + 1;
+ self->list[ self->count ]->producer_length = mlt_producer_get_playtime( producer );
self->list[ self->count ]->event = mlt_events_listen( parent, self, "producer-changed", ( mlt_listener )mlt_playlist_listener );
mlt_event_inc_ref( self->list[ self->count ]->event );
mlt_properties_set( properties, "eof", "pause" );
return producer;
}
+/** The transmitter for the producer-next event
+ *
+ * Invokes the listener.
+ *
+ * \private \memberof mlt_playlist_s
+ * \param listener a function pointer that will be invoked
+ * \param owner the events object that will be passed to \p listener
+ * \param self a service that will be passed to \p listener
+ * \param args an array of pointers.
+ */
+
+static void mlt_playlist_next( mlt_listener listener, mlt_properties owner, mlt_service self, void **args )
+{
+ if ( listener )
+ listener( owner, self, args[ 0 ] );
+}
+
+
/** Seek in the virtual playlist.
*
* This gets the producer at the current position and seeks on the producer
producer = &self->blank;
}
+ // Determine if we have moved to the next entry in the playlist.
+ if ( original == total - 2 )
+ mlt_events_fire( properties, "playlist-next", i, NULL );
+
return MLT_PRODUCER_SERVICE( producer );
}
*
* \public \memberof mlt_playlist_s
* \param self a playlist
- * \param length the ending time of the blank entry, not its duration
+ * \param out the ending time of the blank entry, not its duration
* \return true if there was an error
*/
-int mlt_playlist_blank( mlt_playlist self, mlt_position length )
+int mlt_playlist_blank( mlt_playlist self, mlt_position out )
{
// Append to the virtual list
- if (length >= 0)
- return mlt_playlist_virtual_append( self, &self->blank, 0, length );
+ if ( out >= 0 )
+ return mlt_playlist_virtual_append( self, &self->blank, 0, out );
+ else
+ return 1;
+}
+
+/** Append a blank item to the playlist with duration as a time string.
+ *
+ * \public \memberof mlt_playlist_s
+ * \param self a playlist
+ * \param length the duration of the blank entry as a time string
+ * \return true if there was an error
+ */
+
+int mlt_playlist_blank_time( mlt_playlist self, const char* length )
+{
+ if ( self && length )
+ {
+ mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self );
+ mlt_properties_set( properties , "_blank_time", length );
+ mlt_position duration = mlt_properties_get_position( properties, "_blank_time" );
+ return mlt_playlist_blank( self, duration - 1 );
+ }
else
return 1;
}
// Get the clip info
mlt_playlist_get_clip_info( self, &where_info, where );
- // Make sure the clip to be removed is valid and correct if necessary
- if ( where < 0 )
- where = 0;
- if ( where >= self->count )
- where = self->count - 1;
-
// Reorganise the list
for ( i = where + 1; i < self->count; i ++ )
self->list[ i - 1 ] = self->list[ i ];
if ( mlt_producer_is_blank( producer ) )
{
- // Make sure the blank is long enough to accomodate the length specified
- if ( out - in + 1 > mlt_producer_get_length( &self->blank ) )
+ mlt_position length = out - in + 1;
+
+ // Make sure the parent blank is long enough to accomodate the length specified
+ if ( length > mlt_producer_get_length( &self->blank ) )
{
mlt_properties blank_props = MLT_PRODUCER_PROPERTIES( &self->blank );
- mlt_properties_set_int( blank_props, "length", out - in + 1 );
- mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "length", out - in + 1 );
+ mlt_properties_set_int( blank_props, "length", length );
mlt_producer_set_in_and_out( &self->blank, 0, out - in );
}
+ // Make sure this cut of blank is long enough
+ if ( length > mlt_producer_get_length( producer ) )
+ mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "length", length );
}
if ( in < 0 )
mlt_producer split = mlt_producer_cut( entry->producer, in + position + 1, out );
mlt_properties split_properties = MLT_PRODUCER_PROPERTIES( split );
mlt_playlist_insert( self, split, clip + 1, 0, -1 );
+ mlt_properties_lock( entry_properties );
for ( i = 0; i < mlt_properties_count( entry_properties ); i ++ )
{
char *name = mlt_properties_get_name( entry_properties, i );
if ( name != NULL && !strncmp( name, "meta.", 5 ) )
mlt_properties_set( split_properties, name, mlt_properties_get_value( entry_properties, i ) );
}
+ mlt_properties_unlock( entry_properties );
mlt_producer_close( split );
}
else
if ( error == 0 )
{
int i = clip;
- mlt_playlist new_clip = mlt_playlist_init( );
+ mlt_playlist new_clip = mlt_playlist_new( mlt_service_profile( MLT_PLAYLIST_SERVICE(self) ) );
mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self );
if ( clip + count >= self->count )
count = self->count - clip - 1;
mlt_producer track_a = NULL;
mlt_producer track_b = NULL;
mlt_tractor tractor = mlt_tractor_new( );
+
+ mlt_service_set_profile( MLT_TRACTOR_SERVICE( tractor ),
+ mlt_service_profile( MLT_PLAYLIST_SERVICE( self ) ) );
+ mlt_properties_set_lcnumeric( MLT_TRACTOR_PROPERTIES( tractor ),
+ mlt_properties_get_lcnumeric( MLT_PLAYLIST_PROPERTIES( self ) ) );
mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self );
// Check length is valid for both clips and resize if necessary.
* \public \memberof mlt_playlist_s
* \param self a playlist
* \param clip the index of the playlist entry
- * \return true if there was an error
+ * \return true if \p clip is a "blank" producer
*/
int mlt_playlist_is_blank( mlt_playlist self, int clip )
* \public \memberof mlt_playlist_s
* \param self a playlist
* \param clip the index of the new blank section
- * \param length the ending time of the new blank section (duration - 1)
+ * \param out the ending time of the new blank section (duration - 1)
*/
-void mlt_playlist_insert_blank( mlt_playlist self, int clip, int length )
+void mlt_playlist_insert_blank( mlt_playlist self, int clip, int out )
{
- if ( self != NULL && length >= 0 )
+ if ( self != NULL && out >= 0 )
{
mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self );
mlt_events_block( properties, properties );
- mlt_playlist_blank( self, length );
+ mlt_playlist_blank( self, out );
mlt_playlist_move( self, self->count - 1, clip );
mlt_events_unblock( properties, properties );
mlt_playlist_virtual_refresh( self );