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"
31 /* Forward references */
33 static int transition_get_frame( mlt_service
this, mlt_frame_ptr frame
, int index
);
35 /** Initialize a new transition.
37 * \public \memberof mlt_transition_s
38 * \param this a transition
39 * \param child the object of a subclass
40 * \return true on error
43 int mlt_transition_init( mlt_transition
this, void *child
)
45 mlt_service service
= &this->parent
;
46 memset( this, 0, sizeof( struct mlt_transition_s
) );
48 if ( mlt_service_init( service
, this ) == 0 )
50 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
52 service
->get_frame
= transition_get_frame
;
53 service
->close
= ( mlt_destructor
)mlt_transition_close
;
54 service
->close_object
= this;
56 mlt_properties_set_position( properties
, "in", 0 );
57 mlt_properties_set_position( properties
, "out", 0 );
58 mlt_properties_set_int( properties
, "a_track", 0 );
59 mlt_properties_set_int( properties
, "b_track", 1 );
66 /** Create and initialize a new transition.
68 * \public \memberof mlt_transition_s
69 * \return a new transition
72 mlt_transition
mlt_transition_new( )
74 mlt_transition
this = calloc( 1, sizeof( struct mlt_transition_s
) );
76 mlt_transition_init( this, NULL
);
80 /** Get the service class interface.
82 * \public \memberof mlt_transition_s
83 * \param this a transition
84 * \return the service class
85 * \see MLT_TRANSITION_SERVICE
88 mlt_service
mlt_transition_service( mlt_transition
this )
90 return this != NULL ?
&this->parent
: NULL
;
93 /** Get the properties interface.
95 * \public \memberof mlt_transition_s
96 * \param this a transition
97 * \return the transition's properties
98 * \see MLT_TRANSITION_PROPERTIES
101 mlt_properties
mlt_transition_properties( mlt_transition
this )
103 return MLT_TRANSITION_PROPERTIES( this );
106 /** Connect this transition with a producers a and b tracks.
108 * \public \memberof mlt_transition_s
109 * \param this a transition
110 * \param producer a producer
111 * \param a_track the track index of the first input
112 * \param b_track the track index of the second index
113 * \return true on error
116 int mlt_transition_connect( mlt_transition
this, mlt_service producer
, int a_track
, int b_track
)
118 int ret
= mlt_service_connect_producer( &this->parent
, producer
, a_track
);
121 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
122 this->producer
= producer
;
123 mlt_properties_set_int( properties
, "a_track", a_track
);
124 mlt_properties_set_int( properties
, "b_track", b_track
);
129 /** Set the starting and ending time for when the transition is active.
131 * \public \memberof mlt_transition_s
132 * \param this a transition
133 * \param in the starting time
134 * \param out the ending time
137 void mlt_transition_set_in_and_out( mlt_transition
this, mlt_position in
, mlt_position out
)
139 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
140 mlt_properties_set_position( properties
, "in", in
);
141 mlt_properties_set_position( properties
, "out", out
);
144 /** Get the index of the a track.
146 * \public \memberof mlt_transition_s
147 * \param this a transition
148 * \return the 0-based index of the track of the first producer
151 int mlt_transition_get_a_track( mlt_transition
this )
153 return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "a_track" );
156 /** Get the index of the b track.
158 * \public \memberof mlt_transition_s
159 * \param this a transition
160 * \return the 0-based index of the track of the second producer
163 int mlt_transition_get_b_track( mlt_transition
this )
165 return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "b_track" );
168 /** Get the in point.
170 * \public \memberof mlt_transition_s
171 * \param this a transition
172 * \return the starting time
175 mlt_position
mlt_transition_get_in( mlt_transition
this )
177 return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( this ), "in" );
180 /** Get the out point.
182 * \public \memberof mlt_transition_s
183 * \param this a transition
184 * \return the ending time
187 mlt_position
mlt_transition_get_out( mlt_transition
this )
189 return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( this ), "out" );
192 /** Process the frame.
194 * If we have no process method (unlikely), we simply return the a_frame unmolested.
196 * \public \memberof mlt_transition_s
197 * \param this a transition
198 * \param a_frame a frame from the first producer
199 * \param b_frame a frame from the second producer
203 mlt_frame
mlt_transition_process( mlt_transition
this, mlt_frame a_frame
, mlt_frame b_frame
)
205 if ( this->process
== NULL
)
208 return this->process( this, a_frame
, b_frame
);
211 /** Get a frame from this transition.
213 The logic is complex here. A transition is typically applied to frames on the a and
214 b tracks specified in the connect method above and only if both contain valid info
215 for the transition type (this is either audio or image).
217 However, the fixed a_track may not always contain data of the correct type, eg:
219 +---------+ +-------+
220 |c1 | |c5 | <-- A(0,1) <-- B(0,2) <-- get frame
221 +---------+ +---------+-+-----+ | |
223 +----------+-----------+-+---------+ |
224 |c2 |c3 | <-----------------+
225 +----------+-------------+
227 During the overlap of c1 and c2, there is nothing for the A transition to do, so this
228 results in a no operation, but B is triggered. During the overlap of c2 and c3, again,
229 the A transition is inactive and because the B transition is pointing at track 0,
230 it too would be inactive. This isn't an ideal situation - it's better if the B
231 transition simply treats the frames from c3 as though they're the a track.
233 For this to work, we cache all frames coming from all tracks between the a and b
234 tracks. Before we process, we determine that the b frame contains someting of the
235 right type and then we determine which frame to use as the a frame (selecting a
236 matching frame from a_track to b_track - 1). If both frames contain data of the
237 correct type, we process the transition.
239 This method is invoked for each track and we return the cached frames as needed.
240 We clear the cache only when the requested frame is flagged as a 'last_track' frame.
242 * \private \memberof mlt_transition_s
243 * \param service a service
244 * \param[out] frame a frame by reference
245 * \param index 0-based track index
246 * \return true on error
249 static int transition_get_frame( mlt_service service
, mlt_frame_ptr frame
, int index
)
252 mlt_transition
this = service
->child
;
254 mlt_properties properties
= MLT_TRANSITION_PROPERTIES( this );
256 int accepts_blanks
= mlt_properties_get_int( properties
, "accepts_blanks" );
257 int a_track
= mlt_properties_get_int( properties
, "a_track" );
258 int b_track
= mlt_properties_get_int( properties
, "b_track" );
259 mlt_position in
= mlt_properties_get_position( properties
, "in" );
260 mlt_position out
= mlt_properties_get_position( properties
, "out" );
261 int always_active
= mlt_properties_get_int( properties
, "always_active" );
262 int type
= mlt_properties_get_int( properties
, "_transition_type" );
263 int reverse_order
= 0;
265 // Ensure that we have the correct order
266 if ( a_track
> b_track
)
270 b_track
= mlt_properties_get_int( properties
, "a_track" );
273 // Only act on this operation once per multitrack iteration from the tractor
278 int a_frame
= a_track
;
279 int b_frame
= b_track
;
280 mlt_position position
;
281 int ( *invalid
)( mlt_frame
) = type
== 1 ? mlt_frame_is_test_card
: mlt_frame_is_test_audio
;
283 // Initialise temporary store
284 if ( this->frames
== NULL
)
285 this->frames
= calloc( sizeof( mlt_frame
), b_track
+ 1 );
287 // Get all frames between a and b
288 for( i
= a_track
; i
<= b_track
; i
++ )
289 mlt_service_get_frame( this->producer
, &this->frames
[ i
], i
);
291 // We're holding these frames until the last_track frame property is received
294 // When we need to locate the a_frame
299 // Some transitions (esp. audio) may accept blank frames
300 active
= accepts_blanks
;
302 // If we're not active then...
305 // Hunt for the a_frame
306 while( a_frame
<= b_frame
&& invalid( this->frames
[ a_frame
] ) )
309 // Determine if we're active now
310 active
= a_frame
!= b_frame
&& !invalid( this->frames
[ b_frame
] );
315 mlt_log( service
, MLT_LOG_ERROR
, "invalid transition type\n" );
319 // Now handle the non-always active case
320 if ( active
&& !always_active
)
322 // For non-always-active transitions, we need the current position of the a frame
323 position
= mlt_frame_get_position( this->frames
[ a_frame
] );
325 // If a is in range, we're active
326 active
= position
>= in
&& position
<= out
;
329 // Finally, process the a and b frames
332 mlt_frame a_frame_ptr
= this->frames
[ !reverse_order ? a_frame
: b_frame
];
333 mlt_frame b_frame_ptr
= this->frames
[ !reverse_order ? b_frame
: a_frame
];
334 int a_hide
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( a_frame_ptr
), "hide" );
335 int b_hide
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( b_frame_ptr
), "hide" );
336 if ( !( a_hide
& type
) && !( b_hide
& type
) )
338 // Process the transition
339 *frame
= mlt_transition_process( this, a_frame_ptr
, b_frame_ptr
);
341 // We need to ensure that the tractor doesn't consider this frame for output
342 if ( *frame
== a_frame_ptr
)
347 mlt_properties_set_int( MLT_FRAME_PROPERTIES( a_frame_ptr
), "hide", a_hide
);
348 mlt_properties_set_int( MLT_FRAME_PROPERTIES( b_frame_ptr
), "hide", b_hide
);
353 // Obtain the frame from the cache or the producer we're attached to
354 if ( index
>= a_track
&& index
<= b_track
)
355 *frame
= this->frames
[ index
];
357 error
= mlt_service_get_frame( this->producer
, frame
, index
);
359 // Determine if that was the last track
360 this->held
= !mlt_properties_get_int( MLT_FRAME_PROPERTIES( *frame
), "last_track" );
365 /** Close and destroy the transition.
367 * \public \memberof mlt_transition_s
368 * \param this a transition
371 void mlt_transition_close( mlt_transition
this )
373 if ( this != NULL
&& mlt_properties_dec_ref( MLT_TRANSITION_PROPERTIES( this ) ) <= 0 )
375 this->parent
.close
= NULL
;
376 if ( this->close
!= NULL
)
382 mlt_service_close( &this->parent
);
383 free( this->frames
);