]> git.sesse.net Git - mlt/commitdiff
Transitions reworked (always_active capabilities); remaining audio handling switched...
authorlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Tue, 25 Jan 2005 12:31:08 +0000 (12:31 +0000)
committerlilo_booter <lilo_booter@d19143bc-622f-0410-bfdd-b5b2a6649095>
Tue, 25 Jan 2005 12:31:08 +0000 (12:31 +0000)
git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@627 d19143bc-622f-0410-bfdd-b5b2a6649095

src/framework/mlt_consumer.c
src/framework/mlt_frame.c
src/framework/mlt_frame.h
src/framework/mlt_producer.c
src/framework/mlt_tractor.c
src/framework/mlt_transition.c
src/framework/mlt_transition.h

index 29f248eed10825bf6de7dfab9871cac731f3ed1e..99ca1516d8fcf40240aaaff62355b1cddc7bdfa8 100644 (file)
@@ -366,7 +366,6 @@ static void *consumer_read_ahead_thread( void *arg )
        {
                samples = mlt_sample_calculator( fps, frequency, counter++ );
                mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples );
-               frame->get_audio = NULL;
        }
 
        mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 );
@@ -439,7 +438,6 @@ static void *consumer_read_ahead_thread( void *arg )
                {
                        samples = mlt_sample_calculator( fps, frequency, counter++ );
                        mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples );
-                       frame->get_audio = NULL;
                }
 
                // Increment the time take for this frame
index 5a866272b99b166214446298d16e81995e0bfb35..660f3c1de4ffe3ce00be55c7e8c4e2d8e8aa9647 100644 (file)
@@ -92,12 +92,12 @@ int mlt_frame_is_test_card( mlt_frame this )
        return mlt_deque_count( this->stack_image ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "test_image" );
 }
 
