2 * \file mlt_transition.c
3 * \brief abstraction for all transition services
5 * Copyright (C) 2003-2008 Ushodaya Enterprises Limited
6 * \author Charles Yates <charles.yates@pandora.be>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "mlt_transition.h"
24 #include "mlt_frame.h"
30 /** Forward references.
33 static int transition_get_frame( mlt_service
this, mlt_frame_ptr frame
, int index
);
38 int mlt_transition_init( mlt_transition
this, void *child
)
40 mlt_service service
= &this->parent
;
41 memset( this, 0, sizeof( struct mlt_transition_s
) );
43 if ( mlt_service_init( service
, this ) == 0 )
45 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
47 service
->get_frame
= transition_get_frame
;
48 service
->close
= ( mlt_destructor
)mlt_transition_close
;
49 service
->close_object
= this;
51 mlt_properties_set_position( properties
, "in", 0 );
52 mlt_properties_set_position( properties
, "out", 0 );
53 mlt_properties_set_int( properties
, "a_track", 0 );
54 mlt_properties_set_int( properties
, "b_track", 1 );
61 /** Create a new transition.
64 mlt_transition
mlt_transition_new( )
66 mlt_transition
this = calloc( 1, sizeof( struct mlt_transition_s
) );
68 mlt_transition_init( this, NULL
);
72 /** Get the service associated to the transition.
75 mlt_service
mlt_transition_service( mlt_transition
this )
77 return this != NULL ?
&this->parent
: NULL
;
80 /** Get the properties interface.
83 mlt_properties
mlt_transition_properties( mlt_transition
this )
85 return MLT_TRANSITION_PROPERTIES( this );
88 /** Connect this transition with a producers a and b tracks.
91 int mlt_transition_connect( mlt_transition
this, mlt_service producer
, int a_track
, int b_track
)
93 int ret
= mlt_service_connect_producer( &this->parent
, producer
, a_track
);
96 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
97 this->producer
= producer
;
98 mlt_properties_set_int( properties
, "a_track", a_track
);
99 mlt_properties_set_int( properties
, "b_track", b_track
);
104 /** Set the in and out points.
107 void mlt_transition_set_in_and_out( mlt_transition
this, mlt_position in
, mlt_position out
)
109 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
110 mlt_properties_set_position( properties
, "in", in
);
111 mlt_properties_set_position( properties
, "out", out
);
114 /** Get the index of the a track.
117 int mlt_transition_get_a_track( mlt_transition
this )
119 return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "a_track" );
122 /** Get the index of the b track.
125 int mlt_transition_get_b_track( mlt_transition
this )
127 return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "b_track" );
130 /** Get the in point.
133 mlt_position
mlt_transition_get_in( mlt_transition
this )
135 return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( this ), "in" );
138 /** Get the out point.
141 mlt_position
mlt_transition_get_out( mlt_transition
this )
143 return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( this ), "out" );
146 /** Process the frame.
148 If we have no process method (unlikely), we simply return the a_frame unmolested.
151 mlt_frame
mlt_transition_process( mlt_transition
this, mlt_frame a_frame
, mlt_frame b_frame
)
153 if ( this->process
== NULL
)
156 return this->process( this, a_frame
, b_frame
);
159 /** Get a frame from this transition.
161 The logic is complex here. A transition is typically applied to frames on the a and
162 b tracks specified in the connect method above and only if both contain valid info
163 for the transition type (this is either audio or image).
165 However, the fixed a_track may not always contain data of the correct type, eg:
167 +---------+ +-------+
168 |c1 | |c5 | <-- A(0,1) <-- B(0,2) <-- get frame
169 +---------+ +---------+-+-----+ | |
171 +----------+-----------+-+---------+ |
172 |c2 |c3 | <-----------------+
173 +----------+-------------+
175 During the overlap of c1 and c2, there is nothing for the A transition to do, so this
176 results in a no operation, but B is triggered. During the overlap of c2 and c3, again,
177 the A transition is inactive and because the B transition is pointing at track 0,
178 it too would be inactive. This isn't an ideal situation - it's better if the B
179 transition simply treats the frames from c3 as though they're the a track.
181 For this to work, we cache all frames coming from all tracks between the a and b
182 tracks. Before we process, we determine that the b frame contains someting of the
183 right type and then we determine which frame to use as the a frame (selecting a
184 matching frame from a_track to b_track - 1). If both frames contain data of the
185 correct type, we process the transition.
187 This method is invoked for each track and we return the cached frames as needed.
188 We clear the cache only when the requested frame is flagged as a 'last_track' frame.
191 static int transition_get_frame( mlt_service service
, mlt_frame_ptr frame
, int index
)
194 mlt_transition
this = service
->child
;
196 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
198 int accepts_blanks
= mlt_properties_get_int( properties
, "accepts_blanks" );
199 int a_track
= mlt_properties_get_int( properties
, "a_track" );
200 int b_track
= mlt_properties_get_int( properties
, "b_track" );
201 mlt_position in
= mlt_properties_get_position( properties
, "in" );
202 mlt_position out
= mlt_properties_get_position( properties
, "out" );
203 int always_active
= mlt_properties_get_int( properties
, "always_active" );
204 int type
= mlt_properties_get_int( properties
, "_transition_type" );
205 int reverse_order
= 0;
207 // Ensure that we have the correct order
208 if ( a_track
> b_track
)
212 b_track
= mlt_properties_get_int( properties
, "a_track" );
215 // Only act on this operation once per multitrack iteration from the tractor
220 int a_frame
= a_track
;
221 int b_frame
= b_track
;
222 mlt_position position
;
223 int ( *invalid
)( mlt_frame
) = type
== 1 ? mlt_frame_is_test_card
: mlt_frame_is_test_audio
;
225 // Initialise temporary store
226 if ( this->frames
== NULL
)
227 this->frames
= calloc( sizeof( mlt_frame
), b_track
+ 1 );
229 // Get all frames between a and b
230 for( i
= a_track
; i
<= b_track
; i
++ )
231 mlt_service_get_frame( this->producer
, &this->frames
[ i
], i
);
233 // We're holding these frames until the last_track frame property is received
236 // When we need to locate the a_frame
241 // Some transitions (esp. audio) may accept blank frames
242 active
= accepts_blanks
;
244 // If we're not active then...
247 // Hunt for the a_frame
248 while( a_frame
<= b_frame
&& invalid( this->frames
[ a_frame
] ) )
251 // Determine if we're active now
252 active
= a_frame
!= b_frame
&& !invalid( this->frames
[ b_frame
] );
257 fprintf( stderr
, "invalid transition type\n" );
261 // Now handle the non-always active case
262 if ( active
&& !always_active
)
264 // For non-always-active transitions, we need the current position of the a frame
265 position
= mlt_frame_get_position( this->frames
[ a_frame
] );
267 // If a is in range, we're active
268 active
= position
>= in
&& position
<= out
;
271 // Finally, process the a and b frames
274 mlt_frame a_frame_ptr
= this->frames
[ !reverse_order ? a_frame
: b_frame
];
275 mlt_frame b_frame_ptr
= this->frames
[ !reverse_order ? b_frame
: a_frame
];
276 int a_hide
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( a_frame_ptr
), "hide" );
277 int b_hide
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( b_frame_ptr
), "hide" );
278 if ( !( a_hide
& type
) && !( b_hide
& type
) )
280 // Process the transition
281 *frame
= mlt_transition_process( this, a_frame_ptr
, b_frame_ptr
);
283 // We need to ensure that the tractor doesn't consider this frame for output
284 if ( *frame
== a_frame_ptr
)
289 mlt_properties_set_int( MLT_FRAME_PROPERTIES( a_frame_ptr
), "hide", a_hide
);
290 mlt_properties_set_int( MLT_FRAME_PROPERTIES( b_frame_ptr
), "hide", b_hide
);
295 // Obtain the frame from the cache or the producer we're attached to
296 if ( index
>= a_track
&& index
<= b_track
)
297 *frame
= this->frames
[ index
];
299 error
= mlt_service_get_frame( this->producer
, frame
, index
);
301 // Determine if that was the last track
302 this->held
= !mlt_properties_get_int( MLT_FRAME_PROPERTIES( *frame
), "last_track" );
307 /** Close the transition.
310 void mlt_transition_close( mlt_transition
this )
312 if ( this != NULL
&& mlt_properties_dec_ref( MLT_TRANSITION_PROPERTIES( this ) ) <= 0 )
314 this->parent
.close
= NULL
;
315 if ( this->close
!= NULL
)
321 mlt_service_close( &this->parent
);
322 free( this->frames
);