]> git.sesse.net Git - mlt/commitdiff
Add mlt_playlist_mix_in() and mlt_playlist_mix_out().
authorDan Dennedy <dan@dennedy.org>
Sat, 22 Mar 2014 23:05:26 +0000 (16:05 -0700)
committerDan Dennedy <dan@dennedy.org>
Sat, 22 Mar 2014 23:05:38 +0000 (16:05 -0700)
These are new alternatives to mlt_playlist_mix() that Shotcut is using.

src/framework/mlt.vers
src/framework/mlt_playlist.c
src/framework/mlt_playlist.h
src/mlt++/MltPlaylist.cpp
src/mlt++/MltPlaylist.h
src/mlt++/mlt++.vers

index a0069e41f80e53d8485c4451d14d3d73c5ce0087..244b090fddbd9ac5be143d44f23f1b83ba92604e 100644 (file)
@@ -449,6 +449,8 @@ MLT_0.9.0 {
 } MLT_0.8.8;
 
 MLT_0.9.2 {
+    mlt_playlist_mix_in;
+    mlt_playlist_mix_out;
     mlt_properties_frames_to_time;
     mlt_properties_time_to_frames;
 } MLT_0.9.0;
index b4cc7534222654585ac763f49b0a6529141cb07d..62a1f1643b3ce4a25a44fb4926285f108178aeeb 100644 (file)
@@ -1151,6 +1151,10 @@ int mlt_playlist_join( mlt_playlist self, int clip, int count, int merge )
 
 /** Mix consecutive clips for a specified length and apply transition if specified.
  *
+ * This version of the mix function does not utilize any frames beyond the out of
+ * clip A or before the in point of clip B. It takes the frames needed for the length
+ * of the transition by adjusting the duration of both clips - the out point for clip A
+ * and the in point for clip B.
  * \public \memberof mlt_playlist_s
  * \param self a playlist
  * \param clip the index of the playlist entry
@@ -1257,6 +1261,210 @@ int mlt_playlist_mix( mlt_playlist self, int clip, int length, mlt_transition tr
        return error;
 }
 
+/** Mix consecutive clips for a specified length.
+ *
+ * This version of the mix function maintains the out point of the clip A by occupying the
+ * beginning of clip B before its current in point. Therefore, it ends up adjusting the in
+ * point and duration of clip B without affecting the duration of clip A.
+ * Also, therefore, there must be enough frames after the out point of clip A.
+ * \public \memberof mlt_playlist_s
+ * \param self a playlist
+ * \param clip the index of the playlist entry
+ * \param length the number of frames over which to create the mix
+ * \return true if there was an error
+ */
+
+int mlt_playlist_mix_in( mlt_playlist self, int clip, int length )
+{
+       int error = ( clip < 0 || clip + 1 >= self->count );
+       if ( error == 0 )
+       {
+               playlist_entry *clip_a = self->list[ clip ];
+               playlist_entry *clip_b = self->list[ 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.
+               int max_size = ( clip_a->frame_out + 1 ) > clip_b->frame_count ? ( clip_a->frame_out +  1 ) : clip_b->frame_count;
+               length = length > max_size ? max_size : length;
+
+               // Create the a and b tracks/cuts if necessary - note that no cuts are required if the length matches
+               if ( length != clip_a->frame_out + 1 )
+                       track_a = mlt_producer_cut( clip_a->producer, clip_a->frame_out + 1, clip_a->frame_out + length );
+               else
+                       track_a = clip_a->producer;
+
+               if ( length != clip_b->frame_count )
+                       track_b = mlt_producer_cut( clip_b->producer, clip_b->frame_in, clip_b->frame_in + length - 1 );
+               else
+                       track_b = clip_b->producer;
+
+               // Set the tracks on the tractor
+               mlt_tractor_set_track( tractor, track_a, 0 );
+               mlt_tractor_set_track( tractor, track_b, 1 );
+
+               // Insert the mix object into the playlist
+               mlt_playlist_insert( self, MLT_TRACTOR_PRODUCER( tractor ), clip + 1, -1, -1 );
+               mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mlt_mix", tractor, 0, NULL, NULL );
+
+               // Close our references to the tracks if we created new cuts above (the tracks can still be used here)
+               if ( track_a != clip_a->producer )
+                       mlt_producer_close( track_a );
+               if ( track_b != clip_b->producer )
+                       mlt_producer_close( track_b );
+
+               // Check if we have anything left on the right hand clip
+               if ( track_b == clip_b->producer )
+               {
+                       clip_b->preservation_hack = 1;
+                       mlt_playlist_remove( self, clip + 2 );
+               }
+               else if ( clip_b->frame_out - clip_b->frame_in >= length )
+               {
+                       mlt_playlist_resize_clip( self, clip + 2, clip_b->frame_in + length, clip_b->frame_out );
+                       mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( clip_b->producer ), "mix_in", tractor, 0, NULL, NULL );
+                       mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mix_out", clip_b->producer, 0, NULL, NULL );
+               }
+               else
+               {
+                       mlt_producer_clear( clip_b->producer );
+                       mlt_playlist_remove( self, clip + 2 );
+               }
+
+               // Check if we have anything left on the left hand clip
+               if ( track_a == clip_a->producer )
+               {
+                       clip_a->preservation_hack = 1;
+                       mlt_playlist_remove( self, clip );
+               }
+               else if ( clip_a->frame_out - clip_a->frame_in > 0 )
+               {
+                       mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( clip_a->producer ), "mix_out", tractor, 0, NULL, NULL );
+                       mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mix_in", clip_a->producer, 0, NULL, NULL );
+               }
+               else
+               {
+                       mlt_producer_clear( clip_a->producer );
+                       mlt_playlist_remove( self, clip );
+               }
+
+               // Unblock and force a fire off of change events to listeners
+               mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self );
+               mlt_playlist_virtual_refresh( self );
+               mlt_tractor_close( tractor );
+       }
+       return error;
+}
+
+/** Mix consecutive clips for a specified length.
+ *
+ * This version of the mix function maintains the in point of the B clip by occupying the
+ * end of clip A before its current out point. Therefore, it ends up adjusting the out
+ * point and duration of clip A without affecting the duration or starting frame of clip B.
+ * Also, therefore, there must be enough frames before the in point of clip B.
+ * \public \memberof mlt_playlist_s
+ * \param self a playlist
+ * \param clip the index of the playlist entry
+ * \param length the number of frames over which to create the mix
+ * \return true if there was an error
+ */
+
+int mlt_playlist_mix_out( mlt_playlist self, int clip, int length )
+{
+       int error = ( clip < 0 || clip + 1 >= self->count );
+       if ( error == 0 )
+       {
+               playlist_entry *clip_a = self->list[ clip ];
+               playlist_entry *clip_b = self->list[ 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.
+               int max_size = clip_a->frame_count > clip_b->frame_in ? clip_a->frame_count : clip_b->frame_in;
+               length = length > max_size ? max_size : length;
+
+               // Create the a and b tracks/cuts if necessary - note that no cuts are required if the length matches
+               if ( length != clip_a->frame_count )
+                       track_a = mlt_producer_cut( clip_a->producer, clip_a->frame_out - length + 1, clip_a->frame_out );
+               else
+                       track_a = clip_a->producer;
+
+               if ( length != clip_b->frame_in )
+                       track_b = mlt_producer_cut( clip_b->producer, clip_b->frame_in - length + 1, clip_b->frame_in );
+               else
+                       track_b = clip_b->producer;
+
+               // Set the tracks on the tractor
+               mlt_tractor_set_track( tractor, track_a, 0 );
+               mlt_tractor_set_track( tractor, track_b, 1 );
+
+               // Insert the mix object into the playlist
+               mlt_playlist_insert( self, MLT_TRACTOR_PRODUCER( tractor ), clip + 1, -1, -1 );
+               mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mlt_mix", tractor, 0, NULL, NULL );
+
+               // Close our references to the tracks if we created new cuts above (the tracks can still be used here)
+               if ( track_a != clip_a->producer )
+                       mlt_producer_close( track_a );
+               if ( track_b != clip_b->producer )
+                       mlt_producer_close( track_b );
+
+               // Check if we have anything left on the right hand clip
+               if ( track_b == clip_b->producer )
+               {
+                       clip_b->preservation_hack = 1;
+                       mlt_playlist_remove( self, clip + 2 );
+               }
+               else if ( clip_b->frame_out - clip_b->frame_in > 0 )
+               {
+                       mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( clip_b->producer ), "mix_in", tractor, 0, NULL, NULL );
+                       mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mix_out", clip_b->producer, 0, NULL, NULL );
+               }
+               else
+               {
+                       mlt_producer_clear( clip_b->producer );
+                       mlt_playlist_remove( self, clip + 2 );
+               }
+
+               // Check if we have anything left on the left hand clip
+               if ( track_a == clip_a->producer )
+               {
+                       clip_a->preservation_hack = 1;
+                       mlt_playlist_remove( self, clip );
+               }
+               else if ( clip_a->frame_out - clip_a->frame_in >= length )
+               {
+                       mlt_playlist_resize_clip( self, clip, clip_a->frame_in, clip_a->frame_out - length );
+                       mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( clip_a->producer ), "mix_out", tractor, 0, NULL, NULL );
+                       mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mix_in", clip_a->producer, 0, NULL, NULL );
+               }
+               else
+               {
+                       mlt_producer_clear( clip_a->producer );
+                       mlt_playlist_remove( self, clip );
+               }
+
+               // Unblock and force a fire off of change events to listeners
+               mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self );
+               mlt_playlist_virtual_refresh( self );
+               mlt_tractor_close( tractor );
+       }
+       return error;
+}
+
 /** Add a transition to an existing mix.
  *
  * \public \memberof mlt_playlist_s
index cc5912940dd27c580b39552ba96c93386d515c8f..04eeccb85415786c706df3895c33006f176b3f2f 100644 (file)
@@ -108,6 +108,8 @@ extern int mlt_playlist_split( mlt_playlist self, int clip, mlt_position positio
 extern int mlt_playlist_split_at( mlt_playlist self, mlt_position position, int left );
 extern int mlt_playlist_join( mlt_playlist self, int clip, int count, int merge );
 extern int mlt_playlist_mix( mlt_playlist self, int clip, int length, mlt_transition transition );
+extern int mlt_playlist_mix_in( mlt_playlist self, int clip, int length );
+extern int mlt_playlist_mix_out( mlt_playlist self, int clip, int length );
 extern int mlt_playlist_mix_add( mlt_playlist self, int clip, mlt_transition transition );
 extern mlt_producer mlt_playlist_get_clip( mlt_playlist self, int clip );
 extern mlt_producer mlt_playlist_get_clip_at( mlt_playlist self, mlt_position position );
index 57c2c6acb54939fde219758d9364733c31f6e730..e6393d03e3052bc818226d50e9de16d563f15678 100644 (file)
@@ -226,6 +226,16 @@ int Playlist::mix( int clip, int length, Transition *transition )
        return mlt_playlist_mix( get_playlist( ), clip, length, transition == NULL ? NULL : transition->get_transition( ) );
 }
 
+int Playlist::mix_in(int clip, int length)
+{
+       return mlt_playlist_mix_in( get_playlist( ), clip, length );
+}
+
+int Playlist::mix_out(int clip, int length)
+{
+       return mlt_playlist_mix_out( get_playlist( ), clip, length );
+}
+
 int Playlist::mix_add( int clip, Transition *transition )
 {
        return mlt_playlist_mix_add( get_playlist( ), clip, transition == NULL ? NULL : transition->get_transition( ) );
index 924dc94cef21d0e958bbe4ecb38e16154841e7a1..a6fd44b538e71607a7ec40e73f1cf97e1030db79 100644 (file)
@@ -86,6 +86,8 @@ namespace Mlt
                        int split_at( int position, bool left = true );
                        int join( int clip, int count = 1, int merge = 1 );
                        int mix( int clip, int length, Transition *transition = NULL );
+                       int mix_in( int clip, int length );
+                       int mix_out( int clip, int length );
                        int mix_add( int clip, Transition *transition );
                        int repeat( int clip, int count );
                        Producer *get_clip( int clip );
index 17ec647df2e1a79c96993559baa6c5907d6ac311..4c58b12c2e39ebf5c34807819bfb4ca4a8dbdc46 100644 (file)
@@ -461,6 +461,8 @@ MLTPP_0.9.0 {
 MLTPP_0.9.2 {
   global:
     extern "C++" {
+      "Mlt::Playlist::mix_in(int, int)";
+      "Mlt::Playlist::mix_out(int, int)";
       "Mlt::Properties::frames_to_time(int, mlt_time_format)";
       "Mlt::Properties::time_to_frames(char const*)";
     };