-/** Check if we have a way to derive something than test audio.
+/** Check if we have a way to derive something other than test audio.
 */
 
 int mlt_frame_is_test_audio( mlt_frame this )
 {
-       return this->get_audio == NULL || mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "test_audio" );
+       return mlt_deque_count( this->stack_audio ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "test_audio" );
 }
 
 /** Get the aspect ratio of the frame.
@@ -205,6 +205,42 @@ mlt_deque mlt_frame_service_stack( mlt_frame this )
        return this->stack_service;
 }
 
+/** [EXPERIMENTAL] Replace image stack with the information provided.
+
+       This might prove to be unreliable and restrictive - the idea is that a transition
+       which normally uses two images may decide to only use the b frame (ie: in the case
+       of a composite where the b frame completely obscures the a frame).
+
+       The image must be writable and the destructor for the image itself must be taken
+       care of on another frame and that frame cannot have a replace applied to it... 
+       Further it assumes that no alpha mask is in use.
+
+       For these reasons, it can only be used in a specific situation - when you have 
+       multiple tracks each with their own transition and these transitions are applied
+       in a strictly reversed order (ie: highest numbered [lowest track] is processed 
+       first).
+
+       More reliable approach - the cases should be detected during the process phase
+       and the upper tracks should simply not be invited to stack...
+*/
+
+void mlt_frame_replace_image( mlt_frame this, uint8_t *image, mlt_image_format format, int width, int height )
+{
+       // Herein lies the potential problem for this function - it makes a potentially 
+       // dangerous assumption that all content on the image stack can be removed without a destructor
+       while( mlt_deque_pop_back( this->stack_image ) ) ;
+
+       // Update the information 
+       mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "image", image, 0, NULL, NULL );
+       mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "width", width );
+       mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "height", height );
+       mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "format", format );
+       this->get_alpha_mask = NULL;
+}
+
+/** Get the image associated to the frame.
+*/
+
 int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
 {
        mlt_properties properties = MLT_FRAME_PROPERTIES( this );
@@ -320,13 +356,14 @@ uint8_t *mlt_frame_get_alpha_mask( mlt_frame this )
 
 int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
 {
+       mlt_get_audio get_audio = mlt_frame_pop_audio( this );
        mlt_properties properties = MLT_FRAME_PROPERTIES( this );
        int hide = mlt_properties_get_int( properties, "test_audio" );
 
-       if ( hide == 0 && this->get_audio != NULL )
+       if ( hide == 0 && get_audio != NULL )
        {
                mlt_position position = mlt_frame_get_position( this );
-               this->get_audio( this, buffer, format, frequency, channels, samples );
+               get_audio( this, buffer, format, frequency, channels, samples );
                mlt_frame_set_position( this, position );
        }
        else if ( mlt_properties_get_data( properties, "audio", NULL ) )
index 3a11daa3d9add6129683750a75b66486d8eeff30..899b0d23bb00611ae505240f269da75654f8182f 100644 (file)
@@ -25,6 +25,7 @@
 #include "mlt_deque.h"
 
 typedef int ( *mlt_get_image )( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
+typedef int ( *mlt_get_audio )( mlt_frame self, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
 
 struct mlt_frame_s
 {
@@ -32,7 +33,6 @@ struct mlt_frame_s
        struct mlt_properties_s parent;
 
        // Virtual methods
-       int ( *get_audio )( mlt_frame self, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
        uint8_t * ( *get_alpha_mask )( mlt_frame self );
        
        // Private properties
@@ -52,6 +52,7 @@ extern double mlt_frame_get_aspect_ratio( mlt_frame self );
 extern int mlt_frame_set_aspect_ratio( mlt_frame self, double value );
 extern mlt_position mlt_frame_get_position( mlt_frame self );
 extern int mlt_frame_set_position( mlt_frame self, mlt_position value );
+extern void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height );
 extern int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable );
 extern uint8_t *mlt_frame_get_alpha_mask( mlt_frame self );
 extern int mlt_frame_get_audio( mlt_frame self, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
index d84a0eb0571aeee2609230ad58c994222c86cb88..55f85ada23c7d1c04ba040b1b033c661f480a71b 100644 (file)
@@ -503,6 +503,10 @@ static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int ind
                // We're done with the clone now
                mlt_properties_set_data( parent_properties, "use_clone", NULL, 0, NULL, NULL );
 
+               // This is useful and required by always_active transitions to determine in/out points of the cut
+               if ( mlt_properties_get_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", NULL ) == MLT_PRODUCER_SERVICE( parent ) )
+                       mlt_properties_set_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", this, 0, NULL, NULL );
+
                mlt_properties_set_double( MLT_FRAME_PROPERTIES( *frame ), "_speed", speed );
                mlt_producer_prepare_next( this );
        }
index 4a26d0bf46e6035c8b045c5a8fdf76e31fa61a58..d41eba1eb843e218c457bc01987ca31e79f5cc3f 100644 (file)
@@ -344,7 +344,7 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int tra
                        if ( audio != NULL )
                        {
                                mlt_frame_push_audio( *frame, audio );
-                               ( *frame )->get_audio = producer_get_audio;
+                               mlt_frame_push_audio( *frame, producer_get_audio );
                        }
 
                        if ( video != NULL )
index 435fdb6c62a94b863c53ff1c36623f172838b13f..0f1fceb33fc53842732a9d6fa626371c0fcd52be 100644 (file)
@@ -156,92 +156,150 @@ mlt_frame mlt_transition_process( mlt_transition this, mlt_frame a_frame, mlt_fr
                return this->process( this, a_frame, b_frame );
 }
 
-/** Get a frame from this filter.
-
-       The logic is complex here. A transition is applied to frames on the a and b tracks
-       specified in the connect method above. Since all frames are obtained via this 
-       method for all tracks, we have to take special care that we only obtain the a and
-       b frames once - we do this on the first call to get a frame from either a or b.
-       
-       After that, we have 2 cases to resolve:
-       
-       1)      if the track is the a_track and we're in the time zone, then we need to call the
-               process method to do the effect on the frame and remember we've passed it on
-               otherwise, we pass on the a_frame unmolested;
-       2)      For all other tracks, we get the frames on demand.
+/** Get a frame from this transition.
+
+       The logic is complex here. A transition is typically applied to frames on the a and 
+       b tracks specified in the connect method above and only if both contain valid info
+       for the transition type (this is either audio or image).
+
+       However, the fixed a_track may not always contain data of the correct type, eg:
+
+       +---------+                               +-------+
+       |c1       |                               |c5     | <-- A(0,1) <-- B(0,2) <-- get frame
+       +---------+                     +---------+-+-----+        |          |
+                                       |c4         |       <------+          |
+                +----------+-----------+-+---------+                         |
+                |c2        |c3           |                 <-----------------+
+                +----------+-------------+
+
+       During the overlap of c1 and c2, there is nothing for the A transition to do, so this
+       results in a no operation, but B is triggered. During the overlap of c2 and c3, again, 
+       the A transition is inactive and because the B transition is pointing at track 0, 
+       it too would be inactive. This isn't an ideal situation - it's better if the B 
+       transition simply treats the frames from c3 as though they're the a track.
+
+       For this to work, we cache all frames coming from all tracks between the a and b 
+       tracks.  Before we process, we determine that the b frame contains someting of the 
+       right type and then we determine which frame to use as the a frame (selecting a
+       matching frame from a_track to b_track - 1). If both frames contain data of the 
+       correct type, we process the transition.
+
+       This method is invoked for each track and we return the cached frames as needed.
+       We clear the cache only when the requested frame is flagged as a 'last_track' frame.
 */
 
 static int transition_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
 {
+       int error = 0;
        mlt_transition this = service->child;
 
        mlt_properties properties = MLT_TRANSITION_PROPERTIES( this );
 
-       int accepts_blanks = mlt_properties_get_int( properties, "_accepts_blanks" );
+       int accepts_blanks = mlt_properties_get_int( properties, "accepts_blanks" );
        int a_track = mlt_properties_get_int( properties, "a_track" );
        int b_track = mlt_properties_get_int( properties, "b_track" );
        mlt_position in = mlt_properties_get_position( properties, "in" );
        mlt_position out = mlt_properties_get_position( properties, "out" );
        int always_active = mlt_properties_get_int( properties, "always_active" );
+       int type = mlt_properties_get_int( properties, "_transition_type" );
+       int reverse_order = 0;
 
-       if ( ( index == a_track || index == b_track ) && !( this->a_held || this->b_held ) )
+       // Ensure that we have the correct order
+       if ( a_track > b_track )
        {
-               mlt_service_get_frame( this->producer, &this->a_frame, a_track );
-               mlt_service_get_frame( this->producer, &this->b_frame, b_track );
-               this->a_held = 1;
-               this->b_held = 1;
+               reverse_order = 1;
+               a_track = b_track;
+               b_track = mlt_properties_get_int( properties, "a_track" );
        }
-       
-       // Special case track processing
-       if ( index == a_track )
+
+       // Only act on this operation once per multitrack iteration from the tractor
+       if ( !this->held )
        {
-               // Determine if we're in the right time zone
-               mlt_position position = mlt_frame_get_position( this->a_frame );
-               if ( always_active || ( position >= in && position <= out ) )
+               int active = 0;
+               int i = 0;
+               int a_frame = a_track;
+               int b_frame = b_track;
+               mlt_position position;
+               int ( *invalid )( mlt_frame ) = type == 1 ? mlt_frame_is_test_card : mlt_frame_is_test_audio;
+
+               // Initialise temporary store
+               if ( this->frames == NULL )
+                       this->frames = calloc( sizeof( mlt_frame ), b_track + 1 );
+
+               // Get all frames between a and b
+               for( i = a_track; i <= b_track; i ++ )
+                       mlt_service_get_frame( this->producer, &this->frames[ i ], i );
+
+               // We're holding these frames until the last_track frame property is received
+               this->held = 1;
+
+               // When we need to locate the a_frame
+               switch( type )
                {
-                       if ( !accepts_blanks && ( this->b_frame == NULL || ( mlt_frame_is_test_card( this->b_frame ) && mlt_frame_is_test_audio( this->b_frame ) ) ) )
-                       {
-                               *frame = this->a_frame;
-                       }
-                       else if ( !accepts_blanks && ( this->a_frame == NULL || ( mlt_frame_is_test_card( this->a_frame ) && mlt_frame_is_test_audio( this->a_frame ) ) ) )
-                       {
-                               mlt_frame t = this->a_frame;
-                               this->a_frame = this->b_frame;
-                               this->b_frame = t;
-                               *frame = this->a_frame;
-                       }
-                       else
-                       {
-                               int hide = 0;
-                               *frame = mlt_transition_process( this, this->a_frame, this->b_frame );
-                               if ( !mlt_properties_get_int( MLT_FRAME_PROPERTIES( this->a_frame ), "test_image" ) )
-                                       hide = 1;
-                               if ( !mlt_properties_get_int( MLT_FRAME_PROPERTIES( this->a_frame ), "test_audio" ) )
-                                       hide |= 2;
-                               mlt_properties_set_int( MLT_FRAME_PROPERTIES( this->b_frame ), "hide", hide );
-                       }
-                       this->a_held = 0;
+                       case 1:
+                       case 2:
+                               // Some transitions (esp. audio) may accept blank frames
+                               active = accepts_blanks;
+
+                               // If we're not active then...
+                               if ( !active )
+                               {
+                                       // Hunt for the a_frame
+                                       while( a_frame <= b_frame && invalid( this->frames[ a_frame ] ) )
+                                               a_frame ++;
+
+                                       // Determine if we're active now
+                                       active = a_frame != b_frame && !invalid( this->frames[ b_frame ] );
+                               }
+                               break;
+
+                       default:
+                               fprintf( stderr, "invalid transition type\n" );
+                               break;
                }
-               else
+
+               // Now handle the non-always active case
+               if ( active && !always_active )
                {
-                       // Pass on the 'a frame' and remember that we've done it
-                       *frame = this->a_frame;
-                       this->a_held = 0;
+                       // For non-always-active transitions, we need the current position of the a frame
+                       position = mlt_frame_get_position( this->frames[ a_frame ] );
+
+                       // If a is in range, we're active
+                       active = position >= in && position <= out;
+               }
+
+               // Finally, process the a and b frames
+               if ( active )
+               {
+                       mlt_frame a_frame_ptr = this->frames[ !reverse_order ? a_frame : b_frame ];
+                       mlt_frame b_frame_ptr = this->frames[ !reverse_order ? b_frame : a_frame ];
+                       int a_hide = mlt_properties_get_int( MLT_FRAME_PROPERTIES( a_frame_ptr ), "hide" );
+                       int b_hide = mlt_properties_get_int( MLT_FRAME_PROPERTIES( b_frame_ptr ), "hide" );
+
+                       // Process the transition
+                       *frame = mlt_transition_process( this, a_frame_ptr, b_frame_ptr );
+
+                       // We need to ensure that the tractor doesn't consider this frame for output
+                       if ( *frame == a_frame_ptr )
+                               b_hide |= type;
+                       else
+                               a_hide |= type;
+
+                       mlt_properties_set_int( MLT_FRAME_PROPERTIES( a_frame_ptr ), "hide", a_hide );
+                       mlt_properties_set_int( MLT_FRAME_PROPERTIES( b_frame_ptr ), "hide", b_hide );
                }
-               return 0;
-       }
-       if ( index == b_track )
-       {
-               // Pass on the 'b frame' and remember that we've done it
-               *frame = this->b_frame;
-               this->b_held = 0;
-               return 0;
        }
+       
+       // Obtain the frame from the cache or the producer we're attached to
+       if ( index >= a_track && index <= b_track )
+               *frame = this->frames[ index ];
        else
-       {
-               // Pass through
-               return mlt_service_get_frame( this->producer, frame, index );
-       }
+               error = mlt_service_get_frame( this->producer, frame, index );
+
+       // Determine if that was the last track
+       this->held = !mlt_properties_get_int( MLT_FRAME_PROPERTIES( *frame ), "last_track" );
+
+       return error;
 }
 
 /** Close the transition.
@@ -259,6 +317,7 @@ void mlt_transition_close( mlt_transition this )
                else
                {
                        mlt_service_close( &this->parent );
+                       free( this->frames );
                        free( this );
                }
        }
index c6912db8d5e3e02058095e7a07320a6141faabe7..9db26b3b91452a801fcd3a5f2bbcca74143bba16 100644 (file)
@@ -44,10 +44,8 @@ struct mlt_transition_s
        mlt_service producer;
        
        // Private
-       mlt_frame a_frame;
-       mlt_frame b_frame;
-       int a_held;
-       int b_held;
+       mlt_frame *frames;
+       int held;
 };
 
 /** Public final methods