+ return producer;
+}
+
+/** Insert blank space.
+ *
+ * \public \memberof mlt_playlist_s
+ * \param self a playlist
+ * \param clip the index of the new blank section
+ * \param out the ending time of the new blank section (duration - 1)
+ */
+
+void mlt_playlist_insert_blank( mlt_playlist self, int clip, int out )
+{
+ if ( self != NULL && out >= 0 )
+ {
+ mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self );
+ mlt_events_block( properties, properties );
+ mlt_playlist_blank( self, out );
+ mlt_playlist_move( self, self->count - 1, clip );
+ mlt_events_unblock( properties, properties );
+ mlt_playlist_virtual_refresh( self );
+ }
+}
+
+/** Resize a blank entry.
+ *
+ * \public \memberof mlt_playlist_s
+ * \param self a playlist
+ * \param position the time at which the blank entry exists relative to the start or end (negative) of the playlist.
+ * \param length the additional amount of blank frames to add
+ * \param find true to fist locate the blank after the clip at position
+ */
+void mlt_playlist_pad_blanks( mlt_playlist self, mlt_position position, int length, int find )
+{
+ if ( self != NULL && length != 0 )
+ {
+ int clip = mlt_playlist_get_clip_index_at( self, position );
+ mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self );
+ mlt_events_block( properties, properties );
+ if ( find && clip < self->count && !mlt_playlist_is_blank( self, clip ) )
+ clip ++;
+ if ( clip < self->count && mlt_playlist_is_blank( self, clip ) )
+ {
+ mlt_playlist_clip_info info;
+ mlt_playlist_get_clip_info( self, &info, clip );
+ if ( info.frame_out + length > info.frame_in )
+ mlt_playlist_resize_clip( self, clip, info.frame_in, info.frame_out + length );
+ else
+ mlt_playlist_remove( self, clip );
+ }
+ else if ( find && clip < self->count && length > 0 )
+ {
+ mlt_playlist_insert_blank( self, clip, length );
+ }
+ mlt_events_unblock( properties, properties );
+ mlt_playlist_virtual_refresh( self );
+ }
+}
+
+/** Insert a clip at a specific time.
+ *
+ * \public \memberof mlt_playlist_s
+ * \param self a playlist
+ * \param position the time at which to insert
+ * \param producer the producer to insert
+ * \param mode true if you want to overwrite any blank section
+ * \return true if there was an error
+ */
+
+int mlt_playlist_insert_at( mlt_playlist self, mlt_position position, mlt_producer producer, int mode )
+{
+ int ret = self == NULL || position < 0 || producer == NULL;
+ if ( ret == 0 )
+ {
+ mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self );
+ int length = mlt_producer_get_playtime( producer );
+ int clip = mlt_playlist_get_clip_index_at( self, position );
+ mlt_playlist_clip_info info;
+ mlt_playlist_get_clip_info( self, &info, clip );
+ mlt_events_block( properties, self );
+ if ( clip < self->count && mlt_playlist_is_blank( self, clip ) )
+ {
+ // Split and move to new clip if need be
+ if ( position != info.start && mlt_playlist_split( self, clip, position - info.start - 1 ) == 0 )
+ mlt_playlist_get_clip_info( self, &info, ++ clip );
+
+ // Split again if need be
+ if ( length < info.frame_count )
+ mlt_playlist_split( self, clip, length - 1 );
+
+ // Remove
+ mlt_playlist_remove( self, clip );
+
+ // Insert
+ mlt_playlist_insert( self, producer, clip, -1, -1 );
+ ret = clip;
+ }
+ else if ( clip < self->count )
+ {
+ if ( position > info.start + info.frame_count / 2 )
+ clip ++;
+ if ( mode == 1 && clip < self->count && mlt_playlist_is_blank( self, clip ) )
+ {
+ mlt_playlist_get_clip_info( self, &info, clip );
+ if ( length < info.frame_count )
+ mlt_playlist_split( self, clip, length );
+ mlt_playlist_remove( self, clip );
+ }
+ mlt_playlist_insert( self, producer, clip, -1, -1 );
+ ret = clip;
+ }
+ else
+ {
+ if ( mode == 1 ) {
+ if ( position == info.start )
+ mlt_playlist_remove( self, clip );
+ else
+ mlt_playlist_blank( self, position - mlt_properties_get_int( properties, "length" ) - 1 );
+ }
+ mlt_playlist_append( self, producer );
+ ret = self->count - 1;
+ }
+ mlt_events_unblock( properties, self );
+ mlt_playlist_virtual_refresh( self );
+ }
+ else
+ {
+ ret = -1;
+ }
+ return ret;
+}
+
+/** Get the time at which the clip starts relative to the playlist.
+ *
+ * \public \memberof mlt_playlist_s
+ * \param self a playlist
+ * \param clip the index of the playlist entry
+ * \return the starting time
+ */
+
+int mlt_playlist_clip_start( mlt_playlist self, int clip )
+{
+ mlt_playlist_clip_info info;
+ if ( mlt_playlist_get_clip_info( self, &info, clip ) == 0 )
+ return info.start;
+ return clip < 0 ? 0 : mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( self ) );
+}
+
+/** Get the playable duration of the clip.
+ *
+ * \public \memberof mlt_playlist_s
+ * \param self a playlist
+ * \param clip the index of the playlist entry
+ * \return the duration of the playlist entry
+ */
+
+int mlt_playlist_clip_length( mlt_playlist self, int clip )
+{
+ mlt_playlist_clip_info info;
+ if ( mlt_playlist_get_clip_info( self, &info, clip ) == 0 )
+ return info.frame_count;
+ return 0;
+}
+
+/** Get the duration of a blank space.
+ *
+ * \public \memberof mlt_playlist_s
+ * \param self a playlist
+ * \param clip the index of the playlist entry
+ * \param bounded the maximum number of blank entries or 0 for all
+ * \return the duration of a blank section
+ */
+
+int mlt_playlist_blanks_from( mlt_playlist self, int clip, int bounded )
+{
+ int count = 0;
+ mlt_playlist_clip_info info;
+ if ( self != NULL && clip < self->count )
+ {
+ mlt_playlist_get_clip_info( self, &info, clip );
+ if ( mlt_playlist_is_blank( self, clip ) )
+ count += info.frame_count;
+ if ( bounded == 0 )
+ bounded = self->count;
+ for ( clip ++; clip < self->count && bounded >= 0; clip ++ )
+ {
+ mlt_playlist_get_clip_info( self, &info, clip );
+ if ( mlt_playlist_is_blank( self, clip ) )
+ count += info.frame_count;
+ else
+ bounded --;
+ }
+ }
+ return count;
+}
+
+/** Remove a portion of the playlist by time.
+ *
+ * \public \memberof mlt_playlist_s
+ * \param self a playlist
+ * \param position the starting time
+ * \param length the duration of time to remove
+ * \return the new entry index at the position
+ */
+
+int mlt_playlist_remove_region( mlt_playlist self, mlt_position position, int length )
+{
+ int index = mlt_playlist_get_clip_index_at( self, position );
+ if ( index >= 0 && index < self->count )
+ {
+ mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self );
+ int clip_start = mlt_playlist_clip_start( self, index );
+ int list_length = mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( self ) );
+ mlt_events_block( properties, self );
+
+ if ( position + length > list_length )
+ length -= ( position + length - list_length );
+
+ if ( clip_start < position )
+ {
+ mlt_playlist_split( self, index ++, position - clip_start - 1 );
+ }
+
+ while( length > 0 )
+ {
+ if ( mlt_playlist_clip_length( self, index ) > length )
+ mlt_playlist_split( self, index, length - 1 );
+ length -= mlt_playlist_clip_length( self, index );
+ mlt_playlist_remove( self, index );
+ }
+
+ mlt_playlist_consolidate_blanks( self, 0 );
+ mlt_events_unblock( properties, self );
+ mlt_playlist_virtual_refresh( self );
+
+ // Just to be sure, we'll get the clip index again...
+ index = mlt_playlist_get_clip_index_at( self, position );
+ }
+ return index;
+}
+
+/** Not implemented
+ *
+ * \deprecated not implemented
+ * \public \memberof mlt_playlist_s
+ * \param self
+ * \param position
+ * \param length
+ * \param new_position
+ * \return
+ */
+
+int mlt_playlist_move_region( mlt_playlist self, mlt_position position, int length, int new_position )
+{
+ if ( self != NULL )
+ {
+ }
+ return 0;